package org.python.core.buffer;
import java.nio.ByteBuffer;
import org.python.core.PyBUF;
import org.python.core.PyBuffer;
import org.python.core.PyException;
/**
* Base implementation of the Buffer API for when the storage implementation is byte[].
* The description of {@link BaseBuffer} mostly applies. Methods provided or overridden here are
* appropriate to 1-dimensional arrays, of any item size, backed by byte[].
*/
public abstract class BaseArrayBuffer extends Base1DBuffer {
/**
* Reference to the underlying byte[] storage that the exporter is sharing with the
* consumer. The data need not occupy the whole array: in the constructor of a particular type
* of buffer, the exporter usually indicates an offset to the first significant byte and length
* (contiguous cases) or the index in storage that should be treated as the item
* with index zero (retrieved say by buf.byteAt(0)).
*/
protected byte[] storage;
/**
* Construct an instance of BaseArrayBuffer 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.
*
* To complete initialisation, the sub-class normally must call {@link #checkRequestFlags(int)}
* passing the consumer's request flags.
*
* @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 item[0]
* @param size number of elements in the view
* @param stride byte-index distance from one element to the next
*/
protected BaseArrayBuffer(byte[] storage, int featureFlags, int index0, int size, int stride) {
super(featureFlags | AS_ARRAY, index0, size, stride);
this.storage = storage;
}
@Override
protected byte byteAtImpl(int byteIndex) throws IndexOutOfBoundsException {
return storage[byteIndex];
}
@Override
protected void storeAtImpl(byte value, int byteIndex) throws IndexOutOfBoundsException,
PyException {
checkWritable();
storage[byteIndex] = value;
}
@Override
public int byteIndex(int... indices) throws IndexOutOfBoundsException {
// BaseBuffer implementation can be simplified since if indices.length!=1 we error.
checkDimension(indices.length); // throws if != 1
return byteIndex(indices[0]);
}
/**
* {@inheritDoc}
*
* The implementation in BaseArrayBuffer deals with the general one-dimensional
* case of arbitrary item size and stride.
*/
@Override
public void copyTo(int srcIndex, byte[] dest, int destPos, int count)
throws IndexOutOfBoundsException {
if (count > 0) {
// Pick up attributes necessary to choose an efficient copy strategy
int itemsize = getItemsize();
int stride = getStrides()[0];
int skip = stride - itemsize;
int s = byteIndex(srcIndex);
// Strategy depends on whether items are laid end-to-end contiguously or there are gaps
if (skip == 0) {
// stride == itemsize: straight copy of contiguous bytes
System.arraycopy(storage, s, dest, destPos, count * itemsize);
} else {
int limit = s + count * stride, d = destPos;
if (itemsize == 1) {
// Non-contiguous copy: single byte items
for (; s != limit; s += stride) {
dest[d++] = storage[s];
}
} else {
// Non-contiguous copy: each time, copy itemsize bytes then skip
for (; s != limit; s += skip) {
int t = s + itemsize;
while (s < t) {
dest[d++] = storage[s++];
}
}
}
}
}
}
/**
* {@inheritDoc}
*
* The default implementation in BaseArrayBuffer deals with the general
* one-dimensional case of arbitrary item size and stride.
*/
@Override
public void copyFrom(byte[] src, int srcPos, int destIndex, int count)
throws IndexOutOfBoundsException, PyException {
copyFrom(src, srcPos, 1, destIndex, count);
}
/**
* Generalisation of {@link PyBuffer#copyFrom(byte[], int, int, int)} to allow a stride within
* the source array.
*
* @param src source byte array
* @param srcPos byte-index location in source of first byte to copy
* @param srcStride byte-index increment from one item to the next
* @param destIndex starting item-index in the destination (i.e. this)
* @param count number of items to copy in
* @throws IndexOutOfBoundsException if access out of bounds in source or destination
* @throws PyException {@code TypeError} if read-only buffer
*/
protected void copyFrom(byte[] src, int srcPos, int srcStride, int destIndex, int count)
throws IndexOutOfBoundsException, PyException {
checkWritable();
if (count > 0) {
// Pick up attributes necessary to choose an efficient copy strategy
int itemsize = getItemsize();
int stride = getStrides()[0];
int skip = stride - itemsize;
int d = byteIndex(destIndex);
int srcSkip = srcStride - itemsize;
// Strategy depends on whether items are laid end-to-end or there are gaps
if (skip == 0 && srcSkip == 0) {
// Straight copy of contiguous bytes
System.arraycopy(src, srcPos, storage, d, count * itemsize);
} else {
int limit = d + count * stride, s = srcPos;
if (itemsize == 1) {
// Non-contiguous copy: single byte items
for (; d != limit; d += stride) {
storage[d] = src[s];
s += srcStride;
}
} else {
// Non-contiguous copy: itemsize bytes then skip to next item
for (; d != limit; d += skip) {
int t = d + itemsize;
while (d < t) {
storage[d++] = src[s++];
}
s += srcSkip;
}
}
}
}
}
@Override
public void copyFrom(PyBuffer src) throws IndexOutOfBoundsException, PyException {
if (src instanceof BaseArrayBuffer && !this.overlaps((BaseArrayBuffer)src)) {
// We can do this efficiently, copying between arrays.
copyFromArrayBuffer((BaseArrayBuffer)src);
} else {
super.copyFrom(src);
}
}
private boolean overlaps(BaseArrayBuffer src) {
if (src.storage != this.storage) {
return false;
} else {
int low = calcLeastIndex(), high = calcGreatestIndex();
int srcLow = src.calcLeastIndex(), srcHigh = src.calcGreatestIndex();
return (srcHigh >= low && high >= srcLow);
}
}
private void copyFromArrayBuffer(BaseArrayBuffer src) throws IndexOutOfBoundsException,
PyException {
src.checkDimension(1);
int itemsize = getItemsize();
int count = getSize();
// Block operation if different item or overall size
if (src.getItemsize() != itemsize || src.getSize() != count) {
throw differentStructure();
}
// We depend on the striding copyFrom() acting directly on the source storage
copyFrom(src.storage, src.index0, src.strides[0], 0, count);
}
@Override
protected ByteBuffer getNIOByteBufferImpl() {
// The buffer spans the whole storage, which may include data not in the view
ByteBuffer b = ByteBuffer.wrap(storage);
// Return as read-only if it is.
return isReadonly() ? b.asReadOnlyBuffer() : b;
}
/**
* {@inheritDoc}
*
* 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.
*/
@SuppressWarnings("deprecation")
@Override
public Pointer getBuf() {
return new Pointer(storage, index0);
}
}
Ads help maintain this website.