diff -r e7afa7fd1e5b -r f694386dd3bc src/org/python/core/PyArray.java --- a/src/org/python/core/PyArray.java Tue Jan 13 00:28:38 2015 -0700 +++ b/src/org/python/core/PyArray.java Tue Jan 13 16:50:39 2015 -0800 @@ -11,6 +11,12 @@ import java.lang.ref.WeakReference; import java.lang.reflect.Array; import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.DoubleBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.LongBuffer; +import java.nio.ShortBuffer; import org.python.core.buffer.BaseBuffer; import org.python.core.buffer.SimpleStringBuffer; @@ -143,7 +149,9 @@ self.fromlist(initial); } else if (initial instanceof PyString && !(initial instanceof PyUnicode)) { - self.fromstring(initial.toString()); + self.frombytesInternal(ByteBuffer.wrap( + StringUtil.toBytes(initial.toString()) + ), true); } else if ("u".equals(typecode)) { if (initial instanceof PyUnicode) { @@ -613,8 +621,6 @@ // 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': @@ -1011,11 +1017,6 @@ // 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()); @@ -1135,12 +1136,12 @@ if (pybuf.getNdim() == 1) { if (pybuf.getStrides()[0] == 1) { // Data are contiguous in the buffer - frombytesInternal(pybuf.getNIOByteBuffer()); + frombytesInternal(pybuf.getNIOByteBuffer(), false); } else { // As frombytesInternal only knows contiguous bytes, make a copy. byte[] copy = new byte[pybuf.getLen()]; pybuf.copyTo(copy, 0); - frombytesInternal(ByteBuffer.wrap(copy)); + frombytesInternal(ByteBuffer.wrap(copy), false); } } else { // Currently don't support n-dimensional sources @@ -1162,7 +1163,7 @@ * @param bytes array containing the new array data in machine encoding */ private final void frombytesInternal(byte[] bytes) { - frombytesInternal(ByteBuffer.wrap(bytes)); + frombytesInternal(ByteBuffer.wrap(bytes), false); } /** @@ -1171,8 +1172,9 @@ * or .frombytes() (Python 3.2+ name). * * @param bytes buffer containing the new array data in machine encoding + * @param string true if the underlying bytes come from a static string */ - private final void frombytesInternal(ByteBuffer bytes) { + private final void frombytesInternal(ByteBuffer bytes, boolean string) { // Access the bytes int origsize = delegate.getSize(); @@ -1187,20 +1189,90 @@ // Prohibited operation if we are exporting a buffer resizeCheck(); - try { + if (string) { + // if the backing bytes came from a static string, we can enable some special-case + // optimization here - // Provide argument as stream of bytes for fromstream method - InputStream is = new ByteBufferBackedInputStream(bytes); - fromStream(is); + // since we know how many elements there are in total, let's pre-allocate an array of this known size + //setup(type, Array.newInstance(type, count / itemsize)); + data = Array.newInstance(type, count / itemsize); + delegate = new ArrayDelegate(); - } catch (EOFException e) { - // stubbed catch for fromStream throws - throw Py.EOFError("not enough items in string"); + switch (typecode.charAt(0)) { + case 'c': + CharBuffer cb = CharBuffer.wrap((char[]) data); + while (bytes.hasRemaining()) { + cb.put((char)(bytes.get() & 0xff)); + } + break; + case 'b': + ByteBuffer bb = ByteBuffer.wrap((byte[]) data); + bb.put(bytes); + break; + case 'B': + ShortBuffer sb = ShortBuffer.wrap((short[]) data); + while (bytes.hasRemaining()) { + sb.put(unsignedByte(bytes.get())); + } + break; + case 'u': + // use 32-bit integers since we want UCS-4 storage + IntBuffer ib = IntBuffer.wrap((int[]) data); + ib.put(bytes.asIntBuffer()); + break; + case 'h': + sb = ShortBuffer.wrap((short[]) data); + sb.put(bytes.asShortBuffer()); + break; + case 'H': + ib = IntBuffer.wrap((int[]) data); + while (bytes.hasRemaining()) { + ib.put(unsignedShort(bytes.getShort())); + } + break; + case 'i': + ib = IntBuffer.wrap((int[]) data); + ib.put(bytes.asIntBuffer()); + break; + case 'I': + LongBuffer lb = LongBuffer.wrap((long[]) data); + while (bytes.hasRemaining()) { + lb.put(unsignedInt(bytes.getInt())); + } + break; + case 'l': + case 'L': // faking it + lb = LongBuffer.wrap((long[]) data); + lb.put(bytes.asLongBuffer()); + break; + case 'f': + FloatBuffer fb = FloatBuffer.wrap((float[]) data); + fb.put(bytes.asFloatBuffer()); + break; + case 'd': + DoubleBuffer db = DoubleBuffer.wrap((double[]) data); + db.put(bytes.asDoubleBuffer()); + break; + default: + throw Py.ValueError("bad typecode (must be c, b, B, u, h, H, i, I, l, L, f or d)"); + } + } else { + // otherwise, treat the backing bytes as an input stream + try { - } catch (IOException e) { - // discard anything successfully loaded - delegate.setSize(origsize); - throw Py.IOError(e); + // 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); + } } } @@ -1320,8 +1392,6 @@ public int getStorageSize() { if (type.isPrimitive()) { switch (typecode.charAt(0)) { - case 'z': - return 1; case 'b': return 1; case 'B': @@ -1819,11 +1889,6 @@ 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));