Class SimpleStringBuffer

All Implemented Interfaces:
AutoCloseable, BufferProtocol, PyBUF, PyBuffer

public class SimpleStringBuffer extends SimpleBuffer
Buffer API that appears to be a one-dimensional array of one-byte items providing read-only API, but which is actually backed by a Java String. Some of the buffer API absolutely needs access to the data as a byte array (those parts that involve a ByteBuffer or PyBuffer.Pointer result), and therefore this class must create a byte array from the String for them. However, it defers creation of a byte array until that part of the API is actually used. Where possible, this class overrides those methods in SimpleBuffer that would otherwise access the byte array attribute to use the String instead.
  • Constructor Details

    • SimpleStringBuffer

      public SimpleStringBuffer(int flags, BufferProtocol obj, String bufString)
      Provide an instance of SimpleStringBuffer meeting the consumer's expectations as expressed in the flags argument.
      Parameters:
      flags - consumer requirements
      obj - exporting object (or null)
      bufString - storing the implementation of the object
  • Method Details

    • getLen

      public int getLen()
      The total number of bytes represented by the view, which will be the product of the elements of the shape array, and the item size in bytes.

      SimpleBuffer provides an implementation optimised for contiguous bytes in one-dimension.

      This method uses String.length() rather than create an actual byte buffer.

      Specified by:
      getLen in interface PyBUF
      Overrides:
      getLen in class SimpleBuffer
      Returns:
      the total number of bytes represented.
    • byteAtImpl

      public final byte byteAtImpl(int index)

      This method uses String.charAt(int) rather than create an actual byte buffer.

    • byteIndex

      public final int byteIndex(int index)
      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 PyBuffer is a linearly-indexed sequence of bytes, although it may not actually be a heap-allocated Java byte[] object. The purpose of this method is to allow the exporter to define the relationship between the item index (as used in PyBuffer.byteAt(int)) and the byte-index (as used with the ByteBuffer returned by PyBuffer.getNIOByteBuffer()). See PyBuffer.byteIndex(int[]) for discussion of the multi-dimensional case.

      In SimpleBuffer the calculation is specialised for one dimension, no striding, and an item size of 1.

      In SimpleStringBuffer we can simply return the argument.

      Specified by:
      byteIndex in interface PyBuffer
      Overrides:
      byteIndex in class SimpleBuffer
      Parameters:
      index - item-index from consumer
      Returns:
      corresponding byte-index in actual storage
    • copyTo

      public void copyTo(int srcIndex, byte[] dest, int destPos, int count) throws IndexOutOfBoundsException
      Copy a simple slice of the buffer-view to the destination byte array, defined by a starting item-index in the source buffer and the count of items to copy. This may validly be done only for a one-dimensional buffer, as the meaning of the starting item-index is otherwise not defined. count*itemsize bytes will be occupied in the destination.

      The default implementation in BaseBuffer deals with the general one-dimensional case of arbitrary item size and stride, but is unable to optimise access to sequential bytes.

      The implementation in BaseArrayBuffer deals with the general one-dimensional case of arbitrary item size and stride.

      This method uses String.charAt(int) rather than create an actual byte buffer.

      Specified by:
      copyTo in interface PyBuffer
      Overrides:
      copyTo in class BaseArrayBuffer
      Parameters:
      srcIndex - starting item-index in the source buffer
      dest - destination byte array
      destPos - byte-index in the destination array of the source item [0,...]
      count - number of items to copy
      Throws:
      IndexOutOfBoundsException - if access out of bounds in source or destination
    • getBufferSlice

      public PyBuffer getBufferSlice(int flags, int start, int count)
      Equivalent to PyBuffer.getBufferSlice(int, int, int, int) with stride 1.

      The SimpleStringBuffer implementation avoids creation of a byte buffer.

      Specified by:
      getBufferSlice in interface PyBuffer
      Overrides:
      getBufferSlice in class SimpleBuffer
      Parameters:
      flags - specifying features demanded and the navigational capabilities of the consumer
      start - index in the current buffer
      count - number of items in the required slice
      Returns:
      a buffer representing the slice
    • getBufferSlice

      public PyBuffer getBufferSlice(int flags, int start, int count, int stride)
      Get a PyBuffer that represents a slice of the current one described in terms of a start index, number of items to include in the slice, and the stride in the current buffer. A consumer that obtains a PyBuffer with getBufferSlice must release it with PyBuffer.release() just as if it had been obtained with PyBuffer.getBuffer(int)

      Suppose that x(i) denotes the ith element of the current buffer, that is, the byte retrieved by this.byteAt(i) or the unit indicated by this.getPointer(i). A request for a slice where start = s, count = N and stride = m, results in a buffer y such that y(k) = x(s+km) where k=0..(N-1). In Python terms, this is the slice x[s : s+(N-1)m+1 : m] (if m>0) or the slice x[s : s+(N-1)m-1 : m] (if m<0). Implementations should check that this range is entirely within the current buffer.

      In a simple buffer backed by a contiguous byte array, the result is a strided PyBuffer on the same storage but where the offset is adjusted by s and the stride is as supplied. If the current buffer is already strided and/or has an item size larger than single bytes, the new start index, count and stride will be translated from the arguments given, through this buffer's stride and item size. The caller always expresses start and strides in terms of the abstract view of this buffer.

      SimpleBuffer provides an implementation for slicing contiguous bytes in one dimension. In that case, x(i) = u(r+i) for i = 0..L-1 where u is the underlying buffer, and r and L are the start and count with which x was created from u. Thus y(k) = u(r+s+km), that is, the composite offset is r+s and the stride is m.

      The SimpleStringBuffer implementation creates an actual byte buffer.

      Specified by:
      getBufferSlice in interface PyBuffer
      Overrides:
      getBufferSlice in class SimpleBuffer
      Parameters:
      flags - specifying features demanded and the navigational capabilities of the consumer
      start - index in the current buffer
      count - number of items in the required slice
      stride - index-distance in the current buffer between consecutive items in the slice
      Returns:
      a buffer representing the slice
    • getBuf

      public PyBuffer.Pointer getBuf()
      Return a structure describing the slice of a byte array that holds the data being exported to the consumer. For a one-dimensional contiguous buffer, assuming the following client code where obj has type BufferProtocol:
       PyBuffer a = obj.getBuffer(PyBUF.SIMPLE);
       int itemsize = a.getItemsize();
       PyBuffer.Pointer b = a.getBuf();
       
      the item with index k is in the array b.storage at index [b.offset + k*itemsize] to [b.offset + (k+1)*itemsize - 1] inclusive. And if itemsize==1, the item is simply the byte b.storage[b.offset + k]

      If the buffer is multidimensional or non-contiguous, storage[offset] is still the (first byte of) the item at index [0] or [0,...,0]. However, it is necessary to navigate b.storage using the shape, strides and maybe suboffsets provided by the API.

      BaseArrayBuffer provides a reference to the storage array even when the buffer is intended not to be writable. There can be no enforcement of read-only character once a reference to the byte array has been handed out.

      This method creates an actual byte array from the underlying String if none yet exists.

      Specified by:
      getBuf in interface PyBuffer
      Overrides:
      getBuf in class BaseArrayBuffer
      Returns:
      structure defining the byte[] slice that is the shared data
    • getPointer

      public PyBuffer.Pointer getPointer(int index)
      Return a structure describing the position in a byte array of a single item from the data being exported to the consumer. For a one-dimensional contiguous buffer, assuming the following client code where obj has type BufferProtocol:
       int k = ... ;
       PyBuffer a = obj.getBuffer(PyBUF.FULL);
       int itemsize = a.getItemsize();
       PyBuffer.Pointer b = a.getPointer(k);
       
      the item with index k is in the array b.storage at index [b.offset] to [b.offset + itemsize - 1] inclusive. And if itemsize==1, the item is simply the byte b.storage[b.offset]

      Essentially this is a method for computing the offset of a particular index. The client is free to navigate the underlying buffer b.storage without respecting these boundaries.

      This method creates an actual byte array from the underlying String if none yet exists.

      Specified by:
      getPointer in interface PyBuffer
      Overrides:
      getPointer in class SimpleBuffer
      Parameters:
      index - in the buffer to position the pointer
      Returns:
      structure defining the byte[] slice that is the shared data
    • getPointer

      public PyBuffer.Pointer getPointer(int... indices)
      Return a structure describing the position in a byte array of a single item from the data being exported to the consumer, in the case that array may be multi-dimensional. For a 3-dimensional contiguous buffer, assuming the following client code where obj has type BufferProtocol:
       int i, j, k;
       // ... calculation that assigns i, j, k
       PyBuffer a = obj.getBuffer(PyBUF.FULL);
       int itemsize = a.getItemsize();
       PyBuffer.Pointer b = a.getPointer(i,j,k);
       
      the item with index [i,j,k] is in the array b.storage at index [b.offset] to [b.offset + itemsize - 1] inclusive. And if itemsize==1, the item is simply the byte b.storage[b.offset]

      Essentially this is a method for computing the offset of a particular index. The client is free to navigate the underlying buffer b.storage without respecting these boundaries. If the buffer is non-contiguous, the above description is still valid (since a multi-byte item must itself be contiguously stored), but in any additional navigation of b.storage[] to other items, the client must use the shape, strides and sub-offsets provided by the API. Normally one starts b = a.getBuf() in order to establish the offset of index [0,...,0].

      This method creates an actual byte array from the underlying String if none yet exists.

      Specified by:
      getPointer in interface PyBuffer
      Overrides:
      getPointer in class SimpleBuffer
      Parameters:
      indices - multidimensional index at which to position the pointer
      Returns:
      structure defining the byte[] slice that is the shared data
    • toString

      public String toString()
      The toString() method of a SimpleStringBuffer simply produces the underlying String.
      Specified by:
      toString in interface PyBuffer
      Overrides:
      toString in class SimpleBuffer