org.python.core.buffer

## Class SimpleStringBuffer

- java.lang.Object
- - org.python.core.buffer.BaseBuffer
  - - org.python.core.buffer.Base1DBuffer
    - - org.python.core.buffer.BaseArrayBuffer
      - - org.python.core.buffer.SimpleBuffer
        - - org.python.core.buffer.SimpleStringBuffer

All Implemented Interfaces:
  java.lang.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.

### Nested Class Summary

### Nested classes/interfaces inherited from interface org.python.core.PyBuffer

`PyBuffer.Pointer`

### Field Summary

### Fields inherited from interface org.python.core.PyBUF

`ANY_CONTIGUOUS, AS_ARRAY, C_CONTIGUOUS, CONTIG, CONTIG_RO, CONTIGUITY, F_CONTIGUOUS, FORMAT, FULL, FULL_RO, INDIRECT, IS_C_CONTIGUOUS, IS_F_CONTIGUOUS, MAX_NDIM, NAVIGATION, ND, RECORDS, RECORDS_RO, SIMPLE, STRIDED, STRIDED_RO, STRIDES, WRITABLE`

### Constructor Summary

Constructors
Constructor and Description
`SimpleStringBuffer(int flags, BufferProtocol obj, java.lang.String bufString)` Provide an instance of SimpleStringBuffer meeting the consumer's expectations as expressed in the flags argument.

### Method Summary

All Methods Instance Methods Concrete Methods
`byte` `byteAtImpl(int index)` Retrieve the byte at the given index in the underlying storage treated as a flat sequence of bytes.
`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.
`void` `copyTo(int srcIndex, byte[] dest, int destPos, int count)` 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.
`PyBuffer.Pointer` `getBuf()` Return a structure describing the slice of a byte array that holds the data being exported to the consumer.
`PyBuffer` `getBufferSlice(int flags, int start, int count)` Equivalent to `PyBuffer.getBufferSlice(int, int, int, int)` with stride 1.
`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.
`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.
`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.
`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.
`java.lang.String` `toString()` The `toString()` method of a `SimpleStringBuffer` simply produces the underlying `String`.

### Methods inherited from class org.python.core.buffer.BaseArrayBuffer

`byteIndex, copyFrom, copyFrom`

### Methods inherited from class org.python.core.buffer.Base1DBuffer

`isContiguous`

### Methods inherited from class org.python.core.buffer.BaseBuffer

`byteAt, byteAt, close, copyTo, getBuffer, getBufferAgain, getFormat, getItemsize, getNdim, getNIOByteBuffer, getObj, getShape, getStrides, getSuboffsets, hasArray, intAt, intAt, isReadonly, isReleased, release, storeAt, storeAt`

### Methods inherited from class java.lang.Object

`equals, getClass, hashCode, notify, notifyAll, wait, wait, wait`

### Constructor Detail

#### SimpleStringBuffer

    public SimpleStringBuffer(int flags,
                              BufferProtocol obj,
                              java.lang.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 Detail

#### 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)

Retrieve the byte at the given index in the underlying storage treated as a flat sequence of bytes. This byte-index will have been computed from the item index (which may have been multi-dimensional), taking into account `BaseBuffer.index0`, `BaseBuffer.shape`, `BaseBuffer.strides`, and the item size. The caller is responsible for validating the original item-index and raising (typically) an `IndexOutOfBoundsException`. Misuse of this method may still result in unchecked exceptions characteristic of the storage implementation.

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

Parameters:
  `index` - byte-index of location to retrieve
Returns:
  the byte at byteIndex

#### 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 java.lang.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:
  `java.lang.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 java.lang.String toString()

The `toString()` method of a `SimpleStringBuffer` simply produces the underlying `String`.

Specified by:
  `toString` in interface `PyBuffer`
Overrides:
  `toString` in class `SimpleBuffer`