This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
Re: FYI: Patch: java.nio: Reimplementing byte buffer getType/putTypemethods
- From: Eric Blake <ebb9 at byu dot net>
- To: Michael Koch <konqueror at gmx dot de>
- Cc: java-patches at gcc dot gnu dot org
- Date: Fri, 26 Sep 2003 06:26:27 -0600
- Subject: Re: FYI: Patch: java.nio: Reimplementing byte buffer getType/putTypemethods
- References: <200309250846.20753.konqueror@gmx.de>
I'm not sure this is completely correct.
Michael Koch wrote:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Hi list,
I commited the attached patch to make ByteBuffer implementations work
and easier to maintain. There is still some room for optimization but
having a working version is more important for now. ;-)
+
+ public static final ByteBuffer putChar (ByteBuffer buffer, char value)
+ {
+ checkRemainingForWrite (buffer, 2);
+
+ if (buffer.order() == ByteOrder.LITTLE_ENDIAN)
+ {
+ buffer.put ((byte) (((int) value) & 0x00ff));
^^^^^
Overkill - value is converted to int automatically by the & operator. (Applies
in many places throughout the file).
+ public static final ByteBuffer putChar (ByteBuffer buffer, int index,
+ char value)
+ {
+ checkAvailableForWrite (buffer, index, 2);
+
+ if (buffer.order() == ByteOrder.LITTLE_ENDIAN)
+ {
+ buffer.put (index + 1, (byte) ((((int) value) & 0x00ff) >> 8));
+ buffer.put (index, (byte) (((int) value) & 0xff00));
Question - does the write order have any bearing on efficiency? Writing
'index' before 'index + 1' may be more efficient on the underlying stream if
it prevents a backwards seek. Or I may just be spouting hot air here. :)
+ public static final long getLong (ByteBuffer buffer)
+ {
+ checkRemainingForRead (buffer, 8);
+
+ if (buffer.order() == ByteOrder.LITTLE_ENDIAN)
+ {
+ return (long) (((buffer.get() & 0xff))
+ + ((buffer.get() & 0xff) << 8)
+ + ((buffer.get() & 0xff) << 16)
+ + ((buffer.get() & 0xff) << 24)
+ + ((buffer.get() & 0xff) << 32)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This is still being done on an int, so it is the same as << 0 (not what you
intended). You need to promote the internal expressions to long before the shift.
+ + ((buffer.get() & 0xff) << 40)
+ + ((buffer.get() & 0xff) << 48)
+ + ((buffer.get() & 0xff) << 56));
Something like:
return ((buffer.get() & 0xff)
+ ((buffer.get() & 0xff) << 8)
+ ((buffer.get() & 0xff) << 16)
+ ((buffer.get() & 0xff) << 24)
+ ((buffer.get() & 0xffL) << 32)
+ ((buffer.get() & 0xffL) << 40)
+ ((buffer.get() & 0xffL) << 48)
+ ((buffer.get() & 0xffL) << 56));
+ public static final ByteBuffer putLong (ByteBuffer buffer, long value)
+ {
+ checkRemainingForWrite (buffer, 8);
+
+ if (buffer.order() == ByteOrder.LITTLE_ENDIAN)
+ {
+ buffer.put ((byte) (value & 0xff00000000000000L));
^^^^^^^^^^^^^^^^^^^
Wrong constants. You are unintentionally writing 8 consecutive \0 bytes here.
Also, when compiling to a .class file, you will be more efficient by replacing
'(byte) ((value & 0xff00000000000000L) >> 56)' with
'(byte) (((int) (value >> 56)) & 0xff)' - you are repeating fewer constants in
the constant pool, and the bytecode favors loading an int over loading a long.
Even .o files might benefit on 32-bit processors by leaving 64-bit ops as
soon as possible, depending on the optimizer's abilities.
+ buffer.put ((byte) ((value & 0x00ff000000000000L) >> 8));
+ buffer.put ((byte) ((value & 0x0000ff0000000000L) >> 16));
+ buffer.put ((byte) ((value & 0x000000ff00000000L) >> 24));
+ buffer.put ((byte) ((value & 0x00000000ff000000L) >> 32));
+ buffer.put ((byte) ((value & 0x0000000000ff0000L) >> 40));
+ buffer.put ((byte) ((value & 0x000000000000ff00L) >> 48));
+ buffer.put ((byte) ((value & 0x00000000000000ffL) >> 56));
+ }
+ else
^^^^
Minor nit: You are inconsistent in using else clauses or just falling through
when doing 'if (buffer.order() == ByteOrder.LITTLE_ENDIAN)'.
+ public static final long getLong (ByteBuffer buffer, int index)
+ {
+ checkAvailableForRead (buffer, index, 8);
+
+ if (buffer.order() == ByteOrder.LITTLE_ENDIAN)
+ {
+ return (long) ((buffer.get (index) & 0xff)
+ + ((buffer.get (index + 1) & 0xff) << 8)
+ + ((buffer.get (index + 2) & 0xff) << 16)
+ + ((buffer.get (index + 3) & 0xff) << 24)
+ + ((buffer.get (index + 4) & 0xff) << 32)
Again, coerce to long sooner.
+ public static final float getFloat (ByteBuffer buffer)
+ {
+ checkRemainingForRead (buffer, 4);
+
+ if (buffer.order() == ByteOrder.LITTLE_ENDIAN)
+ {
+ return (float) ((buffer.get() & 0xff)
+ + ((buffer.get() & 0xff) << 8)
+ + ((buffer.get() & 0xff) << 16)
+ + ((buffer.get() & 0xff) << 24));
Not what you meant. Use Float.intBitsToFloat(), not a cast. Same with
Double.longBitsToDouble() on the get direction. And use
Float.floatToIntBits()/Double.doubleToLongBits() on the put direction.
--
Someday, I might put a cute statement here.
Eric Blake ebb9@byu.net