/* * @@COPYRIGHT@@ */ package com.cosylab.acs.maci; import java.io.Serializable; import java.io.ObjectOutputStream; import java.io.ObjectInputStream; import java.io.IOException; /** * A resizable, array of integer primitives. * * @author Matej Sekoranja (matej.sekoranja@cosylab.com) * @version @@VERSION@@ */ public class IntArray implements Serializable, Cloneable { /** * Serial version UID. */ private static final long serialVersionUID = -8356201427005323616L; /** * Default capacity for the array. */ private static final int DEFAULT_CAPACITY = 10; /** * Array data. * @serial */ protected transient int[] data; /** * Index of the first empty bucket (also size). * @serial */ private transient int pos; /** * Constrcuts a new <code>IntArray</code> instance with the default capacity. */ public IntArray() { this(DEFAULT_CAPACITY); } /** * Constrcuts a new <code>IntArray</code> instance with the specified capacity. * * @param capacity an <code>int</code> value */ public IntArray(int capacity) { data = new int[capacity]; pos = 0; } /** * Constrcuts a new <code>IntArray</code> instance whose * capacity is the greater of the length of <tt>values</tt> and * DEFAULT_CAPACITY and whose initial contents are the specified * values. * * @param values an <code>int[]</code> value */ public IntArray(int[] values) { this(Math.max(values.length, DEFAULT_CAPACITY)); add(values); } /** * Grow the internal array as needed to accomodate the specified * number of elements. The size of the array doubles on each * resize unless <tt>capacity</tt> requires more than twice the * current capacity. * * @param capacity an <code>int</code> value */ public void ensureCapacity(int capacity) { if (capacity > data.length) { int newCap = Math.max(data.length << 1, capacity); int[] tmp = new int[newCap]; System.arraycopy(data, 0, tmp, 0, data.length); data = tmp; } } /** * Returns the number of values in the list. * * @return the number of values in the list. */ public int size() { return pos; } /** * Tests whether this list contains any values. * * @return true if the list is empty. */ public boolean isEmpty() { return pos == 0; } /** * Sheds any excess capacity above and beyond the current size of the list. */ public void trimToSize() { if (data.length > size()) { int[] tmp = new int[size()]; toArray(tmp, 0, tmp.length); data = tmp; } } /** * Adds <tt>val</tt> to the end of the list, growing as needed. * * @param val an <code>int</code> value */ public void add(int val) { ensureCapacity(pos + 1); data[pos++] = val; } /** * Adds the values in the array <tt>vals</tt> to the end of the * list, in order. * * @param vals an <code>int[]</code> value */ public void add(int[] vals) { add(vals, 0, vals.length); } /** * Adds a subset of the values in the array <tt>vals</tt> to the * end of the list, in order. * * @param vals an <code>int[]</code> value * @param offset the offset at which to start copying * @param length the number of values to copy. */ public void add(int[] vals, int offset, int length) { ensureCapacity(pos + length); System.arraycopy(vals, offset, data, pos, length); pos += length; } /** * Inserts <tt>value</tt> into the list at <tt>offset</tt>. All * values including and to the right of <tt>offset</tt> are shifted * to the right. * * @param offset an <code>int</code> value * @param value an <code>int</code> value */ public void insert(int offset, int value) { if (offset == pos) { add(value); return; } ensureCapacity(pos + 1); // shift right System.arraycopy(data, offset, data, offset + 1, pos - offset); // insert data[offset] = value; pos++; } /** * Inserts the array of <tt>values</tt> into the list at * <tt>offset</tt>. All values including and to the right of * <tt>offset</tt> are shifted to the right. * * @param offset an <code>int</code> value * @param values an <code>int[]</code> value */ public void insert(int offset, int[] values) { insert(offset, values, 0, values.length); } /** * Inserts a slice of the array of <tt>values</tt> into the list * at <tt>offset</tt>. All values including and to the right of * <tt>offset</tt> are shifted to the right. * * @param offset an <code>int</code> value * @param values an <code>int[]</code> value * @param valOffset the offset in the values array at which to * start copying. * @param len the number of values to copy from the values array */ public void insert(int offset, int[] values, int valOffset, int len) { if (offset == pos) { add(values, valOffset, len); return; } ensureCapacity(pos + len); // shift right System.arraycopy(data, offset, data, offset + len, pos - offset); // insert System.arraycopy(values, valOffset, data, offset, len); pos += len; } /** * Returns the value at the specified offset. * * @param offset an <code>int</code> value * @return an <code>int</code> value */ public int get(int offset) { if (offset >= pos) throw new ArrayIndexOutOfBoundsException(offset); return data[offset]; } /** * Sets the value at the specified offset. * * @param offset an <code>int</code> value * @param val an <code>int</code> value */ public void set(int offset, int val) { if (offset >= pos) throw new ArrayIndexOutOfBoundsException(offset); data[offset] = val; } /** * Replace the values in the list starting at <tt>offset</tt> with * the contents of the <tt>values</tt> array. * * @param offset the first offset to replace * @param values the source of the new values */ public void set(int offset, int[] values) { set(offset, values, 0, values.length); } /** * Replace the values in the list starting at <tt>offset</tt> with * <tt>length</tt> values from the <tt>values</tt> array, starting * at valOffset. * * @param offset the first offset to replace * @param values the source of the new values * @param valOffset the first value to copy from the values array * @param length the number of values to copy */ public void set(int offset, int[] values, int valOffset, int length) { if (offset < 0 || offset + length >= pos) throw new ArrayIndexOutOfBoundsException(offset); System.arraycopy(data, offset, values, valOffset, length); } /** * Flushes the internal state of the list, resetting the capacity * to the default. */ public void clear() { clear(DEFAULT_CAPACITY); } /** * Flushes the internal state of the list, setting the capacity of * the empty list to <tt>capacity</tt>. * * @param capacity an <code>int</code> value */ public void clear(int capacity) { data = new int[capacity]; pos = 0; } /** * Removes the value at <tt>offset</tt> from the list. * * @param offset an <code>int</code> value * @return the value previously stored at offset. */ public int removeAt(int offset) { int old = get(offset); removeAt(offset, 1); return old; } /** * Removes the element with value <tt>value</tt> from the list. * * @param value value of the element to be removed * @return ofset of the removed element, -1 on failure. */ public int remove(int value) { for (int i = pos; i-- > 0;) if (data[i] == value) { removeAt(i, 1); return i; } return -1; } /** * Removes <tt>length</tt> values from the list, starting at * <tt>offset</tt> * * @param offset an <code>int</code> value * @param length an <code>int</code> value */ public void removeAt(int offset, int length) { if (offset < 0 || offset >= pos) throw new ArrayIndexOutOfBoundsException(offset); if (offset == 0) { // data at the front System.arraycopy(data, length, data, 0, pos - length); } else if (pos - length == offset) { // no copy to make, decrementing pos "deletes" values at the end } else { // data in the middle System.arraycopy(data, offset + length, data, offset, pos - (offset + length)); } pos -= length; } /** * Returns a clone of this list. Since this is a primitive * collection, this will be a deep clone. * * @return a deep clone of the list. */ public Object clone() { IntArray clone = null; try { clone = (IntArray)super.clone(); clone.data = (int[])data.clone(); } catch (CloneNotSupportedException e) { // it's supported } return clone; } /** * Copies the contents of the list into a native array. * * @return an <code>int[]</code> value */ public int[] toArray() { return toArray(0, pos); } /** * Copies a slice of the list into a native array. * * @param offset the offset at which to start copying * @param len the number of values to copy. * @return an <code>int[]</code> value */ public int[] toArray(int offset, int len) { int[] rv = new int[len]; toArray(rv, offset, len); return rv; } /** * Copies a slice of the list into a native array. * * @param dest the array to copy into. * @param offset the offset of the first value to copy * @param len the number of values to copy. */ public void toArray(int[] dest, int offset, int len) { if (len == 0) return; if (offset < 0 || offset >= pos) throw new ArrayIndexOutOfBoundsException(offset); System.arraycopy(data, offset, dest, 0, len); } // comparing /** * Compares this list to another list, value by value. * * @param other the object to compare against * @return true if other is a TIntArrayList and has exactly the * same values. */ public boolean equals(Object other) { if (other == this) return true; if (other instanceof IntArray) { IntArray that = (IntArray)other; if (that.size() != this.size()) return false; else { for (int i = pos; i-- > 0;) if (this.data[i] != that.data[i]) return false; return true; } } return false; } /** * Returns the hash code value for this list. <p> * * This implementation uses exactly the code that is used to define the * list hash function in the documentation for the <tt>List.hashCode</tt> * method. * * @return the hash code value for this list. */ public int hashCode() { int h = 0; for (int i = pos; i-- > 0;) h += data[i]; return h; } /** * Searches the list for <tt>value</tt> * * @param value an <code>int</code> value * @return true if value is in the list. */ public boolean contains(int value) { for (int i = pos; i-- > 0;) if (data[i] == value) return true; return false; } /** * Returns a String representation of the list, front to back. * * @return a <code>String</code> value */ public String toString() { StringBuffer buf = new StringBuffer("{"); for (int i = 0; i < pos; i++) { buf.append(data[i]); if (i != pos-1) buf.append(", "); } buf.append("}"); return buf.toString(); } /** * Save the state of the <tt>ArrayList</tt> instance to a stream (that * is, serialize it). * * @serialData The length of the array backing the <tt>ArrayList</tt> * instance is emitted (int), followed by all of its elements * (each an <tt>Object</tt>) in the proper order. */ private void writeObject(ObjectOutputStream stream) throws IOException { stream.defaultWriteObject(); // write out array length stream.writeInt(pos); // write out all elements in the proper order. for (int i = 0; i < pos; i++) stream.writeInt(data[i]); } /** * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is, * deserialize it). */ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); // read in array length and allocate array int size = stream.readInt(); data = new int[size]; // fill array for (int i = 0; i < size; i++) data[i] = stream.readInt(); // set size pos = size; } }