[Jython-checkins] jython: Refactor to introduce Base1DBuffer.
jeff.allen
jython-checkins at python.org
Sat Aug 27 09:12:24 EDT 2016
https://hg.python.org/jython/rev/a3abfca10951
changeset: 7943:a3abfca10951
user: Jeff Allen <ja.py at farowl.co.uk>
date: Thu Jun 23 12:52:53 2016 +0100
summary:
Refactor to introduce Base1DBuffer.
Reduces duplication between Array and NIO. BaseBuffer is now distinctly
the home of generic implementations and Base1DBuffer is the home of all
one-dimensional specialisation. Constructors low in the stack now take
navigation arrays as arguments, favouring clarity of purpose over minor
(illusory?) speed gains.
files:
src/org/python/core/buffer/Base1DBuffer.java | 117 ++++++++++
src/org/python/core/buffer/BaseArrayBuffer.java | 89 +------
src/org/python/core/buffer/BaseBuffer.java | 75 +++---
src/org/python/core/buffer/BaseNIOBuffer.java | 89 +------
src/org/python/core/buffer/SimpleBuffer.java | 38 +--
src/org/python/core/buffer/SimpleNIOBuffer.java | 19 +-
src/org/python/core/buffer/SimpleStringBuffer.java | 3 +-
src/org/python/core/buffer/Strided1DBuffer.java | 16 +-
src/org/python/core/buffer/Strided1DNIOBuffer.java | 64 ++---
src/org/python/core/buffer/Strided1DWritableBuffer.java | 10 +-
src/org/python/core/buffer/ZeroByteBuffer.java | 8 +-
tests/java/org/python/core/PyBufferNIOTest.java | 8 +-
tests/java/org/python/core/PyBufferTest.java | 6 +-
13 files changed, 249 insertions(+), 293 deletions(-)
diff --git a/src/org/python/core/buffer/Base1DBuffer.java b/src/org/python/core/buffer/Base1DBuffer.java
new file mode 100644
--- /dev/null
+++ b/src/org/python/core/buffer/Base1DBuffer.java
@@ -0,0 +1,117 @@
+package org.python.core.buffer;
+
+import org.python.core.PyBUF;
+
+/**
+ * Base implementation of the Buffer API appropriate to 1-dimensional arrays, of any item size,
+ * independent of the storage implementation. The description of {@link BaseBuffer} mostly applies.
+ */
+public abstract class Base1DBuffer extends BaseBuffer {
+
+ /** The strides array for a contiguous 1D byte buffer. */
+ protected static final int[] ONE = {1};
+
+ /** The shape array for a zero length 1D buffer. */
+ protected static final int[] ZERO = {0};
+
+ /**
+ * Construct an instance of <code>Base1DBuffer</code> in support of a sub-class, specifying the
+ * 'feature flags', or at least a starting set to be adjusted later. Also specify the navigation
+ * ( {@link #index0}, number of elements, and {@link #strides} array. These 'feature flags' are
+ * the features of the buffer exported, not the flags that form the consumer's request. The
+ * buffer will be read-only unless {@link PyBUF#WRITABLE} is set. {@link PyBUF#FORMAT} is
+ * implicitly added to the feature flags.
+ * <p>
+ * To complete initialisation, the sub-class normally must create its own wrapped byte-storage,
+ * and call {@link #checkRequestFlags(int)} passing the consumer's request flags.
+ *
+ * @param featureFlags bit pattern that specifies the features allowed
+ * @param index0 index into storage of <code>item[0]</code>
+ * @param size number of elements in the view
+ * @param strides an array of length 1 providing index stride between successive elements
+ */
+ protected Base1DBuffer(int featureFlags, int index0, int size, int[] strides) {
+ super(featureFlags, index0, size == 0 ? ZERO : new int[] {size}, strides);
+ }
+
+ /**
+ * Construct an instance of <code>Base1DBuffer</code> in support of a sub-class, specifying the
+ * 'feature flags', or at least a starting set to be adjusted later. Also specify the navigation
+ * ( {@link #index0}, number of elements, and byte-index distance from one to the next. These
+ * 'feature flags' are the features of the buffer exported, not the flags that form the
+ * consumer's request. The buffer will be read-only unless {@link PyBUF#WRITABLE} is set.
+ * {@link PyBUF#FORMAT} is implicitly added to the feature flags.
+ * <p>
+ * To complete initialisation, the sub-class normally must create its own wrapped byte-storage,
+ * and call {@link #checkRequestFlags(int)} passing the consumer's request flags.
+ *
+ * @param featureFlags bit pattern that specifies the features allowed
+ * @param index0 index into storage of <code>item[0]</code>
+ * @param size number of elements in the view
+ * @param stride byte-index distance from one element to the next
+ */
+ protected Base1DBuffer(int featureFlags, int index0, int size, int stride) {
+ this(featureFlags, index0, size, stride == 1 ? ONE : new int[] {stride});
+ }
+
+ @Override
+ protected int getSize() {
+ return shape[0];
+ }
+
+ @Override
+ public int getLen() {
+ return shape[0] * getItemsize();
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Specialised to one-dimensional, possibly strided buffer.
+ */
+ @Override
+ protected int calcGreatestIndex() {
+ int stride = strides[0];
+ if (stride == 1) {
+ return index0 + shape[0] - 1;
+ } else if (stride > 0) {
+ return index0 + (shape[0] - 1) * stride;
+ } else {
+ return index0 - 1;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Specialised to one-dimensional, possibly strided buffer.
+ */
+ @Override
+ protected int calcLeastIndex() {
+ int stride = strides[0];
+ if (stride < 0) {
+ return index0 + (shape[0] - 1) * stride;
+ } else {
+ return index0;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Specialised in <code>BaseArrayBuffer</code> to one dimension.
+ */
+ @Override
+ public boolean isContiguous(char order) {
+ if ("CFA".indexOf(order) < 0) {
+ return false;
+ } else {
+ if (getShape()[0] < 2) {
+ return true;
+ } else {
+ return getStrides()[0] == getItemsize();
+ }
+ }
+ }
+
+}
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
@@ -11,7 +11,7 @@
* The description of {@link BaseBuffer} mostly applies. Methods provided or overridden here are
* appropriate to 1-dimensional arrays, of any item size, backed by <code>byte[]</code>.
*/
-public abstract class BaseArrayBuffer extends BaseBuffer implements PyBuffer {
+public abstract class BaseArrayBuffer extends Base1DBuffer {
/**
* Reference to the underlying <code>byte[]</code> storage that the exporter is sharing with the
@@ -24,29 +24,24 @@
/**
* Construct an instance of <code>BaseArrayBuffer</code> in support of a sub-class, specifying
- * the 'feature flags', or at least a starting set to be adjusted later. These are the features
- * of the buffer exported, not the flags that form the consumer's request. The buffer will be
- * read-only unless {@link PyBUF#WRITABLE} is set in the feature flags. {@link PyBUF#FORMAT} and
- * {@link PyBUF#AS_ARRAY} are implicitly added to the feature flags. The navigation arrays are
- * all null, awaiting action by the sub-class constructor. To complete initialisation, the
- * sub-class normally must assign: the buffer ( {@link #storage}, {@link #index0}), and the
- * navigation arrays ({@link #shape}, {@link #strides}), and call
- * {@link #checkRequestFlags(int)} passing the consumer's request flags.
+ * the 'feature flags', or at least a starting set to be adjusted later. Also specify the
+ * navigation ( {@link #index0}, number of elements, and stride. These 'feature flags' are the
+ * features of the buffer exported, not the flags that form the consumer's request. The buffer
+ * will be read-only unless {@link PyBUF#WRITABLE} is set. {@link PyBUF#FORMAT} and
+ * {@link PyBUF#AS_ARRAY} are implicitly added to the feature flags.
+ * <p>
+ * To complete initialisation, the sub-class normally must call {@link #checkRequestFlags(int)}
+ * passing the consumer's request flags.
*
- * @param featureFlags bit pattern that specifies the actual features allowed/required
+ * @param storage the array of bytes storing the implementation of the exporting object
+ * @param featureFlags bit pattern that specifies the features allowed
+ * @param index0 index into storage of <code>item[0]</code>
+ * @param size number of elements in the view
+ * @param stride byte-index distance from one element to the next
*/
- protected BaseArrayBuffer(int featureFlags) {
- super(featureFlags | AS_ARRAY);
- }
-
- @Override
- protected int getSize() {
- return shape[0];
- }
-
- @Override
- public int getLen() {
- return shape[0] * getItemsize();
+ protected BaseArrayBuffer(byte[] storage, int featureFlags, int index0, int size, int stride) {
+ super(featureFlags | AS_ARRAY, index0, size, stride);
+ this.storage = storage;
}
@Override
@@ -71,38 +66,6 @@
/**
* {@inheritDoc}
* <p>
- * Specialised to one-dimensional, possibly strided buffer.
- */
- @Override
- protected int calcGreatestIndex() {
- int stride = strides[0];
- if (stride == 1) {
- return index0 + shape[0] - 1;
- } else if (stride > 0) {
- return index0 + (shape[0] - 1) * stride;
- } else {
- return index0 - 1;
- }
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * Specialised to one-dimensional, possibly strided buffer.
- */
- @Override
- protected int calcLeastIndex() {
- int stride = strides[0];
- if (stride < 0) {
- return index0 + (shape[0] - 1) * stride;
- } else {
- return index0;
- }
- }
-
- /**
- * {@inheritDoc}
- * <p>
* The implementation in <code>BaseArrayBuffer</code> deals with the general one-dimensional
* case of arbitrary item size and stride.
*/
@@ -256,22 +219,4 @@
public Pointer getBuf() {
return new Pointer(storage, index0);
}
-
- /**
- * {@inheritDoc}
- * <p>
- * Specialised in <code>BaseArrayBuffer</code> to one dimension.
- */
- @Override
- public boolean isContiguous(char order) {
- if ("CFA".indexOf(order) < 0) {
- return false;
- } else {
- if (getShape()[0] < 2) {
- return true;
- } else {
- return getStrides()[0] == getItemsize();
- }
- }
- }
}
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
@@ -16,22 +16,22 @@
* unglamorous common code need only be implemented once.
* <p>
* This class leaves undefined the storage mechanism for the bytes (typically <code>byte[]</code> or
- * <code>java.nio.ByteBuffer</code>). A concrete class that extends this one must provide elementary
- * accessors {@link #byteAtImpl(int)}, {@link #storeAtImpl(byte, int)} that abstract this storage, a
- * factory {@link #getNIOByteBufferImpl()} for <code>ByteBuffer</code>s that wrap the storage, and a
- * factory for slices {@link #getBufferSlice(int, int, int, int)}. The constructor must specify the
- * feature flags (see {@link #BaseBuffer(int)}), set {@link #index0}, {@link #shape} and
- * {@link #strides}, and finally check the client capabilities with {@link #checkRequestFlags(int)}.
- * Sub-classes intended to represent slices of exporters that must count their exports as part of a
- * locking protocol, as does <code>bytearray</code>, must override {@link #getRoot()} so that a
- * buffer view {@link #release()} on a slice, propagates to the buffer view that provided it.
+ * <code>java.nio.ByteBuffer</code>), while remaining definite that it is an indexable sequence of
+ * bytes. A concrete class that extends this one must provide elementary accessors
+ * {@link #byteAtImpl(int)}, {@link #storeAtImpl(byte, int)} that abstract this storage, a factory
+ * {@link #getNIOByteBufferImpl()} for <code>ByteBuffer</code>s that wrap the storage, and a factory
+ * for slices {@link #getBufferSlice(int, int, int, int)}.
+ * <p>
+ * The sub-class constructor must specify the feature flags (see {@link #BaseBuffer(int)}), set
+ * {@link #index0}, {@link #shape} and {@link #strides}, and finally check the client capabilities
+ * with {@link #checkRequestFlags(int)}. Sub-classes intended to represent slices of exporters that
+ * must count their exports as part of a locking protocol, as does <code>bytearray</code>, must
+ * override {@link #getRoot()} so that a buffer view {@link #release()} on a slice, propagates to
+ * the buffer view that provided it.
* <p>
* Access methods provided here necessarily work with the abstracted {@link #byteAtImpl(int)},
* {@link #storeAtImpl(byte, int)} interface, but subclasses are able to override them with more
- * efficient versions that employ knowledge of the particular storage type used. The provided buffer
- * access methods may be restricted to 1-dimensional arrays where the units are single bytes, stored
- * contiguously. Sub-classes that deal with N-dimensional arrays, non-contiguous storage and items
- * that are not single bytes must sometimes override the default implementations.
+ * efficient versions that employ knowledge of the particular storage type used.
* <p>
* This base implementation is writable only if {@link PyBUF#WRITABLE} is in the feature flags
* passed to the constructor. Otherwise, all methods for write access raise a <code>TypeError</code>
@@ -60,11 +60,6 @@
protected int[] strides;
/**
- * The strides array for a contiguous byte buffer..
- */
- protected static final int[] CONTIG_STRIDES = {1};
-
- /**
* Absolute byte-index in the storage of <code>item[0]</code>. In one dimension, for a positive
* <code>stride</code> this is equal to the offset of the first byte used in whatever
* byte-storage is provided, and for a negative <code>stride</code> it is the first byte of the
@@ -124,19 +119,25 @@
/**
* Construct an instance of <code>BaseBuffer</code> in support of a sub-class, specifying the
- * 'feature flags', or at least a starting set to be adjusted later. These are the features of
- * the buffer exported, not the flags that form the consumer's request. The buffer will be
- * read-only unless {@link PyBUF#WRITABLE} is set in the feature flags. {@link PyBUF#FORMAT} is
- * implicitly added to the feature flags. The navigation arrays are all null, awaiting action by
- * the sub-class constructor. To complete initialisation, the sub-class normally must create its
- * own wrapped byte-storage, assign {@link #index0}) and the navigation arrays ( {@link #shape},
- * {@link #strides}), and call {@link #checkRequestFlags(int)} passing the consumer's request
- * flags.
+ * 'feature flags', or at least a starting set to be adjusted later. Also specify the navigation
+ * ( {@link #index0}, {@link #shape}, and {@link #strides}). These 'feature flags' are the
+ * features of the buffer exported, not the flags that form the consumer's request. The buffer
+ * will be read-only unless {@link PyBUF#WRITABLE} is set. {@link PyBUF#FORMAT} is implicitly
+ * added to the feature flags.
+ * <p>
+ * To complete initialisation, the sub-class normally must create its own wrapped byte-storage,
+ * and call {@link #checkRequestFlags(int)} passing the consumer's request flags.
*
- * @param featureFlags bit pattern that specifies the actual features allowed/required
+ * @param featureFlags bit pattern that specifies the features allowed
+ * @param index0 index into storage of <code>item[0,...,0]</code>
+ * @param shape elements in each dimension
+ * @param strides between successive elements in each dimension
*/
- protected BaseBuffer(int featureFlags) {
+ protected BaseBuffer(int featureFlags, int index0, int[] shape, int[] strides) {
setFeatureFlags(featureFlags | FORMAT);
+ this.index0 = index0;
+ this.shape = shape;
+ this.strides = strides;
}
/**
@@ -636,7 +637,7 @@
// The buffer spans the whole storage
ByteBuffer b = getNIOByteBufferImpl();
// For the one-dimensional contiguous case it makes sense to set the limit:
- if (shape.length == 1) {
+ if (shape.length == 1 && isContiguous('A')) {
int stride = strides[0];
if (getItemsize() == stride) {
b.limit(index0 + shape[0] * stride);
@@ -707,8 +708,8 @@
/*
* If we were to compute the strides array for a C-contiguous array, the last stride would
* equal the item size, and generally stride[k-1] = shape[k]*stride[k]. This is the basis of
- * the test. However, note that for any k where shape[k]==1 there is no "next sub-array"
- * and no discontiguity.
+ * the test. However, note that for any k where shape[k]==1 there is no "next sub-array" and
+ * no discontiguity.
*/
final int N = shape.length;
/*
@@ -731,16 +732,16 @@
private boolean isFortranContiguous() {
/*
- * If we were to compute the strides array for a Fortran-contiguous array, the first stride would
- * equal the item size, and generally stride[k+1] = shape[k]*stride[k]. This is the basis of
- * the test. However, note that for any k where shape[k]==1 there is no "next sub-array"
- * and no discontiguity.
+ * If we were to compute the strides array for a Fortran-contiguous array, the first stride
+ * would equal the item size, and generally stride[k+1] = shape[k]*stride[k]. This is the
+ * basis of the test. However, note that for any k where shape[k]==1 there is no
+ * "next sub-array" and no discontiguity.
*/
final int N = shape.length;
/*
* size is the stride in bytes-index from item[0,...,0,ik,0,...,0] to
- * item[0,...,0,ik+1,0,...,0]. Start the iteration at k=0. An increment of one
- * in the first index makes a stride of the item size.
+ * item[0,...,0,ik+1,0,...,0]. Start the iteration at k=0. An increment of one in the first
+ * index makes a stride of the item size.
*/
int size = getItemsize();
for (int k = 0; k < N; k++) {
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
@@ -14,7 +14,7 @@
* provided or overridden here are appropriate to 1-dimensional arrays, of any item size, backed by
* a <code>ByteBuffer</code>.
*/
-public abstract class BaseNIOBuffer extends BaseBuffer implements PyBuffer {
+public abstract class BaseNIOBuffer extends Base1DBuffer {
/**
* A {@link java.nio.ByteBuffer} (possibly a direct buffer) wrapping the storage that the
@@ -32,22 +32,27 @@
protected ByteBuffer storage;
/**
- * Partially construct an instance of <code>BaseNIOBuffer</code> in support of a sub-class,
- * specifying the 'feature flags', or at least a starting set to be adjusted later. These are
- * the features of the buffer exported, not the flags that form the consumer's request. The
- * buffer will be read-only and/or backed by a (heap) array according to the properties of the
- * <code>ByteBuffer</code> passed in. {@link PyBUF#FORMAT} is implicitly added to the feature
- * flags. To complete initialisation, the sub-class normally must assign: {@link #index0}) and
- * the navigation arrays ({@link #shape}, {@link #strides}), and call
- * {@link #checkRequestFlags(int)} passing the consumer's request flags.
+ * Construct an instance of <code>BaseNIOBuffer</code> in support of a sub-class, specifying the
+ * 'feature flags', or at least a starting set to be adjusted later. Also specify the navigation
+ * ( {@link #index0}, number of elements, and stride. These 'feature flags' are the features of
+ * the buffer exported, not the flags that form the consumer's request. The buffer will be
+ * read-only unless {@link PyBUF#WRITABLE} is set. {@link PyBUF#FORMAT} and
+ * {@link PyBUF#AS_ARRAY} are implicitly added to the feature flags.
+ * <p>
+ * To complete initialisation, the sub-class normally must call {@link #checkRequestFlags(int)}
+ * passing the consumer's request flags.
*
* @param storage the <code>ByteBuffer</code> wrapping the exported object state. NOTE: this
* <code>PyBuffer</code> keeps a reference and may manipulate the position, mark and
* limit hereafter. Use {@link ByteBuffer#duplicate()} to give it an isolated copy.
- * @param featureFlags bit pattern that specifies the actual features allowed/required
+ * @param featureFlags bit pattern that specifies the features allowed
+ * @param index0 index into storage of <code>item[0]</code>
+ * @param size number of elements in the view
+ * @param stride byte-index step between successive elements
*/
- protected BaseNIOBuffer(ByteBuffer storage, int featureFlags) {
- super(featureFlags & ~(WRITABLE | AS_ARRAY));
+
+ protected BaseNIOBuffer(ByteBuffer storage, int featureFlags, int index0, int size, int stride) {
+ super(featureFlags & ~(WRITABLE | AS_ARRAY), index0, size, stride);
this.storage = storage;
// Deduce other feature flags from the client's ByteBuffer
@@ -60,16 +65,6 @@
}
@Override
- protected int getSize() {
- return shape[0];
- }
-
- @Override
- public int getLen() {
- return shape[0] * getItemsize();
- }
-
- @Override
protected byte byteAtImpl(int byteIndex) throws IndexOutOfBoundsException {
return storage.get(byteIndex);
}
@@ -92,38 +87,6 @@
/**
* {@inheritDoc}
* <p>
- * Specialised to one-dimensional, possibly strided buffer.
- */
- @Override
- protected int calcGreatestIndex() {
- int stride = strides[0];
- if (stride == 1) {
- return index0 + shape[0] - 1;
- } else if (stride > 0) {
- return index0 + (shape[0] - 1) * stride;
- } else {
- return index0 - 1;
- }
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * Specialised to one-dimensional, possibly strided buffer.
- */
- @Override
- protected int calcLeastIndex() {
- int stride = strides[0];
- if (stride < 0) {
- return index0 + (shape[0] - 1) * stride;
- } else {
- return index0;
- }
- }
-
- /**
- * {@inheritDoc}
- * <p>
* The default implementation in <code>BaseNIOBuffer</code> deals with the general
* one-dimensional case of arbitrary item size and stride.
*/
@@ -324,22 +287,4 @@
checkHasArray();
return new Pointer(storage.array(), index0);
}
-
- /**
- * {@inheritDoc}
- * <p>
- * Specialised in <code>BaseArrayBuffer</code> to one dimension.
- */
- @Override
- public boolean isContiguous(char order) {
- if ("CFA".indexOf(order) < 0) {
- return false;
- } else {
- if (getShape()[0] < 2) {
- return true;
- } else {
- return getStrides()[0] == getItemsize();
- }
- }
- }
}
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
@@ -9,27 +9,14 @@
*/
public class SimpleBuffer extends BaseArrayBuffer {
- /**
- * Provide an instance of <code>SimpleBuffer</code> with navigation variables partly
- * initialised, for sub-class use. One-dimensional arrays without strides are C- and
- * F-contiguous. To complete initialisation, the sub-class must normally assign the buffer (
- * {@link #storage}, {@link #index0}), and the navigation ({@link #shape} array), and then call
- * {@link #checkRequestFlags(int)} passing the consumer's request flags.
- */
- protected SimpleBuffer() {
- super(CONTIGUITY | SIMPLE);
- // Initialise navigation
- shape = new int[1];
- strides = CONTIG_STRIDES;
- // suboffsets is always null for this type.
- }
/**
* Provide an instance of <code>SimpleBuffer</code> with navigation variables initialised, for
* sub-class use. The buffer ({@link #storage}, {@link #index0}), and the {@link #shape} array
- * will be initialised from the arguments (which are checked for range). The {@link #strides} is
- * set for (one-byte) unit stride. Only the call to {@link #checkRequestFlags(int)}, passing the
- * consumer's request flags really remains for the sub-class constructor to do.
+ * will be initialised from the arguments (which are not checked for range). The
+ * {@link #strides} is set for a one-byte stride. Only the call to
+ * {@link #checkRequestFlags(int)}, passing the consumer's request flags really remains for the
+ * sub-class constructor to do.
*
* <pre>
* super(storage, index0, size);
@@ -40,21 +27,10 @@
* @param index0 offset where the data starts in that array (item[0])
* @param size the number of bytes occupied
* @throws NullPointerException if <code>storage</code> is null
- * @throws ArrayIndexOutOfBoundsException if <code>index0</code> and <code>size</code> are
- * inconsistent with <code>storage.length</code>
*/
protected SimpleBuffer(byte[] storage, int index0, int size) throws PyException,
ArrayIndexOutOfBoundsException {
- this();
- this.storage = storage; // Exported data
- // Initialise navigation
- this.index0 = index0; // Index to be treated as item[0]
- shape[0] = size; // Number of items in exported data
-
- // Check arguments using the "all non-negative" trick
- if ((index0 | size | storage.length - (index0 + size)) < 0) {
- throw new ArrayIndexOutOfBoundsException();
- }
+ super(storage, CONTIGUITY | SIMPLE, index0, size, 1);
}
/**
@@ -75,6 +51,10 @@
ArrayIndexOutOfBoundsException, NullPointerException {
this(storage, index0, size); // Construct checked SimpleBuffer
checkRequestFlags(flags); // Check request is compatible with type
+ // Check arguments using the "all non-negative" trick
+ if ((index0 | size | storage.length - (index0 + size)) < 0) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
}
/**
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
@@ -6,7 +6,7 @@
import org.python.core.PyException;
/**
- * Buffer API over a read-only one-dimensional array of one-byte items.
+ * Buffer API over a read-only one-dimensional <code>java.nio.ByteBuffer</code> of one-byte items.
*/
public class SimpleNIOBuffer extends BaseNIOBuffer {
@@ -40,16 +40,7 @@
*/
protected SimpleNIOBuffer(ByteBuffer storage, int index0, int size) throws PyException,
ArrayIndexOutOfBoundsException {
- super(storage, CONTIGUITY | SIMPLE);
-
- // Initialise navigation
- shape = new int[] {size}; // Number of items in exported data
- strides = SIMPLE_STRIDES;
- // suboffsets is always null for this type.
-
- this.storage = storage; // Exported data
- this.index0 = index0; // Index to be treated as item[0]
-
+ super(storage, CONTIGUITY | SIMPLE, index0, size, 1);
// Check arguments using the "all non-negative" trick
if ((index0 | size | storage.capacity() - (index0 + size)) < 0) {
throw new ArrayIndexOutOfBoundsException();
@@ -181,11 +172,11 @@
* @param flags the request flags of the consumer that requested the slice
* @param storage <code>ByteBuffer</code> wrapping exported data (no reference kept)
* @param offset where the data starts in that buffer (item[0])
- * @param size the number of bytes occupied
+ * @param count the number of items in the sliced view
*/
- public SimpleView(PyBuffer root, int flags, ByteBuffer storage, int offset, int size) {
+ public SimpleView(PyBuffer root, int flags, ByteBuffer storage, int offset, int count) {
// Create a new SimpleNIOBuffer on the buffer passed in (part of the root)
- super(flags, storage, offset, size);
+ super(flags, storage, offset, count);
// Get a lease on the root PyBuffer
this.root = root.getBuffer(FULL_RO);
}
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
@@ -34,10 +34,9 @@
* Leaving storage=null is ok because we carefully override every method that uses it,
* deferring creation of the storage byte array until we absolutely must have one.
*/
- super();
+ super(null, 0, bufString.length());
// Save the backing string
this.bufString = bufString;
- shape[0] = bufString.length();
// Check request is compatible with type
checkRequestFlags(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
@@ -58,12 +58,8 @@
*/
protected Strided1DBuffer(byte[] storage, int index0, int count, int stride)
throws ArrayIndexOutOfBoundsException, NullPointerException {
- super(STRIDES);
- this.storage = storage; // Exported data
- this.index0 = index0; // Index to be treated as item[0]
- this.shape = new int[] {count}; // Number of items in exported data
+ super(storage, STRIDES, index0, count, stride);
this.stride = stride; // Between items
- this.strides = new int[] {stride};
if (count == 0) {
// Nothing to check as we'll make no accesses
@@ -114,7 +110,7 @@
* @param storage raw byte array containing exported data
* @param index0 index into storage of item[0]
* @param count number of items in the slice
- * @param stride in between successive elements of the new PyBuffer
+ * @param stride byte-index distance from one element to the next in the new PyBuffer
* @throws NullPointerException if <code>storage</code> is null
* @throws ArrayIndexOutOfBoundsException if <code>index0</code>, <code>count</code> and
* <code>stride</code> are inconsistent with <code>storage.length</code>
@@ -196,14 +192,14 @@
* @param flags consumer requirements
* @param storage raw byte array containing exported data
* @param index0 index into storage of item[0]
- * @param len number of items in the slice
+ * @param count number of items in the sliced view
* @param stride in between successive elements of the new PyBuffer
* @throws PyException (BufferError) when expectations do not correspond with the type
*/
- public SlicedView(PyBuffer root, int flags, byte[] storage, int index0, int len, int stride)
- throws PyException {
+ public SlicedView(PyBuffer root, int flags, byte[] storage, int index0, int count,
+ int stride) throws PyException {
// Create a new on the buffer passed in (part of the root)
- super(flags, storage, index0, len, stride);
+ super(flags, storage, index0, count, stride);
// Get a lease on the root PyBuffer (read-only)
this.root = root.getBuffer(FULL_RO);
}
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
@@ -5,18 +5,17 @@
import org.python.core.PyBuffer;
import org.python.core.PyException;
-
/**
- * Read-only buffer API over a one-dimensional array of one-byte items, that are evenly-spaced in a
- * storage array. The buffer has <code>storage</code>, <code>index0</code> and <code>length</code>
- * properties in the usual way, designating a slice (or all) of a byte array, but also a
- * <code>stride</code> property (equal to <code>getStrides()[0]</code>).
+ * Read-only buffer API over a one-dimensional <code>java.nio.ByteBuffer</code> of one-byte items,
+ * that are evenly-spaced in that store. The buffer has <code>storage</code>, <code>index0</code>
+ * and <code>length</code> properties in the usual way, designating a slice (or all) of a byte
+ * array, but also a <code>stride</code> property (equal to <code>getStrides()[0]</code>).
* <p>
- * Let the underlying buffer be the byte array <i>u(i)</i> for <i>i=0..N-1</i>, let <i>x</i> be the
- * <code>Strided1DNIOBuffer</code>, and let the stride be <i>p</i>. The storage works as follows.
- * Designate by <i>x(j)</i>, for <i>j=0..L-1</i>, the byte at index <i>j</i>, that is, the byte
- * retrieved by <code>x.byteAt(j)</code>. Thus, we store <i>x(j)</i> at <i>u(a+pj)</i>, that is,
- * <i>x(0) = u(a)</i>. When we construct such a buffer, we have to supply <i>a</i> =
+ * Let the underlying buffer be the byte sequence <i>u(i)</i> for <i>i=0..N-1</i>, let <i>x</i> be
+ * the <code>Strided1DNIOBuffer</code>, and let the stride be <i>p</i>. The storage works as
+ * follows. Designate by <i>x(j)</i>, for <i>j=0..L-1</i>, the byte at index <i>j</i>, that is, the
+ * byte retrieved by <code>x.byteAt(j)</code>. Thus, we store <i>x(j)</i> at <i>u(a+pj)</i>, that
+ * is, <i>x(0) = u(a)</i>. When we construct such a buffer, we have to supply <i>a</i> =
* <code>index0</code>, <i>L</i> = <code>count</code>, and <i>p</i> = <code>stride</code> as the
* constructor arguments. The last item in the slice <i>x(L-1)</i> is stored at <i>u(a+p(L-1))</i>.
* For the simple case of positive stride, constructor argument <code>index0</code> is the low index
@@ -40,7 +39,6 @@
*/
protected int stride;
-
/**
* Provide an instance of <code>Strided1DNIOBuffer</code> with navigation variables initialised,
* for sub-class use. The buffer ({@link #storage}, {@link #index0}), and the navigation (
@@ -49,8 +47,8 @@
* <p>
* The sub-class constructor should check that the intended access is compatible with this
* object by calling {@link #checkRequestFlags(int)}. (See the source of
- * {@link Strided1DWritableBuffer#Strided1DWritableBuffer(int, ByteBuffer, int, int, int)}
- * for an example of this use.)
+ * {@link Strided1DWritableBuffer#Strided1DWritableBuffer(int, ByteBuffer, int, int, int)} for
+ * an example of this use.)
*
* @param storage the <code>ByteBuffer</code> wrapping the exported object state. NOTE: this
* <code>PyBuffer</code> keeps a reference and may manipulate the position, mark and
@@ -64,11 +62,8 @@
*/
protected Strided1DNIOBuffer(ByteBuffer storage, int index0, int count, int stride)
throws ArrayIndexOutOfBoundsException, NullPointerException {
- super(storage, STRIDES);
- this.index0 = index0; // Index to be treated as item[0]
- shape = new int[]{count}; // Number of items in exported data
+ super(storage, STRIDES, index0, count, stride);
this.stride = stride; // Between items
- this.strides = new int[] {stride};
if (count == 0) {
// Nothing to check as we'll make no accesses
@@ -108,16 +103,14 @@
}
}
- /**
+ /**
* Provide an instance of <code>Strided1DNIOBuffer</code> on a particular {@link ByteBuffer}
- * specifying
- * a starting index, the number of items in the result, and a byte-indexing stride. The result
- * of <code>byteAt(i)</code> will be equal to <code>storage.get(index0+stride*i)</code>
- * (whatever
- * the sign of <code>stride</code>), valid for <code>0<=i<count</code>. The constructor
- * checks that all these indices lie within the <code>storage</code> (unless
- * <code>count=0</code>).
- * No reference will be kept to the <code>ByteBuffer</code> passed in. (It is duplicated.)
+ * specifying a starting index, the number of items in the result, and a byte-indexing stride.
+ * The result of <code>byteAt(i)</code> will be equal to
+ * <code>storage.get(index0+stride*i)</code> (whatever the sign of <code>stride</code>), valid
+ * for <code>0<=i<count</code>. The constructor checks that all these indices lie within
+ * the <code>storage</code> (unless <code>count=0</code>). No reference will be kept to the
+ * <code>ByteBuffer</code> passed in. (It is duplicated.)
* <p>
* The constructed <code>PyBuffer</code> meets the consumer's expectations as expressed in the
* <code>flags</code> argument, or an exception will be thrown if these are incompatible with
@@ -149,11 +142,11 @@
return index0 + index * stride;
}
- /**
+ /**
* {@inheritDoc}
* <p>
- * <code>Strided1DNIOBuffer</code> provides an implementation for slicing already-strided bytes in
- * one dimension. In that case, <i>x(i) = u(r+ip)</i> for <i>i = 0..L-1</i> where u is the
+ * <code>Strided1DNIOBuffer</code> provides an implementation for slicing already-strided bytes
+ * in one dimension. In that case, <i>x(i) = u(r+ip)</i> for <i>i = 0..L-1</i> where u is the
* underlying buffer, and <i>r</i>, <i>p</i> and <i>L</i> are the start, stride and count with
* which <i>x</i> was created from <i>u</i>. Thus <i>y(k) = u(r+sp+kmp)</i>, that is, the
* composite <code>index0</code> is <i>r+sp</i> and the composite <code>stride</code> is
@@ -175,10 +168,9 @@
}
}
-
/**
- * A <code>Strided1DNIOBuffer.SlicedView</code> represents a non-contiguous subsequence of a simple
- * buffer.
+ * A <code>Strided1DNIOBuffer.SlicedView</code> represents a non-contiguous subsequence of a
+ * simple buffer.
*/
static class SlicedView extends Strided1DNIOBuffer {
@@ -192,14 +184,14 @@
* @param flags consumer requirements
* @param storage <code>ByteBuffer</code> wrapping exported data (no reference kept)
* @param index0 index into storage of item[0]
- * @param len number of items in the slice
+ * @param count the number of items in the sliced view
* @param stride in between successive elements of the new PyBuffer
* @throws PyException (BufferError) when expectations do not correspond with the type
*/
- public SlicedView(PyBuffer root, int flags, ByteBuffer storage, int index0, int len, int stride)
- throws PyException {
+ public SlicedView(PyBuffer root, int flags, ByteBuffer storage, int index0, int count,
+ int stride) throws PyException {
// Create a new slice on the buffer passed in (part of the root)
- super(flags, storage, index0, len, stride);
+ super(flags, storage, index0, count, stride);
// Get a lease on the root PyBuffer (read-only)
this.root = root.getBuffer(FULL_RO);
}
diff --git a/src/org/python/core/buffer/Strided1DWritableBuffer.java b/src/org/python/core/buffer/Strided1DWritableBuffer.java
--- a/src/org/python/core/buffer/Strided1DWritableBuffer.java
+++ b/src/org/python/core/buffer/Strided1DWritableBuffer.java
@@ -28,7 +28,7 @@
* @param storage raw byte array containing exported data
* @param index0 index into storage of item[0]
* @param count number of items in the slice
- * @param stride in between successive elements of the new PyBuffer
+ * @param stride byte-index distance from one element to the next in the new PyBuffer
* @throws NullPointerException if <code>storage</code> is null
* @throws ArrayIndexOutOfBoundsException if <code>index0</code>, <code>count</code> and
* <code>stride</code> are inconsistent with <code>storage.length</code>
@@ -100,14 +100,14 @@
* @param flags consumer requirements
* @param storage raw byte array containing exported data
* @param index0 index into storage of item[0]
- * @param len number of items in the slice
+ * @param count number of items in the sliced view
* @param stride in between successive elements of the new PyBuffer
* @throws PyException (BufferError) when expectations do not correspond with the type
*/
- public SlicedView(PyBuffer root, int flags, byte[] storage, int index0, int len, int stride)
- throws PyException {
+ public SlicedView(PyBuffer root, int flags, byte[] storage, int index0, int count,
+ int stride) throws PyException {
// Create a new on the buffer passed in (part of the root)
- super(flags, storage, index0, len, stride);
+ super(flags, storage, index0, count, stride);
// Get a lease on the root PyBuffer (writable)
this.root = root.getBuffer(FULL);
}
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
@@ -17,9 +17,6 @@
/** Shared instance of a zero-length storage. */
private static final byte[] EMPTY = new byte[0];
- /** Array containing a single zero for the length */
- protected static final int[] SHAPE = {0};
-
/**
* Construct an instance of a zero-length buffer, choosing whether it should report itself to be
* read-only through {@link #isReadonly()} or as having a backing array through
@@ -33,10 +30,7 @@
* @throws PyException (BufferError) when client expectations do not correspond with the type
*/
public ZeroByteBuffer(int flags, boolean readonly, boolean hasArray) throws PyException {
- super(CONTIGUITY | (readonly ? 0 : WRITABLE));
- this.storage = EMPTY; // Empty array
- this.shape = SHAPE; // {0}
- this.strides = BaseBuffer.CONTIG_STRIDES; // {1}
+ super(EMPTY, CONTIGUITY | (readonly ? 0 : WRITABLE), 0, 0, 1);
if (!hasArray) {
// super() knows we have an array, but this truth is inconvenient here.
removeFeatureFlags(AS_ARRAY);
diff --git a/tests/java/org/python/core/PyBufferNIOTest.java b/tests/java/org/python/core/PyBufferNIOTest.java
--- a/tests/java/org/python/core/PyBufferNIOTest.java
+++ b/tests/java/org/python/core/PyBufferNIOTest.java
@@ -7,7 +7,6 @@
import org.junit.runners.Parameterized.Parameters;
import org.python.core.ByteBufferTestSupport.ByteMaterial;
-import org.python.core.PyBufferTest.TestableExporter;
import org.python.core.PyBufferTestSupport.ExporterFactory;
import org.python.core.PyBufferTestSupport.TestSpec;
import org.python.core.PyBufferTestSupport.WritableExporterFactory;
@@ -249,11 +248,10 @@
int count, int stride) throws IndexOutOfBoundsException, NullPointerException,
PyException {
// Client will need to navigate using shape and strides if this is a slice
- super(FEATURES | ((index0 == 0 && stride == 1) ? 0 : PyBUF.STRIDES));
+ super(FEATURES | ((index0 == 0 && stride == 1) ? 0 : STRIDES), //
+ index0, new int[] {count}, new int[] {stride});
this.storage = storage.duplicate();
- this.index0 = index0;
- shape = new int[] {count};
- strides = new int[] {stride};
+
// Check the potential index range
if (count > 0) {
int end = index0 + (count - 1) * stride;
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
@@ -1304,11 +1304,9 @@
int count, int stride) throws IndexOutOfBoundsException, NullPointerException,
PyException {
// Client will need to navigate using shape and strides if this is a slice
- super(FEATURES | ((index0 == 0 && stride == 1) ? 0 : PyBUF.STRIDES));
+ super(FEATURES | ((index0 == 0 && stride == 1) ? 0 : STRIDES), //
+ index0, new int[] {count}, new int[] {stride});
this.storage = storage;
- this.index0 = index0;
- shape = new int[] {count};
- strides = new int[] {stride};
// Check the potential index range
if (count > 0) {
int end = index0 + (count - 1) * stride;
--
Repository URL: https://hg.python.org/jython
More information about the Jython-checkins
mailing list