//-< ArrayOfChar.java >----------------------------------------------*--------* // GOODS Version 2.02 (c) 1998 GARRET * ? * // (Generic Object Oriented Database System) * /\| * // GOODS Persistent Class Library * / \ * // Created: 1-Oct-98 K.A. Knizhnik * / [] \ * // Last update: 15-Oct-98 K.A. Knizhnik * GARRET * //-------------------------------------------------------------------*--------* // Dynamic array of chars //-------------------------------------------------------------------*--------* package goodslib; import goodsjpi.*; /** * ArrayOfChar is just that, an array of chars. It is fully * persistent, as it it's derived from Persistent. All reads cause a fetch of the * data, all writes mark it dirty and to be saved. * * @author K.A. Knizhnik * @version 1.0 */ public class ArrayOfChar extends AnyArray implements Comparable { /** * array holds the chars in an [] */ protected char[] array; /** * Creates a new ArrayOfChar instance. * * @param size is the initial size, (length) */ public ArrayOfChar(int size) { this(size, size == 0 ? 16 : size); } /** * Creates a new ArrayOfChar instance. (Full of false) * * @param size , or length of the array * @param allocatedSize is the size it can grow to without re-sizing */ public ArrayOfChar(int size, int allocatedSize) { Assert.that(size <= allocatedSize); array = new char[allocatedSize]; used = size; } /** * Creates a new ArrayOfChar instance, as a copy of the given * char[] * * @param src a char[] that will be copied */ public ArrayOfChar(char[] src) { int length = src.length; array = new char[length]; used = length; System.arraycopy(src, 0, array, 0, length); } /** * Creates a new ArrayOfChar instance. * * @param str a String value */ public ArrayOfChar(String str) { int length = str.length(); array = new char[length]; used = length; str.getChars(0, length, array, 0); } /** * Put a char value at a given index * * @param index an int value, where the value should be set * @param value the char value to be set */ public synchronized void putAt(int index, char value) { if (index < 0 || index >= used) { throw new ArrayIndexOutOfBoundsException(index); } Metaobject.modify(); array[index] = value; } /** * Get a char at the specified index * * @param index of the char you want * @return a char value, at index "index" */ public synchronized char getAt(int index) { if (index < 0 || index >= used) { throw new ArrayIndexOutOfBoundsException(index); } return array[index]; } /** * Resize the amount of space taken by the array. Either grow or shrink as * necessary. You get an IndexOutOfBoundException for negative values.
* of course the old data is copied. * * @param newSize an int denoting the new size. */ public synchronized void changeSize(int newSize) { if (newSize < 0) { throw new ArrayIndexOutOfBoundsException(newSize); } int allocated = array.length; if (newSize > allocated) { allocated = (allocated*2 > newSize) ? allocated*2 : newSize; char[] newArray = new char[allocated]; System.arraycopy(array, 0, newArray, 0, used); array = newArray; } else if (newSize < used) { for (int i = used; --i >= newSize; array[i] = 0); } used = newSize; } /** * insert a "count" amount of values at a given index. Throws an * IndexOutOfBoundsException for too small (<0) or too big (>length) count or index. * * @param index , where to start inserting value(s) * @param count , how many values to insert * @param value a char value to insert */ public synchronized void insert(int index, int count, char value) { if (count < 0) { throw new ArrayIndexOutOfBoundsException(count); } else if (index < 0 || index > used) { throw new ArrayIndexOutOfBoundsException(index); } changeSize(used+count); System.arraycopy(array, index, array, index+count, used-index-count); while (--count >= 0) { array[index++] = value; } } /** * remove a number of values. The array shrinks in it's length, but no * resizing is done. Get an IndexOutOfBoundsException for inappropriate index or * count values. * * @param index , where to start removing * @param count , how many values to remove */ public synchronized void remove(int index, int count) { if (count < 0) { throw new ArrayIndexOutOfBoundsException(count); } else if (index < 0) { throw new ArrayIndexOutOfBoundsException(index); } else if (index+count > used) { throw new ArrayIndexOutOfBoundsException(index+count); } System.arraycopy(array, index+count, array, index, used-count-index); changeSize(used-count); } /** * Use the array as a stack with the push method. * * @param value , a char to push to the stack */ public synchronized void push(char value) { changeSize(used+1); array[used-1] = value; } /** * Use the array as a stack and pop a value. (Value is removed) * IndexOutOfBoundsExceptions comes when array has hit 0 length. * * @return the top most char value */ public synchronized char pop() { if (used == 0) { throw new ArrayIndexOutOfBoundsException(0); } char value = array[--used]; array[used] = 0; return value; } /** * Check the top boolean with the top method. This returns what * pop returns, just it doesn't remove the value. In other stack * implementations it may be called peek() * * @return a char value */ public synchronized char top() { if (used == 0) { throw new ArrayIndexOutOfBoundsException(0); } return array[used-1]; } /** * append add the given values to the end of the array * * @param tail a char[] that will be appended */ public synchronized void append(char[] tail) { int size = used; changeSize(size + tail.length); System.arraycopy(tail, 0, array, size, tail.length); } /** * append the given String at the end * * @param tail a String value */ public synchronized void append(String tail) { int size = used; int length = tail.length(); changeSize(size + length); tail.getChars(0, length, array, size); } /** * toArray converts the internal representation to a char[] , of * correct size. Ie: the .length of the return == this.size() * * @return a char[] value */ public synchronized char[] toArray() { char[] arr = new char[used]; System.arraycopy(array, 0, arr, 0, used); return arr; } /** * toString makes a String out of the bytes * * @return a String representation of the bytes */ public synchronized String toString() { return new String(array, 0, used); } /** * copy into this array from a destination, a given amount of values. * Get a IndexOutOfBounds if the src or count don't fit * * @param dstIndex , the index (of this array) where to copy to * @param src a char[] , where to copy from * @param srcIndex an int , where to start copying from * @param count an int , how many values to copy */ public synchronized void copy(int dstIndex, char[] src, int srcIndex, int count) { if (dstIndex < 0) { throw new ArrayIndexOutOfBoundsException(dstIndex); } else if (dstIndex+count > used) { throw new ArrayIndexOutOfBoundsException(dstIndex+count); } Metaobject.modify(); System.arraycopy(src, srcIndex, array, dstIndex, count); } /** * compareTo calls the other compare functions, depending on the * given object * * @param o an Object to compare against * @return an int , the result */ public int compareTo(Object o) { if (o instanceof String) { return compare((String)o); } if (o instanceof ArrayOfChar) { return compare((ArrayOfChar)o); } throw new ClassCastException(); } /** * compare works like the compare(ArrayOfChar) * * @param s a String value to compare against * @return an int , the result */ public synchronized int compare(String s) { int len = s.length(); int n = len < used ? len : used; for (int i = 0; i < n; i++) { int diff = array[i] - s.charAt(i); if (diff != 0) { return diff; } } return used - len; } /** * compare compares two object. In that it works like the * equals method. But compare returns more than just a boolean yes/no, * it also introduces an ordering between the objects. * * @param a ArrayOfChar to compare against * @return an int , 0 if equal, negative if the object is smaller and * positive if it is bigger. */ public synchronized int compare(ArrayOfChar a) { int len = a.used; char[] s = a.array; int n = len < used ? len : used; for (int i = 0; i < n; i++) { int diff = array[i] - s[i]; if (diff != 0) { return diff; } } return used - len; } /** * Return a hashCode * * @return an int value, the hash */ public synchronized int hashCode() { return new String(array, 0, used).hashCode(); /* int h = 0; for (int i = 0, len = used; i < len; i++) { h = 31*h + array[i]; } return h; */ } /** * equals checks whether the given object is equivalent to this. * Ie. If it has the same data representation. It does not have to be the same, * which is checked by == operator. * * @param obj an Object to check * @return a boolean indicating whether obj is equivalent */ public synchronized boolean equals(Object obj) { if (obj == this) { return true; } if (obj == null) { return false; } if (obj instanceof String) { String s = (String)obj; int len = s.length(); if (len != used) { return false; } for (int i = 0; i < len; i++) { if (array[i] != s.charAt(i)) { return false; } } } else if (obj instanceof char[]) { char[] s = (char[])obj; int len = s.length; if (len != used) { return false; } for (int i = 0; i < len; i++) { if (array[i] != s[i]) { return false; } } } else if (obj instanceof ArrayOfChar) { ArrayOfChar a = (ArrayOfChar)obj; int len = a.used; if (used != len) { return false; } for (int i = 0; i < len; i++) { if (array[i] != a.array[i]) { return false; } } } else { return false; } return true; } /** * indexOf returns the first occurrence of val * * @param ch a char to be looked for * @return an int, where the value was found, or -1 */ public synchronized int indexOf(char ch) { for (int i = 0; i < used; i++) { if (array[i] == ch) { return i; } } return -1; } /** * Find the lastIndexOf a given value * * @param ch a char value to be found (from the back) * @return an int , where the value was found, or -1 */ public synchronized int lastIndexOf(char ch) { for (int i = used; --i >= 0;) { if (array[i] == ch) { return i; } } return -1; } }