All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.python.core.PyBuffer Maven / Gradle / Ivy

Go to download

Jython is an implementation of the high-level, dynamic, object-oriented language Python written in 100% Pure Java, and seamlessly integrated with the Java platform. It thus allows you to run Python on any Java platform.

The newest version!
package org.python.core;

import java.nio.ByteBuffer;

/**
 * The Jython buffer API for access to a byte array within an exporting object. This interface is
 * the counterpart of the CPython Py_buffer struct. Several concrete types implement
 * this interface in order to provide tailored support for different storage organisations.
 */
public interface PyBuffer extends PyBUF, BufferProtocol, AutoCloseable {

    /*
     * The different behaviours required as the actual structure of the buffer changes (from one
     * exporter to another, that is) should be dealt with using polymorphism. The implementation of
     * those types may then calculate indices etc. without checking e.g for whether the strides
     * array must be used, or the array is C or F contiguous, since they know the answer to these
     * questions already, and can just get on with the request in their own way.
     *
     * The issue of consumer requests via getBuffer(int) is greatly simplified relative to CPython
     * by the choice always to supply a full description of the buffer organisation, whether the
     * consumer asked for it in the flags or not. Of course, implementations don't actually have to
     * create (for example) a strides array until getStrides() is called.
     */

    // Informational methods inherited from PyBUF
    //
    // boolean isReadonly();
    // int getNdim();
    // int[] getShape();
    // int getLen();

    /**
     * Return the underlying exporting object (or null if no object implementing the
     * {@link BufferProtocol} is in that role). This will often be a PyObject.
     *
     * @return exporting object (or null)
     */
    BufferProtocol getObj();

    /**
     * Return the byte indexed from a one-dimensional buffer with item size one. This is part of the
     * fully-encapsulated API: the buffer implementation exported takes care of navigating the
     * structure of the buffer. Results are undefined where the number of dimensions is not one or
     * if itemsize>1.
     *
     * @param index to retrieve from
     * @return the item at index, which is a byte
     */
    byte byteAt(int index) throws IndexOutOfBoundsException;

    /**
     * Return the unsigned byte value indexed from a one-dimensional buffer with item size one. This
     * is part of the fully-encapsulated API: the exporter takes care of navigating the structure of
     * the buffer. Results are undefined where the number of dimensions is not one or if
     * itemsize>1.
     *
     * @param index to retrieve from
     * @return the item at index, treated as an unsigned byte, {@code =0xff & byteAt(index)}
     */
    int intAt(int index) throws IndexOutOfBoundsException;

    /**
     * Store the given byte at the indexed location in of a one-dimensional buffer with item size
     * one. This is part of the fully-encapsulated API: the buffer implementation exported takes
     * care of navigating the structure of the buffer. Results are undefined where the number of
     * dimensions is not one or if itemsize>1.
     *
     * @param value to store
     * @param index to location
     */
    void storeAt(byte value, int index) throws IndexOutOfBoundsException;

    // Access to n-dimensional array
    //
    /**
     * Return the byte indexed from an N-dimensional buffer with item size one. This is part of the
     * fully-encapsulated API: the buffer implementation exported takes care of navigating the
     * structure of the buffer. The indices must be correct in number and range for the array shape.
     * Results are undefined where itemsize>1.
     *
     * @param indices specifying location to retrieve from
     * @return the item at location, which is a byte
     */
    byte byteAt(int... indices) throws IndexOutOfBoundsException;

    /**
     * Return the unsigned byte value indexed from an N-dimensional buffer with item size one. This
     * is part of the fully-encapsulated API: the buffer implementation exported takes care of
     * navigating the structure of the buffer. The indices must be correct in number and range for
     * the array shape. Results are undefined where itemsize>1.
     *
     * @param indices specifying location to retrieve from
     * @return the item at location, treated as an unsigned byte, {@code =0xff & byteAt(index)}
     */
    int intAt(int... indices) throws IndexOutOfBoundsException;

    /**
     * Store the given byte at the indexed location in of an N-dimensional buffer with item size
     * one. This is part of the fully-encapsulated API: the exporter takes care of navigating the
     * structure of the buffer. The indices must be correct in number and range for the array shape.
     * Results are undefined where itemsize>1.
     *
     * @param value to store
     * @param indices specifying location to store at
     */
    void storeAt(byte value, int... indices) throws IndexOutOfBoundsException;

