//-< ArrayOfBoolean.java >-------------------------------------------*--------* // GOODS Version 2.02 (c) 1998 GARRET * ? * // (Generic Object Oriented Database System) * /\| * // GOODS Persistent Class Library * / \ * // Created: 3-Nov-98 K.A. Knizhnik * / [] \ * // Last update: 3-Nov-98 K.A. Knizhnik * GARRET * //-------------------------------------------------------------------*--------* // Dynamic packed array of boolean //-------------------------------------------------------------------*--------* package goodslib; import goodsjpi.*; /** * ArrayOfBoolean is just that, an array of booleans. For efficiency * they are stored in a byte[] internally. * * @author K.A. Knizhnik * @version 1.0 */ public class ArrayOfBoolean extends AnyArray { /** * array holds the booleans in a byte [] */ protected byte[] array; /** * Creates a new ArrayOfBoolean instance. * * @param size is the initial size, (length) */ public ArrayOfBoolean(int size) { this(size, size == 0 ? 16 : size); } /** * Creates a new ArrayOfBoolean instance. (Full of false) * * @param size, or length of the array * @param allocatedSize is the size it can grow to without resizing */ public ArrayOfBoolean(int size, int allocatedSize) { Assert.that(size <= allocatedSize); array = new byte[(allocatedSize+7) >>>3]; used = size; } /** * Creates a new ArrayOfBoolean instance, as a copy of the given * boolean[] * * @param src a boolean[] that will be copied */ public ArrayOfBoolean(boolean[] src) { int length = src.length; array = new byte[(length + 7) >>> 3]; used = length; while (--length >= 0) { if (src[length]) { array[length >>> 3] |= 1 << (length & 7); } } } /** * Put a boolean value at a given index * * @param index an int value, where the value should be set * @param value the boolean value to be set */ public synchronized void putAt(int index, boolean value) { if (index < 0 || index >= used) { throw new ArrayIndexOutOfBoundsException(index); } Metaobject.modify(); if (value) { array[index >>> 3] |= 1 << (index & 7); } else { array[index >>> 3] &= ~(1 << (index & 7)); } } /** * Get a boolean at the specified index * * @param index of the boolean you want * @return a boolean value, at index "index" */ public synchronized boolean getAt(int index) { if (index < 0 || index >= used) { throw new ArrayIndexOutOfBoundsException(index); } return (array[index >>> 3] & (1 << (index & 7))) != 0; } /** * Resize the amount of space taken by the array. Either grow or shrink as * neccessary. 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 newIntSize = (newSize + 7) >>> 3; int oldIntSize = (used + 7) >>> 3; int allocated = array.length; if (newIntSize > allocated) { allocated = (allocated*2 > newIntSize) ? allocated*2 : newIntSize; byte[] newArray = new byte[allocated]; System.arraycopy(array, 0, newArray, 0, oldIntSize); array = newArray; } else { while (newIntSize < oldIntSize) { array[newIntSize++] = 0; } if (newSize < used && (newSize & 7) != 0) { array[newSize >>> 3] &= (1 << (newSize & 7)) - 1; } } 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 boolean value to insert */ public synchronized void insert(int index, int count, boolean value) { if (count < 0) { throw new ArrayIndexOutOfBoundsException(count); } else if (index < 0 || index > used) { throw new ArrayIndexOutOfBoundsException(index); } int len = used; changeSize(used+count); for (int i = len; --i >= index;) { if ((array[i >>> 3] & (1 << (i & 7))) != 0) { array[(i+count) >>> 3] |= 1 << ((i + count) & 7); } else { array[(i+count) >>> 3] &= ~(1 << ((i + count) & 7)); } } if (value) { while (--count >= 0) { array[index >>> 3] |= 1 << (index & 7); index += 1; } } else { while (--count >= 0) { array[index >>> 3] &= ~(1 << (index & 7)); index += 1; } } } /** * 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); } used -= count; for (int i = index; i < used; i++) { int bit = (1 << ((i + count) & 7)); if ((array[(i + count) >>> 3] & bit) != 0) { array[(i + count) >>> 3] -= bit; array[i >>> 3] |= 1 << (i & 7); } else { array[i >>> 3] &= ~(1 << (i & 7)); } } } /** * Use the array as a stack with the push method. * * @param value , a boolean to push to the stack */ public synchronized void push(boolean value) { changeSize(used+1); if (value) { array[(used-1) >>> 3] |= 1 << ((used-1) & 7); } } /** * 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 boolean value */ public synchronized boolean pop() { if (used == 0) { throw new ArrayIndexOutOfBoundsException(0); } used -= 1; int value = array[used >>> 3] & (1 << (used & 7)); array[used >>> 3] &= ~value; return value != 0; } /** * Check the top boollean 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 boolean value */ public synchronized boolean top() { if (used == 0) { throw new ArrayIndexOutOfBoundsException(0); } return (array[(used-1) >>> 3] & (1 << ((used-1) & 7))) != 0; } /** * append add the given values to the end of the array * * @param tail a boolean[] that will be appended */ public synchronized void append(boolean[] tail) { int size = used; changeSize(size + tail.length); copy(size, tail, 0, tail.length); } /** * toArray makes a Java boolean[] out of the values. Internally they * are stored in a byte[] for space efficiency * * @return the array as a boolean[] */ public synchronized boolean[] toArray() { boolean[] arr = new boolean[used]; for (int i = used; --i >= 0;) { arr[i] = (array[i >>> 3] & (1 << (i & 7))) != 0; } return arr; } /** * 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 boolean[] , 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, boolean[] src, int srcIndex, int count) { if (dstIndex < 0) { throw new ArrayIndexOutOfBoundsException(dstIndex); } else if (dstIndex+count > used) { throw new ArrayIndexOutOfBoundsException(dstIndex+count); } Metaobject.modify(); while (--count >= 0) { if (src[srcIndex++]) { array[dstIndex >>> 3] |= 1 << (dstIndex & 7); } else { array[dstIndex >>> 3] &= ~(1 << (dstIndex & 7)); } dstIndex += 1; } } /** * indexOf returns the first occurrence of val * * @param val a boolean to be looked for * @return an int, where the value was found, or -1 */ public synchronized int indexOf(boolean val) { int i, last = used >>> 3; if (val) { for (i = 0; i < last; i++) { if (array[i] != 0) { return (i << 3) + firstSetBit[array[i] & 0xFF]; } } if ((used & 7) != 0 && array[last] != 0) { return (last << 3) + firstSetBit[array[last] & 0xFF]; } } else { for (i = 0; i < last; i++) { if (array[i] != -1) { return (i << 3) + firstSetBit[~array[i] & 0xFF]; } } if ((used & 7) != 0) { return firstSetBit[~((-1 << (used & 7)) | array[last])]; } } return -1; } /** * Find the lastIndexOf a given value * * @param val a boolean value to be found (from the back) * @return an int , where the value was found, or -1 */ public synchronized int lastIndexOf(boolean val) { int i, last = used >>> 3; if (val) { if ((used & 7) != 0 && array[last] != 0) { return (last << 3) + lastSetBit[array[last] & 0xFF]; } for (i = last; --i >= 0;) { if (array[i] != 0) { return (i << 3) + lastSetBit[array[i] & 0xFF]; } } } else { if ((used & 7) != 0 && array[last] != (1 << (used & 7)) - 1) { return (last << 3) + lastSetBit[~array[last] & 0xFF]; } for (i = last; --i >= 0;) { if (array[i] != -1) { return (i << 3) + lastSetBit[~array[i] & 0xFF]; } } } return -1; } static final byte firstSetBit[] = { -1,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 }; static final byte lastSetBit[] = { -1,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 }; }