[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