    // Bulk access in one dimension
    //
    /**
     * Copy the contents of the buffer to the destination byte array. The number of bytes will be
     * that returned by {@link #getLen()}, and the order is the storage order in the exporter.
     * (Note: Correct ordering for multidimensional arrays, including those with indirection needs
     * further study.)
     *
     * @param dest destination byte array
     * @param destPos byte-index in the destination array of the byte [0]
     * @throws IndexOutOfBoundsException if the destination cannot hold it
     */
    void copyTo(byte[] dest, int destPos) throws IndexOutOfBoundsException, PyException;

    /**
     * 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.
     *
     * @param srcIndex starting item-index in the source buffer
     * @param dest destination byte array
     * @param destPos byte-index in the destination array of the source item [0,...]
     * @param count number of items to copy
     * @throws IndexOutOfBoundsException if access out of bounds in source or destination
     */
    void copyTo(int srcIndex, byte[] dest, int destPos, int count)     // mimic arraycopy args
            throws IndexOutOfBoundsException, PyException;

    /**
     * Copy from a slice of a (Java) byte array into the buffer starting at a given destination
     * item-index. This may validly be done only for a one-dimensional buffer, as the meaning of the
     * destination index is not otherwise defined. count*itemsize bytes will be read
     * from the source.
     *
     * @param src source byte array
     * @param srcPos location in source of first byte to copy
     * @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
     */
    void copyFrom(byte[] src, int srcPos, int destIndex, int count)    // mimic arraycopy args
            throws IndexOutOfBoundsException, PyException;

    /**
     * Copy the whole of another PyBuffer into this buffer. This may validly be done
     * only for buffers that are consistent in their dimensions. When it is necessary to copy
     * partial buffers, this may be achieved using a buffer slice on the source or destination.
     *
     * @param src source buffer
     * @throws IndexOutOfBoundsException if access out of bounds in source or destination
     * @throws PyException {@code TypeError} if read-only buffer
     */
    void copyFrom(PyBuffer src) throws IndexOutOfBoundsException, PyException;

    // Bulk access in n-dimensions may be added here if desired semantics can be settled
    //

    // Buffer management
    //
    /**
     * {@inheritDoc}
     * 

* When a PyBuffer is the target, the same checks are carried out on the consumer * flags, and a return will normally be a reference to that buffer. A Jython * PyBuffer keeps count of these re-exports in order to match them with the number * of calls to {@link #release()}. When the last matching release() arrives it is * considered "final", and release actions may then take place on the exporting object. After * the final release of a buffer, a call to getBuffer should raise an exception. */ @Override PyBuffer getBuffer(int flags) throws PyException; /** * A buffer is (usually) a view onto to the internal state of an exporting object, and that * object may have to restrict its behaviour while the buffer exists. The consumer must * therefore say when it has finished with the buffer if the exporting object is to be released * from this constraint. Each consumer that obtains a reference to a buffer by means of a call * to {@link BufferProtocol#getBuffer(int)} or {@link PyBuffer#getBuffer(int)} should make a * matching call to {@link #release()}. The consumer may be sharing the PyBuffer * with other consumers and the buffer uses the pairing of getBuffer and * release to manage the lock on behalf of the exporter. It is an error to make * more than one call to release for a single call to getBuffer. */ void release(); /** An alias for {@link #release()} to satisfy {@link AutoCloseable}. */ @Override void close(); /** * True only if the buffer has been released with (the required number of calls to) * {@link #release()} or some equivalent operation. The consumer may be sharing the reference * with other consumers and the buffer only achieves the released state when all consumers who * called getBuffer have called release. */ boolean isReleased(); /** * Equivalent to {@link #getBufferSlice(int, int, int, int)} with stride 1. * * @param flags specifying features demanded and the navigational capabilities of the consumer * @param start index in the current buffer * @param count number of items in the required slice * @return a buffer representing the slice */ public PyBuffer getBufferSlice(int flags, int start, int count); /** * 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 {@link PyBuffer#release} just as if it had been obtained with * {@link 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. * * @param flags specifying features demanded and the navigational capabilities of the consumer * @param start index in the current buffer * @param count number of items in the required slice * @param stride index-distance in the current buffer between consecutive items in the slice * @return a buffer representing the slice */ public PyBuffer getBufferSlice(int flags, int start, int count, int stride); // Access to underlying byte-oriented storage // /** * 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 {@link #byteAt(int)}) and the byte-index (as used with the * ByteBuffer returned by {@link #getNIOByteBuffer()}). See * {@link #byteIndex(int[])} for discussion of the multi-dimensional case. * * @param index item-index from consumer * @return corresponding byte-index in actual storage */ // Should it throw IndexOutOfBoundsException if the index <0 or ≥shape[0]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 {@link #byteAt(int...)} and the byte-index (as used with the * ByteBuffer returned by {@link #getNIOByteBuffer()}). * * @param indices n-dimensional item-index from consumer * @return corresponding byte-index in actual storage */ // Should it throw IndexOutOfBoundsException if any index <0 or ≥shape[i]? int byteIndex(int... indices); /** * Obtain a {@link java.nio.ByteBuffer} giving access to the bytes that hold the data being * exported by the original object. The position of the buffer is at the first byte of the item * with zero index (quite possibly not the lowest valid byte-index), the limit of the buffer is * beyond the largest valid byte index, and the mark is undefined. *

* For a one-dimensional contiguous buffer, the limit is one byte beyond the last item, so that * consecutive reads from the ByteBuffer return the data in order. Assuming the * following client code where obj has type BufferProtocol: * *

