[Jython-checkins] jython: bytearray: increment including comparison operations, __add__, append, find
frank.wierzbicki
jython-checkins at python.org
Wed May 23 19:21:27 CEST 2012
http://hg.python.org/jython/rev/f09dfd68d9e4
changeset: 6664:f09dfd68d9e4
user: Jeff Allen <ja...py at farowl.co.uk>
date: Fri May 18 09:30:33 2012 +0100
summary:
bytearray: increment including comparison operations, __add__, append, find
This increment includes _eq__, __ne__ and so on (which makes Python unit test work), and some of the basic Python API. In the absence of a memory buffer equivalent, BaseBytes provides a wrapper that permits bytearray operations to accept str arguments. test_bytes.py currently produces 4 fail and 70 error results. There are also improved JUnit tests to cover slice deletion.
files:
src/org/python/core/BaseBytes.java | 1200 ++++-
src/org/python/core/PyByteArray.java | 1069 ++-
src/org/python/core/PyByteArrayDerived.java | 2232 +++++-----
tests/java/org/python/core/BaseBytesTest.java | 61 +-
tests/java/org/python/core/PyByteArrayTest.java | 921 +++-
5 files changed, 3616 insertions(+), 1867 deletions(-)
diff --git a/src/org/python/core/BaseBytes.java b/src/org/python/core/BaseBytes.java
--- a/src/org/python/core/BaseBytes.java
+++ b/src/org/python/core/BaseBytes.java
@@ -9,28 +9,31 @@
/**
* Base class for Jython bytearray (and bytes in due course) that provides most of the Java API,
- * including Java List behaviour. Attempts to modify the contents through this API will throw
- * a TypeError if the actual type of the object is not mutable.
+ * including Java List behaviour. Attempts to modify the contents through this API will throw a
+ * TypeError if the actual type of the object is not mutable.
* <p>
- * It is possible for a Java client to treat this class as a <tt>List<PyInteger></tt>,
- * obtaining equivalent functionality to the Python interface in a Java paradigm.
- * The reason
- * {@link }
- * <p>Subclasses must define (from {@link PySequence}): <ul>
+ * It is possible for a Java client to treat this class as a <tt>List<PyInteger></tt>, obtaining
+ * equivalent functionality to the Python interface in a Java paradigm. The reason {@link }
+ * <p>
+ * Subclasses must define (from {@link PySequence}):
+ * <ul>
* <li>{@link #getslice(int, int, int)}</li>
* <li>{@link #repeat(int)}</li>
- * </ul>each returning an appropriate concrete type. Mutable subclasses should override:<ul>
+ * </ul>
+ * each returning an appropriate concrete type. Mutable subclasses should override:
+ * <ul>
* <li>{@link #pyset(int, PyObject)}</li>
* <li>{@link #setslice(int, int, int, PyObject)}</li>
* <li>{@link #del(int)}</li>
* <li>{@link #delRange(int, int)}</li>
- * </ul>
+ * </ul>
* since the default implementations will otherwise throw an exception.
*/
public abstract class BaseBytes extends PySequence implements MemoryViewProtocol, List<PyInteger> {
-
+
/**
* Simple constructor of empty zero-length array of defined type.
+ *
* @param type explicit Jython type
*/
public BaseBytes(PyType type) {
@@ -40,17 +43,18 @@
/**
* Simple constructor of zero-filled array of defined size and type.
+ *
* @param size required
* @param type explicit Jython type
*/
public BaseBytes(PyType type, int size) {
super(type);
- newStorage( size );
+ newStorage(size);
}
/**
* Construct byte array of defined type by copying values from int[].
- *
+ *
* @param type explicit Jython type
* @param value source of values (and size)
*/
@@ -58,14 +62,15 @@
super(type);
int n = value.length;
newStorage(n);
- for (int i = offset, j = 0; j < n; i++, j++) // Note offset may be non-zero
+ for (int i = offset, j = 0; j < n; i++, j++) {
storage[i] = byteCheck(value[j]);
+ }
}
/**
* Construct byte array of defined type by copying character values from a String. These values
* have to be in the Python byte range 0 to 255.
- *
+ *
* @param type explicit Jython type
* @param value source of characters
* @throws PyException if any value[i] > 255
@@ -74,17 +79,17 @@
super(type);
int n = value.length();
newStorage(n);
- int i = offset + size;
- while (n > 0)
- storage[--i] = byteCheck(value.charAt(--n));
- }
-
+ for (int i = offset, j = 0; j < n; j++) {
+ storage[i++] = byteCheck(value.charAt(j));
+ }
+ }
+
/**
* Helper for constructors and methods that manipulate the storage in mutable subclasses. It
* also permits shared storage between objects, which in general is unsafe if the storage is
* subject to modification independent of the object now being created. Immutable types may
* share storage (safely).
- *
+ *
* @param storage byte array allocated by client
* @param size number of bytes actually used
* @param offset index of first byte used
@@ -102,9 +107,9 @@
}
/**
- * Helper for constructors and methods that manipulate the storage in mutable subclassesin the
+ * Helper for constructors and methods that manipulate the storage in mutable subclasses in the
* case where the storage should consist of the first part of the given array.
- *
+ *
* @param storage byte array allocated by client
* @param size number of bytes actually used
* @throws IllegalArgumentException if the range [0:size] is not within the array bounds of
@@ -123,7 +128,7 @@
/**
* Helper for constructors and methods that manipulate the storage in mutable subclasses in the
* case where the storage should consist of exactly the whole of the given array.
- *
+ *
* @param storage byte array allocated by client
*/
protected void setStorage(byte[] storage) {
@@ -132,23 +137,25 @@
this.offset = 0;
}
-
/*
* ========================================================================================
* Support for memoryview
* ========================================================================================
- *
+ *
* This is present in order to facilitate development of PyMemoryView which a full
* implementation of bytearray would depend on, while at the same time a full implementation of
* memoryview depends on bytearray.
*/
/**
* Get hold of a <code>memoryview</code> on the current byte array.
+ *
* @see MemoryViewProtocol#getMemoryView()
*/
@Override
public MemoryView getMemoryView() {
- if (mv == null) mv = new MemoryViewImpl();
+ if (mv == null) {
+ mv = new MemoryViewImpl();
+ }
return mv;
}
@@ -198,23 +205,22 @@
}
}
-
-
+
/*
* ========================================================================================
* Support for construction and initialisation
* ========================================================================================
- *
+ *
* Methods here help subclasses set the initial state. They are designed with bytearray in mind,
* but note that from Python 3, bytes() has the same set of calls and behaviours, although in
- * Peterson's "sort of backport" to Python 2.x, bytes is effectively an alias for str and
- * it shows.
+ * Peterson's "sort of backport" to Python 2.x, bytes is effectively an alias for str and it
+ * shows.
*/
/**
* Helper for <code>__new__</code> and <code>__init__</code> and the Java API constructor from
* PyObject in subclasses.
- *
+ *
* @see org.python.core.ByteArray#bytearray___init__(PyObject[], String[])
* @see org.python.core.ByteArray#ByteArray(PyObject)
* @param arg primary argument from which value is taken
@@ -268,7 +274,7 @@
/**
* Helper for <code>__new__</code> and <code>__init__</code> and the Java API constructor from a
* text string with the specified encoding in subclasses.
- *
+ *
* @see #bytearray___init__(PyObject[], String[])
* @see PyByteArray#PyByteArray(PyString, String, String)
* @param arg primary argument from which value is taken
@@ -284,7 +290,7 @@
/**
* Helper for <code>__new__</code> and <code>__init__</code> and the Java API constructor from a
* text string with the specified encoding in subclasses.
- *
+ *
* @see #bytearray___init__(PyObject[], String[])
* @see PyByteArray#PyByteArray(PyString, String, String)
* @param arg primary argument from which value is taken
@@ -298,14 +304,12 @@
setBytes(0, encoded);
}
-
/**
- * Helper for {@linkplain #setslice(int, int, int, PyObject)},
- * for <code>__new__</code> and <code>__init__</code> and the Java API constructor from a
- * text string with the specified encoding in subclasses. This method thinly wraps a call to
- * the codecs module and deals with checking
- * for PyUnicode (where the encoding argument is mandatory).
- *
+ * Helper for {@linkplain #setslice(int, int, int, PyObject)}, for <code>__new__</code> and
+ * <code>__init__</code> and the Java API constructor from a text string with the specified
+ * encoding in subclasses. This method thinly wraps a call to the codecs module and deals with
+ * checking for PyUnicode (where the encoding argument is mandatory).
+ *
* @see #ByteArray(PyString, String, String)
* @param arg primary argument from which value is taken
* @param encoding name of optional encoding
@@ -319,25 +323,24 @@
if (arg instanceof PyUnicode) {
if (encoding != null) {
- encoded = codecs.encode((PyUnicode)arg, encoding, errors);
+ encoded = codecs.encode(arg, encoding, errors);
} else {
throw Py.TypeError("unicode argument without an encoding");
}
} else {
if (encoding != null) {
- encoded = codecs.encode((PyString)arg, encoding, errors);
+ encoded = codecs.encode(arg, encoding, errors);
} else {
- encoded = ((PyString)arg).getString();
+ encoded = arg.getString();
}
}
return encoded;
}
-
/**
* Fill a defined section of a byte array by copying character values from a String. These
* values have to be in the Python byte range 0 to 255.
- *
+ *
* @param start index in this byte array at which the first character code lands
* @param value source of characters
* @throws PyException(ValueError) if any value[i] > 255
@@ -345,14 +348,15 @@
protected void setBytes(int start, String value) throws PyException {
int n = value.length();
int io = offset + start;
- for (int j = 0; j < n; j++)
+ for (int j = 0; j < n; j++) {
storage[io++] = byteCheck(value.charAt(j));
+ }
}
/**
* Fill a strided slice of a byte array by copying character values from a String. These values
* have to be in the Python byte range 0 to 255.
- *
+ *
* @param start index in this byte array at which the first character code lands
* @param value source of characters
* @throws PyException(ValueError) if any value[i] > 255
@@ -365,12 +369,11 @@
io += step;
}
}
-
/**
* Helper for <code>__new__</code> and <code>__init__</code> and the Java API constructor from
* int in subclasses. Construct zero-filled bytearray of specified size.
- *
+ *
* @param n size of zero-filled array
*/
protected void init(int n) {
@@ -383,7 +386,7 @@
/**
* Helper for <code>__new__</code> and <code>__init__</code> and the Java API constructor from
* objects supporting the Jython implementation of PEP 3118 (memoryview) in subclasses.
- *
+ *
* @param value a memoryview object consistent with the slice assignment
* @throws PyException(NotImplementedError) until memoryview is properly supported
* @throws PyException(TypeError) if the memoryview is not byte-oriented
@@ -405,7 +408,7 @@
/**
* Helper for <code>__new__</code> and <code>__init__</code> and the Java API constructor from
* bytearray or bytes in subclasses.
- *
+ *
* @param source bytearray (or bytes) to copy
*/
protected void init(BaseBytes source) {
@@ -416,7 +419,7 @@
/**
* Helper for <code>__new__</code> and <code>__init__</code> and the Java API constructor from
* an arbitrary iterable Python type in subclasses. This will include generators and lists.
- *
+ *
* @param iter iterable source of values to enter in the array
*/
protected void init(Iterable<? extends PyObject> iter) {
@@ -426,33 +429,31 @@
*/
FragmentList fragList = new FragmentList();
fragList.loadFrom(iter);
-
+
// Now, aggregate all those fragments.
//
- if (fragList.totalCount>0) {
-
- if (fragList.size()==1) {
+ if (fragList.totalCount > 0) {
+
+ if (fragList.size() == 1) {
// Note that the first fragment is small: negligible waste if stolen directly.
Fragment frag = fragList.getFirst();
setStorage(frag.storage, frag.count);
-
+
} else {
// Stitch the fragments together in new storage of sufficient size
newStorage(fragList.totalCount);
fragList.emptyInto(storage, offset);
}
-
- } else
+
+ } else {
// Nothing in the iterator
setStorage(emptyStorage);
+ }
}
-
-
-
/**
- * Intended as a fragment of temporary storage for use we do not know how many bytes of allocate, and we are
- * reading in some kind of iterable stream.
+ * Intended as a fragment of temporary storage for use we do not know how many bytes of
+ * allocate, and we are reading in some kind of iterable stream.
*/
protected static class Fragment {
@@ -472,7 +473,7 @@
return count == storage.length;
}
}
-
+
/**
* A container of temporary storage when we do not know how many bytes to allocate, and we are
* reading in some kind of iterable stream.
@@ -486,7 +487,7 @@
/**
* Load bytes into the container from the given iterable
- *
+ *
* @param iter iterable source of values to enter into the container
* @throws PyException(TypeError) if any value not acceptable type
* @throws PyException(ValueError) if any value<0 or value>255 or string length!=1
@@ -522,8 +523,9 @@
}
/**
- * Move the contents of this container to the given byte array at the specified index.
- * This method leaves this container empty.
+ * Move the contents of this container to the given byte array at the specified index. This
+ * method leaves this container empty.
+ *
* @param target destination array
* @param p position to write first byte
*/
@@ -543,7 +545,7 @@
* we run out. (You must have checked beforehand that the destination is big enough.) This
* method leaves this container empty. If the step size is one, it would be much quicker to
* call {@link BaseBytes#emptyInto(byte[], int)}
- *
+ *
* @param target destination array
* @param start position to write first byte
* @param step amount to advance index with each byte
@@ -561,39 +563,39 @@
}
}
-
-
-
- /* ========================================================================================
+
+ /*
+ * ========================================================================================
* Sharable storage
* ========================================================================================
- *
- * The storage is provided by a byte array that may be somewhat larger than the number of
- * bytes actually stored, and these bytes may begin at an offset within the storage.
- * Immutable subclasses of BaseBytes may exploit this to share storage when
- * constructed from a slice of another immutable subclass. Mutable subclasses may exploit it
- * to provide efficient insertions near the start of the array.
+ *
+ * The storage is provided by a byte array that may be somewhat larger than the number of bytes
+ * actually stored, and these bytes may begin at an offset within the storage. Immutable
+ * subclasses of BaseBytes may exploit this to share storage when constructed from a slice of
+ * another immutable subclass. Mutable subclasses may exploit it to provide efficient insertions
+ * near the start of the array.
*/
-
+
/** Empty storage constant */
protected static final byte[] emptyStorage = new byte[0];
-
+
/** Storage array. */
- protected byte[] storage;
-
+ protected byte[] storage = emptyStorage;
+
/** Number of bytes actually used in storage array. */
- protected int size;
+ protected int size = 0;
/** Index of first byte used in storage array. */
- protected int offset;
+ protected int offset = 0;
/**
* Check that an index is within the range of the array, that is <tt>0<=index<size</tt>.
+ *
* @param index to check
* @throws PyException(IndexError) if the index is outside the array bounds
*/
protected final void indexCheck(int index) throws PyException {
- if (index<0 || index>=size) {
+ if (index < 0 || index >= size) {
throw Py.IndexError(getType().fastGetName() + " index out of range");
}
}
@@ -602,11 +604,11 @@
* Allocate fresh, zero-filled storage for the requested number of bytes and make that the size.
* If the size needed is zero, the "storage" allocated is the shared emptyStorage array. The
* allocated size may be bigger than needed, and the method chooses a value for offset.
- *
+ *
* @param needed becomes the new value of this.size
*/
protected void newStorage(int needed) {
- // The implementation for immutable arrays allocates exactly, and with offset zero.
+ // The implementation for immutable arrays allocates only as many bytes as needed.
if (needed > 0) {
setStorage(new byte[needed]); // guaranteed zero (by JLS 2ed para 4.5.5)
} else {
@@ -614,96 +616,955 @@
}
}
-
/**
- * Check that an integer is suitable for storage in a (Python) byte array,
- * and convert it to the Java byte value that can be stored there.
- * (Java bytes run -128..127 whereas Python bytes run 0..255.)
+ * Check that an integer is suitable for storage in a (Python) byte array, and convert it to the
+ * Java byte value that can be stored there. (Java bytes run -128..127 whereas Python bytes run
+ * 0..255.)
+ *
* @param value to convert.
* @throws PyException(ValueError) if value<0 or value>255
*/
protected static final byte byteCheck(int value) throws PyException {
- if (value<0 || value>=255) {
+ if (value < 0 || value > 255) {
throw Py.ValueError("byte must be in range(0, 256)");
}
- return (byte) value;
+ return (byte)value;
}
-
+
/**
- * Check that the value of an PyInteger is suitable for storage in a (Python) byte array,
- * and convert it to the Java byte value that can be stored there.
- * (Java bytes run -128..127 whereas Python bytes run 0..255.)
+ * Check that the value of an PyInteger is suitable for storage in a (Python) byte array, and
+ * convert it to the Java byte value that can be stored there. (Java bytes run -128..127 whereas
+ * Python bytes run 0..255.)
+ *
* @param value to convert.
* @throws PyException(ValueError) if value<0 or value>255
*/
protected static final byte byteCheck(PyInteger value) throws PyException {
return byteCheck(value.asInt());
}
-
+
/**
- * Check that the type and value of a PyObject is suitable for storage in a (Python) byte
- * array, and convert it to the Java byte value that can be stored there.
- * (Java bytes run -128..127 whereas Python bytes run 0..255.)
- * Acceptable types are: <ul>
+ * Check that the type and value of a PyObject is suitable for storage in a (Python) byte array,
+ * and convert it to the Java byte value that can be stored there. (Java bytes run -128..127
+ * whereas Python bytes run 0..255.) Acceptable types are:
+ * <ul>
* <li>PyInteger in range 0 to 255 inclusive</li>
* <li>PyLong in range 0 to 255 inclusive</li>
+ * <li>Any type having an __index__() method, in range 0 to 255 inclusive</li>
* <li>PyString of length 1</li>
* </ul>
+ *
* @param value to convert.
* @throws PyException(TypeError) if not acceptable type
* @throws PyException(ValueError) if value<0 or value>255 or string length!=1
*/
protected static final byte byteCheck(PyObject value) throws PyException {
- if (value instanceof PyInteger || value instanceof PyLong) {
+ if (value.isIndex()) {
// This will possibly produce Py.OverflowError("long int too large to convert")
- return byteCheck(value.asInt());
- } else if (value instanceof PyString) {
+ return byteCheck(value.asIndex());
+ } else if (value.getType() == PyString.TYPE) {
+ // Exactly PyString (not PyUnicode)
String strValue = ((PyString)value).getString();
if (strValue.length() != 1) {
throw Py.ValueError("string must be of size 1");
}
return byteCheck(strValue.charAt(0));
- } else
+ } else {
throw Py.TypeError("an integer or string of size 1 is required");
+ }
}
-
- /* ========================================================================================
- * API for org.python.core.PySequence
+
+ /*
+ * ========================================================================================
+ * Wrapper class to make other objects into byte arrays
+ * ========================================================================================
+ *
+ * In much of the bytearray and bytes API, the "other sequence" argument will accept any type
+ * that supports the buffer protocol, that is, the object can supply a memoryview through which
+ * the value is treated as a byte array. We have not implemented memoryview objects yet, and it
+ * is not clear what the Java API should be. As a temporary expedient, we define here a
+ * byte-oriented view on the key built-in types.
+ */
+
+ interface View {
+
+ /**
+ * Return the indexed byte as a byte
+ *
+ * @param index
+ * @return byte at index
+ */
+ public byte byteAt(int index);
+
+ /**
+ * Return the indexed byte as an unsigned integer
+ *
+ * @param index
+ * @return value of the byte at index
+ */
+ public int intAt(int index);
+
+ /**
+ * Number of bytes in the view: valid indexes are from <code>0</code> to
+ * <code>size()-1</code>.
+ *
+ * @return the size
+ */
+ public int size();
+
+ /**
+ * Return a new view that is a simple slice of this one defined by <code>[start:end]</code>.
+ * <code>Py.None</code> or <code>null</code> are acceptable for start and end, and have
+ * Python slice semantics. Negative values for start or end are treated as "from the end",
+ * in the usual manner of Python slices.
+ *
+ * @param start first element to include
+ * @param end first element after slice, not to include
+ * @return byte-oriented view
+ */
+ public View slice(PyObject start, PyObject end);
+ }
+
+ /**
+ * Some common apparatus for views including the implementation of slice semantics.
+ */
+ static abstract class ViewBase implements View {
+
+ // Implement Python slice semantics
+ public View slice(PyObject ostart, PyObject oend) {
+ PySlice s = new PySlice(ostart, oend, null);
+ int[] index = s.indicesEx(size()); // [ start, end, 1, end-start ]
+ return sliceImpl(index[0], index[(index[3] > 0) ? 1 : 0]);
+ }
+
+ /**
+ * Implementation-specific part of returning a slice of the current view. This is called by
+ * the default implementations of {@link #slice(int, int)} and
+ * {@link #slice(PyObject, PyObject)} once the <code>start</code> and <code>end</code>
+ * arguments have been reduced to simple integer indexes. It is guaranteed that
+ * <code>start>=0</code> and <code>size()>=end>=start</code> when the method is called.
+ * Implementors are encouraged to do something more efficient than piling on anothe wrapper.
+ *
+ * @param start first element to include
+ * @param end first element after slice, not to include
+ * @return byte-oriented view
+ */
+ protected abstract View sliceImpl(int start, int end);
+
+ }
+
+ /**
+ * Return a wrapper providing a byte-oriented view for whatever object is passed, or return
+ * <code>null</code> if we don't know how.
+ *
+ * @param b object to wrap
+ * @return byte-oriented view or null
+ */
+ protected static View getView(PyObject b) {
+ if (b == null) {
+ return null;
+ } else if (b instanceof BaseBytes) {
+ return new ViewOfBytes((BaseBytes)b);
+ } else if (b.getType() == PyString.TYPE) {
+ return new ViewOfString(b.asString());
+ }
+ return null;
+ }
+
+ /**
+ * Return a wrapper providing a byte-oriented view for a slice of whatever object is passed, or
+ * return <code>null</code> if we don't know how.
+ *
+ * @param b object to wrap
+ * @param start index of first byte to include
+ * @param end index of first byte after slice
+ * @return byte-oriented view or null
+ */
+ protected static View getView(PyObject b, PyObject start, PyObject end) {
+ View whole = getView(b);
+ if (whole != null) {
+ return whole.slice(start, end);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Return a wrapper providing a byte-oriented view of a slice of this object.
+ *
+ * @param ostart index of first byte to include
+ * @param oend index of first byte after slice
+ * @return byte-oriented view or null
+ */
+ protected ViewOfBytes slice(PyObject ostart, PyObject oend) {
+ PySlice s = new PySlice(ostart, oend, null);
+ int[] index = s.indicesEx(size); // [ start, end, 1, end-start ]
+ return new ViewOfBytes(storage, offset + index[0], index[3]);
+ }
+
+ /**
+ * Return a wrapper providing a byte-oriented view for whatever object is passed, or raise an
+ * exception if we don't know how.
+ *
+ * @param b object to wrap
+ * @return byte-oriented view
+ */
+ protected static View getViewOrError(PyObject b) {
+ View res = getView(b);
+ if (res == null) {
+ // String fmt = "type %s doesn't support the buffer API"; // CPython
+ String fmt = "cannot access type %s as bytes";
+ throw Py.NotImplementedError(String.format(fmt, b.getType().fastGetName()));
+ }
+ return res;
+ }
+
+ /**
+ * Return a wrapper providing a byte-oriented view for a slice of whatever object is passed, or
+ * raise an exception if we don't know how.
+ *
+ * @param b object to wrap
+ * @param start index of first byte to include
+ * @param end index of first byte after slice
+ * @return byte-oriented view or null
+ */
+ protected static View getViewOrError(PyObject b, PyObject start, PyObject end) {
+ View whole = getViewOrError(b);
+ return whole.slice(start, end);
+ }
+
+ /**
+ * Wrapper providing a byte-oriented view for String (or PyString).
+ */
+ protected static class ViewOfString extends ViewBase {
+
+ private String str;
+
+ /**
+ * Create a byte-oriented view of a String.
+ *
+ * @param str
+ */
+ public ViewOfString(String str) {
+ this.str = str;
+ }
+
+ public byte byteAt(int index) {
+ return byteCheck(str.charAt(index));
+ }
+
+ public int intAt(int index) {
+ return str.charAt(index);
+ }
+
+ public int size() {
+ return str.length();
+ }
+
+ public View sliceImpl(int start, int end) {
+ return new ViewOfString(str.substring(start, end));
+ }
+
+ }
+
+ /**
+ * Wrapper providing a byte-oriented view for byte arrays descended from BaseBytes. Not that
+ * this view is not safe against concurrent modification by this or another thread: if the byte
+ * array type is mutable, and the contents change, the contents of the view are likely to be
+ * invalid.
+ */
+ protected static class ViewOfBytes extends ViewBase {
+
+ private byte[] storage;
+ private int offset;
+ private int size;
+
+ /**
+ * Create a byte-oriented view of a byte array descended from BaseBytes.
+ *
+ * @param obj
+ */
+ public ViewOfBytes(BaseBytes obj) {
+ this.storage = obj.storage;
+ this.offset = obj.offset;
+ this.size = obj.size;
+ }
+
+ /**
+ * Create a byte-oriented view of a byte array explicitly. If the size<0, a zero-length
+ * slice results.
+ *
+ * @param storage storage array
+ * @param offset
+ * @param size
+ */
+ ViewOfBytes(byte[] storage, int offset, int size) {
+ if (size > 0) {
+ this.storage = storage;
+ this.offset = offset;
+ this.size = size;
+ } else {
+ this.storage = emptyStorage;
+ this.offset = 0;
+ this.size = 0;
+ }
+ }
+
+ public byte byteAt(int index) {
+ return storage[offset + index];
+ }
+
+ public int intAt(int index) {
+ return 0xff & storage[offset + index];
+ }
+
+ public int size() {
+ return size;
+ }
+
+ public View sliceImpl(int start, int end) {
+ return new ViewOfBytes(storage, offset + start, end - start);
+ }
+ }
+
+ /*
+ * ======================================================================================== API
+ * for org.python.core.PySequence
* ========================================================================================
*/
protected PyInteger pyget(int index) {
return new PyInteger(intAt(index));
}
-
- /* We're not implementing these here, but we can give a stronger guarantee about the return
- * type and save some casting and type anxiety.
+
+ /*
+ * We're not implementing these here, but we can give a stronger guarantee about the return type
+ * and save some casting and type anxiety.
*/
protected abstract BaseBytes getslice(int start, int stop, int step);
+
protected abstract BaseBytes repeat(int count);
-
+
/*
* And this extension point should be overridden in mutable subclasses
*/
-
+
/**
* Insert the element (interpreted as a Python byte value) at the given index. The default
* implementation produces a Python TypeError, for the benefit of immutable types. Mutable types
* must override it.
- *
+ *
* @param index to insert at
* @param element to insert (by value)
* @throws PyException(IndexError) if the index is outside the array bounds
* @throws PyException(ValueError) if element<0 or element>255
* @throws PyException(TypeError) if the subclass is immutable
*/
- public void pyadd(int index, PyInteger element) {
+ public void pyinsert(int index, PyObject element) {
// This won't succeed: it just produces the right error.
// storageReplace(index, 0, 1);
pyset(index, element);
}
-
- /* ========================================================================================
- * API for Java access as byte[]
+
+ /*
+ * ========================================================================================
+ * Support for Python API common to mutable and immutable subclasses
+ * ========================================================================================
+ */
+
+ @Override
+ public int __len__() {
+ return size;
+ }
+
+ /**
+ * Comparison function between two byte arrays returning 1, 0, or -1 as a>b, a==b, or a<b
+ * respectively. The comparison is by value, using Python unsigned byte conventions, and
+ * left-to-right (low to high index). Zero bytes are significant, even at the end of the array:
+ * <code>[1,2,3]<[1,2,3,0]</code>, for example and <code>[]</code> is less than every other
+ * value, even <code>[0]</code>.
+ *
+ * @param a left-hand array in the comparison
+ * @param b right-hand array in the comparison
+ * @return 1, 0 or -1 as a>b, a==b, or a<b respectively
+ */
+ private static int compare(BaseBytes a, BaseBytes b) {
+
+ // Compare elements one by one in these ranges:
+ int ap = a.offset;
+ int aEnd = ap + a.size;
+ int bp = b.offset;
+ int bEnd = bp + b.size;
+
+ while (ap < aEnd) {
+ if (bp >= bEnd) {
+ // a is longer than b
+ return 1;
+ } else {
+ // Compare the corresponding bytes (as unsigned ints)
+ int aVal = 0xff & a.storage[ap++];
+ int bVal = 0xff & b.storage[bp++];
+ int diff = aVal - bVal;
+ if (diff != 0) {
+ return (diff < 0) ? -1 : 1;
+ }
+ }
+ }
+
+ // All the bytes matched and we reached the end of a
+ if (bp < bEnd) {
+ // But we didn't reach the end of b
+ return -1;
+ } else {
+ // And the end of b at the same time, so they're equal
+ return 0;
+ }
+
+ }
+
+// /**
+// * Comparison function between a byte array and a String returning 1, 0 or -1 as a>b, a==b, or
+// * a<b respectively. The comparison is by value, using Python unsigned byte conventions for
+// * the byte array and character code for elements of the string, and left-to-right (low to high
+// * index). Zero bytes are significant, even at the end of the array:
+// * <code>[65,66,67]<"ABC\u0000"</code>, for example and <code>[]</code> is less than every
+// * non-empty String, while <code>[]==""</code>.
+// *
+// * @param a left-hand array in the comparison
+// * @param b right-hand String in the comparison
+// * @return 1, 0 or -1 as a>b, a==b, or a<b respectively
+// */
+// private static int compare(BaseBytes a, String b) {
+//
+// // Compare elements one by one in these ranges:
+// int ap = a.offset;
+// int aEnd = ap + a.size;
+// int bp = 0;
+// int bEnd = b.length();
+//
+// while (ap < aEnd) {
+// if (bp >= bEnd) {
+// // a is longer than b
+// return 1;
+// } else {
+// // Compare the corresponding bytes and character codes
+// int aVal = 0xff & a.storage[ap++];
+// int bVal = b.charAt(bp++);
+// int diff = aVal - bVal;
+// if (diff != 0) {
+// return (diff < 0) ? -1 : 1;
+// }
+// }
+// }
+//
+// // All the bytes matched and we reached the end of a
+// if (bp < bEnd) {
+// // But we didn't reach the end of b
+// return -1;
+// } else {
+// // And the end of b at the same time, so they're equal
+// return 0;
+// }
+//
+// }
+
+ /**
+ * Comparison function between a byte array and a byte-oriented View of some other object, such
+ * as a String, returning 1, 0 or -1 as a>b, a==b, or a<b respectively. The comparison is by
+ * value, using Python unsigned byte conventions, left-to-right (low to high index). Zero bytes
+ * are significant, even at the end of the array: <code>[65,66,67]<"ABC\u0000"</code>, for
+ * example and <code>[]</code> is less than every non-empty b, while <code>[]==""</code>.
+ *
+ * @param a left-hand array in the comparison
+ * @param b right-hand wrapped object in the comparison
+ * @return 1, 0 or -1 as a>b, a==b, or a<b respectively
+ */
+ private static int compare(BaseBytes a, View b) {
+
+ // Compare elements one by one in these ranges:
+ int ap = a.offset;
+ int aEnd = ap + a.size;
+ int bp = 0;
+ int bEnd = b.size();
+
+ while (ap < aEnd) {
+ if (bp >= bEnd) {
+ // a is longer than b
+ return 1;
+ } else {
+ // Compare the corresponding bytes
+ int aVal = 0xff & a.storage[ap++];
+ int bVal = b.intAt(bp++);
+ int diff = aVal - bVal;
+ if (diff != 0) {
+ return (diff < 0) ? -1 : 1;
+ }
+ }
+ }
+
+ // All the bytes matched and we reached the end of a
+ if (bp < bEnd) {
+ // But we didn't reach the end of b
+ return -1;
+ } else {
+ // And the end of b at the same time, so they're equal
+ return 0;
+ }
+
+ }
+
+ /**
+ * Comparison function between byte array types and any other object. The set of 6
+ * "rich comparison" operators are based on this.
+ *
+ * @param b
+ * @return 1, 0 or -1 as this>b, this==b, or this<b respectively, or -2 if the comparison is
+ * not implemented
+ */
+ private synchronized int basebytes_cmp(PyObject b) {
+
+ // This is not exposed as bytearray and bytes have no __cmp__.
+
+ if (this == b) {
+ // Same object: quick result
+ return 0;
+
+ } else {
+
+ // Try to get a byte-oriented view
+ View bv = getView(b);
+
+ if (bv == null) {
+ // Signifies a type mis-match. See PyObject _cmp_unsafe() and related code.
+ return -2;
+
+ } else {
+ // Object supported by our interim memory view
+ return compare(this, bv);
+
+ }
+ }
+ }
+
+// /**
+// * Comparison function between byte array types and any other object. The set of 6
+// * "rich comparison" operators are based on this.
+// *
+// * @param b
+// * @return 1, 0 or -1 as this>b, this==b, or this<b respectively, or -2 if the comparison is
+// * not implemented
+// */
+// private synchronized int basebytes_cmp(PyObject b) {
+//
+// // This is based on PyFloat.float___cmp__() as it seems to have the same need to support
+// // multiple types for other, but it is not exposed as bytearray and bytes have no __cmp__.
+//
+// if (this == b) {
+// // Same object: quick result
+// return 0;
+//
+// } else if (b instanceof BaseBytes) {
+// return compare(this, (BaseBytes)b);
+//
+// } else if (b.getType() == PyString.TYPE) {
+// /*
+// * Necessary to permit comparison of bytearray and bytes, which in in Python 2.7 is an
+// * alias of str. Remove in 3.0
+// */
+// return compare(this, ((PyString)b).asString());
+//
+// } else if (b instanceof MemoryViewProtocol) {
+// // XXX: Revisit when we have an implementation of memoryview
+// // MemoryView mv = ((MemoryViewProtocol) other).getMemoryView();
+// return -2;
+//
+// } else {
+// // Signifies a type mis-match. See PyObject _cmp_unsafe() and related code.
+// return -2;
+// }
+// }
+
+ /**
+ * Fail-fast comparison function between byte array types and any other object, for when the
+ * test is only for equality. The "rich comparison" operators <code>__eq__</code> and
+ * <code>__ne__</code> are based on this.
+ *
+ * @param b
+ * @return 0 if this==b, or +1 or -1 if this!=b, or -2 if the comparison is not implemented
+ */
+ private synchronized int basebytes_cmpeq(PyObject b) {
+
+ if (this == b) {
+ // Same object: quick result
+ return 0;
+
+ } else {
+
+ // Try to get a byte-oriented view
+ View bv = getView(b);
+
+ if (bv == null) {
+ // Signifies a type mis-match. See PyObject _cmp_unsafe() and related code.
+ return -2;
+
+ } else if (bv.size() != size) {
+ // Different size: can't be equal, and we don't care which is bigger
+ return 1;
+
+ } else {
+ // Object supported by our interim memory view
+ return compare(this, bv);
+
+ }
+ }
+ }
+
+// /**
+// * Fail-fast comparison function between byte array types and any other object, for when the
+// * test is only for equality. The "rich comparison" operators <code>__eq__</code> and
+// * <code>__ne__</code> are based on this.
+// *
+// * @param b
+// * @return 0 if this==b, or +1 or -1 if this!=b, or -2 if the comparison is not implemented
+// */
+// private synchronized int basebytes_cmpeq(PyObject b) {
+//
+// if (b instanceof BaseBytes) {
+// if (((BaseBytes)b).size != size) {
+// // Different size: can't be equal, and we don't care which is bigger
+// return 1;
+// }
+// } else if (b.getType() == PyString.TYPE) {
+// /*
+// * Necessary to permit comparison of bytearray and bytes, which in in Python 2.7 is an
+// * alias of str. Remove in 3.0
+// */
+// if (((PyString)b).__len__() != size) {
+// // Different size: can't be equal, and we don't care which is bigger
+// return 1;
+// }
+// }
+// return basebytes_cmp(b);
+// }
+
+ /**
+ * Implementation of __eq__ (equality) operator, capable of comparison with another byte array
+ * or bytes. Comparison with an invalid type returns null.
+ *
+ * @param other
+ * @return
+ */
+ final PyObject basebytes___eq__(PyObject other) {
+ int cmp = basebytes_cmpeq(other);
+ if (cmp == 0) {
+ return Py.True;
+ } else if (cmp > -2) {
+ return Py.False;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Implementation of __ne__ (not equals) operator, capable of comparison with another byte array
+ * or bytes. Comparison with an invalid type returns null.
+ *
+ * @param other
+ * @return
+ */
+ final PyObject basebytes___ne__(PyObject other) {
+ int cmp = basebytes_cmpeq(other);
+ if (cmp == 0) {
+ return Py.False;
+ } else if (cmp > -2) {
+ return Py.True;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Implementation of __lt__ (less than) operator, capable of comparison with another byte array
+ * or bytes. Comparison with an invalid type returns null.
+ *
+ * @param other
+ * @return
+ */
+ final PyObject basebytes___lt__(PyObject other) {
+ int cmp = basebytes_cmp(other);
+ if (cmp >= 0) {
+ return Py.False;
+ } else if (cmp > -2) {
+ return Py.True;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Implementation of __le__ (less than or equal to) operator, capable of comparison with another
+ * byte array or bytes. Comparison with an invalid type returns null.
+ *
+ * @param other
+ * @return
+ */
+ final PyObject basebytes___le__(PyObject other) {
+ int cmp = basebytes_cmp(other);
+ if (cmp > 0) {
+ return Py.False;
+ } else if (cmp > -2) {
+ return Py.True;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Implementation of __ge__ (greater than or equal to) operator, capable of comparison with
+ * another byte array or bytes. Comparison with an invalid type returns null.
+ *
+ * @param other
+ * @return
+ */
+ final PyObject basebytes___ge__(PyObject other) {
+ int cmp = basebytes_cmp(other);
+ if (cmp >= 0) {
+ return Py.True;
+ } else if (cmp > -2) {
+ return Py.False;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Implementation of __gt__ (greater than) operator, capable of comparison with another byte
+ * array or bytes. Comparison with an invalid type returns null.
+ *
+ * @param other
+ * @return
+ */
+ final PyObject basebytes___gt__(PyObject other) {
+ int cmp = basebytes_cmp(other);
+ if (cmp > 0) {
+ return Py.True;
+ } else if (cmp > -2) {
+ return Py.False;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Equivalent of the 'string_escape' decode to a String that is all-printable, showing non
+ * printable charater as lowercase hex escapes, except '\t', '\n', and '\r'. This supports
+ * <code>__repr__()</code>.
+ *
+ * @return the byte array as a String, still encoded
+ */
+ protected synchronized String asEscapedString() {
+ StringBuilder buf = new StringBuilder(size + (size >> 8) + 10);
+ int jmax = offset + size;
+ for (int j = offset; j < jmax; j++) {
+ int c = 0xff & storage[j];
+ if (c >= 0x7f) { // Unprintable high 128 and DEL
+ appendHexEscape(buf, c);
+ } else if (c >= ' ') { // Printable
+ if (c == '\\') { // Special case
+ buf.append("\\\\");
+ } else {
+ buf.append((char)c);
+ }
+ } else if (c == '\t') { // Spacial cases in the low 32
+ buf.append("\\t");
+ } else if (c == '\n') {
+ buf.append("\\n");
+ } else if (c == '\r') {
+ buf.append("\\r");
+ } else {
+ appendHexEscape(buf, c);
+ }
+ }
+ return buf.toString();
+ }
+
+ private static final void appendHexEscape(StringBuilder buf, int c) {
+ buf.append("\\x")
+ .append(Character.forDigit((c & 0xf0) >> 4, 16))
+ .append(Character.forDigit(c & 0xf, 16));
+ }
+
+ /**
+ * Search for the target in this byte array, returning true if found and false if not. The
+ * target must be compatible with the Python byte range.
+ *
+ * @param target byte value to search for
+ * @return true iff found
+ */
+ protected final synchronized boolean basebytes___contains__(PyObject target) {
+ byte t = byteCheck(target);
+ int jmax = offset + size;
+ for (int j = offset; j < jmax; j++) {
+ if (storage[j] == t) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Copy the bytes of a byte array to the characters of a String with no change in ordinal value.
+ * This could also be described as 'latin-1' decoding of the byte array to a String.
+ *
+ * @return the byte array as a String, still encoded
+ */
+ private synchronized String asEncodedString() {
+ StringBuilder buf = new StringBuilder(size);
+ int jmax = offset + size;
+ for (int j = offset; j < jmax; j++) {
+ buf.append((char)(0xff & storage[j]));
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Decode the byte array to a Unicode string according to the default encoding. The returned
+ * PyObject should be a <code>PyUnicode</code>, since the default codec is well-behaved.
+ *
+ * @return object containing the decoded characters
+ */
+ public PyObject decode() {
+ return decode(null, null);
+ }
+
+ /**
+ * Decode the byte array to a Unicode string according to the specified encoding and default
+ * error policy. The returned PyObject will usually be a <code>PyUnicode</code>, but in practice
+ * it is whatever the <code>decode</code> method of the codec decides.
+ *
+ * @param encoding the name of the codec (uses default codec if null)
+ * @return object containing the decoded characters
+ */
+ public PyObject decode(String encoding) {
+ return decode(encoding, null);
+ }
+
+ /**
+ * Decode the byte array to a Unicode string according to the specified encoding and error
+ * policy. The returned PyObject will usually be a <code>PyUnicode</code>, but in practice it is
+ * whatever the <code>decode</code> method of the codec decides.
+ *
+ * @param encoding the name of the codec (uses default codec if null)
+ * @param errors the name of the error policy (uses 'strict' if null)
+ * @return object containing the decoded characters
+ */
+ public PyObject decode(String encoding, String errors) {
+ /*
+ * Provide a Python <code>str</code> input to the decode method of a codec, which in v2.7
+ * expects a PyString. (In Python 3k the codecs decode from the <code>bytes</code> type, so
+ * we can pass this directly.)
+ */
+ PyString this_ = new PyString(this.asEncodedString());
+ return codecs.decode(this_, encoding, errors);
+ }
+
+ /**
+ * Ready-to-expose implementation of decode( [ encoding [, errors ]] )
+ *
+ * @param args Python argument list
+ * @param keywords Assocaited keywords
+ * @return
+ */
+ protected final PyObject basebytes_decode(PyObject[] args, String[] keywords) {
+ ArgParser ap = new ArgParser("decode", args, keywords, "encoding", "errors");
+ String encoding = ap.getString(0, null);
+ String errors = ap.getString(1, null);
+ return decode(encoding, errors);
+ }
+
+ /**
+ * Ready-to-expose implementation of Python <code>find( sub [, start [, end ]] )</code>. Return
+ * the lowest index in the byte array where byte sequence <code>sub</code> is found, such that
+ * <code>sub</code> is contained in the slice <code>[start:end]</code>. Arguments
+ * <code>start</code> and <code>end</code> (which may be <code>null</code> or
+ * <code>Py.None</code> ) are interpreted as in slice notation. Return -1 if <code>sub</code> is
+ * not found.
+ *
+ * @param sub bytes to find
+ * @param start of slice to search
+ * @param end of slice to search
+ * @return index of start of ocurrence of sub within this byte array
+ */
+ final int basebytes_find(PyObject sub, PyObject start, PyObject end) {
+ ViewOfBytes v = this.slice(start, end);
+ byte[] buf = v.storage;
+ View vsub = getViewOrError(sub);
+ int n = vsub.size();
+ // No point testing beyond this location, as insufficient space:
+ int pmax = v.offset + v.size - n;
+ // Use start positions from v.offset to pmax in the buffer buf
+ for (int p = v.offset; p < pmax; p++) {
+ int j;
+ for (j = 0; j < n; j++) {
+ if (buf[p + j] != vsub.byteAt(j)) {
+ break;
+ }
+ }
+ // If we tested all n bytes, that's a match. Note that the returned index is
+ // relative to the (operative) start of this, not relative to the start of the slice.
+ if (j == n) {
+ return p - this.offset;
+ }
+ }
+ // We tested all the start positions without success
+ return -1;
+ }
+
+ /**
+ * Convenience method to create a <code>TypeError</code> PyException with the message
+ * "can't concat {type} to {toType}"
+ *
+ * @param type
+ * @param toType
+ * @return PyException (TypeError) as detailed
+ */
+ public static PyException ConcatenationTypeError(PyType type, PyType toType) {
+ String fmt = "can't concat %s to %s";
+ return Py.TypeError(String.format(fmt, type.fastGetName(), toType.fastGetName()));
+ }
+
+ /**
+ * Support for pickling byte arrays: reduce a byte array to the actual type, arguments for
+ * (re-)construction of the object, and the dictionary of any user-defined sub-class.
+ *
+ * @return PyTuple that is first stage in pickling byte array
+ */
+ public PyObject __reduce__() {
+ return basebytes___reduce__();
+ }
+
+ final PyTuple basebytes___reduce__() {
+ PyUnicode encoded = new PyUnicode(this.asEncodedString());
+ PyObject args = new PyTuple(encoded, getPickleEncoding());
+ PyObject dict = __findattr__("__dict__");
+ return new PyTuple(getType(), args, (dict != null) ? dict : Py.None);
+ }
+
+ private static PyString PICKLE_ENCODING;
+
+ /**
+ * Name the encoding effectively used in __reduce__() suport for pickling: this choice is
+ * hard-coded in CPython as "latin-1".
+ */
+ private static final PyString getPickleEncoding() {
+ if (PICKLE_ENCODING == null) {
+ PICKLE_ENCODING = new PyString("latin-1");
+ }
+ return PICKLE_ENCODING;
+ }
+
+ /*
+ * ======================================================================================== API
+ * for Java access as byte[]
* ========================================================================================
*
* Just the immutable case for now
@@ -711,29 +1572,33 @@
/**
* No range check access to byte[index].
+ *
* @param index
* @return the byte at the given index
*/
private final synchronized byte byteAt(int index) {
- return storage[index+offset];
+ return storage[index + offset];
}
/**
* Return the Python byte (in range 0 to 255 inclusive) at the given index.
+ *
* @param index of value in byte array
* @return the integer value at the index
* @throws PyException(IndexError) if the index is outside the array bounds
*/
public synchronized int intAt(int index) throws PyException {
indexCheck(index);
- return 0xff & ((int)byteAt(index));
+ return 0xff & byteAt(index);
}
/**
* Helper to implement {@link #repeat(int)}. Use something like:
- *
+ *
* <pre>
- *
+ *
+ *
+ *
* @Override
* protected PyByteArray repeat(int count) {
* PyByteArray ret = new PyByteArray();
@@ -741,7 +1606,7 @@
* return ret;
* }
* </pre>
- *
+ *
* @param count the number of times to repeat this.
* @return this byte array repeated count times.
*/
@@ -753,9 +1618,9 @@
return dst;
}
-
- /* ========================================================================================
- * API for java.util.List<PyInteger>
+ /*
+ * ======================================================================================== API
+ * for java.util.List<PyInteger>
* ========================================================================================
*/
@@ -773,12 +1638,15 @@
}
@Override
- public int size() { return size; }
+ public int size() {
+ return size;
+ }
// For mutable subclass use
-
+
/**
* Replaces the element at the specified position in this list with the specified element.
+ *
* @see java.util.AbstractList#set(int, java.lang.Object)
* @throws PyException(TypeError) if actual class is immutable
* @throws PyException(IndexError) if the index is outside the array bounds
@@ -794,8 +1662,9 @@
}
/**
- * Inserts the specified element at the specified position in this list.
- * Shifts the element currently at that position and any subsequent elements to the right.
+ * Inserts the specified element at the specified position in this list. Shifts the element
+ * currently at that position and any subsequent elements to the right.
+ *
* @see java.util.AbstractList#add(int, java.lang.Object)
* @throws PyException(IndexError) if the index is outside the array bounds
* @throws PyException(ValueError) if element<0 or element>255
@@ -805,13 +1674,14 @@
public void add(int index, PyInteger element) throws PyException {
// Not using __setitem__ as it applies Python index semantics to e.g. b[-1].
indexCheck(index);
- pyadd(index, element); // TypeError if immutable
+ pyinsert(index, element); // TypeError if immutable
}
/**
* Removes the element at the specified position in this list. Shifts any subsequent
- * elements to the left (subtracts one from their indices).
- * Returns the element that was removed from the list.
+ * elements to the left (subtracts one from their indices). Returns the element that was
+ * removed from the list.
+ *
* @see java.util.AbstractList#remove(int)
* @throws PyException(IndexError) if the index is outside the array bounds
*/
@@ -825,17 +1695,22 @@
}
};
- /**
- * Number of bytes in bytearray (or bytes) object.
+ /**
+ * Number of bytes in bytearray (or bytes) object.
+ *
* @see java.util.List#size()
* @return Number of bytes in byte array.
* */
- public int size() { return size;}
+ public int size() {
+ return size;
+ }
/*
* @see java.util.List#isEmpty()
*/
- public boolean isEmpty() { return size==0; }
+ public boolean isEmpty() {
+ return size == 0;
+ }
/**
* Returns true if this list contains the specified value. More formally, returns true if and
@@ -847,6 +1722,7 @@
/*
* @return
+ *
* @see java.util.List#iterator()
*/
public Iterator<PyInteger> iterator() {
@@ -855,6 +1731,7 @@
/*
* @return
+ *
* @see java.util.List#toArray()
*/
public Object[] toArray() {
@@ -863,7 +1740,9 @@
/*
* @param a
+ *
* @return
+ *
* @see java.util.List#toArray(T[])
*/
public <T> T[] toArray(T[] a) {
@@ -872,7 +1751,9 @@
/*
* @param o
+ *
* @return
+ *
* @see java.util.List#add(java.lang.Object)
*/
public boolean add(PyInteger o) {
@@ -881,7 +1762,9 @@
/*
* @param o
+ *
* @return
+ *
* @see java.util.List#remove(java.lang.Object)
*/
public boolean remove(Object o) {
@@ -890,7 +1773,9 @@
/*
* @param c
+ *
* @return
+ *
* @see java.util.List#containsAll(java.util.Collection)
*/
public boolean containsAll(Collection<?> c) {
@@ -899,7 +1784,9 @@
/*
* @param c
+ *
* @return
+ *
* @see java.util.List#addAll(java.util.Collection)
*/
public boolean addAll(Collection<? extends PyInteger> c) {
@@ -908,8 +1795,11 @@
/*
* @param index
+ *
* @param c
+ *
* @return
+ *
* @see java.util.List#addAll(int, java.util.Collection)
*/
public boolean addAll(int index, Collection<? extends PyInteger> c) {
@@ -918,7 +1808,9 @@
/*
* @param c
+ *
* @return
+ *
* @see java.util.List#removeAll(java.util.Collection)
*/
public boolean removeAll(Collection<?> c) {
@@ -927,7 +1819,9 @@
/*
* @param c
+ *
* @return
+ *
* @see java.util.List#retainAll(java.util.Collection)
*/
public boolean retainAll(Collection<?> c) {
@@ -935,7 +1829,7 @@
}
/*
- *
+ *
* @see java.util.List#clear()
*/
public void clear() {
@@ -944,7 +1838,9 @@
/*
* @param o
+ *
* @return
+ *
* @see java.util.List#equals(java.lang.Object)
*/
public boolean equals(Object o) {
@@ -953,6 +1849,7 @@
/*
* @return
+ *
* @see java.util.List#hashCode()
*/
public int hashCode() {
@@ -961,7 +1858,9 @@
/*
* @param index
+ *
* @return
+ *
* @see java.util.List#get(int)
*/
public PyInteger get(int index) {
@@ -970,8 +1869,11 @@
/*
* @param index
+ *
* @param element
+ *
* @return
+ *
* @see java.util.List#set(int, java.lang.Object)
*/
public PyInteger set(int index, PyInteger element) {
@@ -980,7 +1882,9 @@
/*
* @param index
+ *
* @param element
+ *
* @see java.util.List#add(int, java.lang.Object)
*/
public void add(int index, PyInteger element) {
@@ -989,7 +1893,9 @@
/*
* @param index
+ *
* @return
+ *
* @see java.util.List#remove(int)
*/
public PyInteger remove(int index) {
@@ -998,7 +1904,9 @@
/*
* @param o
+ *
* @return
+ *
* @see java.util.List#indexOf(java.lang.Object)
*/
public int indexOf(Object o) {
@@ -1007,7 +1915,9 @@
/*
* @param o
+ *
* @return
+ *
* @see java.util.List#lastIndexOf(java.lang.Object)
*/
public int lastIndexOf(Object o) {
@@ -1016,6 +1926,7 @@
/*
* @return
+ *
* @see java.util.List#listIterator()
*/
public ListIterator<PyInteger> listIterator() {
@@ -1024,7 +1935,9 @@
/*
* @param index
+ *
* @return
+ *
* @see java.util.List#listIterator(int)
*/
public ListIterator<PyInteger> listIterator(int index) {
@@ -1033,12 +1946,15 @@
/*
* @param fromIndex
+ *
* @param toIndex
+ *
* @return
+ *
* @see java.util.List#subList(int, int)
*/
public List<PyInteger> subList(int fromIndex, int toIndex) {
return listDelegate.subList(fromIndex, toIndex);
}
-
+
}
diff --git a/src/org/python/core/PyByteArray.java b/src/org/python/core/PyByteArray.java
--- a/src/org/python/core/PyByteArray.java
+++ b/src/org/python/core/PyByteArray.java
@@ -5,6 +5,7 @@
import org.python.expose.ExposedMethod;
import org.python.expose.ExposedNew;
import org.python.expose.ExposedType;
+import org.python.expose.MethodType;
/**
* Partial implementation of Python bytearray. At the present stage of development, the class
@@ -18,21 +19,22 @@
* implementation does not support the <code>memoryview</code> interface either for access or a a
* source for its constructors although the signatures are present. The rich set of string-like
* operations due a <code>bytearray</code> is not implemented.
- *
+ *
*/
@ExposedType(name = "bytearray", base = PyObject.class, doc = BuiltinDocs.bytearray_doc)
public class PyByteArray extends BaseBytes {
public static final PyType TYPE = PyType.fromClass(PyByteArray.class);
-
+
/**
* Create a zero-length Python bytearray of explicitly-specified sub-type
+ *
* @param type explicit Jython type
*/
public PyByteArray(PyType type) {
super(type);
}
-
+
/**
* Create a zero-length Python bytearray.
*/
@@ -42,6 +44,7 @@
/**
* Create zero-filled Python bytearray of specified size.
+ *
* @param size of bytearray
*/
public PyByteArray(int size) {
@@ -51,7 +54,7 @@
/**
* Construct bytearray by copying values from int[].
- *
+ *
* @param value source of the bytes (and size)
*/
public PyByteArray(int[] value) {
@@ -59,39 +62,40 @@
}
/**
- * Create a new array filled exactly by a copy of the contents of the
- * source.
+ * Create a new array filled exactly by a copy of the contents of the source.
+ *
* @param value source of the bytes (and size)
*/
public PyByteArray(BaseBytes value) {
super(TYPE);
init(value);
}
-
+
/**
- * Create a new array filled exactly by a copy of the contents of the
- * source.
+ * Create a new array filled exactly by a copy of the contents of the source.
+ *
* @param value source of the bytes (and size)
*/
public PyByteArray(MemoryViewProtocol value) {
super(TYPE);
init(value.getMemoryView());
}
-
+
/**
* Create a new array filled from an iterable of PyObject. The iterable must yield objects
* convertible to Python bytes (non-negative integers less than 256 or strings of length 1).
+ *
* @param value source of the bytes (and size)
*/
public PyByteArray(Iterable<? extends PyObject> value) {
super(TYPE);
init(value);
}
-
+
/**
* Create a new array by encoding a PyString argument to bytes. If the PyString is actually a
* PyUnicode, the encoding must be explicitly specified.
- *
+ *
* @param arg primary argument from which value is taken
* @param encoding name of optional encoding (must be a string type)
* @param errors name of optional errors policy (must be a string type)
@@ -104,7 +108,7 @@
/**
* Create a new array by encoding a PyString argument to bytes. If the PyString is actually a
* PyUnicode, the encoding must be explicitly specified.
- *
+ *
* @param arg primary argument from which value is taken
* @param encoding name of optional encoding (may be null to select the default for this
* installation)
@@ -116,6 +120,17 @@
}
/**
+ * Create a new array by encoding a PyString argument to bytes. If the PyString is actually a
+ * PyUnicode, an exception is thrown saying that the encoding must be explicitly specified.
+ *
+ * @param arg primary argument from which value is taken
+ */
+ public PyByteArray(PyString arg) {
+ super(TYPE);
+ init(arg, (String)null, (String)null);
+ }
+
+ /**
* Create a new bytearray object from an arbitrary Python object according to the same rules as
* apply in Python to the bytearray() constructor:
* <ul>
@@ -133,16 +148,17 @@
* <code>bytearray(string, encoding[, errors])</code>, use the constructor
* {@link #PyByteArray(PyString, String, String)}. If the PyString is actually a PyUnicode, an
* encoding must be specified, and using this constructor will throw an exception about that.
- *
+ *
* @param arg primary argument from which value is taken (may be null)
* @throws PyException in the same circumstances as bytearray(arg), TypeError for non-iterable,
- * non-integer argument type, and ValueError if iterables do not yield byte [0..255] values.
+ * non-integer argument type, and ValueError if iterables do not yield byte [0..255]
+ * values.
*/
public PyByteArray(PyObject arg) throws PyException {
super(TYPE);
init(arg);
}
-
+
/* ========================================================================================
* API for org.python.core.PySequence
* ========================================================================================
@@ -160,12 +176,12 @@
protected synchronized PyByteArray getslice(int start, int stop, int step) {
if (step == 1) {
// Efficiently copy contiguous slice
- int n = stop-start;
- if (n<=0) {
+ int n = stop - start;
+ if (n <= 0) {
return new PyByteArray();
} else {
PyByteArray ret = new PyByteArray(n);
- System.arraycopy(storage, offset+start, ret.storage, ret.offset, n);
+ System.arraycopy(storage, offset + start, ret.storage, ret.offset, n);
return ret;
}
} else {
@@ -173,16 +189,17 @@
PyByteArray ret = new PyByteArray(n);
n += ret.offset;
byte[] dst = ret.storage;
- for (int io = start + offset, jo = ret.offset; jo < n; io += step, jo++)
+ for (int io = start + offset, jo = ret.offset; jo < n; io += step, jo++) {
dst[jo] = storage[io];
+ }
return ret;
}
}
-
/**
- * Returns a PyByteArray that repeats this sequence the given number of times, as
- * in the implementation of <tt>__mul__</tt> for strings.
+ * Returns a PyByteArray that repeats this sequence the given number of times, as in the
+ * implementation of <tt>__mul__</tt> for strings.
+ *
* @param count the number of times to repeat this.
* @return this byte array repeated count times.
*/
@@ -191,14 +208,13 @@
PyByteArray ret = new PyByteArray();
ret.setStorage(repeatImpl(count));
return ret;
- }
+ }
/**
- * Sets the indexed element of the bytearray to the given value.
- * This is an extension point called by PySequence in its implementation of
- * {@link #__setitem__}
- * It is guaranteed by PySequence that the index is within the bounds of the array.
- * Any other clients calling <tt>pyset(int)</tt> must make the same guarantee.
+ * Sets the indexed element of the bytearray to the given value. This is an extension point
+ * called by PySequence in its implementation of {@link #__setitem__} It is guaranteed by
+ * PySequence that the index is within the bounds of the array. Any other clients calling
+ * <tt>pyset(int)</tt> must make the same guarantee.
*
* @param index index of the element to set.
* @param value the value to set this element to.
@@ -206,23 +222,26 @@
* @throws PyException(ValueError) if value<0 or value>255
*/
public synchronized void pyset(int index, PyObject value) throws PyException {
- storage[index+offset] = byteCheck(value);
+ storage[index + offset] = byteCheck(value);
}
/**
* Insert the element (interpreted as a Python byte value) at the given index.
- *
+ * Python int, long and string types of length 1 are allowed.
+ *
* @param index to insert at
* @param element to insert (by value)
* @throws PyException(IndexError) if the index is outside the array bounds
* @throws PyException(ValueError) if element<0 or element>255
+ * @throws PyException(TypeError) if the subclass is immutable
*/
- public synchronized void pyadd(int index, PyInteger element) {
+ @Override
+ public synchronized void pyinsert(int index, PyObject element) {
// Open a space at the right location.
storageReplace(index, 0, 1);
- storage[index] = byteCheck(element);
+ storage[offset+index] = byteCheck(element);
}
-
+
/**
* Sets the given range of elements according to Python slice assignment semantics. If the step
* size is one, it is a simple slice and the operation is equivalent to deleting that slice,
@@ -236,15 +255,15 @@
* <code>PyObject</code>s, but acceptable ones are PyInteger, PyLong or PyString of length 1. If
* any one of them proves unsuitable for assignment to a Python bytarray element, an exception
* is thrown and this bytearray is unchanged.
- *
+ *
* <pre>
* a = bytearray(b'abcdefghijklmnopqrst')
* a[2:12:2] = iter( [65, 66, 67, long(68), "E"] )
* </pre>
- *
+ *
* Results in <code>a=bytearray(b'abAdBfChDjElmnopqrst')</code>.
* <p>
- *
+ *
* @param start the position of the first element.
* @param stop one more than the position of the last element.
* @param step the step size.
@@ -308,12 +327,10 @@
}
}
-
-
/**
* Sets the given range of elements according to Python slice assignment semantics from a
* zero-filled bytearray of the given length.
- *
+ *
* @see #setslice(int, int, int, PyObject)
* @param start the position of the first element.
* @param stop one more than the position of the last element.
@@ -330,17 +347,19 @@
} else {
// This is an extended slice which means we are replacing elements
int n = sliceLength(start, stop, step);
- if (n != len) throw SliceSizeError("bytes", len, n);
- for (int io = start + offset; n > 0; io += step, --n)
+ if (n != len) {
+ throw SliceSizeError("bytes", len, n);
+ }
+ for (int io = start + offset; n > 0; io += step, --n) {
storage[io] = 0;
+ }
}
}
-
/**
* Sets the given range of elements according to Python slice assignment semantics from a
* PyString.
- *
+ *
* @see #setslice(int, int, int, PyObject)
* @param start the position of the first element.
* @param stop one more than the position of the last element.
@@ -368,7 +387,7 @@
/**
* Sets the given range of elements according to Python slice assignment semantics from an
* object supporting the Jython implementation of PEP 3118.
- *
+ *
* @see #setslice(int, int, int, PyObject)
* @param start the position of the first element.
* @param stop one more than the position of the last element.
@@ -378,34 +397,37 @@
*/
private void setslice(int start, int stop, int step, MemoryView value) throws PyException {
// XXX Support memoryview once means of access to bytes is defined
- Py.NotImplementedError("memoryview not yet supported in bytearray");
- String format = value.get_format();
- boolean isBytes = format == null || "B".equals(format);
- if (value.get_ndim() != 1 || !isBytes) {
- Py.TypeError("memoryview value must be byte-oriented");
- } else {
- // Dimensions are given as a PyTple (although only one)
- int len = value.get_shape().pyget(0).asInt();
- if (step == 1) {
- // Delete this[start:stop] and open a space of the right size
- storageReplace(start, stop - start, len);
- // System.arraycopy(value.storage, value.offset, storage, start
- // + offset, len);
- } else {
- // This is an extended slice which means we are replacing elements
- int n = sliceLength(start, stop, step);
- if (n != len) throw SliceSizeError("bytes", len, n);
- // int no = n + value.offset;
- // for (int io = start + offset, jo = value.offset; jo < no; io += step, jo++) {
- // storage[io] = value.storage[jo]; // Assign this[i] = value[j]
- // }
- }
- }
+ throw Py.NotImplementedError("memoryview not yet supported in bytearray");
+// String format = value.get_format();
+// boolean isBytes = format == null || "B".equals(format);
+// if (value.get_ndim() != 1 || !isBytes) {
+// throw Py.TypeError("memoryview value must be byte-oriented");
+// } else {
+// // Dimensions are given as a PyTuple (although only one)
+// int len = value.get_shape().pyget(0).asInt();
+// if (step == 1) {
+// // Delete this[start:stop] and open a space of the right size
+// storageReplace(start, stop - start, len);
+// // System.arraycopy(value.storage, value.offset, storage, start
+// // + offset, len);
+// } else {
+// // This is an extended slice which means we are replacing elements
+// int n = sliceLength(start, stop, step);
+// if (n != len) {
+// throw SliceSizeError("bytes", len, n);
+// }
+// // int no = n + value.offset;
+// // for (int io = start + offset, jo = value.offset; jo < no; io += step, jo++) {
+// // storage[io] = value.storage[jo]; // Assign this[i] = value[j]
+// // }
+// }
+// }
}
/**
- * Sets the given range of elements according to Python slice assignment semantics
- * from a bytearray (or bytes).
+ * Sets the given range of elements according to Python slice assignment semantics from a
+ * bytearray (or bytes).
+ *
* @see #setslice(int, int, int, PyObject)
* @param start the position of the first element.
* @param stop one more than the position of the last element.
@@ -414,33 +436,37 @@
* @throws PyException(SliceSizeError) if the value size is inconsistent with an extended slice
*/
private void setslice(int start, int stop, int step, BaseBytes value) throws PyException {
- if (value == this) {
- value = new PyByteArray(value); // Must work with a copy
+
+ if (value == this) { // Must work with a copy
+ value = new PyByteArray(value);
}
+
int len = value.size;
+
if (step == 1) {
- //Delete this[start:stop] and open a space of the right size
+ // Delete this[start:stop] and open a space of the right size
storageReplace(start, stop - start, len);
- System.arraycopy(value.storage, value.offset, storage, start
- + offset, len);
+ System.arraycopy(value.storage, value.offset, storage, start + offset, len);
+
} else {
// This is an extended slice which means we are replacing elements
int n = sliceLength(start, stop, step);
if (n != len) {
throw SliceSizeError("bytes", len, n);
}
+
int no = n + value.offset;
for (int io = start + offset, jo = value.offset; jo < no; io += step, jo++) {
storage[io] = value.storage[jo]; // Assign this[i] = value[j]
}
+
}
}
-
/**
* Sets the given range of elements according to Python slice assignment semantics from a
* bytearray (or bytes).
- *
+ *
* @see #setslice(int, int, int, PyObject)
* @param start the position of the first element.
* @param stop one more than the position of the last element.
@@ -452,7 +478,8 @@
private void setslice(int start, int stop, int step, Iterable<? extends PyObject> iter) {
/*
* As we don't know how many elements the iterable represents, we can't adjust the array
- * until after we run the iterator. We use this elastic byte structure to hold the bytes until then.
+ * until after we run the iterator. We use this elastic byte structure to hold the bytes
+ * until then.
*/
FragmentList fragList = new BaseBytes.FragmentList();
fragList.loadFrom(iter);
@@ -464,29 +491,30 @@
// Stitch the fragments together in the space we made
fragList.emptyInto(storage, start + offset);
}
+
} else {
// This is an extended slice which means we are replacing elements
int n = sliceLength(start, stop, step);
- if (n != fragList.totalCount) throw SliceSizeError("bytes", fragList.totalCount, n);
+ if (n != fragList.totalCount) {
+ throw SliceSizeError("bytes", fragList.totalCount, n);
+ }
fragList.emptyInto(storage, start + offset, step);
}
}
+// Idiom:
+// if (step == 1) {
+// // Do something efficient with block start...stop-1
+// } else {
+// int n = sliceLength(start, stop, step);
+// for (int i = start, j = 0; j < n; i += step, j++) {
+// // Perform jth operation with element i
+// }
+// }
-// Idiom:
-// if (step == 1) {
-// // Do something efficient with block start...stop-1
-// } else {
-// int n = sliceLength(start, stop, step);
-// for (int i = start, j = 0; j < n; i += step, j++) {
-// // Perform jth operation with element i
-// }
-// }
-
-
-
/*
* Deletes an element from the sequence (and closes up the gap).
+ *
* @param index index of the element to delete.
*/
protected synchronized void del(int index) {
@@ -496,17 +524,18 @@
/*
* Deletes contiguous sub-sequence (and closes up the gap).
+ *
* @param start the position of the first element.
+ *
* @param stop one more than the position of the last element.
*/
protected synchronized void delRange(int start, int stop) {
- // XXX Use the specialised storageDelete()
- storageReplace(start, stop-start, 0);
+ storageDelete(start, stop - start);
}
/**
* Deletes a simple or extended slice and closes up the gap(s).
- *
+ *
* @param start the position of the first element.
* @param stop one more than the position of the last element.
* @param step from one element to the next
@@ -532,22 +561,20 @@
}
/**
- * Convenience method to create a <code>ValueError</code> PyException with the message
+ * Convenience method to build (but not throw) a <code>ValueError</code> PyException with the message
* "attempt to assign {type} of size {valueSize} to extended slice of size {sliceSize}"
- *
+ *
* @param valueType
* @param valueSize size of sequence being assigned to slice
* @param sliceSize size of slice expected to receive
- * @throws PyException (ValueError) as detailed
+ * @return PyException (ValueError) as detailed
*/
- public static PyException SliceSizeError(String valueType, int valueSize, int sliceSize)
- throws PyException {
+ public static PyException SliceSizeError(String valueType, int valueSize, int sliceSize) {
String fmt = "attempt to assign %s of size %d to extended slice of size %d";
return Py.ValueError(String.format(fmt, valueType, valueSize, sliceSize));
- // XXX consider moving to SequenceIndexDelegate.java or somewhere else generic
+ // XXX consider moving to SequenceIndexDelegate.java or somewhere else generic, even Py
}
-
/**
* Initialise a mutable bytearray object from various arguments. This single initialisation must
* support:
@@ -566,17 +593,18 @@
* Construct as copy of any object implementing the buffer API.</li> </ul> Although effectively
* a constructor, it is possible to call __init__ on a 'used' object so the method does not
* assume any particular prior state.
- *
+ *
* @param args argument array according to Jython conventions
- * @param kwds Keywords according to Jython conventions
+ * @param kwds Keywords according to Jython conventions
* @throws PyException in the same circumstances as bytearray(arg), TypeError for non-iterable,
- * non-integer argument type, and ValueError if iterables do not yield byte [0..255] values.
+ * non-integer argument type, and ValueError if iterables do not yield byte [0..255]
+ * values.
*/
@ExposedNew
@ExposedMethod(doc = BuiltinDocs.bytearray___init___doc)
final synchronized void bytearray___init__(PyObject[] args, String[] kwds) {
-
- ArgParser ap = new ArgParser("bytearray", args, kwds, "source", "encoding", "errors");
+
+ ArgParser ap = new ArgParser("bytearray", args, kwds, "source", "encoding", "errors");
PyObject arg = ap.getPyObject(0, null);
// If not null, encoding and errors must be PyString (or PyUnicode)
PyObject encoding = ap.getPyObjectByType(1, PyBaseString.TYPE, null);
@@ -598,58 +626,278 @@
throw Py.TypeError("encoding or errors without sequence argument");
}
init((PyString)arg, encoding, errors);
-
+
} else {
// Now construct from arbitrary object (or null)
init(arg);
}
}
-
-
+
+
+ /* ========================================================================================
+ * Python API rich comparison operations
+ * ========================================================================================
+ */
+
@Override
- public int __len__() {
- return list___len__();
+ public PyObject __eq__(PyObject other) {
+ return basebytes___eq__(other);
}
- @ExposedMethod(doc = BuiltinDocs.list___len___doc)
- final int list___len__() {
- return size;
+ @Override
+ public PyObject __ne__(PyObject other) {
+ return basebytes___ne__(other);
}
-
+ @Override
+ public PyObject __lt__(PyObject other) {
+ return basebytes___lt__(other);
+ }
+
+ @Override
+ public PyObject __le__(PyObject other) {
+ return basebytes___le__(other);
+ }
+
+ @Override
+ public PyObject __ge__(PyObject other) {
+ return basebytes___ge__(other);
+ }
+
+ @Override
+ public PyObject __gt__(PyObject other) {
+ return basebytes___gt__(other);
+ }
+
+
+
+ @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___eq___doc)
+ final synchronized PyObject bytearray___eq__(PyObject other) {
+ return basebytes___eq__(other);
+ }
+
+ @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___ne___doc)
+ final synchronized PyObject bytearray___ne__(PyObject other) {
+ return basebytes___ne__(other);
+ }
+
+ @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___lt___doc)
+ final synchronized PyObject bytearray___lt__(PyObject other) {
+ return basebytes___lt__(other);
+ }
+
+ @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___le___doc)
+ final synchronized PyObject bytearray___le__(PyObject other) {
+ return basebytes___le__(other);
+ }
+
+ @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___ge___doc)
+ final synchronized PyObject bytearray___ge__(PyObject other) {
+ return basebytes___ge__(other);
+ }
+
+ @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___gt___doc)
+ final synchronized PyObject bytearray___gt__(PyObject other) {
+ return basebytes___gt__(other);
+ }
+
+/* ========================================================================================
+ * Python API for bytearray
+ * ========================================================================================
+ */
+
+ @Override
+ public PyObject __add__(PyObject o) {
+ return bytearray___add__(o);
+ }
+
+ @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___add___doc)
+ final synchronized PyObject bytearray___add__(PyObject o) {
+ PyByteArray sum = null;
+
+ if (o instanceof BaseBytes) {
+ BaseBytes ob = (BaseBytes)o;
+ // Quick route: allocate the right size bytearray and copy the two parts in.
+ sum = new PyByteArray(size + ob.size);
+ System.arraycopy(storage, offset, sum.storage, sum.offset, size);
+ System.arraycopy(ob.storage, ob.offset, sum.storage, sum.offset + size, ob.size);
+
+ } else if (o.getType() == PyString.TYPE) {
+ // Support bytes type, which in in Python 2.7 is an alias of str. Remove in 3.0
+ PyString os = (PyString)o;
+ // Allocate the right size bytearray and copy the two parts in.
+ sum = new PyByteArray(size + os.__len__());
+ System.arraycopy(storage, offset, sum.storage, sum.offset, size);
+ sum.setslice(size, sum.size, 1, os);
+
+ } else {
+ // Unsuitable type
+ // XXX note reversed order relative to __iadd__ may be wrong, matches Python 2.7
+ throw ConcatenationTypeError(TYPE, o.getType());
+ }
+
+ return sum;
+ }
+
+
+ /**
+ * Returns the number of bytes actually allocated.
+ */
+ public int __alloc__() {
+ return bytearray___alloc__();
+ }
+
+ @ExposedMethod(doc = BuiltinDocs.bytearray___alloc___doc)
+ final int bytearray___alloc__() {
+ return storage.length;
+ }
+
+ /**
+ * Append a single element to the end of the array, equivalent to:
+ * <code>s[len(s):len(s)] = o</code>. The argument must be a PyInteger, PyLong or string of length 1.
+ *
+ * @param o the item to append to the list.
+ */
+ public void append(PyObject o) {
+ bytearray_append(o);
+ }
+
+ @ExposedMethod(doc = BuiltinDocs.bytearray_append_doc)
+ final synchronized void bytearray_append(PyObject o) {
+ // Insert at the end, checked for type and range
+ pyinsert(size, o);
+ }
+
+ @ExposedMethod(doc = BuiltinDocs.bytearray___contains___doc)
+ final boolean bytearray___contains__(PyObject o) {
+ return basebytes___contains__(o);
+ }
+
+ @ExposedMethod(doc = BuiltinDocs.bytearray_decode_doc)
+ final PyObject bytearray_decode(PyObject[] args, String[] keywords) {
+ return basebytes_decode(args, keywords);
+ }
+
+ /**
+ * Implementation of Python <code>find(sub)</code>. Return the lowest index in the byte array
+ * where byte sequence <code>sub</code> is found. Return -1 if <code>sub</code> is not found.
+ *
+ * @param sub bytes to find
+ * @return index of start of ocurrence of sub within this byte array
+ */
+ public int find(PyObject sub) {
+ return basebytes_find(sub, null, null);
+ }
+
+ /**
+ * Implementation of Python <code>find( sub [, start ] )</code>. Return the lowest index in the
+ * byte array where byte sequence <code>sub</code> is found, such that <code>sub</code> is
+ * contained in the slice <code>[start:]</code>. Return -1 if <code>sub</code> is not found.
+ *
+ * @param sub bytes to find
+ * @param start of slice to search
+ * @return index of start of ocurrence of sub within this byte array
+ */
+ public int find(PyObject sub, PyObject start) {
+ return basebytes_find(sub, start, null);
+ }
+
+ /**
+ * Implementation of Python <code>find( sub [, start [, end ]] )</code>. Return the lowest index
+ * in the byte array where byte sequence <code>sub</code> is found, such that <code>sub</code>
+ * is contained in the slice <code>[start:end]</code>. Arguments <code>start</code> and
+ * <code>end</code> (which may be <code>null</code> or <code>Py.None</code> ) are interpreted as
+ * in slice notation. Return -1 if <code>sub</code> is not found.
+ *
+ * @param sub bytes to find
+ * @param start of slice to search
+ * @param end of slice to search
+ * @return index of start of ocurrence of sub within this byte array
+ */
+ public int find(PyObject sub, PyObject start, PyObject end) {
+ return basebytes_find(sub, start, end);
+ }
+
+ @ExposedMethod(defaults = {"null", "null"}, doc = BuiltinDocs.bytearray_find_doc)
+ final int bytearray_find(PyObject sub, PyObject start, PyObject end) {
+ return basebytes_find(sub, start, end);
+ }
+
+
+
+ /**
+ * Append the elements in the argument sequence to the end of the array, equivalent to:
+ * <code>s[len(s):len(s)] = o</code>. The argument must be a subclass of BaseBytes or an
+ * iterable type returning elements compatible with byte assignment.
+ *
+ * @param o the sequence of items to append to the list.
+ */
+ public void extend(PyObject o) {
+ bytearray_extend(o);
+ }
+
+ @ExposedMethod(doc = BuiltinDocs.bytearray_extend_doc)
+ final synchronized void bytearray_extend(PyObject o) {
+ // Use the general method, assigning to the crack at the end of the array.
+ // Note this deals with all legitimate PyObject types and the case o==this.
+ setslice(size, size, 1, o);
+ }
+
+ @Override
+ public PyObject __iadd__(PyObject o) {
+ return bytearray___iadd__(o);
+ }
+
+ @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___iadd___doc)
+ final synchronized PyObject bytearray___iadd__(PyObject o) {
+ PyType oType = o.getType();
+ if (oType == TYPE) {
+ // Use the general method, specifying the crack at the end of the array.
+ // Note this deals with the case o==this.
+ setslice(size, size, 1, (BaseBytes)o);
+ } else if (oType == PyString.TYPE) {
+ // Will fail if somehow not 8-bit clean
+ setslice(size, size, 1, (PyString)o);
+ } else {
+ // Unsuitable type
+ throw ConcatenationTypeError(oType, TYPE);
+ }
+ return this;
+ }
+
+ /**
+ * Insert the argument element into the byte array at the specified index.
+ * Same as <code>s[index:index] = [o] if index >= 0</code>.
+ *
+ * @param index the position where the element will be inserted.
+ * @param value the element to insert.
+ */
+ public void insert(PyObject index, PyObject value) {
+ bytearray_insert(index, value);
+ }
+
+ @ExposedMethod(doc = BuiltinDocs.bytearray_insert_doc)
+ final synchronized void bytearray_insert(PyObject index, PyObject value) {
+ // XXX: do something with delegator instead?
+ pyinsert(boundToSequence(index.asIndex()), value);
+ }
+
+
+ @ExposedMethod(doc = BuiltinDocs.bytearray___len___doc)
+ final int bytearray___len__() {
+ return __len__();
+ }
+
+ @ExposedMethod(doc = BuiltinDocs.bytearray___reduce___doc)
+ final PyObject bytearray___reduce__() {
+ return basebytes___reduce__();
+ }
+
+
+
// Based on PyList and not yet properly implemented.
//
-// @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___ne___doc)
-// final synchronized PyObject bytearray___ne__(PyObject o) {
-// return seq___ne__(o);
-// }
-//
-// @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___eq___doc)
-// final synchronized PyObject bytearray___eq__(PyObject o) {
-// return seq___eq__(o);
-// }
-//
-// @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___lt___doc)
-// final synchronized PyObject bytearray___lt__(PyObject o) {
-// return seq___lt__(o);
-// }
-//
-// @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___le___doc)
-// final synchronized PyObject bytearray___le__(PyObject o) {
-// return seq___le__(o);
-// }
-//
-// @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___gt___doc)
-// final synchronized PyObject bytearray___gt__(PyObject o) {
-// return seq___gt__(o);
-// }
-//
-// @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___ge___doc)
-// final synchronized PyObject bytearray___ge__(PyObject o) {
-// return seq___ge__(o);
-// }
-//
// @Override
// public PyObject __imul__(PyObject o) {
// return bytearray___imul__(o);
@@ -714,37 +962,6 @@
// return repeat(o.asIndex(Py.OverflowError));
// }
//
-// @Override
-// public PyObject __add__(PyObject o) {
-// return bytearray___add__(o);
-// }
-//
-// @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___add___doc)
-// final synchronized PyObject bytearray___add__(PyObject o) {
-// PyByteArray sum = null;
-// if (o instanceof PySequenceList && !(o instanceof PyTuple)) {
-// if (o instanceof PyByteArray) {
-// List oList = ((PyByteArray) o).storage;
-// List newList = new ArrayList(storage.size() + oList.size());
-// newList.addAll(storage);
-// newList.addAll(oList);
-// sum = fromList(newList);
-// }
-// } else if (!(o instanceof PySequenceList)) {
-// // also support adding java lists (but not PyTuple!)
-// Object oList = o.__tojava__(List.class);
-// if (oList != Py.NoConversion && oList != null) {
-// List otherList = (List) oList;
-// sum = new PyByteArray();
-// sum.bytearray_extend(this);
-// for (Iterator i = otherList.iterator(); i.hasNext();) {
-// sum.add(i.next());
-// }
-// }
-// }
-// return sum;
-// }
-//
// @ExposedMethod(doc = BuiltinDocs.bytearray___contains___doc)
// final synchronized boolean bytearray___contains__(PyObject o) {
// return object___contains__(o);
@@ -787,275 +1004,238 @@
// return super.unsupportedopMessage(op, o2);
// }
//
-// public String toString() {
-// return bytearray_toString();
-// }
-//
- @ExposedMethod(names = "__repr__", doc = BuiltinDocs.bytearray___repr___doc)
- final synchronized String bytearray_toString() {
- // XXX revisit: understand the thread state logic and use encode()
-// ThreadState ts = Py.getThreadState();
-// if (!ts.enterRepr(this)) {
-// return "[...]";
-// }
- StringBuilder buf = new StringBuilder("bytearray(b'");
- final int last = size()-1;
- for (int i=0; i<=last; i++) {
- int element = intAt(i);
- if (Character.isISOControl(element))
- buf.append(String.format("\\x%02x", element));
- else
- buf.append((char)element);
- }
- buf.append("')");
-// ts.exitRepr(this);
- return buf.toString();
+ @Override
+ public String toString() {
+ return bytearray_toString();
}
-
-
-
-
+ @ExposedMethod(names = {"__repr__", "__str__"}, doc = BuiltinDocs.bytearray___repr___doc)
+ final synchronized String bytearray_toString() {
+ return "bytearray(b'" + asEscapedString() + "')";
+ }
+
/*
* ========================================================================================
* Manipulation of storage capacity
* ========================================================================================
- *
+ *
* Here we add to the inherited variables defining byte storage, the methods necessary to resize
* it.
- */
-
+ */
+
/**
* Choose a size appropriate to store the given number of bytes, with some room for growth.
- * @param size
- * @return n >= needed
+ * We'll be more generous than CPython for small array sizes to avoid needless reallocation.
+ *
+ * @param size of storage actually needed
+ * @return n >= size a recommended storage array size
*/
private static final int roundUp(int size) {
- // XXX Consider equivalent case statement
- int alloc = size + (size >> 3) + (size < 9 ? 3 : 6); // As CPython
- // XXX What's a good allocation unit size here?
- final int ALLOC = 8;
- return (alloc+(ALLOC-1)) & ~(ALLOC-1); // round up to multiple of ALLOC
- }
-
- /**
- * Used mainly to prevent repeated attempts to shrink an array that is already minimal.
- */
- private static final int minAlloc = roundUp(1);
-
- /**
- * Decide whether a new storage array should be allocated (but don't do it). This method returns
- * true if the needed storage is bigger than the allocated array length.
- *
- * @param needed number of bytes needed
- * @return true if needed number of bytes justifies a new array
- */
- private final boolean shouldGrow(int needed) {
- return needed > storage.length;
+ /*
+ * The CPython formula is: size + (size >> 3) + (size < 9 ? 3 : 6). But when the array
+ * grows, CPython can use a realloc(), which will often be able to extend the allocation
+ * into memory already secretly allocated by the initial malloc(). Extension in Java means
+ * that we have to allocate a new array of bytes and copy to it.
+ */
+ final int ALLOC = 16; // Must be power of two!
+ final int SIZE2 = 10; // Smallest size leading to a return value of 2*ALLOC
+ if (size >= SIZE2) { // Result > ALLOC, so work it out
+ // Same recommendation as Python, but rounded up to multiple of ALLOC
+ return (size + (size >> 3) + (6 + ALLOC - 1)) & ~(ALLOC - 1);
+ } else if (size > 0) { // Easy: save arithmetic
+ return ALLOC;
+ } else { // Very easy
+ return 0;
+ }
}
/**
- * Decide whether a smaller storage array should be allocated (but don't do it). This method
- * returns true if the needed storage size is much smaller than the allocated array length.
- *
+ * Recommend a length for (but don't allocate) a new storage array, taking into account the
+ * current length and the number of bytes now needed. The returned value will always be at least
+ * as big as the argument (the length will always be sufficient). If the return value is equal
+ * to the present length, it is recommending no reallocation; otherwise, the return is either
+ * comfortably bigger than what is currently needed, or significantly smaller than currently
+ * allocated. This method embeds our policy for growing or shrinking the allocated array.
+ *
* @param needed number of bytes needed
- * @return true if needed number of bytes justifies a new array
+ * @return recommended amount to allocate
*/
- private final boolean shouldShrink(int needed) {
- return needed == 0 || (needed * 2 + minAlloc) < storage.length;
- }
-
- /**
- * Decide whether a new storage array should be allocated (but don't do it). This method returns
- * true if the needed storage is bigger, or much smaller, than the allocated array length.
- *
- * @param needed number of bytes needed
- * @return true if needed number of bytes justifies a new array
- */
- private final boolean shouldResize(int needed) {
- return shouldGrow(needed) || shouldShrink(needed);
+ private final int recLength(int needed) {
+ final int L = storage.length;
+ if (needed > L || needed * 2 < L) {
+ // Amount needed is a lot less than current length, or
+ // more space we have, so recommend the new ideal size.
+ return roundUp(needed);
+ } else {
+ // Amount needed is less than current length, but it doesn't justify reallocation
+ return L;
+ }
}
/**
* Allocate fresh storage for at least the requested number of bytes. Spare bytes are alloceted
- * evenly at each end of the new storage by choice of a new value for offset.
- * If the size needed is zero, the "storage" allocated is the shared emptyStorage array.
+ * evenly at each end of the new storage by choice of a new value for offset. If the size needed
+ * is zero, the "storage" allocated is the shared emptyStorage array.
+ *
* @param needed becomes the new value of this.size
*/
protected void newStorage(int needed) {
if (needed > 0) {
- byte[] s = new byte[roundUp(needed)]; // guaranteed zero (by JLS 2ed para 4.5.5)
- setStorage(s, needed, (s.length - needed) / 2);
- } else
+ final int L = recLength(needed);
+ byte[] s = new byte[L]; // guaranteed zero (by JLS 2ed para 4.5.5)
+ setStorage(s, needed, (L - needed) / 2);
+ } else {
setStorage(emptyStorage);
+ }
}
/**
- * Ensure there is storage for at least the requested number of bytes, optionally clearing
- * elements to zero. After the call, the needed number of bytes will be available,
- * and if requested in the second parameter, they are guaranteed to be zero.
- * @param needed number of bytes
- * @param clear if true, storage bytes guaranteed zero
- */
- private void newStorage(int needed, boolean clear) {
- if (shouldResize(needed)) {
- newStorage(needed); // guaranteed zero
- } else {
- setStorage(storage, needed, (storage.length - needed) / 2);
- if (clear) {
- Arrays.fill(storage, (byte)0); // guarantee zero
- }
- }
- }
-
-
-
- /**
- * Delete <code>d</code> elements at index <code>a</code> and prepare to insert
- * <code>e</code> elements there by moving aside the surrounding elements.
- * The method manipulates the <code>storage</code> array contents, <code>size</code> and
- * <code>offset</code>. It will allocate a new array <code>storage</code> if necessary,
- * or if desirable for efficiency. If the initial storage looks like this:
+ * Delete <code>d</code> elements at index <code>a</code> and prepare to insert <code>e</code>
+ * elements there by moving aside the surrounding elements. The method manipulates the
+ * <code>storage</code> array contents, <code>size</code> and <code>offset</code>. It will
+ * allocate a new array <code>storage</code> if necessary, or if desirable for efficiency. If
+ * the initial storage looks like this:
+ *
* <pre>
* |- s -|
* |--f--|--------a--------|---d---|-----b-----|----------------|
* </pre>
+ *
* then after the call the (possibly new) storage looks like this:
+ *
* <pre>
* |- s' -|
* |----f'----|--------a--------|----e----|-----b-----|--------------|
* </pre>
+ *
* where the contents of regions of length <code>a</code> and <code>b=size-(a+d)</code> have
- * been preserved, although probably moved, and the gap between them has been adjusted to
- * the requested size.
+ * been preserved, although probably moved, and the gap between them has been adjusted to the
+ * requested size.
* <p>
* The effect on this PyByteArray is that:
+ *
* <pre>
* this.offset = f'
* this.size = s' = a + e + b
* </pre>
- * The method does not implement the Python repertoire of slice indices but avoids indexing
- * outside the bytearray by silently adjusting a to be within it.
- * Negative d or e is treated as 0 and if d is too large, it is truncated to the array end.
- * @param a index of hole in byte array
+ *
+ * The method does not implement the Python repertoire of slice indices, or bound-check the
+ * sizes given, since code leading up to the call has done that.
+ *
+ * @param a index of hole in byte array
* @param d number to discard (will discard x[a,a+d-1])
* @param e size of hole to open (will be x[a, a+e-1])
*/
private void storageReplace(int a, int d, int e) {
- int s = this.size;
+ final int c = e - d; // Change in overall size
+ if (c == 0)
+ {
+ return; // Everything stays where it is.
+ }
- // Some of these should perhaps be errors but let's silently correct insane requests
- if (a<0) a=0; else if (a>s) a = s;
- if (d<0) d=0; else if (d>s-a) d = s-a;
- if (e<0) e=0;
+ // Compute some handy points of reference
+ final int L = storage.length;
+ final int f = offset;
+ final int b = size - (a + d); // Count of B section
+ final int s2 = a + e + b; // Size of result s'
+ final int L2 = recLength(s2); // Length of storage for result
- if (e != d) {
- // Otherwise, everything stays where it is.
- // Handy derived values:
- int b = s - (a + d); // which is >= 0
- int s2 = a + e + b; // which is >= 0
- int f = this.offset; // Location of x[0]
- int g = f + (a + d); // Location of x[-b]
-
- if (shouldShrink(s2)) {
- if (s2 > 0) {
- // We have far more storage than we need: shrink and copy both parts
- newStorage(f, a, g, b, e);
- } else {
- // Need no storage as a+e+b = 0
- setStorage(emptyStorage);
- }
+ if (L2 == L) {
+ // The result will definitely fit into the existing array
- } else if (a < b) {
+ if (a <= b) {
+
// It would be less copying if we moved A=x[:a] not B=x[-b:].
// If B is to stay where it is, it means A will land here:
- int f2 = f - (e - d);
+ final int f2 = f - c;
if (f2 >= 0) {
// ... which luckily is still inside the array
if (a > 0) {
System.arraycopy(storage, f, storage, f2, a);
}
- this.offset = f2;
+ offset = f2;
size = s2;
+
} else {
// ... which unfortunately is before the start of the array.
- // We have to move both A and B and it might be time for a new array.
- if (s2<=storage.length) {
- // Repack it all in the existing array
- newStorageAvoided(f, a, g, b, e);
- } else {
- newStorage(f, a, g, b, e);
- }
+ // We have to move both A and B within the existing array
+ newStorageAvoided(a, d, b, e);
}
- } else /* a >= b */{
+ } else /* a > b */{
+
// It would be less copying if we moved B=x[-b:] not A=x[:a]
// If A is to stay where it is, it means B will land here:
- int g2 = g + (e - d);
- if (g2 + b <= storage.length) {
+ final int g2 = f + a + e;
+ if (g2 + b <= L) {
// ... which luckily leaves all of B inside the array
if (b > 0) {
- System.arraycopy(storage, g, storage, g2, b);
+ System.arraycopy(storage, g2 - c, storage, g2, b);
}
// this.offset is unchanged
size = s2;
+
} else {
// ... which unfortunately runs beyond the end of the array.
- // We have to move both A and B and it might be time for a new array.
- if (s2<=storage.length) {
- // Repack it all in the existing array
- newStorageAvoided(f, a, g, b, e);
- } else {
- newStorage(f, a, g, b, e);
- }
+ // We have to move both A and B within the existing array
+ newStorageAvoided(a, d, b, e);
}
}
+
+ } else if (L2 > 0) {
+
+ // New storage (bigger or much smaller) is called for. Copy A and B to it.
+ newStorage(L2, a, d, b, e);
+
+ } else {
+
+ // We need no storage at all
+ setStorage(emptyStorage);
+
}
+ }
- }
-
-
/**
* Use the existing storage but move two blocks within it to leave a gap of the required size.
- * This is the strategy usually used when the array is still big enough to hold the required
- * new value, but we can't leave either block fixed.
- * If the initial storage looks like this:
- *
+ * This is the strategy usually used when the array is still big enough to hold the required new
+ * value, but we can't leave either block fixed. If the initial storage looks like this:
+ *
* <pre>
* |-----f-----|--------a--------|---d---|----------b----------|----------|
* </pre>
- *
+ *
* then after the call the storage looks like this:
- *
+ *
* <pre>
* |- s' -|
* |--f'--|--------a--------|---------e---------|----------b----------|---|
* </pre>
- *
+ *
* where the regions of length <code>a</code> and <code>b=size-(a+d)</code> have been preserved
* and the gap between them adjusted to specification. The new offset f' is chosen heuristically
* by the method to optimise the efficiency of repeated adjustment near either end of the array,
* e.g. repeated prepend or append operations. The effect on this PyByteArray is that:
- *
+ *
* <pre>
* this.offset = f'
* this.size = s' = a+e+b
* </pre>
- *
- * Arguments are not checked for validity <b>at all</b>.
- * a, e and b are non-negative and not all zero.
- *
- * @param f location (with offset) of A
+ *
+ * Arguments are not checked for validity <b>at all</b>. At call time, a, d, b, and e are
+ * non-negative and not all zero.
+ *
* @param a length of A
- * @param g = f+a+d location (with offset) of B
+ * @param d gap between A and B in current storage layout
* @param b length of B
- * @param e gap between A and B in new storage.
+ * @param e gap between A and B in new storage layout.
*/
- private void newStorageAvoided(int f, int a, int g, int b, int e) {
+ private void newStorageAvoided(int a, int d, int b, int e) {
- // Shorthands
- int s2 = a + e + b;
+ // Compute some handy points of reference
+ final int f = offset;
+ final int g = f + a + d; // Location of B section x[-b]
+ final int s2 = a + e + b; // Size of result s'
// Choose the new offset f' to make prepend or append operations quicker.
// E.g. if insertion was near the end (b small) put most of the new space at the end.
@@ -1068,164 +1248,201 @@
long spare = storage.length - s2;
f2 = (int)((spare * b) / (a + b));
}
- // We have a new size and offset (but the same storage)
- size = s2;
- offset = f2;
-
+
// This puts B at
- int g2 = f2 + a + e;
+ final int g2 = f2 + a + e;
// We can make do with the existing array. Do an in place copy.
if (f2 + a > g) {
// New A overlaps existing B so we must copy B first
- if (b > 0) System.arraycopy(storage, g, storage, g2, b);
- if (a > 0) System.arraycopy(storage, f, storage, f2, a);
+ if (b > 0) {
+ System.arraycopy(storage, g, storage, g2, b);
+ }
+ if (a > 0) {
+ System.arraycopy(storage, f, storage, f2, a);
+ }
} else {
// Safe to copy A first
- if (a > 0) System.arraycopy(storage, f, storage, f2, a);
- if (b > 0) System.arraycopy(storage, g, storage, g2, b);
+ if (a > 0) {
+ System.arraycopy(storage, f, storage, f2, a);
+ }
+ if (b > 0) {
+ System.arraycopy(storage, g, storage, g2, b);
+ }
}
+ // We have a new size and offset (but the same storage)
+ size = s2;
+ offset = f2;
+
}
-
/**
* Allocate new storage and copy two blocks from the current storage to it. If the initial
* storage looks like this:
- *
+ *
* <pre>
* |--f--|--------a--------|---d---|-----b-----|----------------|
* </pre>
- *
+ *
* then after the call the (definitely new) storage looks like this:
- *
+ *
* <pre>
* |- s' -|
* |----f'----|--------a--------|----e----|-----b-----|--------------|
* </pre>
- *
+ *
* where the regions of length <code>a</code> and <code>b=size-(a+d)</code> have been preserved
* and the gap between them adjusted to specification. The new offset f' is chosen heuristically
* by the method to optimise the efficiency of repeated adjustment near either end of the array,
* e.g. repeated prepend or append operations. The effect on this PyByteArray is that:
- *
+ *
* <pre>
* this.offset = f'
* this.size = s' = a+e+b
* </pre>
- *
- * Arguments are not checked for validity <b>at all</b>.
- * a, e and b are non-negative and not all zero.
- *
- * @param f location (with offset) of A
+ *
+ * Arguments are not checked for validity <b>at all</b>. At call time, a, e and b are
+ * non-negative and not all zero.
+ *
+ * @param L2 length of storage array to allocate (decided by caller)
* @param a length of A
- * @param g = f+a+d location (with offset) of B
+ * @param d gap between A and B in current storage layout
* @param b length of B
- * @param e gap between A and B in new storage.
+ * @param e gap between A and B in new storage layout.
*/
- private void newStorage(int f, int a, int g, int b, int e) {
- // Enough room for the data and the gap
- int s2 = a + e + b;
- // Preserve a reference to the current data in the storage being discarded
- byte[] source = this.storage;
- // New storage with a bit of elbow-room
- byte[] newStorage = new byte[roundUp(s2)];
- // Choose the new offset f' to make prepend or append operations quicker.
+ private void newStorage(int L2, int a, int d, int b, int e) {
+
+ // Compute some handy points of reference
+ final int f = offset;
+ final int g = f + a + d; // Location of B section x[-b]
+ final int s2 = a + e + b; // Size of result s'
+
+ // New storage as specified by caller
+ byte[] newStorage = new byte[L2];
+
+ // Choose the new offset f' to make repeated prepend or append operations quicker.
// E.g. if insertion was near the end (b small) put most of the new space at the end.
int f2;
if (a == b) {
// Mainly to trap the case a=b=0
- f2 = (newStorage.length - s2) / 2;
+ f2 = (L2 - s2) / 2;
} else {
// a and b are not both zero (since not equal)
- long spare = newStorage.length - s2;
+ long spare = L2 - s2;
f2 = (int)((spare * b) / (a + b));
}
+
+ // Copy across the data from existing to new storage.
+ if (a > 0) {
+ System.arraycopy(storage, f, newStorage, f2, a);
+ }
+ if (b > 0) {
+ System.arraycopy(storage, g, newStorage, f2 + a + e, b);
+ }
setStorage(newStorage, s2, f2);
-
- // Copy across the data
- if (a > 0) System.arraycopy(source, f, storage, offset, a);
- if (b > 0) System.arraycopy(source, g, storage, offset + (a + e), b);
}
-
/**
* Delete <code>d</code> elements at index <code>a</code> by moving together the surrounding
* elements. The method manipulates the <code>storage</code> array, <code>size</code> and
* <code>offset</code>, and will allocate a new storage array if necessary, or if the deletion
* is big enough. If the initial storage looks like this:
- *
+ *
* <pre>
* |- L -|
* |- s -|
* |--f--|--------a--------|---d---|-----b-----|----------------|
* </pre>
- *
+ *
* then after the call the (possibly new) storage looks like this:
- *
+ *
* <pre>
* |- L' -|
* |- s' -|
* |-f'-|--------a--------|-----b-----|-------|
* </pre>
- *
+ *
* where the regions of length <code>a</code> and <code>b=size-(a+d)</code> have been preserved
* and the gap between them eliminated. The effect on this PyByteArray is that:
- *
+ *
* <pre>
* this.offset = f'
* this.size = s' = a+b
* </pre>
+ *
* The method does not implement the Python repertoire of slice indices but avoids indexing
- * outside the bytearray by silently adjusting a to be within it.
- * Negative d is treated as 0 and if d is too large, it is truncated to the array end.
- *
+ * outside the bytearray by silently adjusting a to be within it. Negative d is treated as 0 and
+ * if d is too large, it is truncated to the array end.
+ *
* @param a index of hole in byte array
* @param d number to discard (will discard x[a,a+d-1])
* @param e size of hole to open (will be x[a, a+e-1])
*/
private void storageDelete(int a, int d) {
// storageReplace specialised for delete (e=0)
- int s = this.size;
- // Some of these should perhaps be errors but let's silently correct insane requests
- if (a < 0) a = 0; else if (a > s) a = s;
- if (d < 0) d = 0; else if (d > s - a) d = s - a;
+ if (d == 0)
+ {
+ return; // Everything stays where it is.
+ }
- // Handy derived values
- int b = s - (a + d); // which is >= 0
- int s2 = s - d; // which is >= 0
- int f = this.offset; // Location of x[0]
- int g = f + (a + d); // Location of x[-b]
+ // Compute some handy points of reference
+ final int L = storage.length;
+ final int f = offset;
+ final int b = size - (a + d); // Count of B section
+ final int s2 = a + b; // Size of result s'
+ final int L2 = recLength(s2); // Length of storage for result
- if (shouldShrink(s2)) {
- // We have far more storage than we need: shrink and copy both parts
- // Preserve a reference to the current data in the storage being discarded
- byte[] source = this.storage;
- // New storage with a bit of elbow-room
- newStorage(s2);
- // Copy across the data
- if (a > 0) System.arraycopy(source, f, storage, offset, a);
- if (b > 0) System.arraycopy(source, g, storage, offset + a, b);
+ if (L2 == L) {
- } else {
- if (a < b) {
+ // We are re-using the existing array
+ if (a <= b) {
// It would be less copying if we moved A=x[:a] not B=x[-b:].
// If B is to stay where it is, it means A will land here:
- int f2 = f + d;
+ final int f2 = f + d;
if (a > 0) {
System.arraycopy(storage, f, storage, f2, a);
}
- this.offset = f2;
+ offset = f2;
+ size = s2;
- } else /* a >= b */{
+ } else /* a > b */{
// It would be less copying if we moved B=x[-b:] not A=x[:a]
// If A is to stay where it is, it means B will land here:
- int g2 = f + a;
+ final int g2 = f + a;
if (b > 0) {
- System.arraycopy(storage, g, storage, g2, b);
+ System.arraycopy(storage, g2 + d, storage, g2, b);
}
+ // this.offset is unchanged
+ size = s2;
}
+
+ } else if (L2 > 0) {
+
+ // New storage (much smaller) is called for. Copy A and B to it.
+ final int g = f + a + d; // Location of B section x[-b]
+
+ // Choose the new offset f' to distribute space evenly.
+ int f2 = (L2 - s2) / 2;
+
+ // New storage as specified
+ byte[] newStorage = new byte[L2];
+
+ // Copy across the data from existing to new storage.
+ if (a > 0) {
+ System.arraycopy(storage, f, newStorage, f2, a);
+ }
+ if (b > 0) {
+ System.arraycopy(storage, g, newStorage, f2 + a, b);
+ }
+ setStorage(newStorage, s2, f2);
+
+ } else {
+
+ // Everything must go
+ setStorage(emptyStorage);
+
}
}
@@ -1234,46 +1451,48 @@
* <code>a</code> by moving together the surrounding elements. The method manipulates the
* <code>storage</code> array, <code>size</code> and <code>offset</code>, and will allocate a
* new storage array if the deletion is big enough. If the initial storage looks like this:
- *
+ *
* <pre>
* |- L -|
* |- s -|
* |--f--|-----a-----|---------e---------|-----b-----|----------------|
* </pre>
- *
+ *
* then after the call the (possibly new) storage looks like this:
- *
+ *
* <pre>
- * |- L' -|
+ * |- L' -|
* |- s' -|
* |-f'-|-----a-----|---(e-d)---|-----b-----|-------|
* </pre>
- *
+ *
* where the regions of length <code>a</code> and <code>b=size-(a+e)</code> have been preserved
* and the <code>e</code> intervening elements reduced to <code>e-d</code> elements, by removing
* exactly the elements with indices (relative to the start of valid data) <code>a+k*c</code>
* for <code>k=0...d-1</code>. The effect on this PyByteArray is that:
- *
+ *
* <pre>
* this.offset = f'
* this.size = s' = a+b
* </pre>
- *
+ *
* The method does not implement the Python repertoire of slice indices but avoids indexing
* outside the bytearray by silently adjusting a to be within it. Negative d is treated as 0 and
* if d is too large, it is truncated to the array end.
- *
+ *
* @param a index of hole in byte array
* @param c (>0) step size between the locations of elements to delete
* @param d number to discard (will discard x[a+k*c] for k=0...d-1)
*/
private void storageDeleteEx(int a, int c, int d) {
-
+
// XXX Base this on storageReplace with the same a<b logic but piecewise copy
// XXX Change SequenceIndexDelegate to use (and PyList to implement) delslice()
}
}
+
+
/*
* >>> for method in dir(bytearray):
... print method
@@ -1355,4 +1574,4 @@
upper
zfill
>>>
- */
+ */
\ No newline at end of file
diff --git a/src/org/python/core/PyByteArrayDerived.java b/src/org/python/core/PyByteArrayDerived.java
--- a/src/org/python/core/PyByteArrayDerived.java
+++ b/src/org/python/core/PyByteArrayDerived.java
@@ -1,1116 +1,1116 @@
-/* Generated file, do not modify. See jython/src/templates/gderived.py. */
-package org.python.core;
-
-import java.io.Serializable;
-
-public class PyByteArrayDerived extends PyByteArray implements Slotted {
-
- public PyObject getSlot(int index) {
- return slots[index];
- }
-
- public void setSlot(int index,PyObject value) {
- slots[index]=value;
- }
-
- private PyObject[]slots;
-
- private PyObject dict;
-
- public PyObject fastGetDict() {
- return dict;
- }
-
- public PyObject getDict() {
- return dict;
- }
-
- public void setDict(PyObject newDict) {
- if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
- dict=newDict;
- } else {
- throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
- }
- }
-
- public void delDict() {
- // deleting an object's instance dict makes it grow a new one
- dict=new PyStringMap();
- }
-
- public PyByteArrayDerived(PyType subtype) {
- super(subtype);
- slots=new PyObject[subtype.getNumSlots()];
- dict=subtype.instDict();
- }
-
- public PyString __str__() {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__str__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__();
- if (res instanceof PyString)
- return(PyString)res;
- throw Py.TypeError("__str__"+" returned non-"+"string"+" (type "+res.getType().fastGetName()+")");
- }
- return super.__str__();
- }
-
- public PyString __repr__() {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__repr__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__();
- if (res instanceof PyString)
- return(PyString)res;
- throw Py.TypeError("__repr__"+" returned non-"+"string"+" (type "+res.getType().fastGetName()+")");
- }
- return super.__repr__();
- }
-
- public PyString __hex__() {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__hex__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__();
- if (res instanceof PyString)
- return(PyString)res;
- throw Py.TypeError("__hex__"+" returned non-"+"string"+" (type "+res.getType().fastGetName()+")");
- }
- return super.__hex__();
- }
-
- public PyString __oct__() {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__oct__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__();
- if (res instanceof PyString)
- return(PyString)res;
- throw Py.TypeError("__oct__"+" returned non-"+"string"+" (type "+res.getType().fastGetName()+")");
- }
- return super.__oct__();
- }
-
- public PyFloat __float__() {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__float__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__();
- if (res instanceof PyFloat)
- return(PyFloat)res;
- throw Py.TypeError("__float__"+" returned non-"+"float"+" (type "+res.getType().fastGetName()+")");
- }
- return super.__float__();
- }
-
- public PyComplex __complex__() {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__complex__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__();
- if (res instanceof PyComplex)
- return(PyComplex)res;
- throw Py.TypeError("__complex__"+" returned non-"+"complex"+" (type "+res.getType().fastGetName()+")");
- }
- return super.__complex__();
- }
-
- public PyObject __pos__() {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__pos__");
- if (impl!=null)
- return impl.__get__(this,self_type).__call__();
- return super.__pos__();
- }
-
- public PyObject __neg__() {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__neg__");
- if (impl!=null)
- return impl.__get__(this,self_type).__call__();
- return super.__neg__();
- }
-
- public PyObject __abs__() {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__abs__");
- if (impl!=null)
- return impl.__get__(this,self_type).__call__();
- return super.__abs__();
- }
-
- public PyObject __invert__() {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__invert__");
- if (impl!=null)
- return impl.__get__(this,self_type).__call__();
- return super.__invert__();
- }
-
- public PyObject __reduce__() {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__reduce__");
- if (impl!=null)
- return impl.__get__(this,self_type).__call__();
- return super.__reduce__();
- }
-
- public PyObject __add__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__add__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__add__(other);
- }
-
- public PyObject __radd__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__radd__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__radd__(other);
- }
-
- public PyObject __sub__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__sub__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__sub__(other);
- }
-
- public PyObject __rsub__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__rsub__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__rsub__(other);
- }
-
- public PyObject __mul__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__mul__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__mul__(other);
- }
-
- public PyObject __rmul__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__rmul__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__rmul__(other);
- }
-
- public PyObject __div__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__div__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__div__(other);
- }
-
- public PyObject __rdiv__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__rdiv__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__rdiv__(other);
- }
-
- public PyObject __floordiv__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__floordiv__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__floordiv__(other);
- }
-
- public PyObject __rfloordiv__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__rfloordiv__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__rfloordiv__(other);
- }
-
- public PyObject __truediv__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__truediv__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__truediv__(other);
- }
-
- public PyObject __rtruediv__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__rtruediv__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__rtruediv__(other);
- }
-
- public PyObject __mod__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__mod__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__mod__(other);
- }
-
- public PyObject __rmod__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__rmod__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__rmod__(other);
- }
-
- public PyObject __divmod__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__divmod__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__divmod__(other);
- }
-
- public PyObject __rdivmod__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__rdivmod__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__rdivmod__(other);
- }
-
- public PyObject __rpow__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__rpow__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__rpow__(other);
- }
-
- public PyObject __lshift__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__lshift__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__lshift__(other);
- }
-
- public PyObject __rlshift__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__rlshift__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__rlshift__(other);
- }
-
- public PyObject __rshift__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__rshift__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__rshift__(other);
- }
-
- public PyObject __rrshift__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__rrshift__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__rrshift__(other);
- }
-
- public PyObject __and__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__and__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__and__(other);
- }
-
- public PyObject __rand__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__rand__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__rand__(other);
- }
-
- public PyObject __or__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__or__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__or__(other);
- }
-
- public PyObject __ror__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__ror__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__ror__(other);
- }
-
- public PyObject __xor__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__xor__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__xor__(other);
- }
-
- public PyObject __rxor__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__rxor__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__rxor__(other);
- }
-
- public PyObject __lt__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__lt__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__lt__(other);
- }
-
- public PyObject __le__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__le__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__le__(other);
- }
-
- public PyObject __gt__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__gt__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__gt__(other);
- }
-
- public PyObject __ge__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__ge__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__ge__(other);
- }
-
- public PyObject __eq__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__eq__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__eq__(other);
- }
-
- public PyObject __ne__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__ne__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__ne__(other);
- }
-
- public PyObject __iadd__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__iadd__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__iadd__(other);
- }
-
- public PyObject __isub__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__isub__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__isub__(other);
- }
-
- public PyObject __imul__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__imul__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__imul__(other);
- }
-
- public PyObject __idiv__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__idiv__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__idiv__(other);
- }
-
- public PyObject __ifloordiv__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__ifloordiv__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__ifloordiv__(other);
- }
-
- public PyObject __itruediv__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__itruediv__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__itruediv__(other);
- }
-
- public PyObject __imod__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__imod__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__imod__(other);
- }
-
- public PyObject __ipow__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__ipow__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__ipow__(other);
- }
-
- public PyObject __ilshift__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__ilshift__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__ilshift__(other);
- }
-
- public PyObject __irshift__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__irshift__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__irshift__(other);
- }
-
- public PyObject __iand__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__iand__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__iand__(other);
- }
-
- public PyObject __ior__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__ior__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__ior__(other);
- }
-
- public PyObject __ixor__(PyObject other) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__ixor__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__ixor__(other);
- }
-
- public PyObject __int__() {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__int__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__();
- if (res instanceof PyInteger||res instanceof PyLong)
- return res;
- throw Py.TypeError("__int__"+" should return an integer");
- }
- return super.__int__();
- }
-
- public PyObject __long__() {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__long__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__();
- if (res instanceof PyLong||res instanceof PyInteger)
- return res;
- throw Py.TypeError("__long__"+" returned non-"+"long"+" (type "+res.getType().fastGetName()+")");
- }
- return super.__long__();
- }
-
- public int hashCode() {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__hash__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__();
- if (res instanceof PyInteger) {
- return((PyInteger)res).getValue();
- } else
- if (res instanceof PyLong) {
- return((PyLong)res).getValue().intValue();
- }
- throw Py.TypeError("__hash__ should return a int");
- }
- if (self_type.lookup("__eq__")!=null||self_type.lookup("__cmp__")!=null) {
- throw Py.TypeError(String.format("unhashable type: '%.200s'",getType().fastGetName()));
- }
- return super.hashCode();
- }
-
- public PyUnicode __unicode__() {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__unicode__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__();
- if (res instanceof PyUnicode)
- return(PyUnicode)res;
- if (res instanceof PyString)
- return new PyUnicode((PyString)res);
- throw Py.TypeError("__unicode__"+" should return a "+"unicode");
- }
- return super.__unicode__();
- }
-
- public int __cmp__(PyObject other) {
- PyType self_type=getType();
- PyObject[]where_type=new PyObject[1];
- PyObject impl=self_type.lookup_where("__cmp__",where_type);
- // Full Compatibility with CPython __cmp__:
- // If the derived type don't override __cmp__, the
- // *internal* super().__cmp__ should be called, not the
- // exposed one. The difference is that the exposed __cmp__
- // throws a TypeError if the argument is an instance of the same type.
- if (impl==null||where_type[0]==TYPE||Py.isSubClass(TYPE,where_type[0])) {
- return super.__cmp__(other);
- }
- PyObject res=impl.__get__(this,self_type).__call__(other);
- if (res==Py.NotImplemented) {
- return-2;
- }
- int c=res.asInt();
- return c<0?-1:c>0?1:0;
- }
-
- public boolean __nonzero__() {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__nonzero__");
- if (impl==null) {
- impl=self_type.lookup("__len__");
- if (impl==null)
- return super.__nonzero__();
- }
- PyObject o=impl.__get__(this,self_type).__call__();
- Class c=o.getClass();
- if (c!=PyInteger.class&&c!=PyBoolean.class) {
- throw Py.TypeError(String.format("__nonzero__ should return bool or int, returned %s",self_type.getName()));
- }
- return o.__nonzero__();
- }
-
- public boolean __contains__(PyObject o) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__contains__");
- if (impl==null)
- return super.__contains__(o);
- return impl.__get__(this,self_type).__call__(o).__nonzero__();
- }
-
- public int __len__() {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__len__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__();
- if (res instanceof PyInteger)
- return((PyInteger)res).getValue();
- throw Py.TypeError("__len__ should return a int");
- }
- return super.__len__();
- }
-
- public PyObject __iter__() {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__iter__");
- if (impl!=null)
- return impl.__get__(this,self_type).__call__();
- impl=self_type.lookup("__getitem__");
- if (impl==null)
- return super.__iter__();
- return new PySequenceIter(this);
- }
-
- public PyObject __iternext__() {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("next");
- if (impl!=null) {
- try {
- return impl.__get__(this,self_type).__call__();
- } catch (PyException exc) {
- if (exc.match(Py.StopIteration))
- return null;
- throw exc;
- }
- }
- return super.__iternext__(); // ???
- }
-
- public PyObject __finditem__(PyObject key) { // ???
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__getitem__");
- if (impl!=null)
- try {
- return impl.__get__(this,self_type).__call__(key);
- } catch (PyException exc) {
- if (exc.match(Py.LookupError))
- return null;
- throw exc;
- }
- return super.__finditem__(key);
- }
-
- public PyObject __finditem__(int key) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__getitem__");
- if (impl!=null)
- try {
- return impl.__get__(this,self_type).__call__(new PyInteger(key));
- } catch (PyException exc) {
- if (exc.match(Py.LookupError))
- return null;
- throw exc;
- }
- return super.__finditem__(key);
- }
-
- public PyObject __getitem__(PyObject key) {
- // Same as __finditem__, without swallowing LookupErrors. This allows
- // __getitem__ implementations written in Python to raise custom
- // exceptions (such as subclasses of KeyError).
- //
- // We are forced to duplicate the code, instead of defining __finditem__
- // in terms of __getitem__. That's because PyObject defines __getitem__
- // in terms of __finditem__. Therefore, we would end with an infinite
- // loop when self_type.lookup("__getitem__") returns null:
- //
- // __getitem__ -> super.__getitem__ -> __finditem__ -> __getitem__
- //
- // By duplicating the (short) lookup and call code, we are safe, because
- // the call chains will be:
- //
- // __finditem__ -> super.__finditem__
- //
- // __getitem__ -> super.__getitem__ -> __finditem__ -> super.__finditem__
-
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__getitem__");
- if (impl!=null)
- return impl.__get__(this,self_type).__call__(key);
- return super.__getitem__(key);
- }
-
- public void __setitem__(PyObject key,PyObject value) { // ???
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__setitem__");
- if (impl!=null) {
- impl.__get__(this,self_type).__call__(key,value);
- return;
- }
- super.__setitem__(key,value);
- }
-
- public PyObject __getslice__(PyObject start,PyObject stop,PyObject step) { // ???
- if (step!=null) {
- return __getitem__(new PySlice(start,stop,step));
- }
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__getslice__");
- if (impl!=null) {
- PyObject[]indices=PySlice.indices2(this,start,stop);
- return impl.__get__(this,self_type).__call__(indices[0],indices[1]);
- }
- return super.__getslice__(start,stop,step);
- }
-
- public void __setslice__(PyObject start,PyObject stop,PyObject step,PyObject value) {
- if (step!=null) {
- __setitem__(new PySlice(start,stop,step),value);
- return;
- }
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__setslice__");
- if (impl!=null) {
- PyObject[]indices=PySlice.indices2(this,start,stop);
- impl.__get__(this,self_type).__call__(indices[0],indices[1],value);
- return;
- }
- super.__setslice__(start,stop,step,value);
- }
-
- public void __delslice__(PyObject start,PyObject stop,PyObject step) {
- if (step!=null) {
- __delitem__(new PySlice(start,stop,step));
- return;
- }
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__delslice__");
- if (impl!=null) {
- PyObject[]indices=PySlice.indices2(this,start,stop);
- impl.__get__(this,self_type).__call__(indices[0],indices[1]);
- return;
- }
- super.__delslice__(start,stop,step);
- }
-
- public void __delitem__(PyObject key) { // ???
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__delitem__");
- if (impl!=null) {
- impl.__get__(this,self_type).__call__(key);
- return;
- }
- super.__delitem__(key);
- }
-
- public PyObject __call__(PyObject args[],String keywords[]) {
- ThreadState ts=Py.getThreadState();
- if (ts.recursion_depth++>ts.systemState.getrecursionlimit())
- throw Py.RuntimeError("maximum __call__ recursion depth exceeded");
- try {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__call__");
- if (impl!=null)
- return impl.__get__(this,self_type).__call__(args,keywords);
- return super.__call__(args,keywords);
- } finally {
- --ts.recursion_depth;
- }
- }
-
- public PyObject __findattr_ex__(String name) {
- return Deriveds.__findattr_ex__(this,name);
- }
-
- public void __setattr__(String name,PyObject value) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__setattr__");
- if (impl!=null) {
- impl.__get__(this,self_type).__call__(PyString.fromInterned(name),value);
- return;
- }
- super.__setattr__(name,value);
- }
-
- public void __delattr__(String name) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__delattr__");
- if (impl!=null) {
- impl.__get__(this,self_type).__call__(PyString.fromInterned(name));
- return;
- }
- super.__delattr__(name);
- }
-
- public PyObject __get__(PyObject obj,PyObject type) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__get__");
- if (impl!=null) {
- if (obj==null)
- obj=Py.None;
- if (type==null)
- type=Py.None;
- return impl.__get__(this,self_type).__call__(obj,type);
- }
- return super.__get__(obj,type);
- }
-
- public void __set__(PyObject obj,PyObject value) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__set__");
- if (impl!=null) {
- impl.__get__(this,self_type).__call__(obj,value);
- return;
- }
- super.__set__(obj,value);
- }
-
- public void __delete__(PyObject obj) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__delete__");
- if (impl!=null) {
- impl.__get__(this,self_type).__call__(obj);
- return;
- }
- super.__delete__(obj);
- }
-
- public PyObject __pow__(PyObject other,PyObject modulo) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__pow__");
- if (impl!=null) {
- PyObject res;
- if (modulo==null) {
- res=impl.__get__(this,self_type).__call__(other);
- } else {
- res=impl.__get__(this,self_type).__call__(other,modulo);
- }
- if (res==Py.NotImplemented)
- return null;
- return res;
- }
- return super.__pow__(other,modulo);
- }
-
- public void dispatch__init__(PyObject[]args,String[]keywords) {
- Deriveds.dispatch__init__(this,args,keywords);
- }
-
- public PyObject __index__() {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__index__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__();
- if (res instanceof PyInteger||res instanceof PyLong) {
- return res;
- }
- throw Py.TypeError(String.format("__index__ returned non-(int,long) (type %s)",res.getType().fastGetName()));
- }
- return super.__index__();
- }
-
- public Object __tojava__(Class c) {
- // If we are not being asked by the "default" conversion to java, then
- // we can provide this as the result, as long as it is a instance of the
- // specified class. Without this, derived.__tojava__(PyObject.class)
- // would broke. (And that's not pure speculation: PyReflectedFunction's
- // ReflectedArgs asks for things like that).
- if ((c!=Object.class)&&(c!=Serializable.class)&&(c.isInstance(this))) {
- return this;
- }
- // Otherwise, we call the derived __tojava__, if it exists:
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__tojava__");
- if (impl!=null)
- return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class);
- return super.__tojava__(c);
- }
-
- public Object __coerce_ex__(PyObject o) {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__coerce__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__(o);
- if (res==Py.NotImplemented)
- return Py.None;
- if (!(res instanceof PyTuple))
- throw Py.TypeError("__coerce__ didn't return a 2-tuple");
- return((PyTuple)res).getArray();
- }
- return super.__coerce_ex__(o);
- }
-
- public String toString() {
- PyType self_type=getType();
- PyObject impl=self_type.lookup("__repr__");
- if (impl!=null) {
- PyObject res=impl.__get__(this,self_type).__call__();
- if (!(res instanceof PyString))
- throw Py.TypeError("__repr__ returned non-string (type "+res.getType().fastGetName()+")");
- return((PyString)res).toString();
- }
- return super.toString();
- }
-
-}
+/* Generated file, do not modify. See jython/src/templates/gderived.py. */
+package org.python.core;
+
+import java.io.Serializable;
+
+public class PyByteArrayDerived extends PyByteArray implements Slotted {
+
+ public PyObject getSlot(int index) {
+ return slots[index];
+ }
+
+ public void setSlot(int index,PyObject value) {
+ slots[index]=value;
+ }
+
+ private PyObject[]slots;
+
+ private PyObject dict;
+
+ public PyObject fastGetDict() {
+ return dict;
+ }
+
+ public PyObject getDict() {
+ return dict;
+ }
+
+ public void setDict(PyObject newDict) {
+ if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) {
+ dict=newDict;
+ } else {
+ throw Py.TypeError("__dict__ must be set to a Dictionary "+newDict.getClass().getName());
+ }
+ }
+
+ public void delDict() {
+ // deleting an object's instance dict makes it grow a new one
+ dict=new PyStringMap();
+ }
+
+ public PyByteArrayDerived(PyType subtype) {
+ super(subtype);
+ slots=new PyObject[subtype.getNumSlots()];
+ dict=subtype.instDict();
+ }
+
+ public PyString __str__() {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__str__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__();
+ if (res instanceof PyString)
+ return(PyString)res;
+ throw Py.TypeError("__str__"+" returned non-"+"string"+" (type "+res.getType().fastGetName()+")");
+ }
+ return super.__str__();
+ }
+
+ public PyString __repr__() {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__repr__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__();
+ if (res instanceof PyString)
+ return(PyString)res;
+ throw Py.TypeError("__repr__"+" returned non-"+"string"+" (type "+res.getType().fastGetName()+")");
+ }
+ return super.__repr__();
+ }
+
+ public PyString __hex__() {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__hex__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__();
+ if (res instanceof PyString)
+ return(PyString)res;
+ throw Py.TypeError("__hex__"+" returned non-"+"string"+" (type "+res.getType().fastGetName()+")");
+ }
+ return super.__hex__();
+ }
+
+ public PyString __oct__() {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__oct__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__();
+ if (res instanceof PyString)
+ return(PyString)res;
+ throw Py.TypeError("__oct__"+" returned non-"+"string"+" (type "+res.getType().fastGetName()+")");
+ }
+ return super.__oct__();
+ }
+
+ public PyFloat __float__() {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__float__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__();
+ if (res instanceof PyFloat)
+ return(PyFloat)res;
+ throw Py.TypeError("__float__"+" returned non-"+"float"+" (type "+res.getType().fastGetName()+")");
+ }
+ return super.__float__();
+ }
+
+ public PyComplex __complex__() {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__complex__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__();
+ if (res instanceof PyComplex)
+ return(PyComplex)res;
+ throw Py.TypeError("__complex__"+" returned non-"+"complex"+" (type "+res.getType().fastGetName()+")");
+ }
+ return super.__complex__();
+ }
+
+ public PyObject __pos__() {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__pos__");
+ if (impl!=null)
+ return impl.__get__(this,self_type).__call__();
+ return super.__pos__();
+ }
+
+ public PyObject __neg__() {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__neg__");
+ if (impl!=null)
+ return impl.__get__(this,self_type).__call__();
+ return super.__neg__();
+ }
+
+ public PyObject __abs__() {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__abs__");
+ if (impl!=null)
+ return impl.__get__(this,self_type).__call__();
+ return super.__abs__();
+ }
+
+ public PyObject __invert__() {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__invert__");
+ if (impl!=null)
+ return impl.__get__(this,self_type).__call__();
+ return super.__invert__();
+ }
+
+ public PyObject __reduce__() {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__reduce__");
+ if (impl!=null)
+ return impl.__get__(this,self_type).__call__();
+ return super.__reduce__();
+ }
+
+ public PyObject __add__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__add__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__add__(other);
+ }
+
+ public PyObject __radd__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__radd__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__radd__(other);
+ }
+
+ public PyObject __sub__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__sub__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__sub__(other);
+ }
+
+ public PyObject __rsub__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__rsub__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__rsub__(other);
+ }
+
+ public PyObject __mul__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__mul__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__mul__(other);
+ }
+
+ public PyObject __rmul__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__rmul__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__rmul__(other);
+ }
+
+ public PyObject __div__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__div__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__div__(other);
+ }
+
+ public PyObject __rdiv__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__rdiv__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__rdiv__(other);
+ }
+
+ public PyObject __floordiv__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__floordiv__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__floordiv__(other);
+ }
+
+ public PyObject __rfloordiv__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__rfloordiv__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__rfloordiv__(other);
+ }
+
+ public PyObject __truediv__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__truediv__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__truediv__(other);
+ }
+
+ public PyObject __rtruediv__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__rtruediv__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__rtruediv__(other);
+ }
+
+ public PyObject __mod__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__mod__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__mod__(other);
+ }
+
+ public PyObject __rmod__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__rmod__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__rmod__(other);
+ }
+
+ public PyObject __divmod__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__divmod__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__divmod__(other);
+ }
+
+ public PyObject __rdivmod__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__rdivmod__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__rdivmod__(other);
+ }
+
+ public PyObject __rpow__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__rpow__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__rpow__(other);
+ }
+
+ public PyObject __lshift__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__lshift__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__lshift__(other);
+ }
+
+ public PyObject __rlshift__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__rlshift__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__rlshift__(other);
+ }
+
+ public PyObject __rshift__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__rshift__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__rshift__(other);
+ }
+
+ public PyObject __rrshift__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__rrshift__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__rrshift__(other);
+ }
+
+ public PyObject __and__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__and__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__and__(other);
+ }
+
+ public PyObject __rand__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__rand__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__rand__(other);
+ }
+
+ public PyObject __or__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__or__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__or__(other);
+ }
+
+ public PyObject __ror__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__ror__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__ror__(other);
+ }
+
+ public PyObject __xor__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__xor__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__xor__(other);
+ }
+
+ public PyObject __rxor__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__rxor__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__rxor__(other);
+ }
+
+ public PyObject __lt__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__lt__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__lt__(other);
+ }
+
+ public PyObject __le__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__le__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__le__(other);
+ }
+
+ public PyObject __gt__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__gt__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__gt__(other);
+ }
+
+ public PyObject __ge__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__ge__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__ge__(other);
+ }
+
+ public PyObject __eq__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__eq__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__eq__(other);
+ }
+
+ public PyObject __ne__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__ne__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__ne__(other);
+ }
+
+ public PyObject __iadd__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__iadd__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__iadd__(other);
+ }
+
+ public PyObject __isub__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__isub__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__isub__(other);
+ }
+
+ public PyObject __imul__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__imul__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__imul__(other);
+ }
+
+ public PyObject __idiv__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__idiv__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__idiv__(other);
+ }
+
+ public PyObject __ifloordiv__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__ifloordiv__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__ifloordiv__(other);
+ }
+
+ public PyObject __itruediv__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__itruediv__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__itruediv__(other);
+ }
+
+ public PyObject __imod__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__imod__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__imod__(other);
+ }
+
+ public PyObject __ipow__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__ipow__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__ipow__(other);
+ }
+
+ public PyObject __ilshift__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__ilshift__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__ilshift__(other);
+ }
+
+ public PyObject __irshift__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__irshift__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__irshift__(other);
+ }
+
+ public PyObject __iand__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__iand__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__iand__(other);
+ }
+
+ public PyObject __ior__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__ior__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__ior__(other);
+ }
+
+ public PyObject __ixor__(PyObject other) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__ixor__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__ixor__(other);
+ }
+
+ public PyObject __int__() {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__int__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__();
+ if (res instanceof PyInteger||res instanceof PyLong)
+ return res;
+ throw Py.TypeError("__int__"+" should return an integer");
+ }
+ return super.__int__();
+ }
+
+ public PyObject __long__() {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__long__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__();
+ if (res instanceof PyLong||res instanceof PyInteger)
+ return res;
+ throw Py.TypeError("__long__"+" returned non-"+"long"+" (type "+res.getType().fastGetName()+")");
+ }
+ return super.__long__();
+ }
+
+ public int hashCode() {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__hash__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__();
+ if (res instanceof PyInteger) {
+ return((PyInteger)res).getValue();
+ } else
+ if (res instanceof PyLong) {
+ return((PyLong)res).getValue().intValue();
+ }
+ throw Py.TypeError("__hash__ should return a int");
+ }
+ if (self_type.lookup("__eq__")!=null||self_type.lookup("__cmp__")!=null) {
+ throw Py.TypeError(String.format("unhashable type: '%.200s'",getType().fastGetName()));
+ }
+ return super.hashCode();
+ }
+
+ public PyUnicode __unicode__() {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__unicode__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__();
+ if (res instanceof PyUnicode)
+ return(PyUnicode)res;
+ if (res instanceof PyString)
+ return new PyUnicode((PyString)res);
+ throw Py.TypeError("__unicode__"+" should return a "+"unicode");
+ }
+ return super.__unicode__();
+ }
+
+ public int __cmp__(PyObject other) {
+ PyType self_type=getType();
+ PyObject[]where_type=new PyObject[1];
+ PyObject impl=self_type.lookup_where("__cmp__",where_type);
+ // Full Compatibility with CPython __cmp__:
+ // If the derived type don't override __cmp__, the
+ // *internal* super().__cmp__ should be called, not the
+ // exposed one. The difference is that the exposed __cmp__
+ // throws a TypeError if the argument is an instance of the same type.
+ if (impl==null||where_type[0]==TYPE||Py.isSubClass(TYPE,where_type[0])) {
+ return super.__cmp__(other);
+ }
+ PyObject res=impl.__get__(this,self_type).__call__(other);
+ if (res==Py.NotImplemented) {
+ return-2;
+ }
+ int c=res.asInt();
+ return c<0?-1:c>0?1:0;
+ }
+
+ public boolean __nonzero__() {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__nonzero__");
+ if (impl==null) {
+ impl=self_type.lookup("__len__");
+ if (impl==null)
+ return super.__nonzero__();
+ }
+ PyObject o=impl.__get__(this,self_type).__call__();
+ Class c=o.getClass();
+ if (c!=PyInteger.class&&c!=PyBoolean.class) {
+ throw Py.TypeError(String.format("__nonzero__ should return bool or int, returned %s",self_type.getName()));
+ }
+ return o.__nonzero__();
+ }
+
+ public boolean __contains__(PyObject o) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__contains__");
+ if (impl==null)
+ return super.__contains__(o);
+ return impl.__get__(this,self_type).__call__(o).__nonzero__();
+ }
+
+ public int __len__() {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__len__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__();
+ if (res instanceof PyInteger)
+ return((PyInteger)res).getValue();
+ throw Py.TypeError("__len__ should return a int");
+ }
+ return super.__len__();
+ }
+
+ public PyObject __iter__() {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__iter__");
+ if (impl!=null)
+ return impl.__get__(this,self_type).__call__();
+ impl=self_type.lookup("__getitem__");
+ if (impl==null)
+ return super.__iter__();
+ return new PySequenceIter(this);
+ }
+
+ public PyObject __iternext__() {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("next");
+ if (impl!=null) {
+ try {
+ return impl.__get__(this,self_type).__call__();
+ } catch (PyException exc) {
+ if (exc.match(Py.StopIteration))
+ return null;
+ throw exc;
+ }
+ }
+ return super.__iternext__(); // ???
+ }
+
+ public PyObject __finditem__(PyObject key) { // ???
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__getitem__");
+ if (impl!=null)
+ try {
+ return impl.__get__(this,self_type).__call__(key);
+ } catch (PyException exc) {
+ if (exc.match(Py.LookupError))
+ return null;
+ throw exc;
+ }
+ return super.__finditem__(key);
+ }
+
+ public PyObject __finditem__(int key) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__getitem__");
+ if (impl!=null)
+ try {
+ return impl.__get__(this,self_type).__call__(new PyInteger(key));
+ } catch (PyException exc) {
+ if (exc.match(Py.LookupError))
+ return null;
+ throw exc;
+ }
+ return super.__finditem__(key);
+ }
+
+ public PyObject __getitem__(PyObject key) {
+ // Same as __finditem__, without swallowing LookupErrors. This allows
+ // __getitem__ implementations written in Python to raise custom
+ // exceptions (such as subclasses of KeyError).
+ //
+ // We are forced to duplicate the code, instead of defining __finditem__
+ // in terms of __getitem__. That's because PyObject defines __getitem__
+ // in terms of __finditem__. Therefore, we would end with an infinite
+ // loop when self_type.lookup("__getitem__") returns null:
+ //
+ // __getitem__ -> super.__getitem__ -> __finditem__ -> __getitem__
+ //
+ // By duplicating the (short) lookup and call code, we are safe, because
+ // the call chains will be:
+ //
+ // __finditem__ -> super.__finditem__
+ //
+ // __getitem__ -> super.__getitem__ -> __finditem__ -> super.__finditem__
+
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__getitem__");
+ if (impl!=null)
+ return impl.__get__(this,self_type).__call__(key);
+ return super.__getitem__(key);
+ }
+
+ public void __setitem__(PyObject key,PyObject value) { // ???
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__setitem__");
+ if (impl!=null) {
+ impl.__get__(this,self_type).__call__(key,value);
+ return;
+ }
+ super.__setitem__(key,value);
+ }
+
+ public PyObject __getslice__(PyObject start,PyObject stop,PyObject step) { // ???
+ if (step!=null) {
+ return __getitem__(new PySlice(start,stop,step));
+ }
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__getslice__");
+ if (impl!=null) {
+ PyObject[]indices=PySlice.indices2(this,start,stop);
+ return impl.__get__(this,self_type).__call__(indices[0],indices[1]);
+ }
+ return super.__getslice__(start,stop,step);
+ }
+
+ public void __setslice__(PyObject start,PyObject stop,PyObject step,PyObject value) {
+ if (step!=null) {
+ __setitem__(new PySlice(start,stop,step),value);
+ return;
+ }
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__setslice__");
+ if (impl!=null) {
+ PyObject[]indices=PySlice.indices2(this,start,stop);
+ impl.__get__(this,self_type).__call__(indices[0],indices[1],value);
+ return;
+ }
+ super.__setslice__(start,stop,step,value);
+ }
+
+ public void __delslice__(PyObject start,PyObject stop,PyObject step) {
+ if (step!=null) {
+ __delitem__(new PySlice(start,stop,step));
+ return;
+ }
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__delslice__");
+ if (impl!=null) {
+ PyObject[]indices=PySlice.indices2(this,start,stop);
+ impl.__get__(this,self_type).__call__(indices[0],indices[1]);
+ return;
+ }
+ super.__delslice__(start,stop,step);
+ }
+
+ public void __delitem__(PyObject key) { // ???
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__delitem__");
+ if (impl!=null) {
+ impl.__get__(this,self_type).__call__(key);
+ return;
+ }
+ super.__delitem__(key);
+ }
+
+ public PyObject __call__(PyObject args[],String keywords[]) {
+ ThreadState ts=Py.getThreadState();
+ if (ts.recursion_depth++>ts.systemState.getrecursionlimit())
+ throw Py.RuntimeError("maximum __call__ recursion depth exceeded");
+ try {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__call__");
+ if (impl!=null)
+ return impl.__get__(this,self_type).__call__(args,keywords);
+ return super.__call__(args,keywords);
+ } finally {
+ --ts.recursion_depth;
+ }
+ }
+
+ public PyObject __findattr_ex__(String name) {
+ return Deriveds.__findattr_ex__(this,name);
+ }
+
+ public void __setattr__(String name,PyObject value) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__setattr__");
+ if (impl!=null) {
+ impl.__get__(this,self_type).__call__(PyString.fromInterned(name),value);
+ return;
+ }
+ super.__setattr__(name,value);
+ }
+
+ public void __delattr__(String name) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__delattr__");
+ if (impl!=null) {
+ impl.__get__(this,self_type).__call__(PyString.fromInterned(name));
+ return;
+ }
+ super.__delattr__(name);
+ }
+
+ public PyObject __get__(PyObject obj,PyObject type) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__get__");
+ if (impl!=null) {
+ if (obj==null)
+ obj=Py.None;
+ if (type==null)
+ type=Py.None;
+ return impl.__get__(this,self_type).__call__(obj,type);
+ }
+ return super.__get__(obj,type);
+ }
+
+ public void __set__(PyObject obj,PyObject value) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__set__");
+ if (impl!=null) {
+ impl.__get__(this,self_type).__call__(obj,value);
+ return;
+ }
+ super.__set__(obj,value);
+ }
+
+ public void __delete__(PyObject obj) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__delete__");
+ if (impl!=null) {
+ impl.__get__(this,self_type).__call__(obj);
+ return;
+ }
+ super.__delete__(obj);
+ }
+
+ public PyObject __pow__(PyObject other,PyObject modulo) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__pow__");
+ if (impl!=null) {
+ PyObject res;
+ if (modulo==null) {
+ res=impl.__get__(this,self_type).__call__(other);
+ } else {
+ res=impl.__get__(this,self_type).__call__(other,modulo);
+ }
+ if (res==Py.NotImplemented)
+ return null;
+ return res;
+ }
+ return super.__pow__(other,modulo);
+ }
+
+ public void dispatch__init__(PyObject[]args,String[]keywords) {
+ Deriveds.dispatch__init__(this,args,keywords);
+ }
+
+ public PyObject __index__() {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__index__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__();
+ if (res instanceof PyInteger||res instanceof PyLong) {
+ return res;
+ }
+ throw Py.TypeError(String.format("__index__ returned non-(int,long) (type %s)",res.getType().fastGetName()));
+ }
+ return super.__index__();
+ }
+
+ public Object __tojava__(Class c) {
+ // If we are not being asked by the "default" conversion to java, then
+ // we can provide this as the result, as long as it is a instance of the
+ // specified class. Without this, derived.__tojava__(PyObject.class)
+ // would broke. (And that's not pure speculation: PyReflectedFunction's
+ // ReflectedArgs asks for things like that).
+ if ((c!=Object.class)&&(c!=Serializable.class)&&(c.isInstance(this))) {
+ return this;
+ }
+ // Otherwise, we call the derived __tojava__, if it exists:
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__tojava__");
+ if (impl!=null)
+ return impl.__get__(this,self_type).__call__(Py.java2py(c)).__tojava__(Object.class);
+ return super.__tojava__(c);
+ }
+
+ public Object __coerce_ex__(PyObject o) {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__coerce__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__(o);
+ if (res==Py.NotImplemented)
+ return Py.None;
+ if (!(res instanceof PyTuple))
+ throw Py.TypeError("__coerce__ didn't return a 2-tuple");
+ return((PyTuple)res).getArray();
+ }
+ return super.__coerce_ex__(o);
+ }
+
+ public String toString() {
+ PyType self_type=getType();
+ PyObject impl=self_type.lookup("__repr__");
+ if (impl!=null) {
+ PyObject res=impl.__get__(this,self_type).__call__();
+ if (!(res instanceof PyString))
+ throw Py.TypeError("__repr__ returned non-string (type "+res.getType().fastGetName()+")");
+ return((PyString)res).toString();
+ }
+ return super.toString();
+ }
+
+}
diff --git a/tests/java/org/python/core/BaseBytesTest.java b/tests/java/org/python/core/BaseBytesTest.java
--- a/tests/java/org/python/core/BaseBytesTest.java
+++ b/tests/java/org/python/core/BaseBytesTest.java
@@ -42,8 +42,10 @@
super(name);
}
- static PythonInterpreter interp = null;
+ /** Sometimes we need the interpreter to be initialised **/
+ PythonInterpreter interp;
+ /** State for random data fills */
Random random;
public static char toChar(int b) {
@@ -102,17 +104,20 @@
/**
* Compare expected and result array sections at specified locations and length.
*
- * @param expected reference values
+ * @param expected reference values (may be null iff len==0)
* @param first first value to compare in expected values
* @param result bytearray from method under test
* @param start first value to compare in result values
* @param len number of values to compare
*/
static void checkInts(int[] expected, int first, BaseBytes result, int start, int len) {
- int end = first + len;
- if (end > expected.length) end = expected.length;
- for (int i = first, j = start; i < end; i++, j++)
- assertEquals("element value", expected[i], result.intAt(j));
+ if (len > 0) {
+ int end = first + len;
+ if (end > expected.length) end = expected.length;
+ for (int i = first, j = start; i < end; i++, j++) {
+ assertEquals("element value", expected[i], result.intAt(j));
+ }
+ }
}
/**
@@ -125,8 +130,9 @@
// Size must be the same
assertEquals("size", expected.length, result.size());
// And each element
- for (int i = 0; i < expected.length; i++)
+ for (int i = 0; i < expected.length; i++) {
assertEquals("element value", expected[i], result.intAt(i));
+ }
}
/**
@@ -168,7 +174,7 @@
List<PyObject> list = new ArrayList<PyObject>(source.length);
int choose = 0;
for (int b : source) {
- switch(choose++){
+ switch (choose++) {
case 0:
PyInteger i = new PyInteger(b);
list.add(i);
@@ -210,6 +216,7 @@
BaseBytes a = getInstance(aRef);
System.out.println(toString(a));
assertEquals(aRef.length, a.size());
+
// init(int) at various sizes
for (int n : new int[] {0, 1, 2, 7, 8, 9, MEDIUM, LARGE, HUGE}) {
a = getInstance(n);
@@ -231,8 +238,9 @@
assertEquals(a.size(), b.size());
// assertEquals(a.storage, b.storage); // Supposed to share?
// Check we got the same bytes
- for (int i = 0; i < a.size(); i++)
+ for (int i = 0; i < a.size(); i++) {
assertEquals(a.intAt(i), b.intAt(i));
+ }
}
/**
@@ -424,9 +432,11 @@
for (int count = 0; count <= maxCount; count++) {
// Reference answer
int[] bRef = new int[count * L];
- for (int i = 0; i < count; i++)
- for (int j = 0; j < L; j++)
+ for (int i = 0; i < count; i++) {
+ for (int j = 0; j < L; j++) {
bRef[i * L + j] = aRef[j];
+ }
+ }
// Test
BaseBytes b = a.repeat(count);
// System.out.println(toString(b));
@@ -704,13 +714,16 @@
if (step == 1) {
// This is a contiguous slice [start:stop] so we can share storage
r = new MyBytes();
- if (stop > start) r.setStorage(storage, stop - start, start + offset);
+ if (stop > start) {
+ r.setStorage(storage, stop - start, start + offset);
+ }
} else {
// This is an extended slice [start:stop:step] so we have to copy elements from it
r = new MyBytes(sliceLength(start, stop, step));
int iomax = r.size + r.offset;
- for (int io = r.offset, jo = start; io < iomax; jo += step, io++)
+ for (int io = r.offset, jo = start; io < iomax; jo += step, io++) {
r.storage[io] = storage[jo]; // Assign r[i] = this[j]
+ }
}
return r;
}
@@ -747,13 +760,16 @@
super(TYPE);
int n = value.length;
store = new byte[n];
- for (int i = 0; i < n; i++)
+ for (int i = 0; i < n; i++) {
store[i] = (byte)value[i];
+ }
}
@Override
public MemoryView getMemoryView() {
- if (mv == null) mv = new MemoryViewImpl();
+ if (mv == null) {
+ mv = new MemoryViewImpl();
+ }
return mv;
}
@@ -823,26 +839,31 @@
private StringBuilder image = new StringBuilder(100);
private void repeat(char c, int n) {
- for (int i = 0; i < n; i++)
+ for (int i = 0; i < n; i++) {
image.append(i == 0 ? '|' : ' ').append(c);
+ }
}
// Show in image s[pos:pos+n] (as 2*n characters)
private void append(byte[] s, int pos, int n) {
- if (pos < 0 || pos + n > s.length) return;
+ if (pos < 0 || pos + n > s.length)
+ return;
for (int i = 0; i < n; i++) {
int c = 0xff & ((int)s[pos + i]);
- if (c == 0)
+ if (c == 0) {
c = '.';
- else if (Character.isISOControl(c)) c = '#';
+ } else if (Character.isISOControl(c)) {
+ c = '#';
+ }
image.append(i == 0 ? '|' : ' ').append(toChar(c));
}
}
// Show an extent of n bytes (as 2*n charactrs)
public void padTo(int n) {
- while (n > image.length())
+ while (n > image.length()) {
image.append(' ');
+ }
}
/**
diff --git a/tests/java/org/python/core/PyByteArrayTest.java b/tests/java/org/python/core/PyByteArrayTest.java
--- a/tests/java/org/python/core/PyByteArrayTest.java
+++ b/tests/java/org/python/core/PyByteArrayTest.java
@@ -21,12 +21,11 @@
super(name);
}
-
/**
* Generate character codes for in a pattern matching an intended deletion or slice to be
* replaced. If c="adb", something like b'aaaaaaddddbbbb' where the 'd' characters should be
* deleted or replaced in the slice operation.
- *
+ *
* @param na number of c.charAt(0) characters
* @param nd number of c.charAt(1) characters
* @param nb number of c.charAt(2) characters
@@ -36,12 +35,15 @@
public static int[] patternInts(int na, int nd, int nb, String c) {
int[] r = new int[na + nd + nb];
int p = 0;
- for (int i = 0; i < na; i++)
+ for (int i = 0; i < na; i++) {
r[p++] = c.charAt(0);
- for (int i = 0; i < nd; i++)
+ }
+ for (int i = 0; i < nd; i++) {
r[p++] = c.charAt(1);
- for (int i = 0; i < nb; i++)
+ }
+ for (int i = 0; i < nb; i++) {
r[p++] = c.charAt(2);
+ }
return r;
}
@@ -49,7 +51,7 @@
* Generate character codes for 'a', 'D', 'b' in a pattern matching an intended deletion or
* slice to be replaced. Something like b'aaaaaaddddbbbb' where the 'E' characters should be
* deleted or replaced in the slice operation.
- *
+ *
* @param na number of a characters
* @param nd number of D characters
* @param nb number of b characters
@@ -63,7 +65,7 @@
* Generate character codes for 'a', 'E', 'b' in a pattern matching an intended result of slice
* replacement. Something like b'aaaaaaEEEbbbb' where the 'E' characters are the replacement in
* the slice operation.
- *
+ *
* @param na number of a characters
* @param ne number of E characters
* @param nb number of b characters
@@ -74,11 +76,11 @@
}
/**
- * Generate a tuple of int arrays at random in the range 0..255 for testing slice operations.
- * In effect, the method generates 4 arrays of random data A, B, D, E and returns an array of three arrays formed thus:
- * { A + D + B, A + E + B, E } where + means concatenation. This can be used to test slice
- * assignment and deletion.
- *
+ * Generate a tuple of int arrays at random in the range 0..255 for testing slice operations. In
+ * effect, the method generates 4 arrays of random data A, B, D, E and returns an array of three
+ * arrays formed thus: { A + D + B, A + E + B, E } where + means concatenation. This can be used
+ * to test slice assignment and deletion.
+ *
* @param random the random generator
* @param na the number of elements in A
* @param nd the number of elements in D (the deleted material)
@@ -90,34 +92,33 @@
int[] adb = new int[na + nd + nb];
int[] aeb = new int[na + ne + nb];
int[] e = new int[ne];
- int[][] ret = { adb, aeb, e };
- int p=0, q = 0;
+ int[][] ret = {adb, aeb, e};
+ int p = 0, q = 0;
// The A values go into adb and aeb
for (int i = 0; i < na; i++) {
int a = random.nextInt(256);
- adb[p++] =a;
- aeb[q++] =a;
+ adb[p++] = a;
+ aeb[q++] = a;
}
// The D values go into adb only
for (int i = 0; i < nd; i++) {
int d = random.nextInt(256);
- adb[p++] =d;
+ adb[p++] = d;
}
// The E values go into e and aeb
for (int i = 0; i < ne; i++) {
int x = random.nextInt(256);
- e[p++] =x;
- aeb[q++] =x;
+ e[p++] = x;
+ aeb[q++] = x;
}
// The B values go into adb and aeb
for (int i = 0; i < nb; i++) {
int b = random.nextInt(256);
- adb[p++] =b;
- aeb[q++] =b;
+ adb[p++] = b;
+ aeb[q++] = b;
}
return ret;
}
-
/**
* Check result of slice operations, synthesised from the elements passed. This method accepts
@@ -127,7 +128,7 @@
* B=X[-nb:N], D=X[na:nb] and E=Y[:ne], and posed the problem setslice( A + D + B, E ), where +
* means concatenation in this expression, to which the answer should be A + E + B. This method
* checks that the result is exactly that.
- *
+ *
* @param na the number of elements in A
* @param nd the number of elements in D (the deleted material)
* @param nb the number of elements in B
@@ -146,13 +147,13 @@
// Check that B is preserved
checkInts(x, na + nd, result, na + ne, nb);
}
-
+
/**
* Check result of extended slice operations, synthesised from the elements passed. This method
* accepts the 'dimensions' of a slice problem and tests whether a resulting byte array contains
* the correct result. The result array has been filled from (the whole of) array x[], then
* slice assignment took place from y[k] to element u[start + k*step].
- *
+ *
* @param start
* @param step
* @param n number of steps
@@ -163,57 +164,142 @@
public static void checkSlice(int start, int step, int n, int[] x, int[] y, BaseBytes u) {
// Check the size is right
assertEquals("size", x.length, u.size());
+
if (step > 0) {
+
// Check before start of slice
int px = 0, py = 0;
- for (; px < start; px++)
+ for (; px < start; px++) {
assertEquals("before slice", x[px], u.intAt(px));
+ }
+
// Check slice-affected region at n assignments and n-1 gaps of length step-1.
- if (n>0) assertEquals("first affected", y[py++], u.intAt(px++));
+ if (n > 0) {
+ assertEquals("first affected", y[py++], u.intAt(px++));
+ }
+
for (int i = 1; i < n; i++) {
for (int j = 1; j < step; j++, px++) {
assertEquals("in gap", x[px], u.intAt(px));
}
assertEquals("next affected", y[py++], u.intAt(px++));
}
+
// Check after slice-affected region
- for (; px < x.length; px++)
+ for (; px < x.length; px++) {
assertEquals("after slice", x[px], u.intAt(px));
-
+ }
+
} else {
// Negative step but easier to think about as a positive number
step = -step;
// Check after start of slice
int px = x.length - 1, py = 0;
- for (; px > start; --px)
+ for (; px > start; --px) {
assertEquals("after slice", x[px], u.intAt(px));
+ }
+
// Check slice-affected region at n assignments and n-1 gaps of length step-1.
- if (n>0) assertEquals("first affected", y[py++], u.intAt(px--));
+ if (n > 0) {
+ assertEquals("first affected", y[py++], u.intAt(px--));
+ }
+
for (int i = 1; i < n; i++) {
for (int j = 1; j < step; j++, px--) {
assertEquals("in gap", x[px], u.intAt(px));
}
assertEquals("next affected", y[py++], u.intAt(px--));
}
+
// Check before slice-affected region
- for (; px >= 0; px--)
+ for (; px >= 0; px--) {
assertEquals("before slice", x[px], u.intAt(px));
-
+ }
}
}
- /* (non-Javadoc)
+ /**
+ * Check result of extended slice deletion operations, synthesised from the elements passed.
+ * This method accepts the 'dimensions' of a slice deletion problem and tests whether a
+ * resulting byte array contains the correct result. The result array has been filled from (the
+ * whole of) array x[], then slice deletion took place at original element u[start + k*step].
+ *
+ * @param start
+ * @param step
+ * @param n number of steps (deletions)
+ * @param x source of the original data
+ * @param u the result to be tested against properly selected elements of x
+ */
+ public static void checkDelSlice(int start, int step, int n, int[] x, BaseBytes u) {
+ // Check the size is right
+ assertEquals("size", x.length - n, u.size());
+
+ if (step > 0) {
+
+ // Check before start of slice
+ int px = 0, pu = 0;
+ for (; px < start; px++) {
+ assertEquals("before slice", x[px], u.intAt(pu++));
+ }
+
+ // Check slice-affected region at n deletions and n-1 gaps of length step-1.
+ // px now points to the first element that should be missing from u
+ px++;
+ for (int i = 1; i < n; i++) {
+ for (int j = 1; j < step; j++, px++) {
+ assertEquals("in gap", x[px], u.intAt(pu++));
+ }
+ // px now points to the i.th element that should be missing from u
+ px++;
+ }
+
+ // Check after slice-affected region
+ for (; px < x.length; px++) {
+ assertEquals("after slice", x[px], u.intAt(pu++));
+ }
+
+ } else {
+
+ // Negative step but easier to think about as a positive number
+ step = -step;
+
+ // Check after start of slice
+ int px = x.length - 1, pu = u.size - 1;
+ for (; px > start; --px) {
+ assertEquals("after slice", x[px], u.intAt(pu--));
+ }
+
+ // Check slice-affected region at n assignments and n-1 gaps of length step-1.
+ // px now points to the first element that should be missing from u
+ px--;
+ for (int i = 1; i < n; i++) {
+ for (int j = 1; j < step; j++, px--) {
+ assertEquals("in gap", x[px], u.intAt(pu--));
+ }
+ // px now points to the i.th element that should be missing from u
+ px--;
+ }
+
+ // Check before slice-affected region
+ for (; px >= 0; px--) {
+ assertEquals("before slice", x[px], u.intAt(pu--));
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
* @see org.python.core.BaseBytesTest#setUp()
*/
protected void setUp() throws Exception {
super.setUp();
}
-
/**
* Test method for {@link PyObject#__getslice__(PyObject, PyObject)}.
- *
+ *
* @see BaseBytes#getslice(int, int)
*/
public void test__getslice__2() {
@@ -233,29 +319,33 @@
for (int start : posStart) {
PyObject pyStart, pyStop, pyStart_L, pyStop_L;
pyStart = new PyInteger(start);
- if (start > 0)
+ if (start > 0) {
// The other way of saying [start:stop] is [start-L:stop]
pyStart_L = new PyInteger(start - L);
- else
+ } else {
// The other way of saying [0:stop] is [:stop]
pyStart_L = Py.None;
+ }
for (int stop = start; stop <= L; stop++) {
// Make a reference answer by picking elements of aRef in slice pattern
bList.clear();
for (int i = start; i < stop; i++) {
- if (verbose >= 5) System.out.printf(" (%d,%d) i=%d\n", start, stop, i);
+ if (verbose >= 5) {
+ System.out.printf(" (%d,%d) i=%d\n", start, stop, i);
+ }
bList.add(new PyInteger(aRef[i]));
}
// PyObject versions of stop
- if (stop < L)
+ if (stop < L) {
// The other way of saying [start:stop:+s] is [start:stop-L:+s]
pyStop_L = new PyInteger(stop - L);
- else
+ } else {
// The other way of saying [start:L:+s] is [start::+s]
pyStop_L = Py.None;
+ }
pyStop = new PyInteger(stop);
// Generate test result and check it
@@ -273,7 +363,7 @@
/**
* Common code to check {@link PyByteArray#__getslice__(PyObject, PyObject)} against a reference
* answer.
- *
+ *
* @param a object under test
* @param pyStart
* @param pyStop
@@ -285,21 +375,25 @@
PyObject pyStop,
List<PyInteger> bList,
int verbose) {
- if (verbose >= 4) System.out.printf(" __getslice__(%s,%s)\n", pyStart, pyStop);
+ if (verbose >= 4) {
+ System.out.printf(" __getslice__(%s,%s)\n", pyStart, pyStop);
+ }
PyObject b = a.__getslice__(pyStart, pyStop);
- if (verbose >= 3) System.out.println(toString((BaseBytes)b));
+ if (verbose >= 3) {
+ System.out.println(toString((BaseBytes)b));
+ }
checkInts(bList, b);
}
/**
* Test method for {@link PyObject#__getslice__(PyObject, PyObject, PyObject)}.
- *
+ *
* @see BaseBytes#getslice(int, int, int)
*/
public void test__getslice__3() {
int verbose = 0;
// __getslice__() deals with start, stop values also relative to the end.
- String ver = "Quand je br�le et que tu t'enflammes ;";
+ String ver = "Quand je brûle et que tu t'enflammes ;";
final int L = ver.length();
int[] aRef = toInts(ver);
BaseBytes a = getInstance(aRef);
@@ -318,30 +412,33 @@
for (int start : posStart) {
PyObject pyStart, pyStop, pyStart_L, pyStop_L;
pyStart = new PyInteger(start);
- if (start > 0)
+ if (start > 0) {
// The other way of saying [start:stop:+s] is [start-L:stop:+s]
pyStart_L = new PyInteger(start - L);
- else
+ } else {
// The other way of saying [0:stop:+s] is [:stop:+s]
pyStart_L = Py.None;
+ }
for (int stop = start; stop <= L; stop++) {
// Make a reference answer by picking elements of aRef in slice pattern
bList.clear();
for (int i = start; i < stop; i += step) {
- if (verbose >= 5) System.out.printf(" (%d,%d,%d) i=%d\n", start, stop,
- step, i);
+ if (verbose >= 5) {
+ System.out.printf(" (%d,%d,%d) i=%d\n", start, stop, step, i);
+ }
bList.add(new PyInteger(aRef[i]));
}
// PyObject versions of stop
- if (stop < L)
+ if (stop < L) {
// The other way of saying [start:stop:+s] is [start:stop-L:+s]
pyStop_L = new PyInteger(stop - L);
- else
+ } else {
// The other way of saying [start:L:+s] is [start::+s]
pyStop_L = Py.None;
+ }
pyStop = new PyInteger(stop);
// Generate test result and check it
@@ -363,37 +460,41 @@
for (int step = -1; step > -4; step--) {
PyInteger pyStep = new PyInteger(step);
+
for (int start : negStart) {
PyObject pyStart, pyStop, pyStart_L, pyStop_L;
pyStart = new PyInteger(start);
- if (start < L - 1)
+
+ if (start < L - 1) {
// The other way of saying [start:stop:-s] is [start-L:stop:-s]
pyStart_L = new PyInteger(start - L);
- else
+ } else {
// The other way of saying [L-1:stop:-s] is [:stop:-s]
pyStart_L = Py.None;
+ }
for (int stop = start; stop >= -1; stop--) {
// Make a reference answer by picking elements of aRef in slice pattern
bList.clear();
for (int i = start; i > stop; i += step) {
- if (verbose >= 5) System.out.printf(" (%d,%d,%d) i=%d\n", start, stop,
- step, i);
+ if (verbose >= 5) {
+ System.out.printf(" (%d,%d,%d) i=%d\n", start, stop, step, i);
+ }
bList.add(new PyInteger(aRef[i]));
}
// PyObject versions of stop
- if (stop >= 0)
+ if (stop >= 0) {
// The other way of saying [start:stop:-s] is [start:stop-L:-s]
pyStop_L = new PyInteger(stop - L);
- else {
+ } else {
// intended final value is 0, but [start:-1:-s] doesn't mean that
- stop = -(L+1); // This does.
+ stop = -(L + 1); // This does.
pyStop_L = Py.None; // And so does [start::-s]
}
pyStop = new PyInteger(stop);
-
+
// Generate test result and check it
doTest__getslice__3(a, pyStart, pyStop, pyStep, bList, verbose + 2);
// Repeat same result specifying start relative to end
@@ -410,7 +511,7 @@
/**
* Common code to check {@link PyByteArray#__getslice__(PyObject, PyObject, PyObject)} against a
* reference answer.
- *
+ *
* @param a answer from method under test
* @param pyStart
* @param pyStop
@@ -424,13 +525,16 @@
PyObject pyStep,
List<PyInteger> bList,
int verbose) {
- if (verbose >= 4) System.out.printf(" __getslice__(%s,%s,%s)\n", pyStart, pyStop, pyStep);
+ if (verbose >= 4) {
+ System.out.printf(" __getslice__(%s,%s,%s)\n", pyStart, pyStop, pyStep);
+ }
PyObject b = a.__getslice__(pyStart, pyStop, pyStep);
- if (verbose >= 3) System.out.println(toString((BaseBytes)b));
+ if (verbose >= 3) {
+ System.out.println(toString((BaseBytes)b));
+ }
checkInts(bList, b);
}
-
-
+
/**
* Test method for {@link PyByteArray#__setitem__(int,PyObject)}, and through it of
* {@link PyByteArray#pyset(int,PyObject)}.
@@ -464,7 +568,9 @@
fail("Exception not thrown for __setitem__(" + 0 + ", " + b + ")");
} catch (PyException pye) {
assertEquals(Py.ValueError, pye.type);
- if (verbose >= 2) System.out.printf(" Exception: %s\n", pye);
+ if (verbose >= 2) {
+ System.out.printf(" Exception: %s\n", pye);
+ }
}
}
@@ -476,7 +582,9 @@
fail("Exception not thrown for __setitem__(" + i + ", x)");
} catch (PyException pye) {
assertEquals(Py.IndexError, pye.type);
- if (verbose >= 2) System.out.printf(" Exception: %s\n", pye);
+ if (verbose >= 2) {
+ System.out.printf(" Exception: %s\n", pye);
+ }
}
}
@@ -501,8 +609,8 @@
Arrays.fill(eInts, 'E');
PyByteArray e = new PyByteArray(eInts);
- for (int nd : ndList)
- for (int na : naList)
+ for (int nd : ndList) {
+ for (int na : naList) {
for (int nb : nbList) {
int[] aRef = adbInts(na, nd, nb);
int[] bRef = aebInts(na, ne, nb);
@@ -512,9 +620,10 @@
byte[] oldStorage = b.storage;
if (verbose >= 2) {
- System.out.printf("setslice(%d,%d,%d,e[len=%d])\n",
- na, na + nd, 1, ne);
- if (verbose >= 3) System.out.println(toString(b));
+ System.out.printf("setslice(%d,%d,%d,e[len=%d])\n", na, na + nd, 1, ne);
+ if (verbose >= 3) {
+ System.out.println(toString(b));
+ }
}
b.setslice(na, na + nd, 1, e);
@@ -522,11 +631,15 @@
if (verbose >= 2) {
boolean avAlloc = (b.storage != oldStorage)
&& (bRef.length <= oldStorage.length);
- if (b.storage.length * 2 < oldStorage.length) avAlloc = false;
+ if (b.storage.length * 2 < oldStorage.length) {
+ avAlloc = false;
+ }
System.out.println(toString(b) + (avAlloc ? " avoidable new" : ""));
}
checkInts(bRef, b);
}
+ }
+ }
}
// Insertions at a range of positions and all sizes with random data
@@ -543,9 +656,9 @@
int[] nbList2 = {0, 1, BMAX};
- for (int na = 0; na <= AMAX; na++)
+ for (int na = 0; na <= AMAX; na++) {
for (int nb : nbList2) {
- for (int nd = 0; nd < DMAX; nd++)
+ for (int nd = 0; nd < DMAX; nd++) {
for (int ne = 0; ne < EMAX; ne++) {
PyByteArray u = x.getslice(0, na + nd + nb, 1);
PyByteArray e = y.getslice(0, ne, 1);
@@ -558,10 +671,14 @@
}
}
u.setslice(na, na + nd, 1, e);
- if (verbose >= 1) System.out.println("u'= " + toString(u));
+ if (verbose >= 1) {
+ System.out.println("u'= " + toString(u));
+ }
checkSlice(na, nd, nb, ne, xInts, yInts, u);
}
+ }
}
+ }
}
/**
@@ -579,7 +696,7 @@
interp = new PythonInterpreter();
// Source of assigned values.
- int[] eRef = randomInts(random, 2*SMALL, 'V', 'Z');
+ int[] eRef = randomInts(random, 2 * SMALL, 'V', 'Z');
BaseBytes eFull = new BaseBytesTest.MyBytes(eRef);
final int[] posStart = new int[] {0, 4, 10, 18, L - 9};
@@ -588,23 +705,28 @@
for (int start : posStart) {
PyObject pyStart, pyStop, pyStart_L, pyStop_L;
pyStart = new PyInteger(start);
- if (start > 0)
+ if (start > 0) {
// The other way of saying [start:stop] is [start-L:stop]
pyStart_L = new PyInteger(start - L);
- else
+ } else {
// The other way of saying [0:stop] is [:stop]
pyStart_L = Py.None;
+ }
for (int stop : posStop) {
- if (stop < start) continue; // Skip backwards cases
+ if (stop < start)
+ {
+ continue; // Skip backwards cases
+ }
// PyObject versions of stop
- if (stop < L)
+ if (stop < L) {
// The other way of saying [start:stop] is [start:stop-L]
pyStop_L = new PyInteger(stop - L);
- else
+ } else {
// The other way of saying [start:L] is [start:]
pyStop_L = Py.None;
+ }
pyStop = new PyInteger(stop);
for (int n = 0; n <= eRef.length; n++) {
@@ -628,7 +750,7 @@
/**
* Common code to check {@link PyByteArray#__setslice__(PyObject, PyObject, PyObject)} against a
* reference answer.
- *
+ *
* @param uRef to initialise the object to test
* @param pyStart
* @param pyStop
@@ -643,7 +765,9 @@
BaseBytes eFull,
int n,
int[] eRef,
- int start, int stop, int verbose) {
+ int start,
+ int stop,
+ int verbose) {
PyByteArray u = getInstance(uRef);
BaseBytes e = eFull.getslice(0, n, 1);
if (verbose >= 4) {
@@ -653,12 +777,14 @@
}
// Now do the test
u.__setslice__(pyStart, pyStop, e);
- if (verbose >= 3) System.out.println("u'= " + toString(u));
- int nd = stop-start;
- int nb = uRef.length-stop;
+ if (verbose >= 3) {
+ System.out.println("u'= " + toString(u));
+ }
+ int nd = stop - start;
+ int nb = uRef.length - stop;
checkSlice(start, nd, nb, n, uRef, eRef, u);
}
-
+
/**
* Test method for {@link org.python.core.PyByteArray#setslice(int,int,int,PyObject)}, when the
* slice to replace is extended (3-argument slice and step!=0). Note that PySequence checks and
@@ -701,7 +827,9 @@
}
}
u.setslice(start, stop, step, e);
- if (verbose >= 1) System.out.println("u'= " + toString(u));
+ if (verbose >= 1) {
+ System.out.println("u'= " + toString(u));
+ }
checkSlice(start, step, n, uRef, eRef, u);
}
}
@@ -734,7 +862,9 @@
}
}
u.setslice(start, stop, step, e);
- if (verbose >= 1) System.out.println("u'= " + toString(u));
+ if (verbose >= 1) {
+ System.out.println("u'= " + toString(u));
+ }
checkSlice(start, step, n, uRef, eRef, u);
}
}
@@ -742,8 +872,7 @@
}
}
-
-
+
/**
* Test method for {@link org.python.core.PyByteArray#setslice(int,int,int,PyObject)}, when the
* slice to replace is extended (3-argument slice and step!=0). Note that PySequence checks and
@@ -784,15 +913,17 @@
PyByteArray u = getInstance(uRef);
BaseBytes e = eFull.getslice(0, n, 1);
if (verbose >= 2) {
- System.out.printf("setslice(%d,%d,%d, e[len=%d])\n",
- start, stop, step, n);
+ System.out.printf("setslice(%d,%d,%d, e[len=%d])\n", start, stop, step,
+ n);
if (verbose >= 3) {
System.out.println("u = " + toString(u));
System.out.println("e = " + toString(e));
}
}
u.__setslice__(pyStart, pyStop, pyStep, e);
- if (verbose >= 1) System.out.println("u'= " + toString(u));
+ if (verbose >= 1) {
+ System.out.println("u'= " + toString(u));
+ }
checkSlice(start, step, n, uRef, eRef, u);
}
}
@@ -820,21 +951,22 @@
PyByteArray u = getInstance(uRef);
BaseBytes e = eFull.getslice(0, n, 1);
if (verbose >= 2) {
- System.out.printf("setslice(%d,%d,%d, e[len=%d])\n",
- start, stop, step, n);
+ System.out.printf("setslice(%d,%d,%d, e[len=%d])\n", start, stop, step,
+ n);
if (verbose >= 3) {
System.out.println("u = " + toString(u));
System.out.println("e = " + toString(e));
}
}
u.__setslice__(pyStart, pyStop, pyStep, e);
- if (verbose >= 1) System.out.println("u'= " + toString(u));
+ if (verbose >= 1) {
+ System.out.println("u'= " + toString(u));
+ }
checkSlice(start, step, n, uRef, eRef, u);
}
}
}
}
-
}
/**
@@ -842,40 +974,48 @@
* slice to replace is simple and contiguous (2-argument slice).
*/
public void testSetsliceTime() {
- int verbose = 0;
- timeSetslice(100, SMALL, 2*SMALL, verbose);
- timeSetslice(100, MEDIUM, MEDIUM, verbose);
- timeSetslice(10, LARGE, LARGE/5, verbose);
- timeSetslice(10, HUGE, HUGE/5, verbose);
+ int verbose = 1;
+ timeSetslice(100, 200, SMALL, 2*SMALL, verbose);
+ timeSetslice(100, 200, MEDIUM, MEDIUM, verbose);
+ timeSetslice(1000, 20, LARGE, LARGE/5, verbose);
+// timeSetslice(1000, 4, HUGE, HUGE/5, verbose);
}
/**
* Tabulate the elapsed time for calls to setslice, for a given array size and maximum slice
- * length to insert arrays of a range of sizes.
- *
- * @param repeats number of repeats over which to average
+ * length to insert arrays of a range of sizes. The aim is to demonstrate benefit from the
+ * centring of the occupied storage in the storage array as a whole and catch any drop-off in
+ * implementation that while functionally correct (gets the right value) is massively
+ * inefficient.
+ *
+ * @param trials number of trials over which to take minimum "uninterrupted" time
+ * @param repeats number of repeat calls in each trial, over which to average
* @param N of bytearray subjected to the change
* @param M Size of change (inserted, removed or replaced slice)
- * @param verbose Control level of textual output 0=none CSV-style, 1=just the timings, etc..
+ * @param verbose Control level of textual output 1=just the timings, 2=enumerate calls, etc..
*/
- protected void timeSetslice(int repeats, int M, int N, int verbose) {
+ private void timeSetslice(int trials, int repeats, int N, int M, int verbose) {
// Trials we intend to do: insertion at a variety of points.
int[] startList = new int[11]; // 11 means 0%, 10%, 20%, ... 100% of N
- for (int i = 0; i < startList.length; i++)
+ for (int i = 0; i < startList.length; i++) {
startList[i] = N * i / (startList.length - 1);
+ }
// Insertion slice sizes.
int[] changeList = new int[11]; // 0%, ... 100% of M
- for (int i = 0; i < changeList.length; i++)
+ for (int i = 0; i < changeList.length; i++) {
changeList[i] = M * i / (changeList.length - 1);
+ }
// We are going to tabulate this for each startList and changeList entry.
long[][] elapsed = new long[startList.length][changeList.length];
// Initialise the timing record
- for (int row = 0; row < startList.length; row++)
- for (int col = 0; col < changeList.length; col++)
+ for (int row = 0; row < startList.length; row++) {
+ for (int col = 0; col < changeList.length; col++) {
elapsed[row][col] = Long.MAX_VALUE;
+ }
+ }
// Create test material as bytearrays
int[] xRef = randomInts(random, N, 'u', 'z');
@@ -886,21 +1026,20 @@
// We will time repeated calls: need a fresh bytearray each time
PyByteArray[] u = new PyByteArray[repeats];
- // Now take the shortest of 10 trials in each row and column
-
- // Work through the combinations necessary
- for (int trial = 0; trial < 10; trial++) {
- for (int row = 0; row < startList.length; row++) {
- int na = startList[row];
- int nd = 0;
- // nd = changeList[3]; // XXX experiment
- // if (na+nd>N) nd = N-na; // XXX experiment
- for (int col = 0; col < changeList.length; col++) {
- int ne = changeList[col];
- int start = na;
- int stop = na + nd;
- // Data to replace the slice with
- PyByteArray e = y.getslice(0, ne, 1);
+ // Now take the shortest of some number of trials in each row and column
+ for (int trial = 0; trial < trials; trial++) {
+ // Work through the combinations necessary
+ for (int irow = 0; irow < startList.length; irow++) {
+ int row = (irow + 5 * trial) % startList.length; // Shuffle order
+ int na = startList[row];
+ int nd = 0;
+ for (int icol = 0; icol < changeList.length; icol++) {
+ int col = (icol + trial) % changeList.length; // Shuffle order
+ int ne = changeList[col];
+ int start = na;
+ int stop = na + nd;
+ // Data to replace the slice with
+ PyByteArray e = y.getslice(0, ne, 1);
if (trial == 0) {
// First trial: do once untimed in order ensure classes loaded.
@@ -912,34 +1051,39 @@
long t = doTimeSetslice(u, start, stop, e, x, -1);
// Retain the shortest time so far
- if (t < elapsed[row][col]) elapsed[row][col] = t;
+ if (t < elapsed[row][col]) {
+ elapsed[row][col] = t;
+ }
}
}
}
// Tabulate the time for each array size and change size
- System.out.print(" N , na ");
- for (int col = 0; col < changeList.length; col++)
- System.out.printf(", ne=%7d", changeList[col]);
- System.out.println(", elements inserted: time in microseconds.");
+ if (verbose >= 1) {
+ System.out.print(" N , na ");
+ for (int col = 0; col < changeList.length; col++) {
+ System.out.printf(", ne=%7d", changeList[col]);
+ }
+ System.out.println(", elements inserted: time in microseconds.");
- for (int row = 0; row < startList.length; row++) {
- System.out.printf("%8d, %8d", N, startList[row]);
- for (int col = 0; col < changeList.length; col++) {
- double usPerCall = (1e-3 * elapsed[row][col]) / repeats;
- System.out.printf(", %10.3f", usPerCall);
+ for (int row = 0; row < startList.length; row++) {
+ System.out.printf("%8d, %8d", N, startList[row]);
+ for (int col = 0; col < changeList.length; col++) {
+ double usPerCall = (1e-3 * elapsed[row][col]) / repeats;
+ System.out.printf(", %10.3f", usPerCall);
+ // System.out.printf(", %10d", elapsed[row][col]);
+ }
+ System.out.println();
}
- System.out.println();
}
-
}
/**
* Time trial of {@link PyByteArray#setslice(int,int,int)}. Every element of the array of test
* objects will be initialised to the same value then the specified slice replacement will take
* place, with the block of repetitions timed.
- *
+ *
* @param u array of test objects
* @param start
* @param stop
@@ -949,26 +1093,25 @@
* @return elapsed time in nanoseconds for setslice operation on array of objects
*/
private long doTimeSetslice(PyByteArray[] u,
- int start,
- int stop,
- BaseBytes e,
- BaseBytes x,
- int verbose) {
+ int start,
+ int stop,
+ BaseBytes e,
+ BaseBytes x,
+ int verbose) {
- // The call is either to do a time trial (block of test objects) or one test
+ // The call is either to do a time trial (block of test objects) or one test of correctness
int repeats = 1;
- if (verbose < 0)
+ if (verbose < 0) {
// We're doing a timed trial on an array of identical objects.
repeats = u.length;
- else
- // We're testing the correctness of the code with one object.
- repeats = 1;
+ }
// Set up clean bytearray objects
- for (int i = 0; i < repeats; i++)
+ for (int i = 0; i < repeats; i++) {
u[i] = new PyByteArray(x);
+ }
- // First trial: do once untimed in order ensure classes loaded.
+ // Display effects (if verbose) using first element only.
PyByteArray v = u[0];
byte[] oldStorage = v.storage;
@@ -981,23 +1124,29 @@
// Start the clock
long beginTime = System.nanoTime();
// Do the work lots of times
- for (int i = 0; i < repeats; i++)
+ for (int i = 0; i < repeats; i++) {
u[i].setslice(start, stop, 1, e);
+ }
// Stop the clock
long t = System.nanoTime() - beginTime;
// Diagnostic printout
if (verbose >= 2) {
- byte[] newStorage = v.storage;
- boolean avAlloc = (newStorage != oldStorage);
- if (newStorage.length * 2 < oldStorage.length) avAlloc = false;
+ // Was there a reallocation?
+ boolean avAlloc = (v.storage != oldStorage);
+ // Justified if ...
+ if (v.size * 2 <= oldStorage.length) {
+ avAlloc = false;
+ }
+ if (v.size > oldStorage.length) {
+ avAlloc = false;
+ }
System.out.println("u'= " + toString(v) + (avAlloc ? " new" : ""));
}
return t;
}
-
-
+
// /**
// * Test method for {@link org.python.core.PyByteArray#del(int)}.
// */
@@ -1012,9 +1161,453 @@
// fail("Not yet implemented");
// }
//
-
-
-
+
+ /**
+ * Test method for {@link org.python.core.PyByteArray#delslice(int,int,int)}, when the
+ * slice to delete is simple (a contiguous 2-argument slice).
+ */
+ public void testDelslice2() {
+ int verbose = 0;
+
+ // Tests where we transform aaaaaDDDDbbbbb into aaaaabbbbb.
+ // Lists of the lengths to try, for each of the aaaa, DDDD, bbbb sections
+ int[] naList = {2, 5, 0}; // Interesting cases: slice is at start, or not at start
+ int[] ndList = {5, 20, 0}; // Slice to delete is small, large or zero
+ int[] nbList = {4, 7, 0}; // Interesting cases: slice is at end, or not at end
+
+ for (int nd : ndList) {
+ for (int na : naList) {
+ for (int nb : nbList) {
+ int[] aRef = adbInts(na, nd, nb);
+ int[] bRef = aebInts(na, 0, nb);
+
+ PyByteArray b = getInstance(aRef);
+
+ byte[] oldStorage = b.storage;
+
+ if (verbose >= 2) {
+ System.out.printf("delslice(%d,%d,%d)\n",
+ na, na + nd, 1);
+ if (verbose >= 3) {
+ System.out.println(toString(b));
+ }
+ }
+
+ b.delslice(na, na + nd, 1);
+
+ if (verbose >= 2) {
+ // Was there a reallocation?
+ boolean avAlloc = (b.storage != oldStorage);
+ // Justified if ...
+ if (bRef.length * 2 <= oldStorage.length) {
+ avAlloc = false;
+ }
+ System.out.println(toString(b) + (avAlloc ? " avoidable new" : ""));
+ }
+ checkInts(bRef, b);
+ }
+ }
+ }
+
+ // Deletions at a range of positions and all sizes with random data
+
+ final int AMAX = SMALL;
+ final int BMAX = SMALL;
+ final int DMAX = MEDIUM;
+
+ int[] xInts = randomInts(random, AMAX + DMAX + BMAX, 'u', 'z');
+ PyByteArray x = getInstance(xInts);
+ // Use the checker for assignments, pretending to have assigned a zero length array.
+ // int[] yInts = new int[0];
+
+ int[] nbList2 = {0, 1, BMAX};
+
+ for (int na = 0; na <= AMAX; na++) {
+ for (int nb : nbList2) {
+ for (int nd = 0; nd < DMAX; nd++){
+ PyByteArray u = x.getslice(0, na + nd + nb, 1);
+ if (verbose >= 2) {
+ System.out.printf("delslice(start=%d, stop=%d, step=%d)\n",
+ na, na + nd, 1);
+ if (verbose >= 3) {
+ System.out.println("u = " + toString(u));
+ }
+ }
+ u.delslice(na, na + nd, 1);
+ if (verbose >= 1) {
+ System.out.println("u'= " + toString(u));
+ }
+ checkSlice(na, nd, nb, 0, xInts, null, u);
+ }
+ }
+ }
+ }
+
+ /**
+ * Test method for {@link PyByteArray#__delslice__(PyObject, PyObject, PyObject)}, when the
+ * slice to delete is simple (a contiguous 2-argument slice).
+ */
+ public void test__delslice__2() {
+ int verbose = 0;
+ // __delslice__() deals with start, stop values also relative to the end.
+
+ String ver = "Et tes pâleurs, alors que lasse,";
+ final int L = ver.length();
+ int[] uRef = toInts(ver);
+
+ // Need interpreter (for Py.None and exceptions)
+ interp = new PythonInterpreter();
+
+ final int[] posStart = new int[] {0, 3, 7, 16, L - 1};
+ final int[] posStop = new int[] {0, 3, 7, 16, L - 6, L};
+// final int[] posStart = new int[] {16};
+// final int[] posStop = new int[] {L};
+
+ for (int start : posStart) {
+ PyObject pyStart, pyStop, pyStart_L, pyStop_L;
+ pyStart = new PyInteger(start);
+ if (start > 0) {
+ // The other way of saying [start:stop] is [start-L:stop]
+ pyStart_L = new PyInteger(start - L);
+ } else {
+ // The other way of saying [0:stop] is [:stop]
+ pyStart_L = Py.None;
+ }
+
+ for (int stop : posStop) {
+ if (stop < start)
+ {
+ continue; // Skip backwards cases
+ }
+
+ // PyObject versions of stop
+ if (stop < L) {
+ // The other way of saying [start:stop] is [start:stop-L]
+ pyStop_L = new PyInteger(stop - L);
+ } else {
+ // The other way of saying [start:L] is [start:]
+ pyStop_L = Py.None;
+ }
+ pyStop = new PyInteger(stop);
+
+ // Generate test result and check it
+ doTest__delslice__2(uRef, pyStart, pyStop, start, stop, verbose + 2);
+ // Repeat same result specifying start relative to end
+ doTest__delslice__2(uRef, pyStart_L, pyStop, start, stop, verbose);
+ // Repeat same result specifying stop relative to end
+ doTest__delslice__2(uRef, pyStart, pyStop_L, start, stop, verbose);
+ // Repeat same result specifying start and stop relative to end
+ doTest__delslice__2(uRef, pyStart_L, pyStop_L, start, stop, verbose);
+ }
+ }
+ }
+
+ /**
+ * Common code to check {@link PyByteArray#__delslice__(PyObject, PyObject, PyObject)} against a
+ * reference answer.
+ *
+ * @param uRef to initialise the object to test
+ * @param pyStart
+ * @param pyStop
+ * @param verbose 0..4 control output
+ */
+ private void doTest__delslice__2(int[] uRef,
+ PyObject pyStart,
+ PyObject pyStop,
+ int start, int stop, int verbose) {
+ PyByteArray u = getInstance(uRef);
+ if (verbose >= 4) {
+ System.out.printf(" __delslice__(%s,%s,1)\n", pyStart, pyStop);
+ System.out.println("u = " + toString(u));
+ }
+ // Now do the test
+ u.__delslice__(pyStart, pyStop);
+ if (verbose >= 3) {
+ System.out.println("u'= " + toString(u));
+ }
+ int nd = stop-start;
+ int nb = uRef.length-stop;
+ checkSlice(start, nd, nb, 0, uRef, null, u);
+ }
+
+
+ /**
+ * Test method for {@link org.python.core.PyByteArray#delslice(int,int,int)}, when the
+ * slice to delete is extended (3-argument slice and step!=0). Note that PySequence checks and
+ * converts arguments first, so we need only test with valid combinations of indices.
+ */
+ public void test__delslice__3() {
+ int verbose = 0;
+
+ // Need interpreter
+ interp = new PythonInterpreter();
+
+ // Source of assigned values.
+// int[] eRef = randomInts(random, MEDIUM, 'A', 'H');
+// BaseBytes eFull = new BaseBytesTest.MyBytes(eRef);
+
+ // Forwards cases
+
+ int[] uRef = randomInts(random, MEDIUM, 'm', 's');
+
+ // Positive step sizes we will try
+ int[] posStep = {2, 3, 5, 8, 25, 100};
+
+ for (int start = 0; start < uRef.length; start++) {
+ PyInteger pyStart = new PyInteger(start);
+ // Bytes from start to end of array
+ int len = uRef.length - start;
+ for (int step : posStep) {
+ PyInteger pyStep = new PyInteger(step);
+ // Allowable number of deletions to end of array at given step size
+ int nmax = (len + step - 1) / step;
+ for (int n = 1; n <= nmax; n++) {
+ // Location of last i
+ int last = start + step * (n - 1) + 1;
+ // But any stop value in this range results in n deletions
+ for (int stop = last + 1; stop < last + step; stop++) {
+ PyInteger pyStop = new PyInteger(stop);
+ // Now do the test
+ PyByteArray u = getInstance(uRef);
+ if (verbose >= 2) {
+ System.out.printf("delslice(%d,%d,%d) (%d deletions)\n",
+ start, stop, step, n);
+ if (verbose >= 3) {
+ System.out.println("u = " + toString(u));
+ }
+ }
+ u.__delslice__(pyStart, pyStop, pyStep);
+ if (verbose >= 1) {
+ System.out.println("u'= " + toString(u));
+ }
+ checkDelSlice(start, step, n, uRef, u);
+ }
+ }
+ }
+ }
+
+ // Negative step sizes we will try
+ int[] negStep = {-1, -2, -5, -8, -25, -100};
+
+ for (int start = uRef.length - 1; start >= 0; start--) {
+ PyInteger pyStart = new PyInteger(start);
+ // Bytes from slice start to start of array
+ int len = start + 1;
+ for (int step : negStep) {
+ PyInteger pyStep = new PyInteger(step);
+ // Allowable number of assignments to end of array at given step size
+ int nmax = (len + (-step) - 1) / (-step);
+ for (int n = 1; n <= nmax; n++) {
+ // Location of last i
+ int last = start + step * (n - 1) - 1;
+ // But any stop value in this range results in n deletions
+ for (int stop = last; stop > last - (-step) && stop >= 0; stop--) {
+ PyInteger pyStop = new PyInteger(stop);
+ // Now do the test
+ PyByteArray u = getInstance(uRef);
+ if (verbose >= 2) {
+ System.out.printf("delslice(%d,%d,%d) (%d deletions)\n",
+ start, stop, step, n);
+ if (verbose >= 3) {
+ System.out.println("u = " + toString(u));
+ }
+ }
+ u.__delslice__(pyStart, pyStop, pyStep);
+ if (verbose >= 1) {
+ System.out.println("u'= " + toString(u));
+ }
+ checkDelSlice(start, step, n, uRef, u);
+ }
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Performance for {@link org.python.core.PyByteArray#delslice(int,int,int,PyObject)}, when the
+ * slice to replace is extended (3-argument slice).
+ */
+ public void testDelsliceTime3() {
+ int verbose = 1;
+ timeDelslice3(100, 200, SMALL, verbose);
+ timeDelslice3(100, 200, MEDIUM, verbose);
+ timeDelslice3(10, 4, LARGE, verbose);
+ // timeDelslice3(10, 1, HUGE, verbose);
+ }
+
+ /**
+ * Tabulate the elapsed time for calls to __delslice__, for a given array size and maximum
+ * step-size between deleted items length to delete. The aim is to demonstrate benefit from the
+ * centring of the occupied storage in the storage array as a whole and catch any drop-off in
+ * implementation that while functionally correct (gets the right value) is massively
+ * inefficient.
+ *
+ * @param trials number of trials over which to take minimum "uninterrupted" time
+ * @param repeats number of repeat calls in each trial, over which to average
+ * @param N of bytearray subjected to the change
+ * @param verbose Control level of textual output 1=just the timings, 2=eumerate calls, etc..
+ */
+ private void timeDelslice3(int trials, int repeats, int N, int verbose) {
+
+ // Trials we intend to do: deletion from a variety of points.
+ int[] startList = new int[10]; // 10 means 0%, 10%, 20%, ... 90% of N
+ for (int i = 0; i < startList.length; i++) {
+ startList[i] = N * i / startList.length;
+ }
+
+ // Deletion step sizes. Positive and negative of these will be used
+ int[] posStep = {1, 2, 3, 5, 10};
+ int[] stepList = new int[2 * posStep.length];
+ for (int i = 0; i < posStep.length; i++) {
+ stepList[posStep.length - i - 1] = posStep[i];
+ stepList[posStep.length + i] = -posStep[i];
+ }
+
+ // We are going to tabulate this for each startList and changeList entry.
+ long[][] elapsed = new long[startList.length][stepList.length];
+ // Initialise the timing record
+ for (int row = 0; row < startList.length; row++) {
+ for (int col = 0; col < stepList.length; col++) {
+ elapsed[row][col] = Long.MAX_VALUE;
+ }
+ }
+
+ // Create test material as bytearrays
+ int[] xRef = randomInts(random, N, 'u', 'z');
+ PyByteArray x = getInstance(xRef);
+
+ // We will time repeated calls: need a fresh bytearray each time
+ PyByteArray[] u = new PyByteArray[repeats];
+
+ // Now take the shortest of some number of trials in each row and column
+ for (int trial = 0; trial < trials; trial++) {
+
+ // Work through the combinations necessary
+ for (int irow = 0; irow < startList.length; irow++) {
+ int row = (irow + 5 * trial) % startList.length; // Shuffle order
+ int start = startList[row];
+ for (int icol = 0; icol < stepList.length; icol++) {
+ int col = (icol + trial) % stepList.length; // Shuffle order
+ int step = stepList[col];
+ int n;
+
+ if (step > 0) {
+ // Deletions available from start location to end of array
+ n = (xRef.length - start + step-1) / step;
+ } else {
+ // Deletions available from start location to beginning of array
+ n = (start + (-step) ) / (-step);
+ }
+
+ // Make objects of the arguments
+ PyInteger pyStart = new PyInteger(start);
+ PyObject pyStop = Py.None;
+ PyInteger pyStep = new PyInteger(step);
+
+ if (trial == 0) {
+ // First trial: do once untimed in order ensure classes loaded.
+ doTimeDelslice3(u, pyStart, pyStop, pyStep, x, verbose);
+ checkDelSlice(start, step, n, xRef, u[0]);
+ }
+
+ // Now do the trial properly
+ long t = doTimeDelslice3(u, pyStart, pyStop, pyStep, x, -1);
+
+ // Retain the shortest time so far
+ if (t < elapsed[row][col]) {
+ elapsed[row][col] = t;
+ }
+ }
+ }
+ }
+
+ // Tabulate the time for each array size and change size
+
+ System.out.print(" N , start");
+ for (int col = 0; col < stepList.length; col++) {
+ System.out.printf(", step=%5d", stepList[col]);
+ }
+ System.out.println(", deletion time in microseconds.");
+
+ for (int row = 0; row < startList.length; row++) {
+ System.out.printf("%8d, %8d", N, startList[row]);
+ for (int col = 0; col < stepList.length; col++) {
+ double usPerCall = (1e-3 * elapsed[row][col]) / repeats;
+ System.out.printf(", %10.3f", usPerCall);
+ // System.out.printf(", %10d", elapsed[row][col]);
+ }
+ System.out.println();
+ }
+ }
+
+ /**
+ * Time trial of {@link PyByteArray#__delslice__(PyObject,PyObject,PyObject)}. Every element of
+ * the array of test objects will be initialised to the same value then the specified slice
+ * replacement will take place, with the block of repetitions timed.
+ *
+ * @param u array of test objects
+ * @param pyStart
+ * @param pyStop
+ * @param pyStep
+ * @param x value from which to initialise each test object
+ * @param verbose amount of output
+ * @return elapsed time in nanoseconds for delslice operation on array of objects
+ */
+ private long doTimeDelslice3(PyByteArray[] u,
+ PyObject pyStart,
+ PyObject pyStop,
+ PyObject pyStep,
+ BaseBytes x,
+ int verbose) {
+
+ // The call is either to do a time trial (block of test objects) or one test of correctness
+ int repeats = 1;
+ if (verbose < 0) {
+ // We're doing a timed trial on an array of identical objects.
+ repeats = u.length;
+ }
+
+ // Set up clean bytearray objects
+ for (int i = 0; i < repeats; i++) {
+ u[i] = new PyByteArray(x);
+ }
+
+ // Display effects (if verbose) using first element only.
+ PyByteArray v = u[0];
+ byte[] oldStorage = v.storage;
+
+ if (verbose >= 3) {
+ System.out.printf("__delslice__(%s,%s,%s)\n", pyStart, pyStop, pyStep);
+ System.out.println("u = " + toString(v));
+ }
+
+ // Start the clock
+ long beginTime = System.nanoTime();
+ // Do the work lots of times
+ for (int i = 0; i < repeats; i++) {
+ u[i].__delslice__(pyStart, pyStop, pyStep);
+ }
+ // Stop the clock
+ long t = System.nanoTime() - beginTime;
+
+ // Diagnostic printout
+ if (verbose >= 2) {
+ // Was there a reallocation?
+ boolean avAlloc = (v.storage != oldStorage);
+ // Justified if ...
+ if (v.size * 2 <= oldStorage.length) {
+ avAlloc = false;
+ }
+ if (v.size > oldStorage.length) {
+ avAlloc = false;
+ }
+ System.out.println("u'= " + toString(v) + (avAlloc ? " new" : ""));
+ }
+
+ return t;
+ }
+
/*
* Note that JUnit test classes extending this one inherit all the test* methods, and they will
* be run by JUnit. Each test uses getInstance() methods where it might have used a constructor
@@ -1056,6 +1649,6 @@
public PyByteArray getInstance(PyObject arg) throws PyException {
return new PyByteArray(arg);
}
-
-
+
+
}
--
Repository URL: http://hg.python.org/jython
More information about the Jython-checkins
mailing list