Index: ArrayHelper.java =================================================================== RCS file: ArrayHelper.java diff -N ArrayHelper.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ArrayHelper.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,564 @@ +/* + * Copyright 2005 Clark Updike + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.python.core; + +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): + *

+ * Clone cannot be supported since the array is not held locally. + * But the @link #ArrayHelper(ArrayHelper) 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. + * + * @see + * Sosnoski's Type-Specific Collection Library + * @author Clark Updike + */ +public abstract class ArrayHelper { + + /** + * 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 + * occured 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 java.util.AbstractList#modCount + */ + protected int modCountIncr; + + /** + * Since ArrayHelper can support a clone method, this facilitates + * sublcasses that want to implement clone (poor man's cloning). + * Sublclasses can then do this: + *

+   * public MyManagedArray(MyManagedArray toCopy) {
+   *       super(this);
+   *     this.baseArray = ()toCopy.copyArray();
+   *     this.someProp = toCopy.someProp;
+   *     
+   * }
+   * 
+   * public Object clone() {
+   *       return new MyManagedArray(this);
+   * }
+   * 
+ * @param toCopy + */ + public ArrayHelper(ArrayHelper toCopy) { + capacity = toCopy.capacity; + // let modCountIncr default to 0 + size = toCopy.size; + } + + /** + * Use when the subclass has a preexisting array. + * @param size the initial size of the array + */ + public ArrayHelper(int size) { + this.size = size; + capacity = size; + } + + /** + * Creates the managed array with a default size of 10. + * + * @param type array element type (primitive type or object class) + */ + public ArrayHelper(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.

+ * + * @see Array#newInstance(java.lang.Class, int[]) + * @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. + */ + public ArrayHelper(Class type, int[] dimensions) { + Object array = Array.newInstance(type, dimensions); + 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 ArrayHelper(Class type, int size) { + Object array = Array.newInstance(type, size); + 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, 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() { + modCountIncr = 0; + if ( size != 0) { + modCountIncr = 1; + clearRange(0, size - 1); + 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 that the stop value is inclusive (not + * exclusive like some of the jdk equivalents). + *

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, inclusive + */ + protected void clearRange(int start, int stop) { + + if (start < stop && start >= 0 && stop <= size - 1) { + clearRangeInternal(start, stop); + } else { + if(start == stop && start >= 0 && stop <= size - 1) return; + + throw new ArrayIndexOutOfBoundsException( + "start and stop must follow: 0 <= start <= stop <= " + + (size - 1) + ", but found start= " + start + " and stop=" + stop); + } + } + + /** + * Used internally, no bounds checking. + * + * @param start the start index, inclusive + * @param stop the stop index, inclusive + */ + 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 + 1, false); + } else if (arrayType == Character.TYPE) { + Arrays.fill((char[])base, start, stop + 1, '\u0000'); + } else if (arrayType == Byte.TYPE) { + Arrays.fill((byte[])base, start, stop + 1, (byte)0); + } else if (arrayType == Short.TYPE) { + Arrays.fill((short[])base, start, stop + 1, (short)0); + } else if (arrayType == Integer.TYPE) { + Arrays.fill((int[])base, start, stop + 1, 0); + } else if (arrayType == Long.TYPE) { + Arrays.fill((long[])base, start, stop + 1, 0); + } else if (arrayType == Float.TYPE) { + Arrays.fill((float[])base, start, stop + 1, 0.f); + } else if (arrayType == Double.TYPE) { + Arrays.fill((double[])base, start, stop + 1, 0.); + } + } else { + Arrays.fill((Object[])base, start, stop + 1, 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 = Array.newInstance( + getArray().getClass().getComponentType(), size); + System.arraycopy(getArray(), 0, copy, 0, 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. + modCountIncr = 0; + if (minCapacity > capacity) { + modCountIncr = 1; + int newCapacity = (capacity * 2) + 1; + newCapacity = (newCapacity < minCapacity) + ? minCapacity + : newCapacity; + setNewBase(newCapacity); + 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 = size++; + if (size > capacity) { + ensureCapacity(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 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. + * + * @param index index position at which to insert element + */ + protected void makeInsertSpace(int index) { + makeInsertSpace(index, 1); + } +// protected void makeInsertSpace(int index) { +// +// modCountIncr = 0; +// if (index >= 0 && index <= size) { +// if (++size > capacity) { +// ensureCapacity(size); +// } +// if (index < size - 1) { +// modCountIncr = 1; +// Object array = getArray(); +// System.arraycopy(array, index, array, index + 1, +// size - index - 1); +// } +// } else { +// throw new ArrayIndexOutOfBoundsException( +// "Index must be between 0 and " + +// size + ", but was " + index); +// } +// } + + protected void makeInsertSpace(int index, int length) { + + modCountIncr = 0; + if (index >= 0 && index <= size) { + int toCopy = size - index; + size = size + length; + // First increase array size if needed + if (size > capacity) { + ensureCapacity(size); + } + if (index < size - 1) { + modCountIncr = 1; + Object array = getArray(); + System.arraycopy(array, index, array, index + length, toCopy); + } + } else { + throw new ArrayIndexOutOfBoundsException( + "Index must be between 0 and " + + 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 < size) { + size = size - 1; + if (index < size){ + Object base = getArray(); + System.arraycopy(base, index + 1, base, index, size - index); + clearRangeInternal(size, size); + } + + } else { + if (size == 0) { + throw new IllegalStateException( + "Cannot remove data from an empty array"); + } + throw new IndexOutOfBoundsException("Index must be between 0 and " + + (size - 1) + ", but was " + index); + + } + } + + public void remove(int start, int stop) { + if (start >= 0 && stop <= size && start <= stop) { + Object base = getArray(); + int nRemove = stop - start + 1; + System.arraycopy(base, stop + 1, base, start, size - stop - 1); + size = size - nRemove; + clearRangeInternal(size, size + nRemove - 1); + setArray(base); + return; + } + + throw new IndexOutOfBoundsException("start and stop must follow: 0 <= start <= stop <= " + + (size - 1) + ", 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) { + + modCountIncr = 0; + if( !array.getClass().isArray() ) { + throw new IllegalArgumentException("'array' must be an array type"); + } + + if (atIndex < 0 || atIndex > size) { + String message = (atIndex < 0) ? + "Index cannot be negative" : + "Index of " + atIndex + " must not exceed current size of " + size; + + throw new ArrayIndexOutOfBoundsException(message); + } + + int nAddLength = Array.getLength(array); + + int requiredLength = atIndex + nAddLength; + + if( requiredLength > capacity) { + // need to expand to size atIndex + nAddLength + ensureCapacity(requiredLength); + } + + size = Math.max(size, requiredLength); + try { + modCountIncr = 1; + System.arraycopy(array, 0, getArray(), atIndex, nAddLength); + } 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) { + modCountIncr = 1; + Object base = getArray(); + Class baseType = base.getClass().getComponentType(); + Object newBase = Array.newInstance(baseType, newCapacity); + System.arraycopy(base, 0, newBase, 0, 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 > capacity) { + ensureCapacity(count); + } else if (count < size) { + clearRange(count, size); + } + size = count; + } + + /** + * Get the number of values currently present in the array. + * + * @return count of values present + */ + public int getSize() { + return size; + } + + /** + * Provides a default comma-delimited representation of array. + * @see java.lang.Object#toString() + */ + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append("["); + + Object base = getArray(); + Class arrayType = base.getClass().getComponentType(); + int n = 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(size < capacity) { + setNewBase(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 modCountIncr; + } +} Index: PyArray.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/core/PyArray.java,v retrieving revision 2.10 diff -u -r2.10 PyArray.java --- PyArray.java 22 Feb 2005 04:19:30 -0000 2.10 +++ PyArray.java 14 Mar 2005 01:01:09 -0000 @@ -1,7 +1,8 @@ -// Copyright (c) Corporation for National Research Initiatives +// Copyright (c) Corporation for National Research Initiatives package org.python.core; import java.lang.reflect.Array; + /** * A wrapper class around native java arrays. * @@ -10,26 +11,87 @@ *

* See also the jarray module. */ - -public class PyArray extends PySequence { - Object data; - Class type; - +public class PyArray extends PySequence implements Cloneable { + + protected Object data; + protected Class type; + protected String typecode; + protected ArrayDelegate delegate; + + // PyArray can't extend anymore, so delegate + private static class ArrayDelegate extends ArrayHelper { + + final PyArray pyArray; + + private ArrayDelegate(PyArray pyArray) { + super((pyArray.data == null) + ? 0 + : Array.getLength(pyArray.data)); + this.pyArray = pyArray; + } + + protected Object getArray() { + return pyArray.data; + } + protected void setArray(Object array) { + pyArray.data = array; + } + + protected void makeInsertSpace(int index) { + super.makeInsertSpace(index, 1); + } + + protected void makeInsertSpace(int index, int length) { + super.makeInsertSpace(index, length); + } + + public void remove(int index) { + super.remove(index); + } + } + + private PyArray() { + // do nothing, shell instance + } + + public PyArray(PyArray toCopy) { + + data = toCopy.delegate.copyArray(); + delegate = new ArrayDelegate(this); + type = toCopy.type; + } + public PyArray(Class type, Object data) { this.type = type; this.data = data; + delegate = new ArrayDelegate(this); } public PyArray(Class type, int n) { this(type, Array.newInstance(type, n)); } + public static PyArray zeros(int n, char typecode) { + PyArray array = zeros(n, char2class(typecode)); + array.typecode = Character.toString(typecode); + return array; + } + public static PyArray zeros(int n, Class ctype) { - return new PyArray(ctype, n); + PyArray array = new PyArray(ctype, n); + array.typecode = ctype.getName(); + return array; } + public static PyArray array(PyObject seq, char typecode) { + PyArray array = PyArray.array(seq, char2class(typecode)); + array.typecode = Character.toString(typecode); + return array; + } + public static PyArray array(PyObject seq, Class ctype) { PyArray array = new PyArray(ctype, seq.__len__()); + array.typecode = ctype.getName(); PyObject iter = seq.__iter__(); PyObject item = null; for (int i = 0; (item = iter.__iternext__()) != null; i++) { @@ -38,6 +100,10 @@ return array; } + public Object getArray() { + return delegate.copyArray(); + } + public static Class char2class(char type) { switch (type) { case 'z': @@ -72,7 +138,7 @@ } public int __len__() { - return Array.getLength(data); + return delegate.getSize(); } protected PyObject get(int i) { @@ -80,8 +146,7 @@ } protected PyObject getslice(int start, int stop, int step) { - if (step > 0 && stop < start) - stop = start; + if (step > 0 && stop < start) stop = start; int n = sliceLength(start, stop, step); PyArray ret = new PyArray(type, n); @@ -89,10 +154,8 @@ System.arraycopy(data, start, ret.data, 0, n); return ret; } - int j = 0; - for (int i = start; j < n; i += step) { + for (int i = start, j = 0; j < n; i += step, j++) { Array.set(ret.data, j, Array.get(data, i)); - j++; } return ret; } @@ -102,10 +165,126 @@ } protected void del(int i) { - throw Py.TypeError("can't remove from array"); + //Now the ArrayHelper can support this: + //throw Py.TypeError("can't remove from array"); + delegate.remove(i); + } + + public PyObject count(PyObject value) { + // note: cpython does not raise type errors based on item type + int iCount = 0; + for (int i = 0; i < delegate.getSize(); i++) { + if (value.equals(Py.java2py(Array.get(data, i)))) iCount++; + } + return new PyInteger(iCount); } + + private int indexInternal(PyObject value) { + // note: cpython does not raise type errors based on item type + for (int i = 0; i < delegate.getSize(); i++) { + if (value.equals(Py.java2py(Array.get(data, i)))) { + return i; + } + } + return -1; + } + + public PyObject index(PyObject value) { + + int index = indexInternal(value); + if(index != -1) return new PyInteger(index); + + throw Py.ValueError("array.index(" + value + "): " + value + + " not found in array"); + } + + + public void remove(PyObject value) { + int index = indexInternal(value) ; + if(index != -1) { + delegate.remove(index); + return; + } + + throw Py.ValueError("array.remove(" + value + "): " + + value + " not found in array"); + } + + public PyObject __add__(PyObject other) { + PyArray otherArr = null; + if (!(other instanceof PyArray)) { + throw Py.TypeError("can only append another array to an array"); + } + otherArr = (PyArray)other; + if (!otherArr.type.equals(this.type)) { + throw Py.TypeError( + "can only append arrays of the same type, " + + "expected '" + this.type + ", found " + otherArr.type); + } + PyArray ret = new PyArray(this); + ret.delegate.appendArray(otherArr.delegate.copyArray()); + return ret; + } + + public void append(PyObject value) { + // Currently, this is asymmetric with extend, which + // *will* do conversions like append(5.0) to an int array. + // Also, cpython 2.2 will do the append coersion. However, + // it is deprecated in cpython 2.3, so maybe we are just + // ahead of our time ;-) + Object o = Py.tojava(value, type); + int afterLast = delegate.getSize(); + delegate.makeInsertSpace(afterLast); + Array.set(data, afterLast, o); + } + + public void extend(PyObject array) { + PyArray otherArr = null; + if (!(array instanceof PyArray)) { + throw Py.TypeError("can only extend an array witn another array"); + } + otherArr = (PyArray)array; + if (!otherArr.type.equals(this.type)) { + throw Py.TypeError( + "can only extend with an array of the same type, " + + "expected '" + this.type + ", found " + otherArr.type); + } + delegate.appendArray(otherArr.delegate.copyArray()); + } + + public void insert(int index, PyObject value) { + delegate.makeInsertSpace(index); + Array.set(data, index, Py.tojava(value, type)); + } + + public PyObject pop() { + return pop(-1); + } + + public PyObject pop(int index) { + // todo: python-style error handling + index = (index < 0) + ? delegate.getSize() + index + : index; + PyObject ret = Py.java2py(Array.get(data, index)); + delegate.remove(index); + return ret; + } + protected void delRange(int start, int stop, int step) { - throw Py.TypeError("can't remove from array"); + // Now the ArrayHelper can support this: + //throw Py.TypeError("can't remove from array"); + if (step > 0 && stop < start) stop = start; + + if (step == 1) { + delegate.remove(start, stop); + } else { + int n = sliceLength(start, stop, step); + + for (int i = start, j = 0; j < n; i += step, j++) { + delegate.remove(i); + } + } } protected void set(int i, PyObject value) { @@ -114,14 +293,30 @@ } protected void setslice(int start, int stop, int step, PyObject value) { - if (value instanceof PyString && type == Character.TYPE) { - char[] chars = value.toString().toCharArray(); - if (chars.length == stop-start && step == 1) { - System.arraycopy(chars, 0, data, start, chars.length); - } else { - throw Py.ValueError("invalid bounds for setting from string"); - } - + if(type == Character.TYPE && value instanceof PyString) { + char[] chars = null; + //if (value instanceof PyString) { + if (step != 1) { + throw Py.ValueError( + "invalid bounds for setting from string"); + } + chars = value.toString().toCharArray(); + + //} +// else if (value instanceof PyArray && +// ((PyArray)value).type == Character.TYPE) { +// PyArray other = (PyArray)value; +// chars = (char[])other.delegate.copyArray(); +// } + int insertSpace = chars.length - (stop - start); + // adjust the array, either adding space or removing space + if(insertSpace > 0) { + delegate.makeInsertSpace(start, insertSpace); + } else if (insertSpace < 0) { + delegate.remove(start, -insertSpace + start - 1); + } + delegate.replaceSubArray(chars, start); + } else { if (value instanceof PyString && type == Byte.TYPE) { byte[] chars = value.toString().getBytes(); @@ -131,14 +326,38 @@ throw Py.ValueError( "invalid bounds for setting from string"); } - } else { - throw Py.TypeError( - "can't set slice in array (except from string)"); + } else if(value instanceof PyArray){ + PyArray array = (PyArray)value; + int insertSpace = array.delegate.getSize() - (stop - start); + // adjust the array, either adding space or removing space + // ...snapshot in case "value" is "this" + Object arrayCopy = array.delegate.copyArray(); + if(insertSpace > 0) { + delegate.makeInsertSpace(start, insertSpace); + } else if (insertSpace < 0) { + delegate.remove(start, -insertSpace + start - 1); + } + try { + delegate.replaceSubArray(arrayCopy, start); + } catch (IllegalArgumentException e) { + throw Py.TypeError("Slice typecode '" + array.typecode + + "' is not compatible with this array (typecode '" + + this.typecode + "')"); + } } } } + public void reverse() { + // build a new reversed array and set this.data to it when done + Object array = Array.newInstance(type, Array.getLength(data)); + for(int i = 0, lastIndex = delegate.getSize() - 1; i <= lastIndex; i++) { + Array.set(array, lastIndex - i, Array.get(data, i)); + } + data = array; + } + public String tostring() { if (type == Character.TYPE) { return new String((char[])data); @@ -149,6 +368,10 @@ throw Py.TypeError( "can only convert arrays of byte and char to string"); } + + public Object clone() { + return new PyArray(this); + } public PyString __repr__() { StringBuffer buf = new StringBuffer("array(["); @@ -164,4 +387,8 @@ return new PyString(buf.toString()); } + + public String getTypecode() { + return typecode; + } } Index: PySequence.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/core/PySequence.java,v retrieving revision 2.21 diff -u -r2.21 PySequence.java --- PySequence.java 22 Feb 2005 04:19:31 -0000 2.21 +++ PySequence.java 14 Mar 2005 01:02:26 -0000 @@ -480,7 +480,7 @@ array.set(i, o); } //System.out.println("getting: "+component+", "+array.data); - return array.data; + return array.getArray(); } catch (Throwable t) { ;//System.out.println("failed to get: "+component.getName()); } Index: jarray.java =================================================================== RCS file: /cvsroot/jython/jython/org/python/modules/jarray.java,v retrieving revision 2.2 diff -u -r2.2 jarray.java --- jarray.java 28 Oct 2001 17:13:44 -0000 2.2 +++ jarray.java 14 Mar 2005 01:02:54 -0000 @@ -4,14 +4,14 @@ public class jarray { public static PyArray array(PyObject seq, char typecode) { - return PyArray.array(seq, PyArray.char2class(typecode)); + return PyArray.array(seq, typecode); } public static PyArray array(PyObject seq, Class type) { return PyArray.array(seq, type); } public static PyArray zeros(int n, char typecode) { - return PyArray.zeros(n, PyArray.char2class(typecode)); + return PyArray.zeros(n, typecode); } public static PyArray zeros(int n, Class type) { Index: test_jarray.py =================================================================== RCS file: /cvsroot/jython/jython/Lib/test/test_jarray.py,v retrieving revision 1.1 diff -u -r1.1 test_jarray.py --- test_jarray.py 15 Feb 1999 14:54:08 -0000 1.1 +++ test_jarray.py 14 Mar 2005 01:03:26 -0000 @@ -1,3 +1,6 @@ +# CAU: adaptation of the cpython 2.2 test_array.py for jython 2.2 +# combined with the jarray test from 2.1 + from test_support import * print_test('jarray module (test_jarray.py)', 1) @@ -19,3 +22,193 @@ awt.Color.RGBtoHSB(0,255,255, hsb1) #print hsb, hsb1 assert hsb == hsb1 + +def main(): + + testtype('c', 'c') + + for type in (['b', 'h', 'i', 'l', 'f', 'd']): + testtype(type, 1) + +#CAU: nyi unlink(TESTFN) + + +def testoverflow(type, lowerLimit, upperLimit): + # should not overflow assigning lower limit + if verbose: + print "overflow test: array(%s, [%s])" % (`lowerLimit`, `type`) + try: + a = array([lowerLimit], type) + except: + raise TestFailed, "array(%s) overflowed assigning %s" %\ + (`lowerLimit`, `type`) + # should overflow assigning less than lower limit + if verbose: + print "overflow test: array(%s, [%s])" % (`lowerLimit-1`, `type`) + try: + a = array([lowerLimit-1], type) + raise TestFailed, "array(%s) did not overflow assigning %s" %\ + (`lowerLimit-1`, `type`) + except OverflowError: + pass + # should not overflow assigning upper limit + if verbose: + print "overflow test: array(%s, [%s])" % (`upperLimit`, `type`) + try: + a = array([upperLimit], type) + except: + raise TestFailed, "array(%s) overflowed assigning %s" %\ + (`upperLimit`, `type`) + # should overflow assigning more than upper limit + if verbose: + print "overflow test: array(%s, [%s])" % (`upperLimit+1`, `type`) + try: + a = array([upperLimit+1], type) + raise TestFailed, "array(%s) did not overflow assigning %s" %\ + (`upperLimit+1`, `type`) + except OverflowError: + pass + + + +def testtype(type, example): + + print "testing type ", type + + a = array([], type) + a.append(example) + if verbose: + print 40*'*' + print 'array after append: ', a + a.typecode +#CAU: nyi a.itemsize + +#CAU: nyi if a.typecode in ('i', 'b', 'h', 'l'): +#CAU: nyi a.byteswap() + +#CAU: nyi if a.typecode == 'c': +#CAU: nyi f = open(TESTFN, "w") +#CAU: nyi f.write("The quick brown fox jumps over the lazy dog.\n") +#CAU: nyi f.close() +#CAU: nyi f = open(TESTFN, 'r') +#CAU: nyi a.fromfile(f, 10) +#CAU: nyi f.close() +#CAU: nyi if verbose: +#CAU: nyi print 'char array with 10 bytes of TESTFN appended: ', a +#CAU: nyi a.fromlist(['a', 'b', 'c']) +#CAU: nyi if verbose: +#CAU: nyi print 'char array with list appended: ', a + +#CAU: nyi a.insert(0, example) +#CAU: nyi if verbose: +#CAU: nyi print 'array of %s after inserting another:' % a.typecode, a +#CAU: nyi f = open(TESTFN, 'w') +#CAU: nyi a.tofile(f) +#CAU: nyi f.close() + +#CAU: nyi # This block is just to verify that the operations don't blow up. +#CAU: nyi a.tolist() +#CAU: nyi a.tostring() + repr(a) + str(a) + +#CAU: nyi if verbose: +#CAU: nyi print 'array of %s converted to a list: ' % a.typecode, a.tolist() +#CAU: nyi if verbose: +#CAU: jython 2.1 PyArray only supported tostring() on byte and char arrays +#CAU: nyi print 'array of %s converted to a string: ' \ +#CAU: nyi % a.typecode, `a.tostring()` + + if type == 'c': + a = array("abcde", type) + a[:-1] = a + if a != array("abcdee", type): + raise TestFailed, "array(%s) self-slice-assign (head)" % `type` + a = array("abcde", type) + a[1:] = a + if a != array("aabcde", type): + raise TestFailed, "array(%s) self-slice-assign (tail)" % `type` + a = array("abcde", type) + a[1:-1] = a + if a != array("aabcdee", type): + raise TestFailed, "array(%s) self-slice-assign (cntr)" % `type` + if a.index("e") != 5: + raise TestFailed, "array(%s) index-test" % `type` + if a.count("a") != 2: + raise TestFailed, "array(%s) count-test" % `type` + a.remove("e") + if a != array("aabcde", type): + raise TestFailed, "array(%s) remove-test" % `type` + if a.pop(0) != "a": + raise TestFailed, "array(%s) pop-test" % `type` + if a.pop(1) != "b": + raise TestFailed, "array(%s) pop-test" % `type` + a.extend(array("xyz", type)) + if a != array("acdexyz", type): + raise TestFailed, "array(%s) extend-test" % `type` + a.pop() + a.pop() + a.pop() + x = a.pop() + if x != 'e': + raise TestFailed, "array(%s) pop-test" % `type` + if a != array("acd", type): + raise TestFailed, "array(%s) pop-test" % `type` + a.reverse() + if a != array("dca", type): + raise TestFailed, "array(%s) reverse-test" % `type` + else: + a = array([1, 2, 3, 4, 5], type) + a[:-1] = a + if a != array([1, 2, 3, 4, 5, 5], type): + raise TestFailed, "array(%s) self-slice-assign (head)" % `type` + a = array([1, 2, 3, 4, 5], type) + a[1:] = a + if a != array([1, 1, 2, 3, 4, 5], type): + raise TestFailed, "array(%s) self-slice-assign (tail)" % `type` + a = array([1, 2, 3, 4, 5], type) + a[1:-1] = a + if a != array([1, 1, 2, 3, 4, 5, 5], type): + raise TestFailed, "array(%s) self-slice-assign (cntr)" % `type` + if a.index(5) != 5: + raise TestFailed, "array(%s) index-test" % `type` + if a.count(1) != 2: + raise TestFailed, "array(%s) count-test" % `type` + a.remove(5) + if a != array([1, 1, 2, 3, 4, 5], type): + raise TestFailed, "array(%s) remove-test" % `type` + if a.pop(0) != 1: + raise TestFailed, "array(%s) pop-test" % `type` + if a.pop(1) != 2: + raise TestFailed, "array(%s) pop-test" % `type` + a.extend(array([7, 8, 9], type)) + if a != array([1, 3, 4, 5, 7, 8, 9], type): + raise TestFailed, "array(%s) extend-test" % `type` + a.pop() + a.pop() + a.pop() + x = a.pop() + if x != 5: + raise TestFailed, "array(%s) pop-test" % `type` + if a != array([1, 3, 4], type): + raise TestFailed, "array(%s) pop-test" % `type` + a.reverse() + if a != array([4, 3, 1], type): + raise TestFailed, "array(%s) reverse-test" % `type` + + # test that overflow exceptions are raised as expected for assignment + # to array of specific integral types +#CAU: nyi from math import pow +#CAU: nyi if type in ('b', 'h', 'i', 'l'): +#CAU: nyi # check signed and unsigned versions +#CAU: nyi a = array(type) +#CAU: nyi signedLowerLimit = -1 * long(pow(2, a.itemsize * 8 - 1)) +#CAU: nyi signedUpperLimit = long(pow(2, a.itemsize * 8 - 1)) - 1L +#CAU: nyi unsignedLowerLimit = 0 +#CAU: nyi unsignedUpperLimit = long(pow(2, a.itemsize * 8)) - 1L +#CAU: nyi testoverflow(type, signedLowerLimit, signedUpperLimit) +#CAU: nyi testoverflow(type.upper(), unsignedLowerLimit, unsignedUpperLimit) + + + +main()