FYI: Patch: java.nio: Reimplementing byte buffer getType/putType methods
Eric Blake
ebb9@byu.net
Sat Sep 27 08:22:00 GMT 2003
Looks better this time around - the only correctness issue I saw this time was
my bug. Also in my review, I noticed a couple more optimizations.
Michael Koch wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Very much thanks for you review. I have commited the attached patch to
> trunk. I hope I have implemented all your suggestions. If you like
> you can take a look at it again.
>
>
> Michael
> - --
> @@ -88,13 +88,13 @@
>
> if (buffer.order() == ByteOrder.LITTLE_ENDIAN)
> {
> - buffer.put ((byte) (((int) value) & 0x00ff));
> - buffer.put ((byte) ((((int) value) & 0xff00) >> 8));
> + buffer.put ((byte) (value & 0x00ff));
> + buffer.put ((byte) ((value & 0xff00) >> 8));
You can simplify this further, and let the conversion to byte do the masking:
buffer.put ((byte) value);
buffer.put ((byte) (value >> 8));
This will affect quite a few places in the code.
> @@ -106,8 +106,8 @@
>
> if (buffer.order() == ByteOrder.LITTLE_ENDIAN)
> {
> - return (char) (((buffer.get (index + 1) & 0xff) << 8)
> - + (buffer.get (index) & 0xff));
> + return (char) ((buffer.get (index) & 0xff)
> + + ((buffer.get (index + 1) & 0xff) << 8));
Likewise, in building larger types, you can avoid the mask on the most
significant byte (but the mask is necessary on all other bytes: since byte is
signed, not masking could corrupt the higher bytes):
return (char) ((buffer.get (index) & 0xff)
+ (buffer.get (index + 1) << 8));
> public static final int getInt (ByteBuffer buffer)
The cast to int here is redundant, but doesn't affect .class or .o files in size.
> @@ -263,10 +263,10 @@
>
> if (buffer.order() == ByteOrder.LITTLE_ENDIAN)
> {
> - buffer.put (index + 3, (byte) ((value & 0xff000000) >> 24));
> - buffer.put (index + 2, (byte) ((value & 0x00ff0000) >> 16));
> - buffer.put (index + 1, (byte) ((value & 0x0000ff00) >> 8));
> buffer.put (index, (byte) (value & 0x000000ff));
> + buffer.put (index + 1, (byte) ((value & 0x0000ff00) >> 8));
> + buffer.put (index + 2, (byte) ((value & 0x00ff0000) >> 16));
> + buffer.put (index + 3, (byte) ((value & 0xff000000) >> 24));
Another .class file efficiency tip - incrementing local variables uses a
dedicated bytecode:
buffer.put (++index, (byte) (value >> 8));
buffer.put (++index, (byte) (value >> 16));
buffer.put (++index, (byte) (value >> 24));
> @@ -289,16 +289,16 @@
> + ((buffer.get() & 0xff) << 8)
> + ((buffer.get() & 0xff) << 16)
> + ((buffer.get() & 0xff) << 24)
> - + ((buffer.get() & 0xff) << 32)
> - + ((buffer.get() & 0xff) << 40)
> - + ((buffer.get() & 0xff) << 48)
> - + ((buffer.get() & 0xff) << 56));
> + + ((buffer.get() & 0xffL) << 32)
> + + ((buffer.get() & 0xffL) << 40)
> + + ((buffer.get() & 0xffL) << 48)
> + + ((buffer.get() & 0xffL) << 56));
My bad - if the fourth get() was negative, the int math will sign-extend and
ruin the long. Now that I think about it, you can do even less 64-bit math,
and this time get the right result:
return ((buffer.get() & 0xff) // int math until...
+ ((buffer.get() & 0xff) << 8)
+ ((buffer.get() & 0xff) << 16)
+ ((buffer.get() & 0xffL) << 24) // must be long mask to 0-extend
+ (long) ((buffer.get() & 0xff) // more int math...
+ ((buffer.get() & 0xff) << 8)
+ ((buffer.get() & 0xff) << 16)
+ (buffer.get() << 24))
<< 32); // ...until last minute
Unfortunately, it makes the code less legible, so I won't be offended if you
can come up with a nicer solution that uses the same (or fewer) shifts and masks.
> public static final ByteBuffer putFloat (ByteBuffer buffer, float value)
> {
> + return putInt (buffer, Float.floatToIntBits (value));
> }
We should probably use Float.floatToRawIntBits() here, to preserve the hidden
bits in a NaN. But I like your redirection to putInt (now why didn't I think
of that this morning?).
--
Someday, I might put a cute statement here.
Eric Blake ebb9@byu.net
More information about the Java-patches
mailing list