package xxl.core.collections.containers;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.NoSuchElementException;
import xxl.core.cursors.mappers.Mapper;
import xxl.core.cursors.sources.Enumerator;
import xxl.core.functions.AbstractFunction;
import xxl.core.functions.Function;
import xxl.core.io.converters.FixedSizeConverter;
import xxl.core.io.converters.LongConverter;
/**
* Stores entries in {@link ArrayList}. Long values represents index values.
* Note this main memory container does not support remove operation!
* Maximal number of objects are limited by positive integer value.
*
*/
public class ArrayContainer extends AbstractContainer{
private ArrayList<Object> array;
/**
* A unique object used to identify mappings where no object has been
* assigned to so far.
*/
protected static final Object empty = new Object();
/**
* A counter that is used to create unique ids. Everytime an object is
* inserted into the container the counter is increased and a
* <tt>Long</tt> object with the actual value of the counter is
* returned as id.
*/
protected int counter = 0;
/**
*
* @param initialSize
*/
public ArrayContainer(int initialSize){
array = new ArrayList<Object>(initialSize);
}
/**
*
*/
public ArrayContainer(){
this(2048);
}
/**
* Returns a converter for the ids generated by this container. A
* converter transforms an object to its byte representation and vice
* versa - also known as serialization in Java.<br>
* Because this container is returning <tt>Long</tt> objects as ids
* the converter <code>LongConverter.DEFAULT_INSTANCE</code> is
* returned.
*
* @return a converter for serializing the identifiers of the
* container.
* @see LongConverter#DEFAULT_INSTANCE
*/
public FixedSizeConverter objectIdConverter () {
return LongConverter.DEFAULT_INSTANCE;
}
/**
* Returns the size of the ids generated by this container in bytes,
* which is 8.
* @return 8
*/
public int getIdSize() {
return LongConverter.SIZE;
}
/**
* Removes all elements from this container. After a call of this
* method, <tt>size()</tt> will return 0.
*/
public void clear () {
array.clear();
}
/**
* Returns <tt>true</tt> if there is an object stored within the container
* having the identifier <tt>id</tt>.
*
* @param id identifier of the object.
* @return true if the container contains an object for the specified
* identifier.
*/
public boolean contains (Object id) {
int index = ((Long)id).intValue();
return index < array.size();
}
/**
* Returns the object associated to the identifier <tt>id</tt>. An
* exception is thrown if there is not object stored with this
* <tt>id</tt>. The parameter <tt>unfix</tt> has no function because this
* container is unbuffered.
*
* @param id identifier of the object.
* @param unfix signals whether the object can be removed from the
* underlying buffer.
* @return the object associated to the specified identifier.
* @throws NoSuchElementException if the desired object is not found.
*/
public Object get (Object id, boolean unfix) throws NoSuchElementException {
if (!contains(id))
throw new NoSuchElementException();
else{
int index = ((Long)id).intValue();
return array.get(index);
}
}
/**
* Returns an iterator that delivers all the identifiers of
* the container that are in use.
*
* @return an iterator of all identifiers used by this container.
*/
public Iterator ids () {
return new Mapper<Integer, Long>(new AbstractFunction<Integer, Long>() {
@Override
public Long invoke(Integer argument) {
return Long.valueOf(argument.longValue());
}
}, new Enumerator(array.size())) ;
}
/**
* Inserts a new object into the container and returns the unique
* identifier that the container has been associated to the object.
* This container uses a counter to generate an unique id. Everytime
* an object is inserted into the container the counter is increased
* and a <tt>Long</tt> object with the actual value of the counter is
* returned as id. So the identifier will not be reused again when the
* object is deleted from the container. The parameter <tt>unfix</tt>
* has no function because this container is unbuffered.
*
* @param object is the new object.
* @param unfix signals a buffered container whether the object can
* be removed from the underlying buffer.
* @return the identifier of the object.
*/
public Object insert (Object object, boolean unfix) {
int id = counter++;
array.add(object);
return Long.valueOf(id);
}
/**
* Checks whether the <tt>id</tt> has been returned previously by a
* call to insert or reserve and hasn't been removed so far.
*
* @param id the id to be checked.
* @return true exactly if the <tt>id</tt> is still in use.
*/
public boolean isUsed (Object id) {
int index = ((Long)id).intValue();
return index < array.size();
}
/**
* this method always throws {@link UnsupportedOperationException}, since this main memory container does not support remove operations.
* @throws UnsupportedOperationException
*/
public void remove (Object id) throws NoSuchElementException {
throw new UnsupportedOperationException("Array container does not support Remove Operation!");
}
/**
* Reserves an id for subsequent use. The container may or may not
* need an object to be able to reserve an id, depending on the
* implementation. If so, it will call the parameterless function
* provided by the parameter <tt>getObject</tt>.
*
* @param getObject A parameterless function providing the object for
* that an id should be reserved.
* @return the reserved id.
*/
public Object reserve (Function getObject) {
int id = counter++;
array.add(empty);
return Long.valueOf(id);
}
/**
* Returns the number of elements of the container.
*
* @return the number of elements.
*/
public int size () {
return array.size();
}
/**
* Overwrites an existing (id,*)-element by (id, object). This method
* throws an exception if an object with an identifier <tt>id</tt>
* does not exist in the container.
*
* @param id identifier of the element.
* @param object the new object that should be associated to
* <tt>id</tt>.
* @param unfix signals a buffered container whether the object can
* be removed from the underlying buffer.
* @throws NoSuchElementException if an object with an identifier
* <tt>id</tt> does not exist in the container.
*/
public void update (Object id, Object object, boolean unfix) throws NoSuchElementException {
if (isUsed(id)) {
int index = ((Long)id).intValue();
array.set(index, object);
}
else
throw new NoSuchElementException();
}
}