[Jython-checkins] jython: Add PyBuffer.byteIndex methods.
jeff.allen
jython-checkins at python.org
Sat Aug 27 09:12:25 EDT 2016
https://hg.python.org/jython/rev/1cb1ab1e53f3
changeset: 7946:1cb1ab1e53f3
user: Jeff Allen <ja.py at farowl.co.uk>
date: Thu Jun 30 10:02:08 2016 +0100
summary:
Add PyBuffer.byteIndex methods.
Allow buffers to provide their indexing polynomial. This makes
unnecessary methods returning a Pointer or ByteBuffer ready-positioned
at a particular index. Minor impacts throughout the buffer
implementations.
files:
src/org/python/core/PyBuffer.java | 55 +++++----
src/org/python/core/buffer/BaseArrayBuffer.java | 2 +-
src/org/python/core/buffer/BaseBuffer.java | 53 +-------
src/org/python/core/buffer/BaseNIOBuffer.java | 15 +-
src/org/python/core/buffer/SimpleBuffer.java | 2 +-
src/org/python/core/buffer/SimpleNIOBuffer.java | 2 +-
src/org/python/core/buffer/SimpleStringBuffer.java | 5 +-
src/org/python/core/buffer/Strided1DBuffer.java | 2 +-
src/org/python/core/buffer/Strided1DNIOBuffer.java | 2 +-
src/org/python/core/buffer/ZeroByteBuffer.java | 4 +-
tests/java/org/python/core/PyBufferTest.java | 53 ---------
11 files changed, 56 insertions(+), 139 deletions(-)
diff --git a/src/org/python/core/PyBuffer.java b/src/org/python/core/PyBuffer.java
--- a/src/org/python/core/PyBuffer.java
+++ b/src/org/python/core/PyBuffer.java
@@ -238,10 +238,39 @@
*/
public PyBuffer getBufferSlice(int flags, int start, int count, int stride);
- // java.nio access to actual storage
+ // Access to underlying byte-oriented storage
//
/**
+ * Convert an item index (for a one-dimensional buffer) to an absolute byte index in the storage
+ * shared by the exporter. The storage exported as a <code>PyBuffer</code> is a linearly-indexed
+ * sequence of bytes, although it may not actually be a heap-allocated Java <code>byte[]</code>
+ * object. The purpose of this method is to allow the exporter to define the relationship
+ * between the item index (as used in {@link #byteAt(int)}) and the byte-index (as used with the
+ * <code>ByteBuffer</code> returned by {@link #getNIOByteBuffer()}). See
+ * {@link #byteIndex(int[])} for discussion of the multi-dimensional case.
+ *
+ * @param index item-index from consumer
+ * @return corresponding byte-index in actual storage
+ */
+ // Should it throw IndexOutOfBoundsException if the index <0 or ≥<code>shape[0]</code?
+ int byteIndex(int index) throws IndexOutOfBoundsException;
+
+ /**
+ * Convert a multi-dimensional item index to an absolute byte index in the storage shared by the
+ * exporter. The storage exported as a <code>PyBuffer</code> is a linearly-indexed sequence of
+ * bytes, although it may not actually be a heap-allocated Java <code>byte[]</code> object. The
+ * purpose of this method is to allow the exporter to define the relationship between the item
+ * index (as used in {@link #byteAt(int...)} and the byte-index (as used with the
+ * <code>ByteBuffer</code> returned by {@link #getNIOByteBuffer()}).
+ *
+ * @param indices n-dimensional item-index from consumer
+ * @return corresponding byte-index in actual storage
+ */
+ // Should it throw IndexOutOfBoundsException if any index <0 or ≥<code>shape[i]</code>?
+ int byteIndex(int... indices);
+
+ /**
* Obtain a {@link java.nio.ByteBuffer} giving access to the bytes that hold the data being
* exported by the original object. The position of the buffer is at the first byte of the item
* with zero index (quite possibly not the lowest valid byte-index), the limit of the buffer is
@@ -271,30 +300,6 @@
ByteBuffer getNIOByteBuffer();
/**
- * Obtain a {@link java.nio.ByteBuffer} giving access to the bytes that hold the data being
- * exported to the consumer, and positioned at a particular index.
- * <p>
- * Essentially this saves the client from computing the byte offset of a particular index. The
- * client is free to navigate the underlying byte data through the <code>ByteBuffer</code>.
- *
- * @param index in the buffer to position the pointer
- * @return a ByteBuffer onto the exported data contents, positioned at the indexed item.
- */
- ByteBuffer getNIOByteBuffer(int index);
-
- /**
- * Obtain a {@link java.nio.ByteBuffer} giving access to the bytes that hold the data being
- * exported to the consumer, and positioned at a particular multi-dimensional index.
- * <p>
- * Essentially this saves the client from computing the byte offset of a particular index. The
- * client is free to navigate the underlying byte data through the <code>ByteBuffer</code>.
- *
- * @param indices multidimensional index at which to position the pointer
- * @return a ByteBuffer onto the exported data contents, positioned at the indexed item.
- */
- ByteBuffer getNIOByteBuffer(int... indices);
-
- /**
* Report whether the exporter is able to offer direct access to the exported storage as a Java
* byte array (through the API that involves class {@link Pointer}), or only supports the
* abstract API. See also {@link PyBUF#AS_ARRAY}.
diff --git a/src/org/python/core/buffer/BaseArrayBuffer.java b/src/org/python/core/buffer/BaseArrayBuffer.java
--- a/src/org/python/core/buffer/BaseArrayBuffer.java
+++ b/src/org/python/core/buffer/BaseArrayBuffer.java
@@ -57,7 +57,7 @@
}
@Override
- protected int byteIndex(int... indices) throws IndexOutOfBoundsException {
+ public int byteIndex(int... indices) throws IndexOutOfBoundsException {
// BaseBuffer implementation can be simplified since if indices.length!=1 we error.
checkDimension(indices.length); // throws if != 1
return byteIndex(indices[0]);
diff --git a/src/org/python/core/buffer/BaseBuffer.java b/src/org/python/core/buffer/BaseBuffer.java
--- a/src/org/python/core/buffer/BaseBuffer.java
+++ b/src/org/python/core/buffer/BaseBuffer.java
@@ -351,16 +351,13 @@
storeAtImpl(value, byteIndex(indices));
}
- /**
- * Convert an item index (for a one-dimensional buffer) to a checked absolute byte index in the
- * actual storage being shared by the exporter. See {@link #byteIndex(int[])} for discussion.
- *
- * @param index item-index from consumer
- * @return corresponding byte-index in actual storage
- * @throws IndexOutOfBoundsException if the index <0 or ≥<code>shape[0]</code>
+ /*
+ * In this implementation, we throw IndexOutOfBoundsException if index < 0 or > shape[0], but we
+ * could rely on the array or ByteBuffer checks when indexing, especially the latter since
+ * position is checked against limit.
*/
- // XXX Consider making this part of the PyBuffer interface
- protected int byteIndex(int index) throws IndexOutOfBoundsException {
+ @Override
+ public int byteIndex(int index) throws IndexOutOfBoundsException {
// Treat as one-dimensional
if (index < 0 || index >= shape[0]) {
throw new IndexOutOfBoundsException();
@@ -368,25 +365,11 @@
return index0 + index * strides[0];
}
- /**
- * Convert a multi-dimensional item index (if we are not using indirection) to an absolute byte
- * index in the actual storage array being shared by the exporter. The purpose of this method is
- * to allow a sub-class to define, in one place, an indexing calculation that maps the index as
- * provided by the consumer into an index in the storage known to the buffer.
- * <p>
- * In the usual case where the storage is referenced via a <code>storage</code> member and
- * {@link #index0} member, the buffer implementation may use <code>storage[byteIndex(i)]</code>
- * to reference the (first byte of) the item x[i]. This is what the default implementation of
- * accessors in <code>BaseArrayBuffer</code> will do. In the simplest cases, calling
- * <code>byteIndex</code> may be an overhead to avoid, and an implementation will specialise the
- * accessors. The default implementation here is suited to N-dimensional arrays.
- *
- * @param indices n-dimensional item-index from consumer
- * @return corresponding byte-index in actual storage
- * @throws IndexOutOfBoundsException if any index <0 or ≥<code>shape[i]</code>
+ /*
+ * In this implementation, we throw IndexOutOfBoundsException if any index[i] < 0 or > shape[i].
*/
- // XXX Consider making this part of the PyBuffer interface
- protected int byteIndex(int... indices) throws IndexOutOfBoundsException {
+ @Override
+ public int byteIndex(int... indices) throws IndexOutOfBoundsException {
final int N = checkDimension(indices);
// In general: index0 + sum(k=0,N-1) indices[k]*strides[k]
int index = index0;
@@ -653,22 +636,6 @@
}
@Override
- public ByteBuffer getNIOByteBuffer(int index) {
- // The buffer spans the whole storage but is positioned at index
- ByteBuffer b = getNIOByteBufferImpl();
- b.position(byteIndex(index));
- return b;
- }
-
- @Override
- public ByteBuffer getNIOByteBuffer(int... indices) {
- // The buffer spans the whole storage but is positioned at indices[]
- ByteBuffer b = getNIOByteBufferImpl();
- b.position(byteIndex(indices));
- return b;
- }
-
- @Override
public boolean hasArray() {
// AS_ARRAY is a non-navigation flag, so is inverted in gFeatureFlags
return (gFeatureFlags & AS_ARRAY) == 0; // i.e. featureFlags & AS_ARRAY is true
diff --git a/src/org/python/core/buffer/BaseNIOBuffer.java b/src/org/python/core/buffer/BaseNIOBuffer.java
--- a/src/org/python/core/buffer/BaseNIOBuffer.java
+++ b/src/org/python/core/buffer/BaseNIOBuffer.java
@@ -78,7 +78,7 @@
}
@Override
- protected int byteIndex(int... indices) throws IndexOutOfBoundsException {
+ public int byteIndex(int... indices) throws IndexOutOfBoundsException {
// BaseBuffer implementation can be simplified since if indices.length!=1 we error.
checkDimension(indices.length); // throws if != 1
return byteIndex(indices[0]);
@@ -123,7 +123,8 @@
if (count > 0) {
- ByteBuffer src = getNIOByteBuffer(srcIndex);
+ ByteBuffer src = getNIOByteBuffer();
+ int pos = byteIndex(srcIndex);
// Pick up attributes necessary to choose an efficient copy strategy
int itemsize = getItemsize();
@@ -132,12 +133,11 @@
// Strategy depends on whether items are laid end-to-end contiguously or there are gaps
if (stride == itemsize) {
// stride == itemsize: straight copy of contiguous bytes
- src.limit(src.position() + count * itemsize);
+ src.limit(pos + count * itemsize).position(pos);
dest.put(src);
} else if (itemsize == 1) {
// Non-contiguous copy: single byte items
- int pos = src.position();
for (int i = 0; i < count; i++) {
src.position(pos);
dest.put(src.get());
@@ -146,7 +146,6 @@
} else {
// Non-contiguous copy: each time, copy itemsize bytes then skip
- int pos = src.position();
for (int i = 0; i < count; i++) {
src.limit(pos + itemsize).position(pos);
dest.put(src);
@@ -184,7 +183,8 @@
if (count > 0) {
- ByteBuffer dst = getNIOByteBuffer(dstIndex);
+ ByteBuffer dst = getNIOByteBuffer();
+ int pos = byteIndex(dstIndex);
// Pick up attributes necessary to choose an efficient copy strategy
int itemsize = getItemsize();
@@ -194,11 +194,11 @@
// Strategy depends on whether items are laid end-to-end or there are gaps
if (skip == 0) {
// Straight copy of contiguous bytes
+ dst.position(pos);
dst.put(src);
} else if (itemsize == 1) {
// Non-contiguous copy: single byte items
- int pos = dst.position();
for (int i = 0; i < count; i++) {
dst.position(pos);
dst.put(src.get());
@@ -208,7 +208,6 @@
} else {
// Non-contiguous copy: each time, copy itemsize bytes at a time
- int pos = dst.position();
for (int i = 0; i < count; i++) {
dst.position(pos);
// Delineate the next itemsize bytes in the src
diff --git a/src/org/python/core/buffer/SimpleBuffer.java b/src/org/python/core/buffer/SimpleBuffer.java
--- a/src/org/python/core/buffer/SimpleBuffer.java
+++ b/src/org/python/core/buffer/SimpleBuffer.java
@@ -104,7 +104,7 @@
* and an item size of 1.
*/
@Override
- protected int byteIndex(int index) throws IndexOutOfBoundsException {
+ public int byteIndex(int index) throws IndexOutOfBoundsException {
if (index < 0 || index >= shape[0]) {
throw new IndexOutOfBoundsException();
}
diff --git a/src/org/python/core/buffer/SimpleNIOBuffer.java b/src/org/python/core/buffer/SimpleNIOBuffer.java
--- a/src/org/python/core/buffer/SimpleNIOBuffer.java
+++ b/src/org/python/core/buffer/SimpleNIOBuffer.java
@@ -112,7 +112,7 @@
}
@Override
- protected int byteIndex(int index) throws IndexOutOfBoundsException {
+ public final int byteIndex(int index) throws IndexOutOfBoundsException {
return index0 + index;
}
diff --git a/src/org/python/core/buffer/SimpleStringBuffer.java b/src/org/python/core/buffer/SimpleStringBuffer.java
--- a/src/org/python/core/buffer/SimpleStringBuffer.java
+++ b/src/org/python/core/buffer/SimpleStringBuffer.java
@@ -68,7 +68,7 @@
* In <code>SimpleStringBuffer</code> we can simply return the argument.
*/
@Override
- protected final int byteIndex(int index) {
+ public final int byteIndex(int index) {
// We do not check the index because String will do it for us.
return index;
}
@@ -97,8 +97,7 @@
public PyBuffer getBufferSlice(int flags, int start, int count) {
if (count > 0) {
// The new string content is just a sub-string.
- return new SimpleStringView(getRoot(), flags,
- bufString.substring(start, start + count));
+ return new SimpleStringView(getRoot(), flags, bufString.substring(start, start + count));
} else {
// Special case for count==0 where start out of bounds sometimes raises exception.
return new ZeroByteBuffer.View(getRoot(), flags);
diff --git a/src/org/python/core/buffer/Strided1DBuffer.java b/src/org/python/core/buffer/Strided1DBuffer.java
--- a/src/org/python/core/buffer/Strided1DBuffer.java
+++ b/src/org/python/core/buffer/Strided1DBuffer.java
@@ -129,7 +129,7 @@
}
@Override
- protected final int byteIndex(int index) throws IndexOutOfBoundsException {
+ public final int byteIndex(int index) throws IndexOutOfBoundsException {
if (index < 0 || index >= shape[0]) {
throw new IndexOutOfBoundsException();
}
diff --git a/src/org/python/core/buffer/Strided1DNIOBuffer.java b/src/org/python/core/buffer/Strided1DNIOBuffer.java
--- a/src/org/python/core/buffer/Strided1DNIOBuffer.java
+++ b/src/org/python/core/buffer/Strided1DNIOBuffer.java
@@ -138,7 +138,7 @@
}
@Override
- protected int byteIndex(int index) throws IndexOutOfBoundsException {
+ public final int byteIndex(int index) throws IndexOutOfBoundsException {
return index0 + index * stride;
}
diff --git a/src/org/python/core/buffer/ZeroByteBuffer.java b/src/org/python/core/buffer/ZeroByteBuffer.java
--- a/src/org/python/core/buffer/ZeroByteBuffer.java
+++ b/src/org/python/core/buffer/ZeroByteBuffer.java
@@ -47,7 +47,7 @@
* In a ZeroByteBuffer, the index is always out of bounds.
*/
@Override
- protected int byteIndex(int index) throws IndexOutOfBoundsException {
+ public int byteIndex(int index) throws IndexOutOfBoundsException {
// This causes all access to the bytes in to throw (since BaseBuffer calls it).
throw new IndexOutOfBoundsException();
}
@@ -56,7 +56,7 @@
* In a ZeroByteBuffer, if the dimensions are right, the index is out of bounds anyway.
*/
@Override
- protected int byteIndex(int... indices) throws IndexOutOfBoundsException {
+ public int byteIndex(int... indices) throws IndexOutOfBoundsException {
// Bootless dimension check takes precedence (for consistency with other buffers)
checkDimension(indices);
// This causes all access to the bytes to throw (since BaseBuffer calls it).
diff --git a/tests/java/org/python/core/PyBufferTest.java b/tests/java/org/python/core/PyBufferTest.java
--- a/tests/java/org/python/core/PyBufferTest.java
+++ b/tests/java/org/python/core/PyBufferTest.java
@@ -1061,59 +1061,6 @@
}
- /** Test method for {@link org.python.core.PyBuffer#getNIOByteBuffer(int)}. */
- @Test
- public void testGetNIOByteBufferInt() {
- announce("getNIOByteBuffer (int)");
-
- int n = ref.length, itemsize = view.getItemsize();
- byte[] exp = new byte[itemsize], bytes = ref.bytes;
-
- for (int i = 0; i < n; i++) {
- // Expected result is one item (allow for itemsize)
- int p = i * itemsize;
- for (int j = 0; j < itemsize; j++) {
- exp[j] = bytes[p + j];
- }
- // Get buffer and check for correct data at bb.position()
- ByteBuffer bb = view.getNIOByteBuffer(i);
- ByteBufferTestSupport.assertBytesEqual("getNIOByteBuffer(int) value", exp, bb);
- }
- }
-
- /** Test method for {@link org.python.core.PyBuffer#getNIOByteBuffer(int[])}. */
- @Test
- public void testGetNIOByteBufferIntArray() {
- int[] index = new int[1];
- announce("getNIOByteBuffer (n-dim)");
-
- int n = ref.length, itemsize = view.getItemsize();
- byte[] exp = new byte[itemsize], bytes = ref.bytes;
-
- for (int i = 0; i < n; i++) {
- // Expected result is one item (allow for itemsize)
- int p = i * itemsize;
- for (int j = 0; j < itemsize; j++) {
- exp[j] = bytes[p + j];
- }
-
- // Get buffer and check for correct data at bb.position()
- index[0] = i;
- ByteBuffer bb = view.getNIOByteBuffer(index);
- ByteBufferTestSupport.assertBytesEqual("getNIOByteBuffer(int[]) value", exp, bb);
- }
-
- // Check 2D index throws
- try {
- view.getNIOByteBuffer(0, 0);
- fail("Use of 2D index did not raise exception");
- } catch (PyException pye) {
- // Expect BufferError
- // XXX ... but should it be TypeError here?
- assertEquals(Py.BufferError, pye.type);
- }
- }
-
/** Test method for {@link org.python.core.PyBuffer#hasArray()}. */
@Test
public void testHasArray() {
--
Repository URL: https://hg.python.org/jython
More information about the Jython-checkins
mailing list