All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.python.core.AbstractArray Maven / Gradle / Ivy

Go to download

Jython is an implementation of the high-level, dynamic, object-oriented language Python written in 100% Pure Java, and seamlessly integrated with the Java platform. It thus allows you to run Python on any Java platform.

The newest version!
package org.python.core;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.Arrays;

/**
 * Abstract class that manages bulk structural and data operations
 * on arrays, defering type-specific element-wise operations to the
 * subclass.  Subclasses supply the underlying array and the
 * type-specific operations--greatly reducing the need for casting
 * (thus achieving array-like performances with collection-like
 * flexibility).  Also includes
 * functionality to support integration with the the jdk's
 * collections (via methods that return a modification increment).

* Subclasses will want to provide the following methods (which are * not declared in this class since subclasses should specify the * explicit return type): *

    *
  • <type> get(int)
  • *
  • void set(int, <type>)
  • *
  • void add(<type>)
  • *
  • void add(int, <type>)
  • *
  • <type>[] toArray()
  • *

* Clone cannot be supported since the array is not held locally. * But the @link #AbstractArray(AbstractArray) constructor can be used * for suclasses that need to support clone. *

* This "type-specific collections" approach was originally developed * by Dennis Sosnoski, who provides a more complete library at the * referenced URL. Sosnoski's library does not integrate with the * jdk collection classes but provides collection-like classes. * * @author Clark Updike * @see * Sosnoski's Type-Specific Collection Library */ public abstract class AbstractArray implements Serializable{ /** * Size of the current array, which can be larger than the * size field. */ protected int capacity; /** * The number of values currently present in the array. */ protected int size; /** * The modification count increment indicates if a structural change * occurred as a result of an operation that would make concurrent iteration * over the array invalid. It is typically used by subclasses that * extend AbstractList, by adding the value to * AbstractList.modCount after performing a potentially * structure-altering operation. A value of 0 indicates that * it is still valid to iterate over the array. A value of 1 * indicates it is no longer valid to iterate over the range.

* This class uses a somewhat stricter semantic for modCount. * Namely, modCountIncr is only set to 1 if a structural * change occurred. The jdk collections generally increment * modCount if a potentially structure-altering method * is called, regardless of whether or not a change actually occurred. * * See also: java.util.AbstractList#modCount */ protected int modCountIncr; /** * Since AbstractArray can support a clone method, this facilitates subclasses that want to * implement clone (poor man's cloning). Subclasses can then do this: * *

{@literal
     * public MyManagedArray(MyManagedArray toCopy) {
     *     super(this);
     *     this.baseArray = () toCopy.copyArray();
     *     this.someProp = toCopy.someProp;
     *     
     * }
     *
     * public Object clone() {
     *     return new MyManagedArray(this);
     * }
     * }
* * @param toCopy */ public AbstractArray(AbstractArray toCopy) { this.capacity = toCopy.capacity; // let modCountIncr default to 0 this.size = toCopy.size; } /** * Use when the subclass has a preexisting array. * * @param size the initial size of the array */ public AbstractArray(int size) { this.size = size; this.capacity = size; } /** * Creates the managed array with a default size of 10. * * @param type array element type (primitive type or object class) */ public AbstractArray(Class type) { this(type, 10); } /** * Construtor for multi-dimensional array types. * For example, char[][]. This class only manages the * top level dimension of the array. For single dimension * arrays (the more typical usage), use the other constructors.

* * @param type Array element type (primitive type or object class). * @param dimensions An int array specifying the dimensions. For * a 2D array, something like new int[] {10,0} to * create 10 elements each of which can hold an reference to an * array of the same type. * @see Array#newInstance(java.lang.Class, int[]) */ public AbstractArray(Class type, int[] dimensions) { Object array = Array.newInstance(type, dimensions); this.capacity = dimensions[0]; setArray(array); } /** * Creates the managed array with the specified size. * * @param type array element type (primitive type or object class) * @param size number of elements initially allowed in array */ public AbstractArray(Class type, int size) { Object array = Array.newInstance(type, size); this.capacity = Math.max(size, 10); setArray(array); } /** * Appends the supplied array, which must be an array of the same * type as this, to the end of this. *

AbstractList subclasses should update their * modCount after calling this method. * * @param ofArrayType the array to append */ public void appendArray(Object ofArrayType) { replaceSubArray(ofArrayType, this.size); } /** * Set the array to the empty state, clearing all the data out and * nulling objects (or "zero-ing" primitives). *

Note: This method does not set modCountIncr to * 1 even though java.util.ArrayList * would. * *

AbstractList subclasses should update their * modCount after calling this method. */ public void clear() { this.modCountIncr = 0; if (this.size != 0) { this.modCountIncr = 1; clearRange(0, this.size); setSize(0); } } /** * Clears out the values in the specified range. For object arrays, * the cleared range is nullified. For primitve arrays, it is * "zero-ed" out. *

Note: This method does not set modCountIncr to * 1 even though java.util.ArrayList * would. * * @param start the start index, inclusive * @param stop the stop index, exclusive */ protected void clearRange(int start, int stop) { if (start < stop && start >= 0 && stop <= this.size) { clearRangeInternal(start, stop); } else { if (start == stop && start >= 0 && stop <= this.size) { return; } throw new ArrayIndexOutOfBoundsException("start and stop must follow: 0 <= start <= stop <= " + (this.size) + ", but found start= " + start + " and stop=" + stop); } } /** * Used internally, no bounds checking. * * @param start the start index, inclusive * @param stop the stop index, exclusive */ private void clearRangeInternal(int start, int stop) { Object base = getArray(); Class arrayType = base.getClass().getComponentType(); if (arrayType.isPrimitive()) { if (arrayType == Boolean.TYPE) { Arrays.fill((boolean[]) base, start, stop, false); } else if (arrayType == Character.TYPE) { Arrays.fill((char[]) base, start, stop, '\u0000'); } else if (arrayType == Byte.TYPE) { Arrays.fill((byte[]) base, start, stop, (byte) 0); } else if (arrayType == Short.TYPE) { Arrays.fill((short[]) base, start, stop, (short) 0); } else if (arrayType == Integer.TYPE) { Arrays.fill((int[]) base, start, stop, 0); } else if (arrayType == Long.TYPE) { Arrays.fill((long[]) base, start, stop, 0); } else if (arrayType == Float.TYPE) { Arrays.fill((float[]) base, start, stop, 0.f); } else if (arrayType == Double.TYPE) { Arrays.fill((double[]) base, start, stop, 0.); } } else { Arrays.fill((Object[]) base, start, stop, null); } } /** * Constructs and returns a simple array containing the same data as held * in this growable array. * * @return array containing a shallow copy of the data. */ public Object copyArray() { Object copy = createArray(this.size); System.arraycopy(getArray(), 0, copy, 0, this.size); return copy; } /** * Ensures that the base array has at least the specified * minimum capacity. *

AbstractList subclasses should update their * modCount after calling this method. * * @param minCapacity new minimum size required */ protected void ensureCapacity(int minCapacity) { // ArrayList always increments the mod count, even if no // structural change is made (not sure why). // This only indicates a mod count change if a change is made. this.modCountIncr = 0; if (minCapacity > this.capacity) { this.modCountIncr = 1; int newCapacity = (this.capacity * 2) + 1; newCapacity = (newCapacity < minCapacity) ? minCapacity : newCapacity; setNewBase(newCapacity); this.capacity = newCapacity; } } /** * Gets the next add position for appending a value to those in the array. * If the underlying array is full, it is grown by the appropriate size * increment so that the index value returned is always valid for the * array in use by the time of the return. *

AbstractList subclasses should update their * modCount after calling this method. * * @return index position for next added element */ protected int getAddIndex() { int index = this.size++; if (this.size > this.capacity) { ensureCapacity(this.size); } return index; } /** * Get the backing array. This method is used by the type-agnostic base * class code to access the array used for type-specific storage by the * child class. * * @return backing array object */ protected abstract Object getArray(); protected boolean isEmpty() { return this.size == 0; } /** * Makes room to insert a value at a specified index in the array. *

AbstractList subclasses should update their * modCount after calling this method. Does not change * the size property of the array. * * @param index index position at which to insert element */ protected void makeInsertSpace(int index) { makeInsertSpace(index, 1); } protected void makeInsertSpace(int index, int length) { this.modCountIncr = 0; if (index >= 0 && index <= this.size) { int toCopy = this.size - index; this.size = this.size + length; // First increase array size if needed if (this.size > this.capacity) { ensureCapacity(this.size); } if (index < this.size - 1) { this.modCountIncr = 1; Object array = getArray(); System.arraycopy(array, index, array, index + length, toCopy); } } else { throw new ArrayIndexOutOfBoundsException("Index must be between 0 and " + this.size + ", but was " + index); } } /** * Remove a value from the array. All values above the index removed * are moved down one index position. *

AbstractList subclasses should always increment * their modCount method after calling this, as * remove always causes a structural modification. * * @param index index number of value to be removed */ public void remove(int index) { if (index >= 0 && index < this.size) { this.size = this.size - 1; if (index < this.size) { Object base = getArray(); System.arraycopy(base, index + 1, base, index, this.size - index); clearRangeInternal(this.size, this.size); } } else { if (this.size == 0) { throw new IllegalStateException("Cannot remove data from an empty array"); } throw new IndexOutOfBoundsException("Index must be between 0 and " + (this.size - 1) + ", but was " + index); } } /** * Removes a range from the array at the specified indices. * @param start inclusive * @param stop exclusive */ public void remove(int start, int stop) { if (start >= 0 && stop <= this.size && start <= stop) { Object base = getArray(); int nRemove = stop - start; if (nRemove == 0) { return; } System.arraycopy(base, stop, base, start, this.size - stop); this.size = this.size - nRemove; clearRangeInternal(this.size, this.size + nRemove); setArray(base); return; } throw new IndexOutOfBoundsException("start and stop must follow: 0 <= start <= stop <= " + this.size + ", but found start= " + start + " and stop=" + stop); } /** * Allows an array type to overwrite a segment of the array. * Will expand the array if (atIndex + 1) + ofArrayType's length * is greater than the current length. *

AbstractList subclasses should update their * modCount after calling this method. * * @param array * @param atIndex */ public void replaceSubArray(Object array, int atIndex) { int arrayLen = Array.getLength(array); replaceSubArray(atIndex, Math.min(this.size, atIndex + arrayLen), array, 0, arrayLen); } /** * Replace a range of this array with another subarray. * @param thisStart the start index (inclusive) of the subarray in this * array to be replaced * @param thisStop the stop index (exclusive) of the subarray in this * array to be replaced * @param srcArray the source array from which to copy * @param srcStart the start index (inclusive) of the replacement subarray * @param srcStop the stop index (exclusive) of the replacement subarray */ public void replaceSubArray(int thisStart, int thisStop, Object srcArray, int srcStart, int srcStop) { this.modCountIncr = 0; if (!srcArray.getClass().isArray()) { throw new IllegalArgumentException("'array' must be an array type"); } int replacedLen = thisStop - thisStart; if (thisStart < 0 || replacedLen < 0 || thisStop > this.size) { String message = null; if (thisStart < 0) { message = "thisStart < 0 (thisStart = " + thisStart + ")"; } else if (replacedLen < 0) { message = "thisStart > thistStop (thisStart = " + thisStart + ", thisStop = " + thisStop + ")"; } else if (thisStop > this.size) { message = "thisStop > size (thisStop = " + thisStop + ", size = " + this.size + ")"; } else { throw new InternalError("Incorrect validation logic"); } throw new ArrayIndexOutOfBoundsException(message); } int srcLen = Array.getLength(srcArray); int replacementLen = srcStop - srcStart; if (srcStart < 0 || replacementLen < 0 || srcStop > srcLen) { String message = null; if (srcStart < 0) { message = "srcStart < 0 (srcStart = " + srcStart +")"; } else if (replacementLen < 0) { message = "srcStart > srcStop (srcStart = " + srcStart + ", srcStop = " + srcStop + ")"; } else if (srcStop > srcLen) { message = "srcStop > srcArray length (srcStop = " + srcStop + ", srcArray length = " +srcLen + ")"; } else { throw new InternalError("Incorrect validation logic"); } throw new IllegalArgumentException("start, stop and array must follow:\n\t" + "0 <= start <= stop <= array length\nBut found\n\t" + message); } int lengthChange = replacementLen - replacedLen; // Adjust array size if needed. if (lengthChange < 0) { remove(thisStop + lengthChange, thisStop); } else if (lengthChange > 0) { makeInsertSpace(thisStop, lengthChange); } try { this.modCountIncr = 1; System.arraycopy(srcArray, srcStart, getArray(), thisStart, replacementLen); } catch (ArrayStoreException e) { throw new IllegalArgumentException("'ofArrayType' must be compatible with existing array type of " + getArray().getClass().getName() + "\tsee java.lang.Class.getName()."); } } /** * Set the backing array. This method is used by the type-agnostic base * class code to set the array used for type-specific storage by the * child class. * * @param array the backing array object */ protected abstract void setArray(Object array); /** * Replaces the existing base array in the subclass with a new * base array resized to the specified capacity. * * @param newCapacity */ private void setNewBase(int newCapacity) { this.modCountIncr = 1; Object base = getArray(); Object newBase = createArray(newCapacity); System.arraycopy(base, 0, newBase, 0, capacity > newCapacity ? newCapacity : capacity); setArray(newBase); } /** * Sets the number of values currently present in the array. If the new * size is greater than the current size, the added values are initialized * to the default values. If the new size is less than the current size, * all values dropped from the array are discarded. *

AbstractList subclasses should update their * modCount after calling this method. * * @param count number of values to be set */ public void setSize(int count) { if (count > this.capacity) { ensureCapacity(count); } else if (count < this.size) { clearRange(count, this.size); } this.size = count; } /** * Get the number of values currently present in the array. * * @return count of values present */ public int getSize() { return this.size; } /** * Provides a default comma-delimited representation of array. * * @see java.lang.Object#toString() */ @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append("["); Object base = getArray(); Class arrayType = base.getClass().getComponentType(); int n = this.size - 1; if (arrayType.isPrimitive()) { for (int i = 0; i < n; i++) { buf.append(Array.get(base, i)).append(", "); } if (n >= 0) { buf.append(Array.get(base, n)); } } else { Object[] objects = (Object[]) base; for (int i = 0; i < n; i++) { buf.append(objects[i]).append(", "); } if (n >= 0) { buf.append(objects[n]); } } buf.append("]"); return buf.toString(); } /** * Removes any excess capacity in the backing array so it is * just big enough to hold the amount of data actually in the array. */ protected void trimToSize() { // Don't need to adjust modCountIncr since AbstractList subclasses // should only ever see up to the size (and not the capacity--which // is encapsulated). if (this.size < this.capacity) { setNewBase(this.size); } } /** * Returns the modification count increment, which is used by * AbstractList subclasses to adjust modCount * AbstractList uses it's modCount field * to invalidate concurrent operations (like iteration) that should * fail if the underlying array changes structurally during the * operation. * * @return the modification count increment (0 if no change, 1 if changed) */ public int getModCountIncr() { return this.modCountIncr; } /** * @return an array of the given size for the type used by this abstract array. */ protected abstract Object createArray(int size); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy