/*
* Kodkod -- Copyright (c) 2005-present, Emina Torlak
*
* 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 kodkod.util.ints;
/**
* A mutable implementation of the <tt>IntVector</tt> interface. Implements
* all optional IntVector operations. In addition to implementing the <tt>IntVector</tt> interface,
* this class provides methods to manipulate the size of the array that is
* used internally to store the elements of the IntVector. <p>
*
* The <tt>size</tt>, <tt>isEmpty</tt>, <tt>get</tt>, <tt>set</tt>,
* and <tt>iterator</tt> operations run in constant
* time. The <tt>insert</tt> operations run in <i>amortized constant time</i>,
* that is, adding n elements requires O(n) time. All of the other operations
* run in linear time (roughly speaking). <p>
*
* Each <tt>MutableIntVector</tt> instance has a <i>capacity</i>. The capacity is
* the size of the array used to store the elements in the list. It is always
* at least as large as the list size. As elements are added to a MutableIntVector,
* its capacity grows automatically. The details of the growth policy are not
* specified beyond the fact that adding an element has constant amortized
* time cost.<p>
*
* An application can increase the capacity of an <tt>MutableIntVector</tt> instance
* before adding a large number of elements using the <tt>ensureCapacity</tt>
* operation. This may reduce the amount of incremental reallocation.<p>
*
* This impementation is not synchronized and its iterators are not fail-fast.
*
* @author Emina Torlak
*/
public final class ArrayIntVector extends AbstractIntVector {
private int[] elements;
private int size;
/**
* Constructs an empty <tt>MutableIntVector</tt> with the specified initial capacity.
*
* @exception IllegalArgumentException if the specified initial capacity
* is negative
*/
public ArrayIntVector(int initialCapacity) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elements = new int[initialCapacity];
}
/**
* Constructs an empty <tt>MutableIntVector</tt> with an initial capacity of ten.
*/
public ArrayIntVector() {
this(10);
}
/**
* Constructs a <tt>MutableIntVector</tt> containing the elements of the specified
* array, in proper sequence. The <tt>MutableIntVector</tt> instance has an initial capacity of
* 110% the size of the specified collection.
*
* @throws NullPointerException if the specified array is null.
*/
public ArrayIntVector(int[] array) {
size = array.length;
// Allow 10% room for growth
int capacity = (int) Math.min((size*110L)/100, Integer.MAX_VALUE);
elements = new int[capacity];
System.arraycopy(array, 0, elements, 0, size);
}
/**
* Trims the capacity of this <tt>MutableIntVector</tt> instance to be the
* list's current size. An application can use this operation to minimize
* the storage of an <tt>MutableIntVector</tt> instance.
*/
public void trimToSize() {
int oldCapacity = elements.length;
if (size < oldCapacity) {
int[] oldData = elements;
elements = new int[size];
System.arraycopy(oldData, 0, elements, 0, size);
}
}
/**
* Increases the capacity of this <tt>MutableIntVector</tt> instance, if
* necessary, to ensure that it can hold at least the number of elements
* specified by the minimum capacity argument.
*/
public void ensureCapacity(int minCapacity) {
int oldCapacity = elements.length;
if (minCapacity > oldCapacity) {
int[] oldData = elements;
int newCapacity = (oldCapacity * 3)/2 + 1;
if (newCapacity < minCapacity)
newCapacity = minCapacity;
elements = new int[newCapacity];
System.arraycopy(oldData, 0, elements, 0, size);
}
}
/**
* @throws IndexOutOfBoundsException index < 0 or index >= size
*/
private void checkExcludeLength(int index) {
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException();
}
/**
* @throws IndexOutOfBoundsException index < 0 or index > size
*/
private void checkIncludeLength(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException();
}
/**
* {@inheritDoc}
* @see kodkod.util.ints.IntVector#get(int)
*/
public int get(int index) {
checkExcludeLength(index);
return elements[index];
}
/**
* {@inheritDoc}
* @see kodkod.util.ints.IntVector#size()
*/
public int size() {
return size;
}
/**
* {@inheritDoc}
* @see kodkod.util.ints.IntVector#set(int, int)
*/
@Override
public int set(int index, int element) {
final int oldValue = get(index);
elements[index] = element;
return oldValue;
}
/**
* {@inheritDoc}
* @see kodkod.util.ints.IntVector#add(int)
*/
@Override
public boolean add(int element) {
ensureCapacity(size+1);
elements[size++] = element;
return true;
}
/**
* {@inheritDoc}
* @see kodkod.util.ints.IntVector#add(int, int)
*/
@Override
public void add(int index, int element) {
checkIncludeLength(index);
ensureCapacity(size+1);
System.arraycopy(elements, index, elements, index + 1, size - index);
elements[index] = element;
size++;
}
/**
* {@inheritDoc}
* @see kodkod.util.ints.IntVector#addAll(int, kodkod.util.ints.IntCollection)
*/
@Override
public boolean addAll(int index, IntCollection c) {
checkIncludeLength(index);
final int csize = c.size();
if (csize==0) return false;
ensureCapacity(size+csize);
System.arraycopy(elements, index, elements, index + csize, size - index);
for(IntIterator iter = c.iterator(); iter.hasNext(); ) {
elements[index++] = iter.next();
}
return true;
}
/**
* {@inheritDoc}
* @see kodkod.util.ints.AbstractIntVector#removeAt(int)
*/
@Override
public int removeAt(int index) {
checkExcludeLength(index);
final int old = elements[index];
System.arraycopy(elements, index+1, elements, index, size - index - 1);
size--;
return old;
}
/**
* {@inheritDoc}
* @see kodkod.util.ints.AbstractIntCollection#toArray(int[])
*/
@Override
public int[] toArray(int[] array) {
if (array.length < size) {
array = new int[size];
}
System.arraycopy(elements, 0, array, 0, size);
return array;
}
}