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

org.python.core.PyArray 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.

There is a newer version: 2.7.4
Show newest version
// Copyright (c) Corporation for National Research Initiatives
package org.python.core;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.lang.reflect.Array;
import java.nio.ByteBuffer;

import org.python.core.buffer.BaseBuffer;
import org.python.core.buffer.SimpleBuffer;
import org.python.core.buffer.SimpleStringBuffer;
import org.python.core.util.ByteSwapper;
import org.python.core.util.StringUtil;
import org.python.expose.ExposedGet;
import org.python.expose.ExposedMethod;
import org.python.expose.ExposedNew;
import org.python.expose.ExposedType;
import org.python.expose.MethodType;
import org.python.modules.gc;

/**
 * A wrapper class around native java arrays.
 *
 * Instances of PyArray are created either by java functions or directly by the jarray module.
 * 

* See also the jarray module. */ @ExposedType(name = "array.array", base = PyObject.class) public class PyArray extends PySequence implements Cloneable, BufferProtocol, Traverseproc { public static final PyType TYPE = PyType.fromClass(PyArray.class); /** The underlying Java array. */ private Object data; /** The Java array class. */ private Class type; /** The Python style typecode of the array. */ private String typecode; private ArrayDelegate delegate; public PyArray(PyType type) { super(type); } public PyArray(Class type, Object data) { this(TYPE); setup(type, data); } public PyArray(Class type, PyObject initial) { this(TYPE); this.type = type; typecode = class2char(type); data = Array.newInstance(type, 0); delegate = new ArrayDelegate(); useInitial(initial); } public PyArray(Class type, int n) { this(type, Array.newInstance(type, n)); } public PyArray(PyArray toCopy) { this(toCopy.type, toCopy.delegate.copyArray()); typecode = toCopy.typecode; } private void setup(Class type, Object data) { this.type = type; typecode = class2char(type); if (data == null) { this.data = Array.newInstance(type, 0); } else { this.data = data; } delegate = new ArrayDelegate(); } private void useInitial(PyObject initial) { /* * The initialiser may be omitted, or may validly be one of several types in the broad * categories of a byte string (which is treated as a machine representation of the data) or * an iterable yielding values assignable to the elements. There is special treatment for * type 'u' Unicode. */ if (initial == null) { // Fall through } else if (initial instanceof PyList) { fromlist(initial); } else if (initial instanceof PyString && !(initial instanceof PyUnicode)) { fromstring(initial.toString()); } else if ("u".equals(typecode)) { if (initial instanceof PyUnicode) { extendArray(((PyUnicode)initial).toCodePoints()); } else { extendUnicodeIter(initial); } } else { extendInternal(initial); } } @ExposedNew static final PyObject array_new(PyNewWrapper new_, boolean init, PyType subtype, PyObject[] args, String[] keywords) { if (new_.for_type != subtype && keywords.length > 0) { /* * We're constructing as a base for a derived type (via PyDerived) and there are * keywords. The effective args locally should not include the keywords. */ int argc = args.length - keywords.length; PyObject[] justArgs = new PyObject[argc]; System.arraycopy(args, 0, justArgs, 0, argc); args = justArgs; } // Build the argument parser for this call ArgParser ap = new ArgParser("array", args, Py.NoKeywords, new String[] {"typecode", "initializer"}, 1); ap.noKeywords(); // Retrieve the mandatory type code that determines the element type PyObject obj = ap.getPyObject(0); Class type; String typecode; if (obj instanceof PyString && !(obj instanceof PyUnicode)) { if (obj.__len__() != 1) { throw Py.TypeError("array() argument 1 must be char, not str"); } typecode = obj.toString(); type = char2class(typecode.charAt(0)); } else if (obj instanceof PyJavaType) { type = ((PyJavaType)obj).getProxyType(); typecode = type.getName(); } else { throw Py.TypeError("array() argument 1 must be char, not " + obj.getType().fastGetName()); } /* * Create a 'blank canvas' of the appropriate concrete class. */ PyArray self; if (new_.for_type == subtype) { self = new PyArray(subtype); } else { self = new PyArrayDerived(subtype); } // Initialize the typecode (and validate type) before creating the backing Array class2char(type); self.setup(type, Array.newInstance(type, 0)); self.typecode = typecode; self.useInitial(ap.getPyObject(1, null)); return self; } public static PyArray zeros(int n, char typecode) { PyArray array = zeros(n, char2class(typecode)); array.typecode = Character.toString(typecode); return array; } public static PyArray zeros(int n, Class ctype) { PyArray array = new PyArray(ctype, n); array.typecode = ctype.getName(); return array; } public static PyArray array(PyObject seq, char typecode) { PyArray array = PyArray.array(seq, char2class(typecode)); array.typecode = Character.toString(typecode); return array; } public static Class array_class(Class type) { return Array.newInstance(type, 0).getClass(); } /** * Create a PyArray storing ctype types and being initialised with * init. * * @param init an initialiser for the array - can be PyString or PySequence (including PyArray) * or iterable type. * @param ctype Class type of the elements stored in the array. * @return a new PyArray */ public static PyArray array(PyObject init, Class ctype) { PyArray array = new PyArray(ctype, 0); array.typecode = ctype.getName(); array.extendInternal(init); return array; } @ExposedMethod(type = MethodType.BINARY) final PyObject array___ne__(PyObject o) { return seq___ne__(o); } @ExposedMethod(type = MethodType.BINARY) final PyObject array___eq__(PyObject o) { return seq___eq__(o); } @Override public int hashCode() { return array___hash__(); } @ExposedMethod final int array___hash__() { throw Py.TypeError(String.format("unhashable type: '%.200s'", getType().fastGetName())); } @ExposedMethod(type = MethodType.BINARY) final PyObject array___lt__(PyObject o) { return seq___lt__(o); } @ExposedMethod(type = MethodType.BINARY) final PyObject array___le__(PyObject o) { return seq___le__(o); } @ExposedMethod(type = MethodType.BINARY) final PyObject array___gt__(PyObject o) { return seq___gt__(o); } @ExposedMethod(type = MethodType.BINARY) final PyObject array___ge__(PyObject o) { return seq___ge__(o); } @ExposedMethod final boolean array___contains__(PyObject o) { return object___contains__(o); } @ExposedMethod final void array___delitem__(PyObject index) { seq___delitem__(index); } @ExposedMethod final void array___setitem__(PyObject o, PyObject def) { seq___setitem__(o, def); } @ExposedMethod final PyObject array___getitem__(PyObject o) { PyObject ret = seq___finditem__(o); if (ret == null) { throw Py.IndexError("index out of range: " + o); } return ret; } @ExposedMethod final boolean array___nonzero__() { return seq___nonzero__(); } @ExposedMethod public PyObject array___iter__() { return seq___iter__(); } @ExposedMethod(defaults = "null") final PyObject array___getslice__(PyObject start, PyObject stop, PyObject step) { return seq___getslice__(start, stop, step); } @ExposedMethod(defaults = "null") final void array___setslice__(PyObject start, PyObject stop, PyObject step, PyObject value) { seq___setslice__(start, stop, step, value); } @ExposedMethod(defaults = "null") final void array___delslice__(PyObject start, PyObject stop, PyObject step) { seq___delslice__(start, stop, step); } @Override public PyObject __imul__(PyObject o) { return array___imul__(o); } @ExposedMethod(type = MethodType.BINARY) final PyObject array___imul__(PyObject o) { if (!o.isIndex()) { return null; } resizeCheck(); // Prohibited if exporting a buffer if (delegate.getSize() > 0) { int count = o.asIndex(Py.OverflowError); if (count <= 0) { delegate.clear(); return this; } Object copy = delegate.copyArray(); delegate.ensureCapacity(delegate.getSize() * count); for (int i = 1; i < count; i++) { delegate.appendArray(copy); } } return this; } @Override public PyObject __mul__(PyObject o) { return array___mul__(o); } @ExposedMethod(type = MethodType.BINARY) final PyObject array___mul__(PyObject o) { if (!o.isIndex()) { return null; } return repeat(o.asIndex(Py.OverflowError)); } @Override public PyObject __rmul__(PyObject o) { return array___rmul__(o); } @ExposedMethod(type = MethodType.BINARY) final PyObject array___rmul__(PyObject o) { if (!o.isIndex()) { return null; } return repeat(o.asIndex(Py.OverflowError)); } @Override public PyObject __iadd__(PyObject other) { return array___iadd__(other); } @ExposedMethod(type = MethodType.BINARY) final PyObject array___iadd__(PyObject other) { if (!(other instanceof PyArray)) { return null; } PyArray otherArr = (PyArray)other; if (!otherArr.typecode.equals(this.typecode)) { throw Py.TypeError("can only append arrays of the same type, expected '" + this.type + ", found " + otherArr.type); } resizeCheck(); // Prohibited if exporting a buffer delegate.appendArray(otherArr.delegate.copyArray()); return this; } @Override public PyObject __add__(PyObject other) { return array___add__(other); } /** * Adds (appends) two PyArrays together * * @param other a PyArray to be added to the instance * @return the result of the addition as a new PyArray instance */ @ExposedMethod(type = MethodType.BINARY) final PyObject array___add__(PyObject other) { if (!(other instanceof PyArray)) { return null; } PyArray otherArr = (PyArray)other; if (!otherArr.typecode.equals(this.typecode)) { throw Py.TypeError("can only append arrays of the same type, expected '" + this.type + "', found '" + otherArr.type + "'"); } PyArray ret = new PyArray(this); ret.delegate.appendArray(otherArr.delegate.copyArray()); return ret; } /** * Length of the array * * @return number of elements in the array */ @Override public int __len__() { return array___len__(); } @ExposedMethod final int array___len__() { return delegate.getSize(); } @Override public PyObject __reduce__() { return array___reduce__(); } @ExposedMethod final PyObject array___reduce__() { PyObject dict = __findattr__("__dict__"); if (dict == null) { dict = Py.None; } if (__len__() > 0) { return new PyTuple(getType(), new PyTuple(Py.newString(typecode), Py.newString(tostring())), dict); } else { return new PyTuple(getType(), new PyTuple(Py.newString(typecode)), dict); } } @Override public String toString() { if (__len__() == 0) { return String.format("array(%s)", encodeTypecode(typecode)); } String value; if ("c".equals(typecode)) { value = PyString.encode_UnicodeEscape(tostring(), true); } else if ("u".equals(typecode)) { value = (new PyUnicode(tounicode())).__repr__().toString(); } else { value = tolist().toString(); } return String.format("array(%s, %s)", encodeTypecode(typecode), value); } private String encodeTypecode(String typecode) { if (typecode.length() > 1) { return typecode; } else { return "'" + typecode + "'"; } } /** * * @param c target Class for the conversion * @return Java object converted to required class type if possible. */ @Override public Object __tojava__(Class c) { boolean isArray = c.isArray(); Class componentType = c.getComponentType(); if (c == Object.class || (isArray && componentType.isAssignableFrom(type))) { if (delegate.capacity != delegate.size) { // when unboxing, need to shrink the array first, otherwise incorrect // results to Java return delegate.copyArray(); } else { return data; } } // rebox: this array is made of primitives but converting to Object[] if (isArray && componentType == Object.class) { Object[] boxed = new Object[delegate.size]; for (int i = 0; i < delegate.size; i++) { boxed[i] = Array.get(data, i); } return boxed; } if (c.isInstance(this)) { return this; } return Py.NoConversion; } @ExposedMethod public final void array_append(PyObject value) { resizeCheck(); // Prohibited if exporting a buffer appendUnchecked(value); } private static int getCodePoint(PyObject obj) { if (obj instanceof PyUnicode) { PyUnicode u = (PyUnicode)obj; int[] codepoints = u.toCodePoints(); if (codepoints.length == 1) { return codepoints[0]; } } throw Py.TypeError("array item must be unicode character"); } // relax to allow mixing with PyString, integers private static int getCodePointOrInt(PyObject obj) { if (obj instanceof PyUnicode) { PyUnicode u = (PyUnicode)obj; return u.toCodePoints()[0]; } else if (obj instanceof PyString) { PyString s = (PyString)obj; return s.toString().charAt(0); } else if (obj.__nonzero__()) { return obj.asInt(); } else { return -1; } } /** * Append new value x to the end of the array. * * @param value item to be appended to the array */ public void append(PyObject value) { resizeCheck(); // Prohibited if exporting a buffer appendUnchecked(value); } /** * Common helper method used internally to append a new value x to the end of the array: * {@link #resizeCheck()} is not called, so the client must do so in advance. * * @param value item to be appended to the array */ private final void appendUnchecked(PyObject value) { // Currently, append is asymmetric with extend, which // *will* do conversions like append(5.0) to an int array. // Also, CPython 2.2 will do the append coercion. However, // it is deprecated in CPython 2.3, so maybe we are just // ahead of our time ;-) int afterLast = delegate.getSize(); if ("u".equals(typecode)) { int codepoint = getCodePoint(value); delegate.makeInsertSpace(afterLast); Array.setInt(data, afterLast, codepoint); } else { delegate.makeInsertSpace(afterLast); try { set(afterLast, value); } catch (PyException e) { delegate.setSize(afterLast); throw new PyException(e.type, e.value); } } } @ExposedMethod public void array_byteswap() { byteswap(); } /** * "Byteswap" all items of the array. This is only supported for values which are 1, 2, 4, or 8 * bytes in size; for other types of values, RuntimeError is raised. It is useful when reading * data from a file written on a machine with a different byte order. */ public void byteswap() { if (getStorageSize() == 0 || "u".equals(typecode)) { throw Py.RuntimeError("don't know how to byteswap this array type"); } ByteSwapper.swap(data); } /** * Implementation of Cloneable interface. * * @return copy of current PyArray */ @Override public Object clone() { return new PyArray(this); } /** * Converts a character code for the array type to a Java Class. *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Supported character codes and their native types
Type codenative type
zboolean
cchar
bbyte
hshort
iint
llong
ffloat
ddouble
*

* * @param type character code for the array type * @return Class of the native type */ // promote B, H, I (unsigned int) to next larger size public static Class char2class(char type) throws PyIgnoreMethodTag { switch (type) { case 'z': return Boolean.TYPE; case 'b': return Byte.TYPE; case 'B': return Short.TYPE; case 'u': return Integer.TYPE; case 'c': return Character.TYPE; case 'h': return Short.TYPE; case 'H': return Integer.TYPE; case 'i': return Integer.TYPE; case 'I': return Long.TYPE; case 'l': return Long.TYPE; case 'L': return Long.TYPE; case 'f': return Float.TYPE; case 'd': return Double.TYPE; default: throw Py.ValueError("bad typecode (must be c, b, B, u, h, H, i, I, l, L, f or d)"); } } private static String class2char(Class cls) { if (cls.equals(Boolean.TYPE)) { return "z"; } else if (cls.equals(Character.TYPE)) { return "c"; } else if (cls.equals(Byte.TYPE)) { return "b"; } else if (cls.equals(Short.TYPE)) { return "h"; } else if (cls.equals(Integer.TYPE)) { return "i"; } else if (cls.equals(Long.TYPE)) { return "l"; } else if (cls.equals(Float.TYPE)) { return "f"; } else if (cls.equals(Double.TYPE)) { return "d"; } else { return cls.getName(); } } @ExposedMethod public final int array_count(PyObject value) { // note: cpython does not raise type errors based on item type; int iCount = 0; int len = delegate.getSize(); if ("u".equals(typecode)) { int codepoint = getCodePointOrInt(value); for (int i = 0; i < len; i++) { if (codepoint == Array.getInt(data, i)) { iCount++; } } } else { for (int i = 0; i < len; i++) { if (value.equals(Py.java2py(Array.get(data, i)))) { iCount++; } } } return iCount; } /** * Return the number of occurrences of x in the array. * * @param value instances of the value to be counted * @return number of time value was found in the array. */ public PyInteger count(PyObject value) { return Py.newInteger(array_count(value)); } /** * Delete the element at position i from the array * * @param i index of the item to be deleted from the array */ @Override protected void del(int i) { resizeCheck(); // Prohibited if exporting a buffer delegate.remove(i); } /** * Delete the slice defined by start to stop from the array. * * @param start starting index of slice * @param stop finishing index of slice */ @Override protected void delRange(int start, int stop) { resizeCheck(); // Prohibited if exporting a buffer delegate.remove(start, stop); } @ExposedMethod public final void array_extend(PyObject iterable) { extendInternal(iterable); } /** * Append items from iterable to the end of the array. If iterable is another * array, it must have exactly the same type code; if not, TypeError will be raised. If iterable * is not an array, it must be iterable and its elements must be the right type to be appended * to the array. * * @param iterable iterable object used to extend the array */ public void extend(PyObject iterable) { extendInternal(iterable); } /** * Internal extend function, provides basic interface for extending arrays. Handles specific * cases of iterable being PyStrings or PyArrays. Default behaviour is to defer to * {@link #extendInternalIter(PyObject) extendInternalIter } * * @param iterable object of type PyString, PyArray or any object that can be iterated over. */ private void extendInternal(PyObject iterable) { if (iterable instanceof PyUnicode) { if ("u".equals(typecode)) { extendUnicodeIter(iterable); } else if ("c".equals(typecode)) { throw Py.TypeError("array item must be char"); } else { throw Py.TypeError("an integer is required"); } // } else if (iterable instanceof PyString) { // // XXX CPython treats a str/bytes as an iterable, not as previously here: // fromstring(((PyString)iterable).toString()); } else if (iterable instanceof PyArray) { PyArray source = (PyArray)iterable; if (!source.typecode.equals(typecode)) { throw Py.TypeError("can only extend with array of same kind"); } resizeCheck(); // Prohibited if exporting a buffer delegate.appendArray(source.delegate.copyArray()); } else { extendInternalIter(iterable); } } /** * Internal extend function to process iterable objects. * * @param iterable any object that can be iterated over. */ private void extendInternalIter(PyObject iterable) { // Prohibited operation if exporting a buffer resizeCheck(); if (iterable.__findattr__("__len__") != null) { // Make room according to source length int last = delegate.getSize(); delegate.ensureCapacity(last + iterable.__len__()); for (PyObject item : iterable.asIterable()) { set(last++, item); delegate.size++; } } else { // iterable has no length property: cannot size the array so append each item. for (PyObject item : iterable.asIterable()) { appendUnchecked(item); // we already did a resizeCheck } } } /** * Helper used only when the array elements are Unicode characters (typecode=='u'). * (Characters are stored as integer point codes.) The parameter must be an iterable yielding * PyUnicodes. Often this will be an instance of {@link PyUnicode}, which is an * iterable yielding single-character PyUnicodes. But it is also acceptable to this * method for the argument to yield arbitrary PyUnicodes, which will be * concatenated in the array. * * @param iterable of PyUnicodes */ private void extendUnicodeIter(PyObject iterable) { // Prohibited operation if exporting a buffer resizeCheck(); try { // Append all the code points of all the strings in the iterable for (PyObject item : iterable.asIterable()) { PyUnicode uitem = (PyUnicode)item; // Append all the code points of this item for (int codepoint : uitem.toCodePoints()) { int afterLast = delegate.getSize(); delegate.makeInsertSpace(afterLast); Array.setInt(data, afterLast, codepoint); } } } catch (ClassCastException e) { // One of the PyUnicodes wasn't throw Py.TypeError("Type not compatible with array type"); } } private void extendArray(int[] items) { // Prohibited operation if exporting a buffer resizeCheck(); int last = delegate.getSize(); delegate.ensureCapacity(last + items.length); for (int item : items) { Array.set(data, last++, item); delegate.size++; } } @ExposedMethod public final void array_fromfile(PyObject f, int count) { fromfile(f, count); } /** * Read count items (as machine values) from the file object f and * append them to the end of the array. If less than count items are available, * EOFError is raised, but the items that were available are still inserted into the array. * f must be a real built-in file object; something else with a read() method won't * do. * * @param f Python builtin file object to retrieve data * @param count number of array elements to read */ public void fromfile(PyObject f, int count) { /* * Prohibit when exporting a buffer. Different from CPython, BufferError takes precedence in * Jython over EOFError: if there's nowhere to write the data, we don't read it. */ resizeCheck(); /* * Now get the required number of bytes from the file. Guard against non-file or closed. */ if (f instanceof PyFile) { PyFile file = (PyFile)f; if (!file.getClosed()) { // Load required amount or whatever is available into a bytes object int readbytes = count * getStorageSize(); String buffer = file.read(readbytes).toString(); fromstring(buffer); // check for underflow if (buffer.length() < readbytes) { int readcount = buffer.length() / getStorageSize(); throw Py.EOFError("not enough items in file. " + Integer.toString(count) + " requested, " + Integer.toString(readcount) + " actually read"); } } return; } throw Py.TypeError("arg1 must be open file"); } @ExposedMethod public final void array_fromlist(PyObject obj) { fromlist(obj); } /** * Append items from the list. This is equivalent to "for x in list: a.append(x)" except that if * there is a type error, the array is unchanged. * * @param obj input list object that will be appended to the array */ public void fromlist(PyObject obj) { if (!(obj instanceof PyList)) { throw Py.TypeError("arg must be list"); } // Prohibited operation if exporting a buffer resizeCheck(); // store the current size of the internal array int size = delegate.getSize(); try { extendInternalIter(obj); } catch (PyException e) { // trap any exception - any error invalidates the whole list delegate.setSize(size); // re-throw throw new PyException(e.type, e.value); } } /** * Generic stream reader to read the entire contents of a stream into the array. * * @param is InputStream to source the data from * * @return number of primitives successfully read * * @throws IOException * @throws EOFException */ private int fromStream(InputStream is) throws IOException, EOFException { return fromStream(is, is.available() / getStorageSize()); } /** * Generic stream reader to read count primitive types from a stream into the * array. * * @param is InputStream to source the data from * @param count number of primitive types to read from the stream * * @return number of primitives successfully read * * @throws IOException * @throws EOFException */ private int fromStream(InputStream is, int count) throws IOException, EOFException { // Current number of items present int origsize = delegate.getSize(); // Read into the array, after the current contents, up to new size (or EOF thrown) int n = fromStream(is, origsize, origsize + count, true); return n - origsize; } /** * Read primitive values from a stream into the array without resizing. Data is read until the * array is filled or the stream runs out. If the stream does not contain a whole number of * items (possible if the item size is not one byte), the behaviour in respect of the final * partial item and straem position is not defined. * * @param is InputStream to source the data from * @return number of primitives successfully read * @throws IOException reflecting I/O errors during reading */ public int fillFromStream(InputStream is) throws IOException { return fromStream(is, 0, delegate.size, false); } /** * Helper for reading primitive values from a stream into a slice of the array. Data is read * until the array slice is filled or the stream runs out. The purpose of the method is to * concentrate in one place the manipulation of bytes into the several primitive element types * on behalf of {@link #fillFromStream(InputStream)} etc.. The storage is resized if the slice * being written ends beyond the current end of the array, i.e. it is increased to the value of * limit. *

* Since different read methods respond differently to it, the caller must specify whether the * exhaustion of the stream (EOF) should be treated as an error or not. If the stream does not * contain a whole number of items (possible if the item size is not one byte), the behaviour in * respect of the final partial item and stream position is not defined. * * @param dis data stream source for the values * @param index first element index to read * @param limit first element index not to read * @param eofIsError if true, treat EOF as expected way to end * @return index of first element not read (=limit, if not ended by EOF) * @throws IOException reflecting I/O errors during reading * @throws EOFException if stream ends before read is satisfied and eofIsError is true */ private int fromStream(InputStream is, int index, int limit, boolean eofIsError) throws IOException, EOFException { // Ensure the array is dimensioned to fit the data expected if (limit > delegate.getSize()) { // Prohibited operation if exporting a buffer resizeCheck(); delegate.setSize(limit); } // We need a wrapper capable of decoding the data from the representation defined by Java. DataInputStream dis = new DataInputStream(is); try { // We have to deal with each primitive type as a distinct case if (type.isPrimitive()) { switch (typecode.charAt(0)) { case 'z': for (; index < limit; index++) { Array.setBoolean(data, index, dis.readBoolean()); } break; case 'b': for (; index < limit; index++) { Array.setByte(data, index, dis.readByte()); } break; case 'B': for (; index < limit; index++) { Array.setShort(data, index, unsignedByte(dis.readByte())); } break; case 'u': // use 32-bit integers since we want UCS-4 storage for (; index < limit; index++) { Array.setInt(data, index, dis.readInt()); } break; case 'c': for (; index < limit; index++) { Array.setChar(data, index, (char)(dis.readByte() & 0xff)); } break; case 'h': for (; index < limit; index++) { Array.setShort(data, index, dis.readShort()); } break; case 'H': for (; index < limit; index++) { Array.setInt(data, index, unsignedShort(dis.readShort())); } break; case 'i': for (; index < limit; index++) { Array.setInt(data, index, dis.readInt()); } break; case 'I': for (; index < limit; index++) { Array.setLong(data, index, unsignedInt(dis.readInt())); } break; case 'l': for (; index < limit; index++) { Array.setLong(data, index, dis.readLong()); } break; case 'L': // faking it for (; index < limit; index++) { Array.setLong(data, index, dis.readLong()); } break; case 'f': for (; index < limit; index++) { Array.setFloat(data, index, dis.readFloat()); } break; case 'd': for (; index < limit; index++) { Array.setDouble(data, index, dis.readDouble()); } break; } } } catch (EOFException eof) { if (eofIsError) { throw eof; } // EOF = end of reading: excess odd bytes read inside dis.readXXX() discarded } // index points to the first element *not* written return index; } /** * Appends items from the object, which is a byte string of some kind (PyString or object with * the buffer interface providing bytes) The string of bytes is interpreted as an array of * machine values (as if it had been read from a file using the {@link #fromfile(PyObject, int) * fromfile()} method). * * @param input string of bytes containing array data */ public void fromstring(PyObject input) { array_fromstring(input); } /** * Appends items from the string, interpreting the string as an array of machine values (as if * it had been read from a file using the {@link #fromfile(PyObject, int) fromfile()} method). * * @param input string of bytes containing array data */ public void fromstring(String input) { frombytesInternal(StringUtil.toBytes(input)); } /** * Appends items from the string, interpreting the string as an array of machine values (as if * it had been read from a file using the {@link #fromfile(PyObject, int) fromfile()} method). * * @param input string of bytes containing array data */ @ExposedMethod final void array_fromstring(PyObject input) { if (input instanceof BufferProtocol) { if (input instanceof PyUnicode) { // Unicode is treated as specifying a byte string via the default encoding. String s = ((PyUnicode)input).encode(); frombytesInternal(StringUtil.toBytes(s)); } else { // Access the bytes through the abstract API of the BufferProtocol try (PyBuffer pybuf = ((BufferProtocol)input).getBuffer(PyBUF.STRIDED_RO)) { if (pybuf.getNdim() == 1) { if (pybuf.getStrides()[0] == 1) { // Data are contiguous in the buffer frombytesInternal(pybuf.getNIOByteBuffer()); } else { // As frombytesInternal only knows contiguous bytes, make a copy. byte[] copy = new byte[pybuf.getLen()]; pybuf.copyTo(copy, 0); frombytesInternal(ByteBuffer.wrap(copy)); } } else { // Currently don't support n-dimensional sources throw Py.ValueError("multi-dimensional buffer not supported"); } } } } else { String fmt = "must be string or read-only buffer, not %s"; throw Py.TypeError(String.format(fmt, input.getType().fastGetName())); } } /** * Common code supporting Java and Python versions of .fromstring() or * .frombytes() (Python 3.2+ name). * * @param bytes array containing the new array data in machine encoding */ private final void frombytesInternal(byte[] bytes) { frombytesInternal(ByteBuffer.wrap(bytes)); } /** * Copy into this array, the remaining bytes of a ByteBuffer (from the current position to the * limit). This is common code supporting Java and Python versions of .fromstring() * or .frombytes() (Python 3.2+ name). * * @param bytes buffer containing the new array data in machine encoding */ private final void frombytesInternal(ByteBuffer bytes) { // Access the bytes int origsize = delegate.getSize(); // Check validity wrt array itemsize int itemsize = getStorageSize(); int count = bytes.remaining(); if ((count % itemsize) != 0) { throw Py.ValueError("string length not a multiple of item size"); } // Prohibited operation if we are exporting a buffer resizeCheck(); try { // Provide argument as stream of bytes for fromstream method InputStream is = new ByteBufferBackedInputStream(bytes); fromStream(is); } catch (EOFException e) { // stubbed catch for fromStream throws throw Py.EOFError("not enough items in string"); } catch (IOException e) { // discard anything successfully loaded delegate.setSize(origsize); throw Py.IOError(e); } } public void fromunicode(PyUnicode input) { array_fromunicode(input); } @ExposedMethod final void array_fromunicode(PyObject input) { if (!(input instanceof PyUnicode)) { throw Py.ValueError("fromunicode argument must be an unicode object"); } if (!"u".equals(typecode)) { throw Py.ValueError("fromunicode() may only be called on type 'u' arrays"); } extend(input); } /** * Get the element at position i from the array * * @param i index of the item to be retrieved from the array */ @Override protected PyObject pyget(int i) { if ("u".equals(typecode)) { return new PyUnicode(Array.getInt(data, i)); } return Py.java2py(Array.get(data, i)); } /** * Return the internal Java array storage of the PyArray instance * * @return the Array store. */ public Object getArray() throws PyIgnoreMethodTag { return delegate.copyArray(); } /** * Getter for the storage size of the array's type. *

* The sizes returned by this method represent the number of bytes used to store the type. In * the case of streams, this is the number of bytes written to, or read from a stream. For * memory this value is the minimum number of bytes required to store the type. *

* This method is used by other methods to define read/write quanta from strings and streams. *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Values returned
TypeSize
boolean1
byte1
char1
short2
int4
long8
float4
double8
* * @return number of bytes used to store array type. */ @ExposedGet(name = "itemsize") public int getItemsize() { if (type.isPrimitive()) { if (type == Boolean.TYPE) { return 1; } else if (type == Byte.TYPE) { return 1; } else if (type == Character.TYPE) { return 1; } else if (type == Short.TYPE) { return 2; } else if (type == Integer.TYPE) { return 4; } else if (type == Long.TYPE) { return 8; } else if (type == Float.TYPE) { return 4; } else if (type == Double.TYPE) { return 8; } } // return something here... could be a calculated size? return 0; } public int getStorageSize() { if (type.isPrimitive()) { switch (typecode.charAt(0)) { case 'z': return 1; case 'b': return 1; case 'B': return 1; case 'u': return 4; case 'c': return 1; case 'h': return 2; case 'H': return 2; case 'i': return 4; case 'I': return 4; case 'l': return 8; case 'L': return 8; case 'f': return 4; case 'd': return 8; default: throw Py.ValueError("bad typecode (must be c, b, B, u, h, H, i, I, l, L, f or d)"); } } // return something here... could be a calculated size? return 0; } /** * Retrieve a slice from the array specified by the start, stop and * step. * * @param start start index of the slice * @param stop stop index of the slice * @param step stepping increment of the slice * @return A new PyArray object containing the described slice */ @Override protected PyObject getslice(int start, int stop, int step) { if (step > 0 && stop < start) { stop = start; } int n = sliceLength(start, stop, step); PyArray ret = new PyArray(type, n); // XXX: ret.typecode = typecode; if (step == 1) { System.arraycopy(data, start, ret.data, 0, n); return ret; } for (int i = start, j = 0; j < n; i += step, j++) { Array.set(ret.data, j, Array.get(data, i)); } return ret; } /** * Getter for the type code of the array. {@link #char2class(char) char2class} describes the * possible type codes and their meaning. * * @return single character type code for the array */ @ExposedGet(name = "typecode") public String getTypecode() { return typecode; } @ExposedMethod public final int array_index(PyObject value) { int index = indexInternal(value); if (index != -1) { return index; } throw Py.ValueError("array.index(" + value + "): " + value + " not found in array"); } /** * Return the smallest i such that i is the index of the first occurrence of * value in the array. * * @param value value to find the index of * @return index of the first occurrence of value */ public PyObject index(PyObject value) { return Py.newInteger(array_index(value)); } /** * Return the smallest i such that i is the index of the first occurrence of * value in the array. * * @param value value to find the index of * @return index of the first occurrence of value */ private int indexInternal(PyObject value) { // note: cpython does not raise type errors based on item type int len = delegate.getSize(); if ("u".equals(typecode)) { int codepoint = getCodePointOrInt(value); for (int i = 0; i < len; i++) { if (codepoint == Array.getInt(data, i)) { return i; } } } else { for (int i = 0; i < len; i++) { if (value.equals(Py.java2py(Array.get(data, i)))) { return i; } } } return -1; } @ExposedMethod public final void array_insert(int index, PyObject value) { insert(index, value); } /** * Insert a new item with value value in the array before position * index. Negative values are treated as being relative to the end of the array. * * @param index insert position * @param value value to be inserted into array */ public void insert(int index, PyObject value) { resizeCheck(); // Prohibited operation if exporting a buffer index = boundToSequence(index); if ("u".equals(typecode)) { int codepoint = getCodePoint(value); delegate.makeInsertSpace(index); Array.setInt(data, index, codepoint); } else { delegate.makeInsertSpace(index); Array.set(data, index, Py.tojava(value, type)); } } /** * Removes the item at the index i from the array and returns it. The optional * argument defaults to -1, so that by default the last item is removed and returned. */ @ExposedMethod(defaults = "-1") public final PyObject array_pop(int i) { PyObject val = pop(i); if ("u".equals(typecode)) { return new PyUnicode(val.asInt()); } return val; } /** * Removes the last item from the array and return it. */ public PyObject pop() { return pop(-1); } /** * Removes the item with the index index from the array and returns it. * * @param index array location to be popped from the array * @return array element popped from index */ public PyObject pop(int index) { if (delegate.getSize() == 0) { throw Py.IndexError("pop from empty array"); } index = delegator.fixindex(index); if (index == -1) { throw Py.IndexError("pop index out of range"); } // Prohibited operation if exporting a buffer resizeCheck(); PyObject ret = Py.java2py(Array.get(data, index)); delegate.remove(index); return ret; } @ExposedMethod public final void array_remove(PyObject value) { remove(value); } /** * Remove the first occurrence of value from the array. * * @param value array value to be removed */ public void remove(PyObject value) { int index = indexInternal(value); if (index != -1) { // Prohibited operation if exporting a buffer resizeCheck(); delegate.remove(index); return; } throw Py.ValueError("array.remove(" + value + "): " + value + " not found in array"); } /** * Repeat the array count times. * * @param count number of times to repeat the array * @return A new PyArray object containing the source object repeated count times. */ @Override protected PyObject repeat(int count) { Object arraycopy = delegate.copyArray(); PyArray ret = new PyArray(type, 0); ret.typecode = typecode; for (int i = 0; i < count; i++) { ret.delegate.appendArray(arraycopy); } return ret; } @ExposedMethod public final void array_reverse() { reverse(); } /** * Reverse the elements in the array */ public void reverse() { // build a new reversed array and set this.data to it when done Object array = Array.newInstance(type, Array.getLength(data)); for (int i = 0, lastIndex = delegate.getSize() - 1; i <= lastIndex; i++) { Array.set(array, lastIndex - i, Array.get(data, i)); } data = array; } /** * Set an element in the array - the index needs to exist, this method does not automatically * extend the array. See {@link AbstractArray#setSize(int) AbstractArray.setSize()} or * {@link AbstractArray#ensureCapacity(int) AbstractArray.ensureCapacity()} for ways to extend * capacity. *

* This code specifically checks for overflows of the integral types: byte, short, int and long. * * @param i index of the element to be set * @param value value to set the element to */ public void set(int i, PyObject value) { pyset(i, value); } @Override protected void pyset(int i, PyObject value) { if ("u".equals(typecode)) { Array.setInt(data, i, getCodePoint(value)); return; } if (type == Byte.TYPE) { long val; try { val = ((Long)value.__tojava__(Long.TYPE)).longValue(); } catch (ClassCastException e) { throw Py.TypeError("Type not compatible with array type"); } if (val < (isSigned() ? 0 : Byte.MIN_VALUE)) { throw Py.OverflowError("value too small for " + type.getName()); } else if (val > Byte.MAX_VALUE) { throw Py.OverflowError("value too large for " + type.getName()); } } else if (type == Short.TYPE) { long val; try { val = ((Long)value.__tojava__(Long.TYPE)).longValue(); } catch (ClassCastException e) { throw Py.TypeError("Type not compatible with array type"); } if (val < (isSigned() ? 0 : Short.MIN_VALUE)) { throw Py.OverflowError("value too small for " + type.getName()); } else if (val > Short.MAX_VALUE) { throw Py.OverflowError("value too large for " + type.getName()); } } else if (type == Integer.TYPE) { long val; try { val = ((Long)value.__tojava__(Long.TYPE)).longValue(); } catch (ClassCastException e) { throw Py.TypeError("Type not compatible with array type"); } if (val < (isSigned() ? 0 : Integer.MIN_VALUE)) { throw Py.OverflowError("value too small for " + type.getName()); } else if (val > Integer.MAX_VALUE) { throw Py.OverflowError("value too large for " + type.getName()); } } else if (type == Long.TYPE) { if (isSigned() && value instanceof PyInteger) { if (((PyInteger)value).getValue() < 0) { throw Py.OverflowError("value too small for " + type.getName()); } } else if (value instanceof PyLong) { ((PyLong)value).getLong(isSigned() ? 0 : Long.MIN_VALUE, Long.MAX_VALUE); } else { Object o; try { o = value.__tojava__(Long.TYPE); } catch (ClassCastException e) { throw Py.TypeError("Type not compatible with array type"); } if (o == Py.NoConversion) { throw Py.TypeError("Type not compatible with array type"); } } } Object o = Py.tojava(value, type); if (o == Py.NoConversion) { throw Py.TypeError("Type not compatible with array type"); } Array.set(data, i, o); } // xxx - add more efficient comparable typecode lookup via an enumset, and expand public void set(int i, int value) { if ("u".equals(typecode) || type == Integer.TYPE || type == Long.TYPE) { Array.setInt(data, i, value); } else { throw Py.TypeError("Type not compatible with array type"); } } public void set(int i, char value) { if ("c".equals(typecode) || type == Integer.TYPE || type == Long.TYPE) { Array.setChar(data, i, value); } else { throw Py.TypeError("Type not compatible with array type"); } } private boolean isSigned() { return typecode.length() == 1 && typecode.equals(typecode.toUpperCase()); } /** * Sets a slice of the array. value can be a string (for byte and * char types) or PyArray. If a PyArray, its type must be convertible into the type * of the target PyArray. * * @param start start index of the delete slice * @param stop end index of the delete slice * @param step stepping increment of the slice */ @Override protected void setslice(int start, int stop, int step, PyObject value) { if (stop < start) { stop = start; } if (type == Character.TYPE && value instanceof PyString) { char[] chars = null; // if (value instanceof PyString) { if (step != 1) { throw Py.ValueError("invalid bounds for setting from string"); } chars = value.toString().toCharArray(); if (start + chars.length != stop) { // This is a size-changing operation: check for buffer exports resizeCheck(); } delegate.replaceSubArray(start, stop, chars, 0, chars.length); } else { if (value instanceof PyString && type == Byte.TYPE) { byte[] chars = ((PyString)value).toBytes(); if (chars.length == stop - start && step == 1) { System.arraycopy(chars, 0, data, start, chars.length); } else { throw Py.ValueError("invalid bounds for setting from string"); } } else if (value instanceof PyArray) { PyArray array = (PyArray)value; if (!array.typecode.equals(typecode)) { throw Py.TypeError("bad argument type for built-in operation|" + array.typecode + "|" + typecode); } if (step == 1) { Object arrayDelegate; if (array == this) { arrayDelegate = array.delegate.copyArray(); } else { arrayDelegate = array.delegate.getArray(); } int len = array.delegate.getSize(); if (start + len != stop) { // This is a size-changing operation: check for buffer exports resizeCheck(); } try { delegate.replaceSubArray(start, stop, arrayDelegate, 0, len); } catch (IllegalArgumentException e) { throw Py.TypeError("Slice typecode '" + array.typecode + "' is not compatible with this array (typecode '" + this.typecode + "')"); } } else if (step > 1) { int len = array.__len__(); for (int i = 0, j = 0; i < len; i++, j += step) { Array.set(data, j + start, Array.get(array.data, i)); } } else if (step < 0) { if (array == this) { array = (PyArray)array.clone(); } int len = array.__len__(); for (int i = 0, j = start; i < len; i++, j += step) { Array.set(data, j, Array.get(array.data, i)); } } } else { throw Py.TypeError(String.format("can only assign array (not \"%.200s\") to array " + "slice", value.getType().fastGetName())); } } } @ExposedMethod public final void array_tofile(PyObject f) { tofile(f); } @ExposedMethod public void array_write(PyObject f) { tofile(f); } /** * Write all items (as machine values) to the file object f. * * @param f Python builtin file object to write data */ public void tofile(PyObject f) { if (!(f instanceof PyFile)) { throw Py.TypeError("arg must be open file"); } PyFile file = (PyFile)f; file.write(tostring()); } @ExposedMethod public final PyObject array_tolist() { return tolist(); } /** * Convert the array to an ordinary list with the same items. * * @return array contents as a list */ public PyObject tolist() { PyList list = new PyList(); int len = delegate.getSize(); if ("u".equals(typecode)) { for (int i = 0; i < len; i++) { list.append(new PyUnicode(Array.getInt(data, i))); } } else { for (int i = 0; i < len; i++) { list.append(Py.java2py(Array.get(data, i))); } } return list; } /** * Generic stream writer to write the entire contents of the array to the stream as primitive * types. * * @param os OutputStream to sink the array data to * @return number of bytes successfully written * @throws IOException */ public int toStream(OutputStream os) throws IOException { DataOutputStream dos = new DataOutputStream(os); switch (typecode.charAt(0)) { case 'z': for (int i = 0; i < delegate.getSize(); i++) { dos.writeBoolean(Array.getBoolean(data, i)); } break; case 'b': for (int i = 0; i < delegate.getSize(); i++) { dos.writeByte(Array.getByte(data, i)); } break; case 'B': for (int i = 0; i < delegate.getSize(); i++) { dos.writeByte(signedByte(Array.getShort(data, i))); } break; case 'u': // use 32-bit integers since we want UCS-4 storage for (int i = 0; i < delegate.getSize(); i++) { dos.writeInt(Array.getInt(data, i)); } break; case 'c': for (int i = 0; i < delegate.getSize(); i++) { dos.writeByte((byte)Array.getChar(data, i)); } break; case 'h': for (int i = 0; i < delegate.getSize(); i++) { dos.writeShort(Array.getShort(data, i)); } break; case 'H': for (int i = 0; i < delegate.getSize(); i++) { dos.writeShort(signedShort(Array.getInt(data, i))); } break; case 'i': for (int i = 0; i < delegate.getSize(); i++) { dos.writeInt(Array.getInt(data, i)); } break; case 'I': for (int i = 0; i < delegate.getSize(); i++) { dos.writeInt(signedInt(Array.getLong(data, i))); } break; case 'l': for (int i = 0; i < delegate.getSize(); i++) { dos.writeLong(Array.getLong(data, i)); } break; case 'L': // faking it for (int i = 0; i < delegate.getSize(); i++) { dos.writeLong(Array.getLong(data, i)); } break; case 'f': for (int i = 0; i < delegate.getSize(); i++) { dos.writeFloat(Array.getFloat(data, i)); } break; case 'd': for (int i = 0; i < delegate.getSize(); i++) { dos.writeDouble(Array.getDouble(data, i)); } break; } return dos.size(); // bytes written } private static byte signedByte(short x) { if (x >= 128 && x < 256) { return (byte)(x - 256); } else if (x >= 0) { return (byte)x; } else { throw Py.ValueError("invalid storage"); } } private static short signedShort(int x) { if (x >= 32768 && x < 65536) { return (short)(x - 65536); } else if (x >= 0) { return (short)x; } else { throw Py.ValueError("invalid storage"); } } private static int signedInt(long x) { if (x >= 2147483648L && x < 4294967296L) { return (int)(x - 4294967296L); } else if (x >= 0) { return (int)x; } else { throw Py.ValueError("invalid storage"); } } private static short unsignedByte(byte x) { if (x < 0) { return (short)(x + 256); } else { return x; } } private static int unsignedShort(short x) { if (x < 0) { return x + 65536; } else { return x; } } private static long unsignedInt(int x) { if (x < 0) { return x + 4294967296L; } else { return x; } } @ExposedMethod public final PyObject array_tostring() { return new PyString(tostring()); } /** * Convert the array to an array of machine values and return the string representation (the * same sequence of bytes that would be written to a file by the {@link #tofile(PyObject) * tofile()} method.) */ public String tostring() { ByteArrayOutputStream bos = new ByteArrayOutputStream(); try { toStream(bos); } catch (IOException e) { throw Py.IOError(e); } return StringUtil.fromBytes(bos.toByteArray()); } public String tounicode() { if (!"u".equals(typecode)) { throw Py.ValueError("tounicode() may only be called on type 'u' arrays"); } int len = delegate.getSize(); int[] codepoints = new int[len]; for (int i = 0; i < len; i++) { codepoints[i] = Array.getInt(data, i); } return new String(codepoints, 0, codepoints.length); } @ExposedMethod public final PyObject array_tounicode() { return new PyUnicode(tounicode()); } // PyArray can't extend anymore, so delegate private class ArrayDelegate extends AbstractArray { private ArrayDelegate() { super(data == null ? 0 : Array.getLength(data)); } @Override protected Object getArray() { return data; } @Override protected void setArray(Object array) { data = array; } @Override protected Object createArray(int size) { Class baseType = data.getClass().getComponentType(); return Array.newInstance(baseType, size); } } /* * ============================================================================================ * Support for the Buffer API * ============================================================================================ * * The buffer API allows other classes to access the storage directly. * * This is a close duplicate of the same mechanism in PyByteArray. There is perhaps scope for a * shared helper class to implement this logic. For type code 'b', the workings are almost * identical. The fully-fledged buffer interface for PyArray is richer, more like the Python 3 * memoryview, as it must cope with items of size other than one byte. This goes beyond the * capabilities of the Jython BufferProtocol at this stage of its development. */ /** * Hold weakly a reference to a PyBuffer export not yet released, used to prevent untimely * resizing. */ private WeakReference export; /** * {@inheritDoc} *

* The {@link PyBuffer} returned from this method is a one-dimensional array of single byte * items that allows modification of the object state. The existence of this export prohibits * resizing the array. This prohibition is not only on the consumer of the view but extends * to operations on the underlying array, such as {@link #insert(int, PyObject)} or * {@link #pop()}. */ @Override public synchronized PyBuffer getBuffer(int flags) { if ((flags & ~PyBUF.WRITABLE) == PyBUF.SIMPLE) { // Client requests a flat byte-oriented read-view, typically from buffer(a). // If we have already exported a buffer it may still be available for re-use BaseBuffer pybuf = getExistingBuffer(flags); if (pybuf == null) { // No existing export we can re-use: create a new one if ("b".equals(typecode)) { // This is byte data, so we can export directly byte[] storage = (byte[]) data; int size = delegate.getSize(); pybuf = new SimpleBuffer(flags, this, storage, 0, size); } else { // As the client only intends to read, fake the answer with a String pybuf = new SimpleStringBuffer(flags, this, tostring()); } // Hold a reference for possible re-use export = new WeakReference(pybuf); } return pybuf; } else { // Client request goes beyond Python 2 capability, typically from memoryview(a). throw new ClassCastException("'array' supports only a byte-buffer view"); } } /** * Try to re-use an existing exported buffer, or return null if we can't. * * @throws PyException {@code BufferError} if the the flags are incompatible with the buffer */ private BaseBuffer getExistingBuffer(int flags) throws PyException { BaseBuffer pybuf = null; if (export != null) { // A buffer was exported at some time. pybuf = export.get(); if (pybuf != null) { /* * We do not test for pybuf.isReleased() as, if any operation had taken place that * invalidated the buffer, resizeCheck() would have set export=null. The exported * buffer (navigation, buf member, etc.) remains valid through any operation that * does not need a resizeCheck. */ pybuf = pybuf.getBufferAgain(flags); } } return pybuf; } /** * Test to see if the array may be resized and raise a BufferError if not. This must be called * by the implementation of any operation that changes the number of elements in the array. * * @throws PyException {@code BufferError} if there are buffer exports preventing a resize */ private void resizeCheck() throws PyException { if (export != null) { // A buffer was exported at some time and we have not explicitly discarded it. PyBuffer pybuf = export.get(); if (pybuf != null && !pybuf.isReleased()) { // A consumer still has the exported buffer throw Py.BufferError("cannot resize an array that is exporting buffers"); } else { /* * Either the reference has expired or all consumers have released it. Either way, * the weak reference is useless now. */ export = null; } } } /** * Wrap a ByteBuffer in an InputStream. Reference: * Stackoverflow question 4332264. */ private class ByteBufferBackedInputStream extends InputStream { ByteBuffer buf; public ByteBufferBackedInputStream(ByteBuffer buf) { this.buf = buf; } /** * Return the number of bytes remaining in the underlying buffer. */ @Override public int available() throws IOException { return buf.remaining(); } @Override public int read() { return buf.hasRemaining() ? buf.get() & 0xff : -1; } @Override public int read(byte[] bytes, int off, int len) { int n = buf.remaining(); if (n >= len) { // There are enough bytes remaining to satisfy the request. buf.get(bytes, off, len); return len; } else if (n > 0) { // There are some bytes remaining: truncate request. buf.get(bytes, off, n); return n; } else { // Signal that there are no bytes left return -1; } } } /* Traverseproc implementation */ @Override public int traverse(Visitproc visit, Object arg) { if (data == null || !gc.canLinkToPyObject(data.getClass(), true)) { return 0; } return gc.traverseByReflection(data, visit, arg); } @Override public boolean refersDirectlyTo(PyObject ob) throws UnsupportedOperationException { if (data == null || !gc.canLinkToPyObject(data.getClass(), true)) { return false; } throw new UnsupportedOperationException(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy