package java.util;
/**
* An expandable array.
*
* @author Andre Nijholt
* @author Sven Köhler
* @param <E> type of the elements
*/
public class ArrayList<E> extends AbstractList<E> implements RandomAccess
{
private static final int INITIAL_CAPACITY = 10;
private static final int CAPACITY_INCREMENT_NUM = 3; //numerator of the increment factor
private static final int CAPACITY_INCREMENT_DEN = 2; //denominator of the increment factor
//MISSING implements Clonable
//MISSING implements Serializable
private class MyIterator implements ListIterator<E>
{
private int modcount;
private int lastpos;
private int nextpos;
public MyIterator(int index)
{
this.lastpos = -1;
this.nextpos = index;
this.modcount = ArrayList.this.modCount;
}
private void checkModCount()
{
if (this.modcount != ArrayList.this.modCount)
throw new ConcurrentModificationException();
}
private void checkLastPos()
{
if (this.lastpos < 0)
throw new IllegalStateException();
}
public boolean hasNext()
{
return this.nextpos < ArrayList.this.size();
}
public boolean hasPrevious()
{
return this.nextpos > 0;
}
public E next()
{
this.checkModCount();
if (!this.hasNext())
throw new NoSuchElementException();
return ArrayList.this.get(this.lastpos = this.nextpos++);
}
public E previous()
{
this.checkModCount();
if (!this.hasPrevious())
throw new NoSuchElementException();
return ArrayList.this.get(this.lastpos = --this.nextpos);
}
public void remove()
{
this.checkLastPos();
this.checkModCount();
ArrayList.this.remove(this.lastpos);
this.modcount = ArrayList.this.modCount;
this.lastpos = -1;
}
public void set(E e)
{
this.checkLastPos();
this.checkModCount();
ArrayList.this.set(this.lastpos, e);
}
public void add(E e)
{
this.checkModCount();
ArrayList.this.add(this.nextpos, e);
this.modcount = ArrayList.this.modCount;
this.lastpos = -1;
}
public int nextIndex()
{
return this.nextpos;
}
public int previousIndex()
{
return this.nextpos - 1;
}
}
private int elementCount;
private Object[] elementData;
protected transient int modCount;
/**
* Create an array list.
*/
public ArrayList()
{
elementCount = 0;
elementData = new Object[INITIAL_CAPACITY];
}
public ArrayList(Collection<? extends E> c)
{
this(c.size());
this.addAll(c);
}
/**
* Create an array list.
*
* @param initialCapacity The initial size of the array list.
*/
public ArrayList(int initialCapacity)
{
if (initialCapacity < 0)
throw new IllegalArgumentException("capacity is negative");
elementCount = 0;
elementData = new Object[initialCapacity];
}
/**
* Create an array list.
*
* @param elements The initial elements in the array list.
* @deprecated not in JDK
*/
@Deprecated
public ArrayList(E[] elements)
{
this((elements.length * 13) / 10);
addAll(elements);
}
/**
* Add a element at a specific index.
*
* @param index The index at which the element should be added.
* @param element The element to add.
*/
public void add(int index, E element)
{
if (index < 0 || index > elementCount)
throw new IndexOutOfBoundsException();
ensureCapacity(elementCount + 1);
//overlapping source/target area should work
System.arraycopy(elementData, index, elementData, index+1, elementCount-index);
elementData[index] = element;
elementCount++;
}
/**
* Add a element at the end of the array list.
*
* @param element The element to add.
*/
public boolean add(E element)
{
ensureCapacity(elementCount + 1);
elementData[elementCount++] = element;
return true;
}
/**
* Add all elements from the array to the array list.
*
* @param elements The array of elements to add.
* @deprecated not in JDK
*/
@Deprecated
public void addAll(E[] elements)
{
int len = elements.length;
if (len <= 0)
return;
ensureCapacity(elementCount + len);
System.arraycopy(elements, 0, elementData, elementCount, len);
elementCount += len;
}
/**
* Add all elements from the array to the array list at a specific index.
*
* @param index The index to start adding elements.
* @param elements The array of elements to add.
* @deprecated not in JDK
*/
@Deprecated
public void addAll(int index, E[] elements)
{
if (index < 0 || index > elementCount)
throw new IndexOutOfBoundsException();
int len = elements.length;
if (len <= 0)
return;
ensureCapacity(elementCount + len);
System.arraycopy(elementData, index, elementData, index+len, elementCount - index);
System.arraycopy(elements, 0, elementData, index, len);
elementCount += len;
}
@Override
public boolean addAll(Collection<? extends E> c)
{
return this.addAll(elementCount, c);
}
public boolean addAll(int index, Collection<? extends E> c)
{
if (index < 0 || index > elementCount)
throw new IndexOutOfBoundsException();
int size = c.size();
if (size <= 0)
return false;
this.ensureCapacity(elementCount + size);
System.arraycopy(elementData, index, elementData, index+size, elementCount - index);
Iterator<? extends E> i = c.iterator();
for (int j=0; j<size; j++)
elementData[index + j] = i.next();
elementCount += size;
return true;
}
/**
* Clear the array list.
*/
public void clear()
{
modCount++;
for (int i = 0; i < elementCount; i++)
elementData[i] = null;
elementCount = 0;
}
/**
* Ensure that we have sufficient capacity in the array to store
* the requested number of elements. Expand the array if required.
* @param minCapacity
*/
public void ensureCapacity(int minCapacity)
{
modCount++;
int el = elementData.length;
if (el < minCapacity)
{
el = el * CAPACITY_INCREMENT_NUM / CAPACITY_INCREMENT_DEN + 1;
while (el < minCapacity)
el = el * CAPACITY_INCREMENT_NUM / CAPACITY_INCREMENT_DEN + 1;
Object[] newData = new Object[el];
System.arraycopy(elementData, 0, newData, 0, elementCount);
elementData = newData;
}
}
/**
* Get a specific element.
*
* @param index The index of the wanted element.
* @return The wanted element.
*/
@SuppressWarnings("unchecked")
public E get(int index)
{
if (index < 0 || index >= elementCount)
throw new IndexOutOfBoundsException();
return (E)elementData[index];
}
/**
* Get the first index of a specific element.
*
* @param element The wanted element.
* @return The index of the wanted element, or -1 if not found.
*/
public int indexOf(Object element)
{
if (element == null)
{
for (int i = 0; i < elementCount; i++)
if (elementData[i] == null)
return i;
}
else
{
for (int i = 0; i < elementCount; i++)
if (element.equals(elementData[i]))
return i;
}
return -1;
}
/**
* Get the last index of a specific element.
*
* @param element The wanted element.
* @return The index of the wanted element, or -1 if not found.
*/
public int lastIndexOf(Object element)
{
if (element == null)
{
for (int i = elementCount -1; i >= 0; i--)
if (elementData[i] == null)
return i;
}
else
{
for (int i = elementCount -1; i >= 0; i--)
if (element.equals(elementData[i]))
return i;
}
return -1;
}
/**
* Remove a element at a specific index.
*
* @param index The index of the element to remove.
* @return the removed element.
*/
@SuppressWarnings("unchecked")
public E remove(int index)
{
if (index < 0 || index >= elementCount)
throw new IndexOutOfBoundsException();
modCount++;
Object element = elementData[index];
System.arraycopy(elementData, index + 1, elementData, index, elementCount - index - 1);
elementData[--elementCount] = null;
return (E)element;
}
public boolean remove(Object o)
{
int i = this.indexOf(o);
if (i < 0)
return false;
this.remove(i);
return true;
}
protected void removeRange(int start, int end)
{
if (start <= 0)
throw new IndexOutOfBoundsException();
if (end > elementCount)
throw new IndexOutOfBoundsException();
if (start > end)
throw new IndexOutOfBoundsException();
if (start == end)
return;
this.modCount++;
int oldcount = elementCount;
int newcount = oldcount - end + start;
System.arraycopy(elementData, end, elementData, start, oldcount - end);
for (int i=newcount; i<oldcount; i++)
elementData[i] = null;
elementCount = newcount;
}
/**
* Replace an element at a specific index with a new element.
*
* @param index The index of the element to set.
* @param element The new element.
* @return the old element.
*/
@SuppressWarnings("unchecked")
public E set(int index, E element)
{
if (index >= elementCount)
throw new IndexOutOfBoundsException();
Object o = elementData[index];
elementData[index] = element;
return (E)o;
}
/**
* Get the number of elements in this array list.
*
* @return the number of elements.
*/
public int size()
{
return elementCount;
}
public ListIterator<E> listIterator(int index)
{
return new MyIterator(index);
}
public List<E> subList(int start, int end)
{
//TODO implement
throw new UnsupportedOperationException("subList not yet supported");
}
public void trimToSize()
{
if (elementCount < elementData.length)
{
modCount++;
Object[] newData = new Object[elementCount];
System.arraycopy(elementData, 0, newData, 0, elementCount);
elementData = newData;
}
}
}