//-< 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;
}
}