package LBJ2.util;
import java.util.Arrays;
import java.util.Comparator;
/**
* This class implements an expandable array of objects that should be faster
* than java's <code>Vector</code>.
*
* @author Nick Rizzolo
**/
public class OVector implements Cloneable, java.io.Serializable
{
/** The default capacity of a vector upon first construction. */
protected static final int defaultCapacity = 8;
/** The elements of the vector. */
protected Object[] vector;
/** The number of elements in the vector. */
protected int size;
/**
* Constructs a new vector with capacity equal to {@link #defaultCapacity}.
**/
public OVector() { this(defaultCapacity); }
/**
* Constructs a new vector with the specified capacity.
*
* @param c The initial capacity for the new vector.
**/
public OVector(int c) { vector = new Object[Math.max(defaultCapacity, c)]; }
/**
* Constructs a new vector using the specified array as a starting point.
*
* @param v The initial array.
**/
public OVector(Object[] v) {
if (v.length == 0) vector = new Object[defaultCapacity];
else {
vector = v;
size = vector.length;
}
}
/**
* Constructs a copy of a vector starting with capacity equal to that
* vector's size.
*
* @param v The vector to copy.
**/
public OVector(OVector v) {
int N = v.size();
if (N == 0) vector = new Object[defaultCapacity];
else {
vector = new Object[N];
size = N;
System.arraycopy(v.vector, 0, vector, 0, N);
}
}
/**
* Throws an exception when the specified index is negative.
*
* @param i The index.
* @throws ArrayIndexOutOfBoundsException When <code>i</code> < 0.
**/
protected void boundsCheck(int i) {
if (i < 0)
throw
new ArrayIndexOutOfBoundsException(
"Attempted to access negative index of OVector.");
}
/**
* Retrieves the value stored at the specified index of the vector, or
* <code>null</code> if the vector isn't long enough.
*
* @param i The index of the value to retrieve.
* @return The retrieved value.
* @throws ArrayIndexOutOfBoundsException When <code>i</code> < 0.
**/
public Object get(int i) { return get(i, null); }
/**
* Retrieves the value stored at the specified index of the vector or
* <code>d</code> if the vector isn't long enough.
*
* @param i The index of the value to retrieve.
* @param d The default value.
* @return The retrieved value.
* @throws ArrayIndexOutOfBoundsException When <code>i</code> < 0.
**/
public Object get(int i, Object d) {
boundsCheck(i);
return i < size ? vector[i] : d;
}
/**
* Sets the value at the specified index to the given value.
*
* @param i The index of the value to set.
* @param v The new value at that index.
* @return The value that used to be at index <code>i</code>.
* @throws ArrayIndexOutOfBoundsException When <code>i</code> < 0.
**/
public Object set(int i, Object v) { return set(i, v, null); }
/**
* Sets the value at the specified index to the given value. If the given
* index is greater than the vector's current size, the vector will expand
* to accomodate it.
*
* @param i The index of the value to set.
* @param v The new value at that index.
* @param d The default value for other new indexes that might get
* created.
* @return The value that used to be at index <code>i</code>.
* @throws ArrayIndexOutOfBoundsException When <code>i</code> < 0.
**/
public Object set(int i, Object v, Object d) {
boundsCheck(i);
expandFor(i, d);
Object result = vector[i];
vector[i] = v;
return result;
}
/**
* Adds the specified value on to the end of the vector, expanding its
* capacity as necessary.
*
* @param v The new value to appear last in the vector.
**/
public void add(Object v) {
expandFor(size, null);
vector[size - 1] = v;
}
/**
* Adds all the values in the given vector to the end of this vector,
* expanding its capacity as necessary.
*
* @param v The new vector of values to appear at the end of this vector.
**/
public void addAll(OVector v) {
expandFor(size + v.size - 1, null);
System.arraycopy(v.vector, 0, vector, size - v.size, v.size);
}
/**
* Removes the element at the specified index of the vector.
*
* @param i The index of the element to remove.
* @return The removed element.
**/
public Object remove(int i) {
boundsCheck(i);
if (i >= size)
throw
new ArrayIndexOutOfBoundsException(
"LBJ: OVector: Can't remove element at index " + i
+ " as it is larger than the size (" + size + ")");
Object result = vector[i];
for (int j = i + 1; j < size; ++j)
vector[j - 1] = vector[j];
vector[--size] = null;
return result;
}
/** Returns the value of {@link #size}. */
public int size() { return size; }
/**
* Sorts this vector in increasing order according to the given comparator.
*
* @param c A comparator for the elements of this vector.
**/
public void sort(Comparator c) { Arrays.sort(vector, 0, size, c); }
/**
* Makes sure the capacity and size of the vector can accomodate the
* given index. The capacity of the vector is simply doubled until it can
* accomodate its size.
*
* @param index The index where a new value will be stored.
* @param d The default value for other new indexes that might get
* created.
**/
protected void expandFor(int index, Object d) {
if (index < size) return;
int oldSize = size, capacity = vector.length;
size = index + 1;
if (capacity >= size) return;
while (capacity < size) capacity *= 2;
Object[] t = new Object[capacity];
System.arraycopy(vector, 0, t, 0, oldSize);
if (d != null) Arrays.fill(t, oldSize, size, d);
vector = t;
}
/**
* Returns a new array of <code>objects</code>s containing the same data as
* this vector.
**/
public Object[] toArray() {
Object[] result = new Object[size];
System.arraycopy(vector, 0, result, 0, size);
return result;
}
/**
* Two <code>OVector</code>s are considered equal if they contain
* equivalent elements and have the same size.
**/
public boolean equals(Object o) {
if (!(o instanceof OVector)) return false;
OVector v = (OVector) o;
return size == v.size && Arrays.equals(vector, v.vector);
}
/** A hash code based on the hash code of {@link #vector}. */
public int hashCode() { return vector.hashCode(); }
/**
* Returns a shallow clone of this vector; the vector itself is cloned, but
* the element objects aren't.
**/
public Object clone() {
OVector clone = null;
try { clone = (OVector) super.clone(); }
catch (Exception e) {
System.err.println("Error cloning " + getClass().getName() + ":");
e.printStackTrace();
System.exit(1);
}
clone.vector = (Object[]) vector.clone();
return clone;
}
/** Returns a text representation of this vector. */
public String toString() {
StringBuffer result = new StringBuffer();
result.append("[");
for (int i = 0; i < size; ++i) {
result.append(vector[i]);
if (i + 1 < size) result.append(", ");
}
result.append("]");
return result.toString();
}
}