/*
* Copyright (c) 2009-2015
* IT-Consulting Stephan Schloepke (http://www.schloepke.de/)
* klemm software consulting Mirko Klemm (http://www.klemm-scs.com/)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jbasics.arrays;
import org.jbasics.annotation.ImmutableState;
import org.jbasics.annotation.ThreadSafe;
import org.jbasics.arrays.unstable.ArrayIterator;
import org.jbasics.checker.ContractCheck;
import org.jbasics.checker.ContractViolationException;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/**
* A collection which is directly backed by an array. The collection itself does not offer any operation to change
* therefore the collection is immutable itself. However since the array given is not copied any change to the array
* will be reflected in this collection as well!
* <p>
* FIXME: Currently this class is under consolidation and most likely will be removed since there is no real
* benefit compared to Arrays.asList(...) which does exactly the same. It seems that the Arrays.asList is not as
* nice like this collection. The idea of this class here is to actually have an immutable array as collection.
* Arrays version is mutable to the content while not to the length.
* </p>
*
* @param <T> The type of the array collection.
*
* @author Stephan Schloepke
* @since 1.0
*/
@ThreadSafe(derived = true)
@ImmutableState(derived = true)
public class ArrayCollection<T> implements List<T> {
private final T[] data;
private final int offset;
private final int size;
/**
* Creates an {@link ArrayCollection} with the given data. The data is copied and therefore the resulting
* collection
* is immutable!
*
* @param data The data to create the collection for (NOT copied and must NOT be null)
*
* @throws ContractViolationException If the given data is null.
* @since 1.0
*/
public ArrayCollection(final T... data) {
this(ContractCheck.mustNotBeNull(data, "data").clone(), 0, data.length); //$NON-NLS-1$
}
/**
* Creates an {@link ArrayCollection} with the given data. The data is NOT copied and therefore any change to the
* array will also lead to a change in the collection! However since this method is only reachable by {@link
* #subList(int, int)} it does not affect the immutability. The contract here MUST guarantee that the caller of
* this
* constructor never changes the given array at all!
*
* @param data The data to create the collection for (NOT copied and must NOT be null)
*
* @throws ContractViolationException If the given data is null.
* @since 1.0
*/
protected ArrayCollection(final T[] data, final int offset, final int size) {
this.data = ContractCheck.mustNotBeNull(data, "data"); //$NON-NLS-1$
this.offset = offset;
this.size = size;
}
/*
* (non-Javadoc)
*
* @see java.util.Collection#size()
*/
@Override
public int size() {
return this.size;
}
/*
* (non-Javadoc)
*
* @see java.util.Collection#isEmpty()
*/
@Override
public boolean isEmpty() {
return this.size == 0;
}
/*
* (non-Javadoc)
*
* @see java.util.Collection#contains(java.lang.Object)
*/
@Override
public boolean contains(final Object obj) {
for (int i = 0; i < this.size; i++) {
final Object current = this.data[i + this.offset];
if (current == obj || current != null && current.equals(obj)) {
return true;
}
}
return false;
}
/*
* (non-Javadoc)
*
* @see java.util.Collection#iterator()
*/
@Override
public Iterator<T> iterator() {
return new ArrayIterator<T>(this.offset, this.size, this.data);
}
/*
* (non-Javadoc)
*
* @see java.util.Collection#toArray()
*/
@Override
public Object[] toArray() {
final Object[] dest = new Object[this.size];
System.arraycopy(this.data, this.offset, dest, 0, this.size);
return dest;
}
/*
* (non-Javadoc)
*
* @see java.util.Collection#toArray(T[])
*/
@Override
public <TA> TA[] toArray(final TA[] dest) {
@SuppressWarnings("unchecked") final TA[] destination = dest.length >= this.size ? dest : (TA[]) Array.newInstance(dest.getClass()
.getComponentType(), this.size);
System.arraycopy(this.data, this.offset, destination, 0, this.size);
return destination;
}
/**
* Operation is not supported.
*
* @see java.util.Collection#add(java.lang.Object)
*/
@Override
public boolean add(final T e) {
throw new UnsupportedOperationException("Unsuported for imutable array collection"); //$NON-NLS-1$
}
/**
* Operation is not supported.
*
* @see java.util.Collection#remove(java.lang.Object)
*/
@Override
public boolean remove(final Object o) {
throw new UnsupportedOperationException("Unsuported for imutable array collection"); //$NON-NLS-1$
}
/*
* (non-Javadoc)
*
* @see java.util.Collection#containsAll(java.util.Collection)
*/
@Override
public boolean containsAll(final Collection<?> c) {
for (final Object obj : c) {
if (!contains(obj)) {
return false;
}
}
return true;
}
/**
* Operation is not supported.
*
* @see java.util.Collection#addAll(java.util.Collection)
*/
@Override
public boolean addAll(final Collection<? extends T> c) {
throw new UnsupportedOperationException("Unsuported for imutable array collection"); //$NON-NLS-1$
}
/**
* Operation is not supported.
*
* @see java.util.List#addAll(int, java.util.Collection)
*/
@Override
public boolean addAll(final int index, final Collection<? extends T> c) {
throw new UnsupportedOperationException("Unsuported for imutable array collection"); //$NON-NLS-1$
}
/**
* Operation is not supported.
*
* @see java.util.Collection#removeAll(java.util.Collection)
*/
@Override
public boolean removeAll(final Collection<?> c) {
throw new UnsupportedOperationException("Unsuported for imutable array collection"); //$NON-NLS-1$
}
/**
* Operation is not supported.
*
* @see java.util.Collection#retainAll(java.util.Collection)
*/
@Override
public boolean retainAll(final Collection<?> c) {
throw new UnsupportedOperationException("Unsuported for imutable array collection"); //$NON-NLS-1$
}
// The rest is unsupported since optional and not interesting for an immutable collection.
/**
* Operation is not supported.
*
* @see java.util.Collection#clear()
*/
@Override
public void clear() {
throw new UnsupportedOperationException("Unsuported for imutable array collection"); //$NON-NLS-1$
}
/*
* (non-Javadoc)
*
* @see java.util.List#get(i)
*/
@Override
public T get(final int index) {
if (index >= this.size) {
throw new IndexOutOfBoundsException();
}
return this.data[index + this.offset];
}
/**
* Operation is not supported.
*
* @see java.util.List#set(int, java.lang.Object)
*/
@Override
public T set(final int index, final T element) {
throw new UnsupportedOperationException("Unsuported for imutable array collection"); //$NON-NLS-1$
}
/**
* Operation is not supported.
*
* @see java.util.List#add(int, java.lang.Object)
*/
@Override
public void add(final int index, final T element) {
throw new UnsupportedOperationException("Unsuported for imutable array collection"); //$NON-NLS-1$
}
/**
* Operation is not supported.
*
* @see java.util.List#remove(int)
*/
@Override
public T remove(final int index) {
throw new UnsupportedOperationException("Unsuported for imutable array collection"); //$NON-NLS-1$
}
/*
* (non-Javadoc)
*
* @see java.util.List#indexOf(java.lang.Object)
*/
@Override
public int indexOf(final Object check) {
if (check == null) {
for (int i = 0; i < this.size; i++) {
if (this.data[i + this.offset] == null) {
return i;
}
}
} else {
for (int i = 0; i < this.size; i++) {
final T dataElement = this.data[i + this.offset];
if (check == dataElement || check.equals(dataElement)) {
return i;
}
}
}
return -1;
}
/*
* (non-Javadoc)
*
* @see java.util.List#lastIndexOf(java.lang.Object)
*/
@Override
public int lastIndexOf(final Object check) {
if (check == null) {
for (int i = this.size - 1; i >= 0; i--) {
if (this.data[i + this.offset] == null) {
return i;
}
}
} else {
for (int i = this.size - 1; i >= 0; i--) {
final T dataElement = this.data[i + this.offset];
if (check == dataElement || check.equals(dataElement)) {
return i;
}
}
}
return -1;
}
/*
* (non-Javadoc)
*
* @see java.util.List#listIterator()
*/
@Override
public ListIterator<T> listIterator() {
return new ArrayIterator<T>(this.offset, this.size, this.data);
}
/*
* (non-Javadoc)
*
* @see java.util.List#listIterator(int)
*/
@Override
public ListIterator<T> listIterator(final int index) {
return new ArrayIterator<T>(index, this.offset, this.size, this.data);
}
/*
* (non-Javadoc)
*
* @see java.util.List#subList(int, int)
*/
@Override
public List<T> subList(final int fromIndex, final int toIndex) {
if (fromIndex < 0 || toIndex + this.offset > this.data.length || fromIndex > toIndex) {
throw new IndexOutOfBoundsException();
}
return new ArrayCollection<T>(this.data, this.offset + fromIndex, toIndex - fromIndex);
}
}