     * PyBuffer a = obj.getBuffer(PyBUF.SIMPLE);
     * int itemsize = a.getItemsize();
     * ByteBuffer bb = a.getNIOBuffer();
     * 
* * the item with index k is in bb at positions * bb.pos()+k*itemsize to bb.pos()+(k+1)*itemsize - 1 inclusive. And * if itemsize==1, the item is simply the byte at position bb.pos()+k. *

* If the buffer is multidimensional or non-contiguous (strided), the buffer position is still * the (first byte of) the item at index [0] or [0,...,0]. However, it * is necessary to navigate bb using the shape, strides * and maybe suboffsets provided by the API. * * @return a ByteBuffer onto the exported data contents. */ ByteBuffer getNIOByteBuffer(); /** * Report whether the exporter is able to offer direct access to the exported storage as a Java * byte array (through the API that involves class {@link Pointer}), or only supports the * abstract API. See also {@link PyBUF#AS_ARRAY}. * * @return true if array access is supported, false if it is not. */ boolean hasArray(); // Direct access to actual storage (deprecated) // /** * A class that references a byte[] array and a particular offset within it, as the * return type for methods that give direct access to byte-oriented data exported by a Python * object. In some contexts the consumer will be entitled to make changes to the contents of * this array, and in others not. See {@link PyBuffer#isReadonly()}. It is used by the Jython * buffer API roughly where the CPython buffer API uses a C (char *) pointer. */ @Deprecated public static class Pointer { /** Reference to the array holding the bytes. */ public byte[] storage; /** Starting position within the array for the data being pointed to. */ public int offset; /** * Construct a reference to the given array and offset. * * @param storage array at reference * @param offset index of the reference byte */ public Pointer(byte[] storage, int offset) { this.storage = storage; this.offset = offset; } } /** * 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. * * @return structure defining the byte[] slice that is the shared data */ PyBuffer.Pointer getBuf(); /** * 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. * * @param index in the buffer to position the pointer * @return structure defining the byte[] slice that is the shared data */ 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, 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]. * * @param indices multidimensional index at which to position the pointer * @return structure defining the byte[] slice that is the shared data */ PyBuffer.Pointer getPointer(int... indices); // Inherited from PyBUF and belonging here // // int[] getStrides(); // int[] getSuboffsets(); // boolean isContiguous(char order); // Interpretation of bytes as items /** * A format string in the language of Python structs describing how the bytes of each item * should be interpreted. Irrespective of the {@link PyBUF#FORMAT} bit in the consumer's call to * getBuffer, a valid format string is always returned (difference * from CPython). *

* Jython only implements "B" so far, and it is debatable whether anything fancier than * "<n>B" can be supported in Java. * * @return the format string */ String getFormat(); // Inherited from PyBUF and belonging here // // int getItemsize(); /** * The toString() method of a buffer reproduces the byte values in the buffer (treated as * unsigned integers) as the character codes of a String. */ @Override public String toString(); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy