[Jython-checkins] jython: Faster extended slice deletion in bytearray.
jeff.allen
jython-checkins at python.org
Thu Apr 9 09:28:36 CEST 2015
https://hg.python.org/jython/rev/d2824374b29a
changeset: 7649:d2824374b29a
parent: 7596:cf9ad15fca87
user: Jeff Allen <ja.py at farowl.co.uk>
date: Sun Feb 15 20:49:30 2015 +0000
summary:
Faster extended slice deletion in bytearray.
Replace iterative deletion of single elements (causing repeat copy),
with a single-copy strategy approriate to the array implementation.
This is a perfromance loose-end in the original implementation.
Incidental code cleanup, particularly in JUnit test.
files:
src/org/python/core/BaseBytes.java | 19 +-
src/org/python/core/PyByteArray.java | 113 +---
src/org/python/core/PySequence.java | 80 +-
src/org/python/core/SequenceIndexDelegate.java | 9 +-
tests/java/org/python/core/BaseBytesTest.java | 92 +-
tests/java/org/python/core/PyByteArrayTest.java | 233 ++++-----
6 files changed, 243 insertions(+), 303 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
@@ -736,20 +736,10 @@
*/
private class IndexDelegate extends PySequence.DefaultIndexDelegate {
- /*
+ /**
* bytearray treats assignment of a zero-length object to a slice as equivalent to deletion,
* unlike list, even for an extended slice.
*/
- // >>> a = range(10)
- // >>> b = bytearray(a)
- // >>> a[1:6:2] = []
- // Traceback (most recent call last):
- // File "<stdin>", line 1, in <module>
- // ValueError: attempt to assign sequence of size 0 to extended slice of size 3
- // >>> b[1:6:2] = []
- // >>> b
- // bytearray(b'\x00\x02\x04\x06\x07\x08\t')
- //
@Override
public void checkIdxAndSetSlice(PySlice slice, PyObject value) {
if (value.__len__() != 0) {
@@ -757,9 +747,14 @@
super.checkIdxAndSetSlice(slice, value);
} else {
// Treat as deletion
- super.checkIdxAndDelItem(slice);
+ checkIdxAndDelItem(slice);
}
}
+
+ @Override
+ protected void delSlice(int[] indices) {
+ delslice(indices[0], indices[1], indices[2], indices[3]);
+ }
};
/*
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
@@ -676,53 +676,59 @@
}
}
- /*
- * Deletes an element from the sequence (and closes up the gap).
- *
- * @param index index of the element to delete.
- */
@Override
protected synchronized void del(int index) {
- // XXX Change SequenceIndexDelegate to avoid repeated calls to del(int) for extended slice
storageDelete(index, 1);
}
- /*
- * 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.
- */
@Override
protected synchronized void delRange(int start, int stop) {
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
- */
- protected synchronized void delslice(int start, int stop, int step) {
+ @Override
+ protected synchronized void delslice(int start, int stop, int step, int n) {
+ // This will not be possible if this object has buffer exports
+ resizeCheck();
+
if (step == 1) {
- // Delete this[start:stop] and closing up the space
- storageDelete(start, stop - start);
+ // Delete this[start:stop] and close up the space.
+ storageDelete(start, n);
+
+ } else if (step == -1) {
+ // Also a contiguous case, but start > stop.
+ storageDelete(stop + 1, n);
+
} else {
- // This is an extended slice which means we are removing isolated elements
- int n = sliceLength(start, stop, step);
+ // This is an extended slice. We will be deleting n isolated elements.
+ int p, m;
- if (n > 0) {
- if (step > 0) {
- // The first element is x[start] and the last is x[start+(n-1)*step+1]
- storageDeleteEx(start, step, n);
- } else {
- // The first element is x[start+(n-1)*step+1] and the last is x[start]
- storageDeleteEx(start + (n - 1) * step + 1, -step, n);
+ // We delete by copying from high to low memory, whatever the sign of step.
+ if (step > 1) {
+ // The lowest numbered element to delete is x[start]
+ p = start;
+ m = step - 1;
+ } else {
+ // The lowest numbered element to delete is x[start+(n-1)*step]]
+ p = start + (n - 1) * step;
+ m = -1 - step;
+ }
+
+ // Offset p to be a storage index.
+ p += offset;
+
+ // Copy n-1 blocks blocks of m bytes, each time skipping the byte to be deleted.
+ for (int i = 1; i < n; i++) {
+ // Skip q over the one we are deleting
+ int q = p + i;
+ // Now copy the m elements that follow.
+ for (int j = 0; j < m; j++) {
+ storage[p++] = storage[q++];
}
}
+
+ // Close up the gap. Note that for the copy, p was adjusted by the storage offset.
+ storageDelete(p - offset, n);
}
}
@@ -2654,47 +2660,4 @@
}
}
- /**
- * Delete <code>d</code> elements on a stride of <code>c</code> beginning 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 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' -|
- * |- 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 <code>PyByteArray</code> 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 <code>bytearray</code> 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()
- }
}
diff --git a/src/org/python/core/PySequence.java b/src/org/python/core/PySequence.java
--- a/src/org/python/core/PySequence.java
+++ b/src/org/python/core/PySequence.java
@@ -2,8 +2,8 @@
package org.python.core;
/**
- * The abstract superclass of PyObjects that implements a Sequence. Minimize the work in
- * creating such objects.
+ * The abstract superclass of PyObjects that implements a Sequence. Minimize the work in creating
+ * such objects.
*
* Method names are designed to make it possible for subclasses of PySequence to implement
* java.util.List.
@@ -24,7 +24,7 @@
/**
* Construct a PySequence for the given sub-type with the default index behaviour.
- *
+ *
* @param type actual (Python) type of sub-class
*/
protected PySequence(PyType type) {
@@ -36,7 +36,7 @@
* Construct a PySequence for the given sub-type with custom index behaviour. In practice,
* restrictions on the construction of inner classes will mean null has to be passed and the
* actual delegator assigned later.
- *
+ *
* @param type actual (Python) type of sub-class
* @param behaviour specific index behaviour (or null)
*/
@@ -51,7 +51,7 @@
* PySequence in its implementation of {@link #__getitem__} It is guaranteed by PySequence that
* when it calls <code>pyget(int)</code> the index is within the bounds of the array. Any other
* clients must make the same guarantee.
- *
+ *
* @param index index of element to return.
* @return the element at the given position in the list.
*/
@@ -68,8 +68,8 @@
protected abstract PyObject getslice(int start, int stop, int step);
/**
- * Returns a (concrete subclass of) PySequence that repeats the given sequence, as
- * in the implementation of <code>__mul__</code> for strings.
+ * Returns a (concrete subclass of) PySequence that repeats the given sequence, as in the
+ * implementation of <code>__mul__</code> for strings.
*
* @param count the number of times to repeat the sequence.
* @return this sequence repeated count times.
@@ -82,7 +82,7 @@
* called by PySequence in its implementation of {@link #__setitem__} It is guaranteed by
* PySequence that when it calls pyset(int) the index is within the bounds of the array. Any
* other clients must make the same guarantee.
- *
+ *
* @param index index of the element to set.
* @param value the value to set this element to.
*/
@@ -91,45 +91,60 @@
}
/**
- * 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, then inserting the value at that position, regarding the
- * value as a sequence (if possible) or as a single element if it is not a sequence.
- * If the step size is not one, but <code>start==stop</code>, it is equivalent to insertion
- * at that point.
- * If the step size is not one, and <code>start!=stop</code>, the slice defines a certain number
- * of elements to be replaced, and the value must be a sequence of exactly that many
- * elements (or convertible to such a sequence).
- *
+ * 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,
+ * then inserting the value at that position, regarding the value as a sequence (if possible) or
+ * as a single element if it is not a sequence. If the step size is not one, but
+ * <code>start==stop</code>, it is equivalent to insertion at that point. If the step size is
+ * not one, and <code>start!=stop</code>, the slice defines a certain number of elements to be
+ * replaced, and the value must be a sequence of exactly that many elements (or convertible to
+ * such a sequence).
+ *
* @param start the position of the first element.
* @param stop one more than the position of the last element.
* @param step the step size.
* @param value an object consistent with the slice assignment
*/
protected void setslice(int start, int stop, int step, PyObject value) {
- throw Py.TypeError(String.format("'%s' object does not support item assignment",
- getType().fastGetName()));
+ throw Py.TypeError(String.format("'%s' object does not support item assignment", getType()
+ .fastGetName()));
}
/**
* Deletes an element from the sequence (and closes up the gap).
- *
+ *
* @param index index of the element to delete.
*/
protected void del(int index) {
- throw Py.TypeError(String.format("'%s' object does not support item deletion",
- getType().fastGetName()));
+ delslice(index, index, 1, 1); // Raises TypeError (for immutable types).
}
/**
* Deletes a 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 void delRange(int start, int stop) {
- throw Py.TypeError(String.format("'%s' object does not support item deletion",
- getType().fastGetName()));
+ delslice(start, stop, 1, Math.abs(stop - start)); // Raises TypeError (for immutable types).
+ }
+
+ /**
+ * Deletes a simple or extended slice and closes up the gap(s). The slice parameters
+ * <code>[start:stop:step]</code> mean what they would in Python, <i>after</i> application of
+ * the "end-relative" rules for negative numbers and <code>None</code>. The count <code>n</code>
+ * is as supplied by {@link PySlice#indicesEx(int)}. This method is unsafe in that slice
+ * parameters are assumed correct.
+ *
+ * @param start the position of the first element.
+ * @param stop beyond the position of the last element (not necessarily just beyond).
+ * @param step from one element to the next (positive or negative)
+ * @param n number of elements to delete
+ */
+ protected void delslice(int start, int stop, int step, int n) {
+ // Raises TypeError (for immutable types).
+ throw Py.TypeError(String.format("'%s' object does not support item deletion", getType()
+ .fastGetName()));
}
@Override
@@ -265,10 +280,9 @@
/**
* Compare the specified object/length pairs.
*
- * @return value >= 0 is the index where the sequences differs.
- * -1: reached the end of o1 without a difference
- * -2: reached the end of both seqeunces without a difference
- * -3: reached the end of o2 without a difference
+ * @return value >= 0 is the index where the sequences differs. -1: reached the end of o1
+ * without a difference -2: reached the end of both seqeunces without a difference -3:
+ * reached the end of o2 without a difference
*/
protected static int cmp(PyObject o1, int ol1, PyObject o2, int ol2) {
if (ol1 < 0) {
@@ -320,9 +334,8 @@
}
/**
- * Adjusts <code>index</code> such that it's >= 0 and <= __len__. If
- * <code>index</code> starts off negative, it's treated as an index from the end of
- * the sequence going back to the start.
+ * Adjusts <code>index</code> such that it's >= 0 and <= __len__. If <code>index</code> starts
+ * off negative, it's treated as an index from the end of the sequence going back to the start.
*/
protected int boundToSequence(int index) {
int length = __len__();
@@ -514,7 +527,6 @@
delRange(start, stop);
}
-
@Override
public PyObject getItem(int idx) {
return pyget(idx);
diff --git a/src/org/python/core/SequenceIndexDelegate.java b/src/org/python/core/SequenceIndexDelegate.java
--- a/src/org/python/core/SequenceIndexDelegate.java
+++ b/src/org/python/core/SequenceIndexDelegate.java
@@ -109,7 +109,14 @@
}
}
- private void delSlice(int[] indices) {
+ /**
+ * Implement the deletion of a slice. This method is called by
+ * {@link #checkIdxAndDelItem(PyObject)} when the argument is a {@link PySlice}. The argument is
+ * the return from {@link PySlice#indicesEx(int)}.
+ *
+ * @param indices containing [start, stop, step, count] of the slice to delete
+ */
+ protected void delSlice(int[] indices) {
int p = indices[0], step = indices[2], count = indices[3];
if (step > 1) {
/*
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
@@ -33,7 +33,7 @@
// Constants for array sizes
public static final int SMALL = 7; // Less than minimum storage size
public static final int MEDIUM = 25; // Medium array size
- public static final int LARGE = 10000; // Large enough for performance measurement
+ public static final int LARGE = 2000; // Large enough for performance measurement
public static final int HUGE = 100000; // Serious performance challenge
/**
@@ -55,7 +55,7 @@
/**
* Turn a String into ints, but in the Python byte range, reducing character codes mod 256.
- *
+ *
* @param s the string
* @return
*/
@@ -71,7 +71,7 @@
/**
* Generate ints at random in the range 0..255.
- *
+ *
* @param random the random generator
* @param n length of array
* @return the array of random values
@@ -86,7 +86,7 @@
/**
* Generate ints at random in a restricted range.
- *
+ *
* @param random the random generator
* @param n length of array
* @param lo lowest value to generate
@@ -104,7 +104,7 @@
/**
* Compare expected and result array sections at specified locations and length.
- *
+ *
* @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
@@ -114,7 +114,9 @@
static void checkInts(int[] expected, int first, BaseBytes result, int start, int len) {
if (len > 0) {
int end = first + len;
- if (end > expected.length) end = expected.length;
+ 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));
}
@@ -123,7 +125,7 @@
/**
* Compare expected and result array in their entirety.
- *
+ *
* @param expected
* @param result
*/
@@ -138,7 +140,7 @@
/**
* Compare expected List<PyInteger> and result array in their entirety.
- *
+ *
* @param expected
* @param result
*/
@@ -157,7 +159,7 @@
/**
* Compare expected List<PyInteger> and result object in their entirety.
- *
+ *
* @param expected
* @param result
*/
@@ -168,7 +170,7 @@
/**
* Turn array into Iterable<PyObject>, treating as unsigned (Python-style) bytes, and producing
* an abusive mixture of object types.
- *
+ *
* @return iterable list
*/
public static Iterable<PyObject> iterableBytes(int[] source) {
@@ -198,7 +200,7 @@
/*
* (non-Javadoc)
- *
+ *
* @see junit.framework.TestCase#setUp()
*/
protected void setUp() throws Exception {
@@ -206,7 +208,6 @@
random = new Random(20120310L);
}
-
/**
* Test method for {@link org.python.core.BaseBytes#init(int)} via MyBytes constructor, and for
* {@link org.python.core.BaseBytes#size()}.
@@ -274,17 +275,13 @@
*/
public void testInit_PyObject() {
// A scary set of objects
- final PyObject[] brantub = {null,
- new PyInteger(5),
- new PyString("\u00A0\u00A1\u00A2\u00A3\u00A4"),
- getInstance(new int[] {180, 190, 200}),
- new PyXRange(1, 301, 50)};
+ final PyObject[] brantub =
+ {null, new PyInteger(5), new PyString("\u00A0\u00A1\u00A2\u00A3\u00A4"),
+ getInstance(new int[] {180, 190, 200}), new PyXRange(1, 301, 50)};
// The array contents we should obtain
- final int[][] prize = { {},
- {0, 0, 0, 0, 0},
- {160, 161, 162, 163, 164},
- {180, 190, 200},
- {1, 51, 101, 151, 201, 251}};
+ final int[][] prize =
+ { {}, {0, 0, 0, 0, 0}, {160, 161, 162, 163, 164}, {180, 190, 200},
+ {1, 51, 101, 151, 201, 251}};
// Work down the lists
for (int dip = 0; dip < brantub.length; dip++) {
int[] aRef = prize[dip];
@@ -359,7 +356,7 @@
/**
* Test method for {@link BaseBytes#getslice(int, int, int)}.
- *
+ *
* @see PySequence#__getslice__(PyObject, PyObject)
*/
public void testGetslice() {
@@ -480,7 +477,7 @@
a.setslice(start, stop, step, x);
System.out.println(toString(a));
fail(String.format("Exception not thrown for setslice(%d,%d,%d,%s)", start, stop, step,
- x));
+ x));
} catch (PyException pye) {
// System.out.println(pye);
PyObject b = pye.type;
@@ -549,7 +546,7 @@
/**
* Create a zero-length Python byte array of explicitly-specified sub-type
- *
+ *
* @param type explicit Jython type
*/
public MyBytes(PyType type) {
@@ -565,7 +562,7 @@
/**
* Create zero-filled Python byte array of specified size.
- *
+ *
* @param size of byte array
*/
public MyBytes(int size) {
@@ -574,7 +571,7 @@
/**
* Create from integer array
- *
+ *
* @param value
*/
MyBytes(int[] value) {
@@ -583,7 +580,7 @@
/**
* Create a new array filled exactly by a copy of the contents of the source byte array.
- *
+ *
* @param value of the bytes
*/
public MyBytes(BaseBytes value) {
@@ -593,7 +590,7 @@
/**
* Create a new array filled exactly by a copy of the contents of the source.
- *
+ *
* @param value source of the bytes (and size)
*/
public MyBytes(BufferProtocol value) {
@@ -604,7 +601,7 @@
/**
* 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 of the bytes
*/
public MyBytes(Iterable<? extends PyObject> value) {
@@ -615,7 +612,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 (must be a string type)
* @param errors name of optional errors policy (must be a string type)
@@ -628,7 +625,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)
@@ -658,7 +655,7 @@
* {@link #MyBytes(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 bytes(arg), TypeError for non-iterable,
* non-integer argument type, and ValueError if iterables do not yield byte
@@ -675,7 +672,7 @@
* just one term. It is safe because MyBytes is immutable. But it may not be wise if the
* source object is a large array from which only a small part needs to be retained in
* memory.
- *
+ *
* @param type explicit Jython type
* @param start index of first byte to use in source
* @param stop 1 + index of last byte to use in source
@@ -689,7 +686,7 @@
/**
* 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.
*/
@@ -702,7 +699,7 @@
/**
* Returns a range of elements from the sequence.
- *
+ *
* @see org.python.core.PySequence#getslice(int, int, int)
*/
@Override
@@ -727,7 +724,7 @@
/**
* Return number of elements
- *
+ *
* @see org.python.core.PyObject#__len__()
*/
@Override
@@ -776,7 +773,7 @@
/**
* Store integer array as bytes: range must be 0..255 inclusive.
- *
+ *
* @param value integers to store
*/
BufferedObject(int[] value) {
@@ -823,8 +820,9 @@
// 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)
+ 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) {
@@ -836,7 +834,7 @@
}
}
- // Show an extent of n bytes (as 2*n charactrs)
+ // Show an extent of n bytes (as 2*n characters)
public void padTo(int n) {
while (n > image.length()) {
image.append(' ');
@@ -845,7 +843,7 @@
/**
* Write summary numbers offset [ size ] remainder
- *
+ *
* @param b
*/
public String showSummary(BaseBytes b) {
@@ -857,7 +855,7 @@
/**
* Make text image of just the buffer boundaries.
- *
+ *
* @param b
*/
public String showExtent(BaseBytes b) {
@@ -871,7 +869,7 @@
/**
* Make text image of the buffer content and boundaries.
- *
+ *
* @param b
*/
public String showContent(BaseBytes b) {
@@ -895,7 +893,7 @@
* struct</a>. <code>buf</code> is an n-dimensional array of Object, implementing the storage of
* some Python type, and it is required to access one element of it at an index defined by n
* integers in sequence.
- *
+ *
* @param n The number of dimensions the memory represents as a multi-dimensional array.
* @param buf An n-dimensional array containing the value of the object
* @param strides An array of length n giving the number of elements to skip to get to a new
@@ -904,7 +902,8 @@
* @param indices An array of n indices indexing the element to retrieve.
* @return
*/
- private static Object getItem(int n, Object buf, int[] strides, int[] suboffsets, int[] indices) {
+ private static Object
+ getItem(int n, Object buf, int[] strides, int[] suboffsets, int[] indices) {
for (int i = 0; i < n; i++) {
Object[] p = (Object[])buf;
buf = p[indices[i] * strides[i] + suboffsets[i]];
@@ -916,7 +915,8 @@
* If it was an ndim-dimensional array of byte, we treat it as an (ndim-1)-dimensional array of
* byte[] arrays. This method exemplifies getting just one byte.
*/
- private static byte getByte(int ndim, Object buf, int[] strides, int[] suboffsets, int[] indices) {
+ private static byte
+ getByte(int ndim, Object buf, int[] strides, int[] suboffsets, int[] indices) {
int n = ndim - 1;
byte[] b = (byte[])getItem(n, buf, strides, suboffsets, indices);
return b[indices[n] + suboffsets[n]];
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
@@ -7,7 +7,6 @@
import org.python.util.PythonInterpreter;
-
/**
* JUnit tests for PyByteArray.
*/
@@ -15,6 +14,7 @@
/**
* Constructor required by JUnit.
+ *
* @param name
*/
public PyByteArrayTest(String name) {
@@ -137,7 +137,8 @@
* @param y source of the E data
* @param result the result to be tested against A+E+B
*/
- public static void checkSlice(int na, int nd, int nb, int ne, int[] x, int[] y, BaseBytes result) {
+ public static void
+ checkSlice(int na, int nd, int nb, int ne, int[] x, int[] y, BaseBytes result) {
// Check the size is right
assertEquals("size", na + ne + nb, result.size());
// Check that A is preserved
@@ -293,6 +294,7 @@
*
* @see org.python.core.BaseBytesTest#setUp()
*/
+ @Override
protected void setUp() throws Exception {
super.setUp();
}
@@ -305,7 +307,7 @@
public void test__getslice__2() {
int verbose = 0;
// __getslice__() deals with start, stop values also relative to the end.
- String ver = "D�rob�e au sang de nos c�urs";
+ String ver = "L'un a la pourpre de nos âmes";
final int L = ver.length();
int[] aRef = toInts(ver);
BaseBytes a = getInstance(aRef);
@@ -370,11 +372,8 @@
* @param bList reference answer
* @param verbose 0..4 control output
*/
- private void doTest__getslice__2(BaseBytes a,
- PyObject pyStart,
- PyObject pyStop,
- List<PyInteger> bList,
- int verbose) {
+ private void doTest__getslice__2(BaseBytes a, PyObject pyStart, PyObject pyStop,
+ List<PyInteger> bList, int verbose) {
if (verbose >= 4) {
System.out.printf(" __getslice__(%s,%s)\n", pyStart, pyStop);
}
@@ -519,12 +518,8 @@
* @param bList reference answer
* @param verbose 0..4 control output
*/
- private void doTest__getslice__3(BaseBytes a,
- PyObject pyStart,
- PyObject pyStop,
- PyObject pyStep,
- List<PyInteger> bList,
- int verbose) {
+ private void doTest__getslice__3(BaseBytes a, PyObject pyStart, PyObject pyStop,
+ PyObject pyStep, List<PyInteger> bList, int verbose) {
if (verbose >= 4) {
System.out.printf(" __getslice__(%s,%s,%s)\n", pyStart, pyStop, pyStep);
}
@@ -539,6 +534,7 @@
* Test method for {@link PyByteArray#__setitem__(int,PyObject)}, and through it of
* {@link PyByteArray#pyset(int,PyObject)}.
*/
+ @Override
public void testPyset() {
int verbose = 0;
@@ -629,8 +625,8 @@
b.setslice(na, na + nd, 1, e);
if (verbose >= 2) {
- boolean avAlloc = (b.storage != oldStorage)
- && (bRef.length <= oldStorage.length);
+ boolean avAlloc =
+ (b.storage != oldStorage) && (bRef.length <= oldStorage.length);
if (b.storage.length * 2 < oldStorage.length) {
avAlloc = false;
}
@@ -664,7 +660,7 @@
PyByteArray e = y.getslice(0, ne, 1);
if (verbose >= 2) {
System.out.printf("setslice(start=%d, stop=%d, step=%d, e[len=%d])\n",
- na, na + nd, 1, ne);
+ na, na + nd, 1, ne);
if (verbose >= 3) {
System.out.println("u = " + toString(u));
System.out.println("e = " + toString(e));
@@ -714,8 +710,7 @@
}
for (int stop : posStop) {
- if (stop < start)
- {
+ if (stop < start) {
continue; // Skip backwards cases
}
@@ -732,16 +727,16 @@
for (int n = 0; n <= eRef.length; n++) {
// Generate test result and check it
doTest__setslice__2(uRef, pyStart, pyStop, eFull, n, eRef, start, stop,
- verbose + 2);
+ verbose + 2);
// Repeat same result specifying start relative to end
doTest__setslice__2(uRef, pyStart_L, pyStop, eFull, n, eRef, start, stop,
- verbose);
+ verbose);
// Repeat same result specifying stop relative to end
doTest__setslice__2(uRef, pyStart, pyStop_L, eFull, n, eRef, start, stop,
- verbose);
+ verbose);
// Repeat same result specifying start and stop relative to end
doTest__setslice__2(uRef, pyStart_L, pyStop_L, eFull, n, eRef, start, stop,
- verbose);
+ verbose);
}
}
}
@@ -759,15 +754,8 @@
* @param eRef from which eFull was initialised
* @param verbose 0..4 control output
*/
- private void doTest__setslice__2(int[] uRef,
- PyObject pyStart,
- PyObject pyStop,
- BaseBytes eFull,
- int n,
- int[] eRef,
- int start,
- int stop,
- int verbose) {
+ private void doTest__setslice__2(int[] uRef, PyObject pyStart, PyObject pyStop,
+ BaseBytes eFull, int n, int[] eRef, int start, int stop, int verbose) {
PyByteArray u = getInstance(uRef);
BaseBytes e = eFull.getslice(0, n, 1);
if (verbose >= 4) {
@@ -790,6 +778,7 @@
* slice to replace 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.
*/
+ @Override
public void testSetslice3() {
int verbose = 0;
@@ -820,7 +809,7 @@
BaseBytes e = eFull.getslice(0, n, 1);
if (verbose >= 2) {
System.out.printf("setslice(start=%d, stop=%d, step=%d, e[len=%d])\n",
- start, stop, step, n);
+ start, stop, step, n);
if (verbose >= 3) {
System.out.println("u = " + toString(u));
System.out.println("e = " + toString(e));
@@ -855,7 +844,7 @@
BaseBytes e = eFull.getslice(0, n, 1);
if (verbose >= 2) {
System.out.printf("setslice(start=%d, stop=%d, step=%d, e[len=%d])\n",
- start, stop, step, n);
+ start, stop, step, n);
if (verbose >= 3) {
System.out.println("u = " + toString(u));
System.out.println("e = " + toString(e));
@@ -913,8 +902,8 @@
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));
@@ -951,8 +940,8 @@
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));
@@ -975,10 +964,10 @@
*/
public void testSetsliceTime() {
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);
+ timeSetslice(50, 100, SMALL, 2 * SMALL, verbose);
+ timeSetslice(50, 100, MEDIUM, MEDIUM, verbose);
+ timeSetslice(500, 20, LARGE, LARGE / 5, verbose);
+ // timeSetslice(1000, 4, HUGE, HUGE/5, verbose);
}
/**
@@ -1092,12 +1081,8 @@
* @param verbose amount of output
* @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) {
+ private long doTimeSetslice(PyByteArray[] u, 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 of correctness
int repeats = 1;
@@ -1147,24 +1132,9 @@
return t;
}
-// /**
-// * Test method for {@link org.python.core.PyByteArray#del(int)}.
-// */
-// public void testDel() {
-// fail("Not yet implemented");
-// }
-//
-// /**
-// * Test method for {@link org.python.core.PyByteArray#delRange(int, int)}.
-// */
-// public void testDelRange() {
-// 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).
+ * 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;
@@ -1175,39 +1145,38 @@
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);
+ 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);
+ PyByteArray b = getInstance(aRef);
- byte[] oldStorage = b.storage;
+ 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));
- }
+ if (verbose >= 2) {
+ System.out.printf("delslice(%d,%d,%d,%d)\n", na, na + nd, 1, nd);
+ if (verbose >= 3) {
+ System.out.println(toString(b));
}
+ }
- b.delslice(na, na + nd, 1);
+ b.delslice(na, na + nd, 1, nd);
- 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" : ""));
+ if (verbose >= 2) {
+ // Was there a reallocation?
+ boolean avAlloc = (b.storage != oldStorage);
+ // Justified if ...
+ if (bRef.length * 2 <= oldStorage.length) {
+ avAlloc = false;
}
- checkInts(bRef, b);
+ System.out.println(toString(b) + (avAlloc ? " avoidable new" : ""));
}
+ checkInts(bRef, b);
}
}
+ }
// Deletions at a range of positions and all sizes with random data
@@ -1224,21 +1193,21 @@
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));
- }
+ 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=%d)\n", na, na
+ + nd, 1, nd);
+ 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);
}
+ u.delslice(na, na + nd, 1, nd);
+ if (verbose >= 1) {
+ System.out.println("u'= " + toString(u));
+ }
+ checkSlice(na, nd, nb, 0, xInts, null, u);
+ }
}
}
}
@@ -1260,8 +1229,6 @@
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;
@@ -1275,8 +1242,7 @@
}
for (int stop : posStop) {
- if (stop < start)
- {
+ if (stop < start) {
continue; // Skip backwards cases
}
@@ -1311,10 +1277,8 @@
* @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) {
+ 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);
@@ -1325,16 +1289,15 @@
if (verbose >= 3) {
System.out.println("u'= " + toString(u));
}
- int nd = stop-start;
- int nb = uRef.length-stop;
+ 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.
+ * 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;
@@ -1342,10 +1305,6 @@
// 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');
@@ -1370,8 +1329,8 @@
// 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);
+ System.out.printf("__delslice__(%d,%d,%d) (%d deletions)\n", start,
+ stop, step, n);
if (verbose >= 3) {
System.out.println("u = " + toString(u));
}
@@ -1406,8 +1365,8 @@
// 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);
+ System.out.printf("__delslice__(%d,%d,%d) (%d deletions)\n", start,
+ stop, step, n);
if (verbose >= 3) {
System.out.println("u = " + toString(u));
}
@@ -1430,9 +1389,9 @@
*/
public void testDelsliceTime3() {
int verbose = 1;
- timeDelslice3(100, 200, SMALL, verbose);
- timeDelslice3(100, 200, MEDIUM, verbose);
- timeDelslice3(10, 4, LARGE, verbose);
+ timeDelslice3(50, 100, SMALL, verbose);
+ timeDelslice3(50, 100, MEDIUM, verbose);
+ timeDelslice3(20, 4, LARGE, verbose);
// timeDelslice3(10, 1, HUGE, verbose);
}
@@ -1494,10 +1453,10 @@
if (step > 0) {
// Deletions available from start location to end of array
- n = (xRef.length - start + step-1) / step;
+ n = (xRef.length - start + step - 1) / step;
} else {
// Deletions available from start location to beginning of array
- n = (start + (-step) ) / (-step);
+ n = (start + (-step)) / (-step);
}
// Make objects of the arguments
@@ -1554,12 +1513,8 @@
* @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) {
+ 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;
@@ -1614,41 +1569,49 @@
* with a similar signature. The idea is to override the getInstance() methods to return an
* instance of the class actually under test in the derived test.
*/
+ @Override
public PyByteArray getInstance(PyType type) {
return new PyByteArray(type);
}
+ @Override
public PyByteArray getInstance() {
return new PyByteArray();
}
+ @Override
public PyByteArray getInstance(int size) {
return new PyByteArray(size);
}
+ @Override
public PyByteArray getInstance(int[] value) {
return new PyByteArray(value);
}
+ @Override
public PyByteArray getInstance(BaseBytes source) {
return new PyByteArray(source);
}
+ @Override
public PyByteArray getInstance(Iterable<? extends PyObject> source) {
return new PyByteArray(source);
}
+ @Override
public PyByteArray getInstance(PyString arg, PyObject encoding, PyObject errors) {
return new PyByteArray(arg, encoding, errors);
}
+ @Override
public PyByteArray getInstance(PyString arg, String encoding, String errors) {
return new PyByteArray(arg, encoding, errors);
}
+ @Override
public PyByteArray getInstance(PyObject arg) throws PyException {
return new PyByteArray(arg);
}
-
}
--
Repository URL: https://hg.python.org/jython
More information about the Jython-checkins
mailing list