diff --git a/README.md b/README.md index 41e47be..7ec8982 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,26 @@ Another source of performance is not just making the available abstractions fast - Binary formats often use length-prefixed blocks. perfIO provides length-limited views for reading them (at essentially zero cost), and advanced buffer management for writing a length prefix after the content without double buffering or manual buffer management. +## Setup + +Add the dependency to your project. Check the [Maven Central page](https://central.sonatype.com/artifact/com.novocode/perfio) for the latest versions and other dependency formats. + +``` + + com.novocode + perfio + 0.1.0 + +``` + +The minimum required JDK version is 21 with `--enable-preview` (for the FFM API), or 22 without. There are no other dependencies. + +- The Vector incubator API will be used automatically if it has been enabled with `--add-modules jdk.incubator.vector` and the JDK and CPU have appropriate support. Use of the Vector API can be disabled with `-Dperfio.disableVectorized=true`. + +- JDK-internal String features will be used automatically if the `java.lang` package has been made accessible with `--add-opens java.base/java.lang=ALL-UNNAMED`. This can be disabled with `-Dperfio.disableStringInternals=true`. + +- Unsafe memory access is disabled by default. It can improve the performance in some cases but result in less optimized code in others. Both `-Dperfio.enableUnsafe=true` and `--enable-native-access=ALL-UNNAMED` are required to enable it. + ## Usage A top-level `BufferedInput` or `BufferedOutput` object is instantiated by calling one of the static factory methods in the respective class. It should be closed after use by calling `close()`. @@ -76,7 +96,9 @@ Since Java does not have unsigned integers, the main methods for reading and wri | float32 | 32 bits floating-point | float | | float64 | 64 bits floating-point | double | -The methods for reading and writing multi-byte numeric values require a byte order. All factory methods set it to `BIG_ENDIAN` by default, but it can be changed at any time with the `order` method. This is consistent with `ByteBuffer` but different from the FFM API (which is mostly intended for interacting with native code and consequently uses the native byte order by default). +The methods for reading and writing multi-byte numeric values require a byte order. Most factory methods set it to `BIG_ENDIAN` by default, but it can be changed at any time with the `order` method. This is consistent with `ByteBuffer` but different from the FFM API (which is mostly intended for interacting with native code and consequently uses the native byte order by default). + +All methods except `int8` have additional variants ending in `n` (e.g. `int32n`), `b` and `l` for native, big endian and little endian byte order respectively. These methods are independent of the `BufferedInput`'s or `BufferedOutput`'s current byte order and slightly faster. ### Views diff --git a/core/src/main/java/perfio/BufferedInput.java b/core/src/main/java/perfio/BufferedInput.java index ca5b962..52723e7 100644 --- a/core/src/main/java/perfio/BufferedInput.java +++ b/core/src/main/java/perfio/BufferedInput.java @@ -1,6 +1,7 @@ package perfio; import perfio.internal.BufferUtil; +import perfio.internal.MemoryAccessor; import java.io.Closeable; import java.io.EOFException; @@ -241,23 +242,74 @@ public boolean hasMore() throws IOException { return pos < lim; } + /// Read a signed 8-bit integer (`byte`). public abstract byte int8() throws IOException; + /// Read an unsigned 8-bit integer into the lower 8 bits of an `int`. public final int uint8() throws IOException { return int8() & 0xFF; } + /// Read a signed 16-bit integer (`short`) in the current byte [#order()]. public abstract short int16() throws IOException; - + /// Read a signed 16-bit integer (`short`) in the native byte order. + public abstract short int16n() throws IOException; + /// Read a signed 16-bit integer (`short`) in big endian byte order. + public abstract short int16b() throws IOException; + /// Read a signed 16-bit integer (`short`) in little endian byte order. + public abstract short int16l() throws IOException; + + /// Read an unsigned 16-bit integer (`char`) in the current byte [#order()]. public abstract char uint16() throws IOException; - + /// Read an unsigned 16-bit integer (`char`) in the native byte order. + public abstract char uint16n() throws IOException; + /// Read an unsigned 16-bit integer (`char`) in big endian byte order. + public abstract char uint16b() throws IOException; + /// Read an unsigned 16-bit integer (`char`) in little endian byte order. + public abstract char uint16l() throws IOException; + + /// Read a signed 32-bit integer (`int`) in the current byte [#order()]. public abstract int int32() throws IOException; - + /// Read a signed 32-bit integer (`int`) in the native byte order. + public abstract int int32n() throws IOException; + /// Read a signed 32-bit integer (`int`) in big endian byte order. + public abstract int int32b() throws IOException; + /// Read a signed 32-bit integer (`int`) in little endian byte order. + public abstract int int32l() throws IOException; + + /// Read an unsigned 32-bit integer into the lower 32 bits of a `long` in the current byte [#order()]. public final long uint32() throws IOException { return int32() & 0xFFFFFFFFL; } - + /// Read an unsigned 32-bit integer into the lower 32 bits of a `long` in the native byte order. + public final long uint32n() throws IOException { return int32n() & 0xFFFFFFFFL; } + /// Read an unsigned 32-bit integer into the lower 32 bits of a `long` in the big endian byte order. + public final long uint32b() throws IOException { return int32b() & 0xFFFFFFFFL; } + /// Read an unsigned 32-bit integer into the lower 32 bits of a `long` in the little endian byte order. + public final long uint32l() throws IOException { return int32l() & 0xFFFFFFFFL; } + + /// Read a signed 64-bit integer (`long`) in the current byte [#order()]. public abstract long int64() throws IOException; - + /// Read a signed 64-bit integer (`long`) in the native byte order. + public abstract long int64n() throws IOException; + /// Read a signed 64-bit integer (`long`) in big endian byte order. + public abstract long int64b() throws IOException; + /// Read a signed 64-bit integer (`long`) in little endian byte order. + public abstract long int64l() throws IOException; + + /// Read a 32-bit IEEE-754 floating point value (`float`) in the current byte [#order()]. public abstract float float32() throws IOException; - + /// Read a 32-bit IEEE-754 floating point value (`float`) in the native byte order. + public abstract float float32n() throws IOException; + /// Read a 32-bit IEEE-754 floating point value (`float`) in big endian byte order. + public abstract float float32b() throws IOException; + /// Read a 32-bit IEEE-754 floating point value (`float`) in little endian byte order. + public abstract float float32l() throws IOException; + + /// Read a 64-bit IEEE-754 floating point value (`double`) in the current byte [#order()]. public abstract double float64() throws IOException; + /// Read a 64-bit IEEE-754 floating point value (`double`) in the native byte order. + public abstract double float64n() throws IOException; + /// Read a 64-bit IEEE-754 floating point value (`double`) in big endian byte order. + public abstract double float64b() throws IOException; + /// Read a 64-bit IEEE-754 floating point value (`double`) in little endian byte order. + public abstract double float64l() throws IOException; /// Close this BufferedInput and mark it as closed. Calling [#close()] again has no effect, /// calling most other methods after closing results in an [IOException]. diff --git a/core/src/main/java/perfio/BufferedOutput.java b/core/src/main/java/perfio/BufferedOutput.java index 816a1b3..cd61118 100644 --- a/core/src/main/java/perfio/BufferedOutput.java +++ b/core/src/main/java/perfio/BufferedOutput.java @@ -1,5 +1,6 @@ package perfio; +import perfio.internal.MemoryAccessor; import perfio.internal.StringInternals; import java.io.*; @@ -12,7 +13,7 @@ import java.util.Arrays; import java.util.Objects; -import static perfio.internal.BufferUtil.*; +import static perfio.internal.BufferUtil.growBuffer; /// BufferedOutput provides buffered streaming writes to an OutputStream or similar data sink. @@ -197,56 +198,177 @@ public final BufferedOutput write(byte[] a, int off, int len) throws IOException /// Write a signed 8-bit integer (`byte`). public final BufferedOutput int8(byte b) throws IOException { +// if(pos >= lim) { +// flushAndGrow(1); +// if(pos >= lim) throw new EOFException(); +// } +// MemoryAccessor.INSTANCE.int8(buf, pos++, b); +// return this; + var p = fwd(1); - buf[p] = b; + MemoryAccessor.INSTANCE.int8(buf, p, b); return this; } /// Write the lower 8 bits of the given `int` as an unsigned 8-bit integer. public final BufferedOutput uint8(int b) throws IOException { return int8((byte)b); } - /// Write a signed 16-bit integer (`short`) in the current [#order()]. + /// Write a signed 16-bit integer (`short`) in the current byte [#order()]. public final BufferedOutput int16(short s) throws IOException { var p = fwd(2); - (bigEndian ? BA_SHORT_BIG : BA_SHORT_LITTLE).set(buf, p, s); + MemoryAccessor.INSTANCE.int16(buf, p, s, bigEndian); + return this; + } + /// Write a signed 16-bit integer (`short`) in the native byte order. + public final BufferedOutput int16n(short s) throws IOException { + var p = fwd(2); + MemoryAccessor.INSTANCE.int16n(buf, p, s); + return this; + } + /// Write a signed 16-bit integer (`short`) in big endian byte order. + public final BufferedOutput int16b(short s) throws IOException { + var p = fwd(2); + MemoryAccessor.INSTANCE.int16b(buf, p, s); + return this; + } + /// Write a signed 16-bit integer (`short`) in little endian byte order. + public final BufferedOutput int16l(short s) throws IOException { + var p = fwd(2); + MemoryAccessor.INSTANCE.int16l(buf, p, s); return this; } - /// Write an unsigned 16-bit integer (`char`) in the current [#order()]. + /// Write an unsigned 16-bit integer (`char`) in the current byte [#order()]. public final BufferedOutput uint16(char c) throws IOException { var p = fwd(2); - (bigEndian ? BA_CHAR_BIG : BA_CHAR_LITTLE).set(buf, p, c); + MemoryAccessor.INSTANCE.uint16(buf, p, c, bigEndian); + return this; + } + /// Write an unsigned 16-bit integer (`char`) in the native byte order. + public final BufferedOutput uint16n(char c) throws IOException { + var p = fwd(2); + MemoryAccessor.INSTANCE.uint16n(buf, p, c); + return this; + } + /// Write an unsigned 16-bit integer (`char`) in big endian byte order. + public final BufferedOutput uint16b(char c) throws IOException { + var p = fwd(2); + MemoryAccessor.INSTANCE.uint16b(buf, p, c); + return this; + } + /// Write an unsigned 16-bit integer (`char`) in little endian byte order. + public final BufferedOutput uint16l(char c) throws IOException { + var p = fwd(2); + MemoryAccessor.INSTANCE.uint16l(buf, p, c); return this; } - /// Write a signed 32-bit integer (`int`) in the current [#order()]. + /// Write a signed 32-bit integer (`int`) in the current byte [#order()]. public final BufferedOutput int32(int i) throws IOException { var p = fwd(4); - (bigEndian ? BA_INT_BIG : BA_INT_LITTLE).set(buf, p, i); + MemoryAccessor.INSTANCE.int32(buf, p, i, bigEndian); + return this; + } + /// Write a signed 32-bit integer (`int`) in the native byte order. + public final BufferedOutput int32n(int i) throws IOException { + var p = fwd(4); + MemoryAccessor.INSTANCE.int32n(buf, p, i); + return this; + } + /// Write a signed 32-bit integer (`int`) in big endian byte order. + public final BufferedOutput int32b(int i) throws IOException { + var p = fwd(4); + MemoryAccessor.INSTANCE.int32b(buf, p, i); + return this; + } + /// Write a signed 32-bit integer (`int`) in little endian byte order. + public final BufferedOutput int32l(int i) throws IOException { + var p = fwd(4); + MemoryAccessor.INSTANCE.int32l(buf, p, i); return this; } - /// Write the lower 32 bits of the given `long` as an unsigned 32-bit integer in the current [#order()]. + /// Write the lower 32 bits of the given `long` as an unsigned 32-bit integer in the current byte [#order()]. public final BufferedOutput uint32(long i) throws IOException { return int32((int)i); } - - /// Write a signed 64-bit integer (`long`) in the current [#order()]. + /// Write the lower 32 bits of the given `long` as an unsigned 32-bit integer in the native byte order. + public final BufferedOutput uint32n(long i) throws IOException { return int32n((int)i); } + /// Write the lower 32 bits of the given `long` as an unsigned 32-bit integer in big endian byte order. + public final BufferedOutput uint32b(long i) throws IOException { return int32b((int)i); } + /// Write the lower 32 bits of the given `long` as an unsigned 32-bit integer in little endian byte order. + public final BufferedOutput uint32l(long i) throws IOException { return int32l((int)i); } + + /// Write a signed 64-bit integer (`long`) in the current byte [#order()]. public final BufferedOutput int64(long l) throws IOException { var p = fwd(8); - (bigEndian ? BA_LONG_BIG : BA_LONG_LITTLE).set(buf, p, l); + MemoryAccessor.INSTANCE.int64(buf, p, l, bigEndian); + return this; + } + /// Write a signed 64-bit integer (`long`) in the native byte order. + public final BufferedOutput int64n(long l) throws IOException { + var p = fwd(8); + MemoryAccessor.INSTANCE.int64n(buf, p, l); + return this; + } + /// Write a signed 64-bit integer (`long`) in big endian byte order. + public final BufferedOutput int64b(long l) throws IOException { + var p = fwd(8); + MemoryAccessor.INSTANCE.int64b(buf, p, l); + return this; + } + /// Write a signed 64-bit integer (`long`) in little endian byte order. + public final BufferedOutput int64l(long l) throws IOException { + var p = fwd(8); + MemoryAccessor.INSTANCE.int64l(buf, p, l); return this; } - /// Write a 32-bit IEEE-754 floating point value (`float`) in the current [#order()]. + /// Write a 32-bit IEEE-754 floating point value (`float`) in the current byte [#order()]. public final BufferedOutput float32(float f) throws IOException { var p = fwd(4); - (bigEndian ? BA_FLOAT_BIG : BA_FLOAT_LITTLE).set(buf, p, f); + MemoryAccessor.INSTANCE.float32(buf, p, f, bigEndian); + return this; + } + /// Write a 32-bit IEEE-754 floating point value (`float`) in the native byte order. + public final BufferedOutput float32n(float f) throws IOException { + var p = fwd(4); + MemoryAccessor.INSTANCE.float32n(buf, p, f); + return this; + } + /// Write a 32-bit IEEE-754 floating point value (`float`) in big endian byte order. + public final BufferedOutput float32b(float f) throws IOException { + var p = fwd(4); + MemoryAccessor.INSTANCE.float32b(buf, p, f); + return this; + } + /// Write a 32-bit IEEE-754 floating point value (`float`) in little endian byte order. + public final BufferedOutput float32l(float f) throws IOException { + var p = fwd(4); + MemoryAccessor.INSTANCE.float32l(buf, p, f); return this; } - /// Write a 64-bit IEEE-754 floating point value (`double`) in the current [#order()]. + /// Write a 64-bit IEEE-754 floating point value (`double`) in the current byte [#order()]. public final BufferedOutput float64(double d) throws IOException { var p = fwd(8); - (bigEndian ? BA_DOUBLE_BIG : BA_DOUBLE_LITTLE).set(buf, p, d); + MemoryAccessor.INSTANCE.float64(buf, p, d, bigEndian); + return this; + } + /// Write a 64-bit IEEE-754 floating point value (`double`) in the native byte order. + public final BufferedOutput float64n(double d) throws IOException { + var p = fwd(8); + MemoryAccessor.INSTANCE.float64n(buf, p, d); + return this; + } + /// Write a 64-bit IEEE-754 floating point value (`double`) in big endian byte order. + public final BufferedOutput float64b(double d) throws IOException { + var p = fwd(8); + MemoryAccessor.INSTANCE.float64b(buf, p, d); + return this; + } + /// Write a 64-bit IEEE-754 floating point value (`double`) in little endian byte order. + public final BufferedOutput float64l(double d) throws IOException { + var p = fwd(8); + MemoryAccessor.INSTANCE.float64l(buf, p, d); return this; } @@ -714,7 +836,17 @@ void closeUpstream() throws IOException { } void flushBlocks(boolean forceFlush) throws IOException { - while(next != this) { + if(next != this) flushPrefix(forceFlush); + var len = pos-start; + if((forceFlush && len > 0) || len > initialBufferSize/2) { + writeToOutput(buf, start, len); + totalFlushed += len; + pos = start; + } + } + + private void flushPrefix(boolean forceFlush) throws IOException { + do { var b = next; var blen = b.pos - b.start; if(!b.closed) { @@ -739,13 +871,7 @@ void flushBlocks(boolean forceFlush) throws IOException { else if(blen > 0) writeToOutput(b.buf, b.start, blen); } b.unlinkAndReturn(); - } - var len = pos-start; - if((forceFlush && len > 0) || len > initialBufferSize/2) { - writeToOutput(buf, start, len); - totalFlushed += len; - pos = start; - } + } while(next != this); } private boolean maybeMergeToRight(BufferedOutput b) { diff --git a/core/src/main/java/perfio/DirectBufferedInput.java b/core/src/main/java/perfio/DirectBufferedInput.java index a1ddc7d..a6ac21b 100644 --- a/core/src/main/java/perfio/DirectBufferedInput.java +++ b/core/src/main/java/perfio/DirectBufferedInput.java @@ -1,6 +1,7 @@ package perfio; import perfio.internal.BufferUtil; +import perfio.internal.MemoryAccessor; import java.io.Closeable; import java.io.IOException; @@ -8,7 +9,6 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.charset.Charset; -import static perfio.internal.BufferUtil.*; // This could be a lot simpler if we didn't have to do pagination but ByteBuffer is limited // to 2 GB and direct MemorySegment access is much, much slower as of JDK 22. @@ -73,40 +73,37 @@ private String makeString(int start, int len, Charset charset) { return new String(lb, 0, len, charset); } - public byte int8() throws IOException { - var p = fwd(1); - return bb.get(p); - } + public byte int8() throws IOException { var p = fwd(1); return MemoryAccessor.INSTANCE.int8(bb, p); } - public short int16() throws IOException { - var p = fwd(2); - return (short)(bigEndian ? BB_SHORT_BIG : BB_SHORT_LITTLE).get(bb, p); - } + public short int16() throws IOException { var p = fwd(2); return MemoryAccessor.INSTANCE.int16(bb, p, bigEndian); } + public short int16n() throws IOException { var p = fwd(2); return MemoryAccessor.INSTANCE.int16n(bb, p); } + public short int16b() throws IOException { var p = fwd(2); return MemoryAccessor.INSTANCE.int16b(bb, p); } + public short int16l() throws IOException { var p = fwd(2); return MemoryAccessor.INSTANCE.int16l(bb, p); } - public char uint16() throws IOException { - var p = fwd(2); - return (char)(bigEndian ? BB_CHAR_BIG : BB_CHAR_LITTLE).get(bb, p); - } + public char uint16() throws IOException { var p = fwd(2); return MemoryAccessor.INSTANCE.uint16(bb, p, bigEndian); } + public char uint16n() throws IOException { var p = fwd(2); return MemoryAccessor.INSTANCE.uint16n(bb, p); } + public char uint16b() throws IOException { var p = fwd(2); return MemoryAccessor.INSTANCE.uint16b(bb, p); } + public char uint16l() throws IOException { var p = fwd(2); return MemoryAccessor.INSTANCE.uint16l(bb, p); } - public int int32() throws IOException { - var p = fwd(4); - return (int)(bigEndian ? BB_INT_BIG : BB_INT_LITTLE).get(bb, p); - } + public int int32() throws IOException { var p = fwd(4); return MemoryAccessor.INSTANCE.int32(bb, p, bigEndian); } + public int int32n() throws IOException { var p = fwd(4); return MemoryAccessor.INSTANCE.int32n(bb, p); } + public int int32b() throws IOException { var p = fwd(4); return MemoryAccessor.INSTANCE.int32b(bb, p); } + public int int32l() throws IOException { var p = fwd(4); return MemoryAccessor.INSTANCE.int32l(bb, p); } - public long int64() throws IOException { - var p = fwd(8); - return (long)(bigEndian ? BB_LONG_BIG : BB_LONG_LITTLE).get(bb, p); - } + public long int64() throws IOException { var p = fwd(8); return MemoryAccessor.INSTANCE.int64(bb, p, bigEndian); } + public long int64n() throws IOException { var p = fwd(8); return MemoryAccessor.INSTANCE.int64n(bb, p); } + public long int64b() throws IOException { var p = fwd(8); return MemoryAccessor.INSTANCE.int64b(bb, p); } + public long int64l() throws IOException { var p = fwd(8); return MemoryAccessor.INSTANCE.int64l(bb, p); } - public float float32() throws IOException { - var p = fwd(4); - return (float)(bigEndian ? BB_FLOAT_BIG : BB_FLOAT_LITTLE).get(bb, p); - } + public float float32() throws IOException { var p = fwd(4); return MemoryAccessor.INSTANCE.float32(bb, p, bigEndian); } + public float float32n() throws IOException { var p = fwd(4); return MemoryAccessor.INSTANCE.float32n(bb, p); } + public float float32b() throws IOException { var p = fwd(4); return MemoryAccessor.INSTANCE.float32b(bb, p); } + public float float32l() throws IOException { var p = fwd(4); return MemoryAccessor.INSTANCE.float32l(bb, p); } - public double float64() throws IOException { - var p = fwd(8); - return (double)(bigEndian ? BB_DOUBLE_BIG : BB_DOUBLE_LITTLE).get(bb, p); - } + public double float64() throws IOException { var p = fwd(8); return MemoryAccessor.INSTANCE.float64(bb, p, bigEndian); } + public double float64n() throws IOException { var p = fwd(8); return MemoryAccessor.INSTANCE.float64n(bb, p); } + public double float64b() throws IOException { var p = fwd(8); return MemoryAccessor.INSTANCE.float64b(bb, p); } + public double float64l() throws IOException { var p = fwd(8); return MemoryAccessor.INSTANCE.float64l(bb, p); } public String string(int len, Charset charset) throws IOException { if(len == 0) { diff --git a/core/src/main/java/perfio/HeapBufferedInput.java b/core/src/main/java/perfio/HeapBufferedInput.java index 520910c..e0e01b7 100644 --- a/core/src/main/java/perfio/HeapBufferedInput.java +++ b/core/src/main/java/perfio/HeapBufferedInput.java @@ -1,13 +1,12 @@ package perfio; import perfio.internal.BufferUtil; +import perfio.internal.MemoryAccessor; import java.io.Closeable; import java.io.IOException; import java.nio.charset.Charset; -import static perfio.internal.BufferUtil.*; - sealed abstract class HeapBufferedInput extends BufferedInput permits StreamingHeapBufferedInput, SwitchingHeapBufferedInput { byte[] buf; @@ -24,40 +23,37 @@ void clearBuffer() { buf = null; } - public byte int8() throws IOException { - var p = fwd(1); - return buf[p]; - } - - public short int16() throws IOException { - var p = fwd(2); - return (short)(bigEndian ? BA_SHORT_BIG : BA_SHORT_LITTLE).get(buf, p); - } - - public char uint16() throws IOException { - var p = fwd(2); - return (char)(bigEndian ? BA_CHAR_BIG : BA_CHAR_LITTLE).get(buf, p); - } - - public int int32() throws IOException { - var p = fwd(4); - return (int)(bigEndian ? BA_INT_BIG : BA_INT_LITTLE).get(buf, p); - } - - public long int64() throws IOException { - var p = fwd(8); - return (long)(bigEndian ? BA_LONG_BIG : BA_LONG_LITTLE).get(buf, p); - } - - public float float32() throws IOException { - var p = fwd(4); - return (float)(bigEndian ? BA_FLOAT_BIG : BA_FLOAT_LITTLE).get(buf, p); - } - - public double float64() throws IOException { - var p = fwd(8); - return (double)(bigEndian ? BA_DOUBLE_BIG : BA_DOUBLE_LITTLE).get(buf, p); - } + public byte int8() throws IOException { var p = fwd(1); return MemoryAccessor.INSTANCE.int8(buf, p); } + + public short int16() throws IOException { var p = fwd(2); return MemoryAccessor.INSTANCE.int16(buf, p, bigEndian); } + public short int16n() throws IOException { var p = fwd(2); return MemoryAccessor.INSTANCE.int16n(buf, p); } + public short int16b() throws IOException { var p = fwd(2); return MemoryAccessor.INSTANCE.int16b(buf, p); } + public short int16l() throws IOException { var p = fwd(2); return MemoryAccessor.INSTANCE.int16l(buf, p); } + + public char uint16() throws IOException { var p = fwd(2); return MemoryAccessor.INSTANCE.uint16(buf, p, bigEndian); } + public char uint16n() throws IOException { var p = fwd(2); return MemoryAccessor.INSTANCE.uint16n(buf, p); } + public char uint16b() throws IOException { var p = fwd(2); return MemoryAccessor.INSTANCE.uint16b(buf, p); } + public char uint16l() throws IOException { var p = fwd(2); return MemoryAccessor.INSTANCE.uint16l(buf, p); } + + public int int32() throws IOException { var p = fwd(4); return MemoryAccessor.INSTANCE.int32(buf, p, bigEndian); } + public int int32n() throws IOException { var p = fwd(4); return MemoryAccessor.INSTANCE.int32n(buf, p); } + public int int32b() throws IOException { var p = fwd(4); return MemoryAccessor.INSTANCE.int32b(buf, p); } + public int int32l() throws IOException { var p = fwd(4); return MemoryAccessor.INSTANCE.int32l(buf, p); } + + public long int64() throws IOException { var p = fwd(8); return MemoryAccessor.INSTANCE.int64(buf, p, bigEndian); } + public long int64n() throws IOException { var p = fwd(8); return MemoryAccessor.INSTANCE.int64n(buf, p); } + public long int64b() throws IOException { var p = fwd(8); return MemoryAccessor.INSTANCE.int64b(buf, p); } + public long int64l() throws IOException { var p = fwd(8); return MemoryAccessor.INSTANCE.int64l(buf, p); } + + public float float32() throws IOException { var p = fwd(4); return MemoryAccessor.INSTANCE.float32(buf, p, bigEndian); } + public float float32n() throws IOException { var p = fwd(4); return MemoryAccessor.INSTANCE.float32n(buf, p); } + public float float32b() throws IOException { var p = fwd(4); return MemoryAccessor.INSTANCE.float32b(buf, p); } + public float float32l() throws IOException { var p = fwd(4); return MemoryAccessor.INSTANCE.float32l(buf, p); } + + public double float64() throws IOException { var p = fwd(8); return MemoryAccessor.INSTANCE.float64(buf, p, bigEndian); } + public double float64n() throws IOException { var p = fwd(8); return MemoryAccessor.INSTANCE.float64n(buf, p); } + public double float64b() throws IOException { var p = fwd(8); return MemoryAccessor.INSTANCE.float64b(buf, p); } + public double float64l() throws IOException { var p = fwd(8); return MemoryAccessor.INSTANCE.float64l(buf, p); } public String string(int len, Charset charset) throws IOException { if(len == 0) { diff --git a/core/src/main/java/perfio/internal/MemoryAccessor.java b/core/src/main/java/perfio/internal/MemoryAccessor.java new file mode 100644 index 0000000..08a44e3 --- /dev/null +++ b/core/src/main/java/perfio/internal/MemoryAccessor.java @@ -0,0 +1,113 @@ +package perfio.internal; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import static perfio.internal.BufferUtil.*; +import static perfio.internal.BufferUtil.BA_DOUBLE_LITTLE; + +public abstract class MemoryAccessor { + public static final MemoryAccessor INSTANCE; + public static final boolean BIG_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN; + + static { + MemoryAccessor a = null; + var unsafeEnabled = "true".equals(System.getProperty("perfio.enableUnsafe")); + if(unsafeEnabled) + try { a = UnsafeMemoryAccessor.INSTANCE; } catch (Throwable t) {} + INSTANCE = a != null ? a : SafeMemoryAccessor.INSTANCE; + } + + public abstract boolean isUnsafe(); + + public abstract byte int8(byte[] a, int i); + public abstract void int8(byte[] a, int i, byte v); + + public abstract short int16(byte[] a, int i, boolean big); + public abstract short int16n(byte[] a, int i); + public abstract short int16b(byte[] a, int i); + public abstract short int16l(byte[] a, int i); + public abstract void int16(byte[] a, int i, short v, boolean big); + public abstract void int16n(byte[] a, int i, short v); + public abstract void int16b(byte[] a, int i, short v); + public abstract void int16l(byte[] a, int i, short v); + + public abstract char uint16(byte[] a, int i, boolean big); + public abstract char uint16n(byte[] a, int i); + public abstract char uint16b(byte[] a, int i); + public abstract char uint16l(byte[] a, int i); + public abstract void uint16(byte[] a, int i, char v, boolean big); + public abstract void uint16n(byte[] a, int i, char v); + public abstract void uint16b(byte[] a, int i, char v); + public abstract void uint16l(byte[] a, int i, char v); + + public abstract int int32(byte[] a, int i, boolean big); + public abstract int int32n(byte[] a, int i); + public abstract int int32b(byte[] a, int i); + public abstract int int32l(byte[] a, int i); + public abstract void int32(byte[] a, int i, int v, boolean big); + public abstract void int32n(byte[] a, int i, int v); + public abstract void int32b(byte[] a, int i, int v); + public abstract void int32l(byte[] a, int i, int v); + + public abstract long int64(byte[] a, int i, boolean big); + public abstract long int64n(byte[] a, int i); + public abstract long int64b(byte[] a, int i); + public abstract long int64l(byte[] a, int i); + public abstract void int64(byte[] a, int i, long v, boolean big); + public abstract void int64n(byte[] a, int i, long v); + public abstract void int64b(byte[] a, int i, long v); + public abstract void int64l(byte[] a, int i, long v); + + public abstract float float32(byte[] a, int i, boolean big); + public abstract float float32n(byte[] a, int i); + public abstract float float32b(byte[] a, int i); + public abstract float float32l(byte[] a, int i); + public abstract void float32(byte[] a, int i, float v, boolean big); + public abstract void float32n(byte[] a, int i, float v); + public abstract void float32b(byte[] a, int i, float v); + public abstract void float32l(byte[] a, int i, float v); + + public abstract double float64(byte[] a, int i, boolean big); + public abstract double float64n(byte[] a, int i); + public abstract double float64b(byte[] a, int i); + public abstract double float64l(byte[] a, int i); + public abstract void float64(byte[] a, int i, double v, boolean big); + public abstract void float64n(byte[] a, int i, double v); + public abstract void float64b(byte[] a, int i, double v); + public abstract void float64l(byte[] a, int i, double v); + + // No unsafe implementations of direct access. They were slower in all benchmarks. + + public byte int8(ByteBuffer a, int i) { return a.get(i); } + + public short int16(ByteBuffer a, int i, boolean big) { return (short)(big ? BB_SHORT_BIG : BB_SHORT_LITTLE).get(a, i); } + public short int16n(ByteBuffer a, int i) { return (short)(BIG_ENDIAN ? BB_SHORT_BIG : BB_SHORT_LITTLE).get(a, i); } + public short int16b(ByteBuffer a, int i) { return (short)BB_SHORT_BIG.get(a, i); } + public short int16l(ByteBuffer a, int i) { return (short)BB_SHORT_LITTLE.get(a, i); } + + public char uint16(ByteBuffer a, int i, boolean big) { return (char)(big ? BB_CHAR_BIG : BB_CHAR_LITTLE).get(a, i); } + public char uint16n(ByteBuffer a, int i) { return (char)(BIG_ENDIAN ? BB_CHAR_BIG : BB_CHAR_LITTLE).get(a, i); } + public char uint16b(ByteBuffer a, int i) { return (char)BB_CHAR_BIG.get(a, i); } + public char uint16l(ByteBuffer a, int i) { return (char)BB_CHAR_LITTLE.get(a, i); } + + public int int32(ByteBuffer a, int i, boolean big) { return (int)(big ? BB_INT_BIG : BB_INT_LITTLE).get(a, i); } + public int int32n(ByteBuffer a, int i) { return (int)(BIG_ENDIAN ? BB_INT_BIG : BB_INT_LITTLE).get(a, i); } + public int int32b(ByteBuffer a, int i) { return (int)BB_INT_BIG.get(a, i); } + public int int32l(ByteBuffer a, int i) { return (int)BB_INT_LITTLE.get(a, i); } + + public long int64(ByteBuffer a, int i, boolean big) { return (long)(big ? BB_LONG_BIG : BB_LONG_LITTLE).get(a, i); } + public long int64n(ByteBuffer a, int i) { return (long)(BIG_ENDIAN ? BB_LONG_BIG : BB_LONG_LITTLE).get(a, i); } + public long int64b(ByteBuffer a, int i) { return (long)BB_LONG_BIG.get(a, i); } + public long int64l(ByteBuffer a, int i) { return (long)BB_LONG_LITTLE.get(a, i); } + + public float float32(ByteBuffer a, int i, boolean big) { return (float)(big ? BB_FLOAT_BIG : BB_FLOAT_LITTLE).get(a, i); } + public float float32n(ByteBuffer a, int i) { return (float)(BIG_ENDIAN ? BB_FLOAT_BIG : BB_FLOAT_LITTLE).get(a, i); } + public float float32b(ByteBuffer a, int i) { return (float)BB_FLOAT_BIG.get(a, i); } + public float float32l(ByteBuffer a, int i) { return (float)BB_FLOAT_LITTLE.get(a, i); } + + public double float64(ByteBuffer a, int i, boolean big) { return (double)(big ? BB_DOUBLE_BIG : BB_DOUBLE_LITTLE).get(a, i); } + public double float64n(ByteBuffer a, int i) { return (double)(BIG_ENDIAN ? BB_DOUBLE_BIG : BB_DOUBLE_LITTLE).get(a, i); } + public double float64b(ByteBuffer a, int i) { return (double)BB_DOUBLE_BIG.get(a, i); } + public double float64l(ByteBuffer a, int i) { return (double)BB_DOUBLE_LITTLE.get(a, i); } +} diff --git a/core/src/main/java/perfio/internal/SafeMemoryAccessor.java b/core/src/main/java/perfio/internal/SafeMemoryAccessor.java new file mode 100644 index 0000000..206de69 --- /dev/null +++ b/core/src/main/java/perfio/internal/SafeMemoryAccessor.java @@ -0,0 +1,71 @@ +package perfio.internal; + +import java.nio.ByteOrder; + +import static perfio.internal.BufferUtil.*; +import static perfio.internal.BufferUtil.BA_DOUBLE_LITTLE; + +final class SafeMemoryAccessor extends MemoryAccessor { + private SafeMemoryAccessor() {} + + public static final SafeMemoryAccessor INSTANCE = new SafeMemoryAccessor(); + + public boolean isUnsafe() { return false; } + + public byte int8(byte[] a, int i) { return a[i]; } + public void int8(byte[] a, int i, byte v) { a[i] = v; } + + public short int16(byte[] a, int i, boolean big) { return (short)(big ? BA_SHORT_BIG : BA_SHORT_LITTLE).get(a, i); } + public short int16n(byte[] a, int i) { return (short)(BIG_ENDIAN ? BA_SHORT_BIG : BA_SHORT_LITTLE).get(a, i); } + public short int16b(byte[] a, int i) { return (short)BA_SHORT_BIG.get(a, i); } + public short int16l(byte[] a, int i) { return (short)BA_SHORT_LITTLE.get(a, i); } + public void int16(byte[] a, int i, short v, boolean big) { (big ? BA_SHORT_BIG : BA_SHORT_LITTLE).set(a, i, v); } + public void int16n(byte[] a, int i, short v) { (BIG_ENDIAN ? BA_SHORT_BIG : BA_SHORT_LITTLE).set(a, i, v); } + public void int16b(byte[] a, int i, short v) { BA_SHORT_BIG.set(a, i, v); } + public void int16l(byte[] a, int i, short v) { BA_SHORT_LITTLE.set(a, i, v); } + + public char uint16(byte[] a, int i, boolean big) { return (char)(big ? BA_CHAR_BIG : BA_CHAR_LITTLE).get(a, i); } + public char uint16n(byte[] a, int i) { return (char)(BIG_ENDIAN ? BA_CHAR_BIG : BA_CHAR_LITTLE).get(a, i); } + public char uint16b(byte[] a, int i) { return (char)BA_CHAR_BIG.get(a, i); } + public char uint16l(byte[] a, int i) { return (char)BA_CHAR_LITTLE.get(a, i); } + public void uint16(byte[] a, int i, char v, boolean big) { (big ? BA_CHAR_BIG : BA_CHAR_LITTLE).set(a, i, v); } + public void uint16n(byte[] a, int i, char v) { (BIG_ENDIAN ? BA_CHAR_BIG : BA_CHAR_LITTLE).set(a, i, v); } + public void uint16b(byte[] a, int i, char v) { BA_CHAR_BIG.set(a, i, v); } + public void uint16l(byte[] a, int i, char v) { BA_CHAR_LITTLE.set(a, i, v); } + + public int int32(byte[] a, int i, boolean big) { return (int)(big ? BA_INT_BIG : BA_INT_LITTLE).get(a, i); } + public int int32n(byte[] a, int i) { return (int)(BIG_ENDIAN ? BA_INT_BIG : BA_INT_LITTLE).get(a, i); } + public int int32b(byte[] a, int i) { return (int)BA_INT_BIG.get(a, i); } + public int int32l(byte[] a, int i) { return (int)BA_INT_LITTLE.get(a, i); } + public void int32(byte[] a, int i, int v, boolean big) { (big ? BA_INT_BIG : BA_INT_LITTLE).set(a, i, v); } + public void int32n(byte[] a, int i, int v) { (BIG_ENDIAN ? BA_INT_BIG : BA_INT_LITTLE).set(a, i, v); } + public void int32b(byte[] a, int i, int v) { BA_INT_BIG.set(a, i, v); } + public void int32l(byte[] a, int i, int v) { BA_INT_LITTLE.set(a, i, v); } + + public long int64(byte[] a, int i, boolean big) { return (long)(big ? BA_LONG_BIG : BA_LONG_LITTLE).get(a, i); } + public long int64n(byte[] a, int i) { return (long)(BIG_ENDIAN ? BA_LONG_BIG : BA_LONG_LITTLE).get(a, i); } + public long int64b(byte[] a, int i) { return (long)BA_LONG_BIG.get(a, i); } + public long int64l(byte[] a, int i) { return (long)BA_LONG_LITTLE.get(a, i); } + public void int64(byte[] a, int i, long v, boolean big) { (big ? BA_LONG_BIG : BA_LONG_LITTLE).set(a, i, v); } + public void int64n(byte[] a, int i, long v) { (BIG_ENDIAN ? BA_LONG_BIG : BA_LONG_LITTLE).set(a, i, v); } + public void int64b(byte[] a, int i, long v) { BA_LONG_BIG.set(a, i, v); } + public void int64l(byte[] a, int i, long v) { BA_LONG_LITTLE.set(a, i, v); } + + public float float32(byte[] a, int i, boolean big) { return (float)(big ? BA_FLOAT_BIG : BA_FLOAT_LITTLE).get(a, i); } + public float float32n(byte[] a, int i) { return (float)(BIG_ENDIAN ? BA_FLOAT_BIG : BA_FLOAT_LITTLE).get(a, i); } + public float float32b(byte[] a, int i) { return (float)BA_FLOAT_BIG.get(a, i); } + public float float32l(byte[] a, int i) { return (float)BA_FLOAT_LITTLE.get(a, i); } + public void float32(byte[] a, int i, float v, boolean big) { (big ? BA_FLOAT_BIG : BA_FLOAT_LITTLE).set(a, i, v); } + public void float32n(byte[] a, int i, float v) { (BIG_ENDIAN ? BA_FLOAT_BIG : BA_FLOAT_LITTLE).set(a, i, v); } + public void float32b(byte[] a, int i, float v) { BA_FLOAT_BIG.set(a, i, v); } + public void float32l(byte[] a, int i, float v) { BA_FLOAT_LITTLE.set(a, i, v); } + + public double float64(byte[] a, int i, boolean big) { return (double)(big ? BA_DOUBLE_BIG : BA_DOUBLE_LITTLE).get(a, i); } + public double float64n(byte[] a, int i) { return (double)(BIG_ENDIAN ? BA_DOUBLE_BIG : BA_DOUBLE_LITTLE).get(a, i); } + public double float64b(byte[] a, int i) { return (double)BA_DOUBLE_BIG.get(a, i); } + public double float64l(byte[] a, int i) { return (double)BA_DOUBLE_LITTLE.get(a, i); } + public void float64(byte[] a, int i, double v, boolean big) { (big ? BA_DOUBLE_BIG : BA_DOUBLE_LITTLE).set(a, i, v); } + public void float64n(byte[] a, int i, double v) { (BIG_ENDIAN ? BA_DOUBLE_BIG : BA_DOUBLE_LITTLE).set(a, i, v); } + public void float64b(byte[] a, int i, double v) { BA_DOUBLE_BIG.set(a, i, v); } + public void float64l(byte[] a, int i, double v) { BA_DOUBLE_LITTLE.set(a, i, v); } +} diff --git a/core/src/main/java/perfio/internal/UnsafeMemoryAccessor.java b/core/src/main/java/perfio/internal/UnsafeMemoryAccessor.java new file mode 100644 index 0000000..9eca2aa --- /dev/null +++ b/core/src/main/java/perfio/internal/UnsafeMemoryAccessor.java @@ -0,0 +1,150 @@ +package perfio.internal; + +import sun.misc.Unsafe; + +import java.nio.ByteOrder; + +public abstract class UnsafeMemoryAccessor extends MemoryAccessor { + protected UnsafeMemoryAccessor() {} + + public boolean isUnsafe() { return true; } + + public byte int8(byte[] a, int i) { return UNSAFE.getByte(a, (long)BA_OFFSET + i); } + public void int8(byte[] a, int i, byte v) { UNSAFE.putByte(a, (long)BA_OFFSET + i, v); } + + public short int16n(byte[] a, int i) { return UNSAFE.getShort(a, (long)BA_OFFSET + i); } + public void int16n(byte[] a, int i, short v) { UNSAFE.putShort(a, (long)BA_OFFSET + i, v); } + + public char uint16n(byte[] a, int i) { return UNSAFE.getChar(a, (long)BA_OFFSET + i); } + public void uint16n(byte[] a, int i, char v) { UNSAFE.putChar(a, (long)BA_OFFSET + i, v); } + + public int int32n(byte[] a, int i) { return UNSAFE.getInt(a, (long)BA_OFFSET + i); } + public void int32n(byte[] a, int i, int v) { UNSAFE.putInt(a, (long)BA_OFFSET + i, v); } + + public long int64n(byte[] a, int i) { return UNSAFE.getLong(a, (long)BA_OFFSET + i); } + public void int64n(byte[] a, int i, long v) { UNSAFE.putLong(a, (long)BA_OFFSET + i, v); } + + public float float32n(byte[] a, int i) { return UNSAFE.getFloat(a, (long)BA_OFFSET + i); } + public void float32n(byte[] a, int i, float v) { UNSAFE.putFloat(a, (long)BA_OFFSET + i, v); } + public float float32(byte[] a, int i, boolean big) { return Float.intBitsToFloat(int32(a, i, big)); } + public void float32(byte[] a, int i, float v, boolean big) { int32(a, i, Float.floatToRawIntBits(v), big); } + + public double float64n(byte[] a, int i) { return UNSAFE.getDouble(a, (long)BA_OFFSET + i); } + public void float64n(byte[] a, int i, double v) { UNSAFE.putDouble(a, (long)BA_OFFSET + i, v); } + public double float64(byte[] a, int i, boolean big) { return Double.longBitsToDouble(int64(a, i, big)); } + public void float64(byte[] a, int i, double v, boolean big) { int64(a, i, Double.doubleToRawLongBits(v), big); } + + /// Error encountered during initialization of Unsafe, or null if successful. + public static final Throwable initializationError; + + /// MemoryAccessor instance if unsafe access is available, otherwise null. + public static final UnsafeMemoryAccessor INSTANCE; + + static final Unsafe UNSAFE; + static final int BA_OFFSET; + + static { + UnsafeMemoryAccessor instanceL = null; + Unsafe unsafeL = null; + int baOffsetL = 0; + Throwable initializationErrorL = null; + var ok = false; + try { + var f = Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + unsafeL = (Unsafe)f.get(null); + baOffsetL = unsafeL.arrayBaseOffset(byte[].class); + instanceL = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN ? new UnsafeBigMemoryAccessor() : new UnsafeLittleMemoryAccessor(); + ok = true; + } catch (Throwable t) { + initializationErrorL = t; + } + if(!ok) instanceL = null; + UNSAFE = unsafeL; + INSTANCE = instanceL; + BA_OFFSET = baOffsetL; + initializationError = initializationErrorL; + } +} + + +final class UnsafeBigMemoryAccessor extends UnsafeMemoryAccessor { + public short int16(byte[] a, int i, boolean big) { return big ? int16n(a, i) : Short.reverseBytes(int16n(a, i)); } + public short int16b(byte[] a, int i) { return int16n(a, i); } + public short int16l(byte[] a, int i) { return Short.reverseBytes(int16n(a, i)); } + public void int16(byte[] a, int i, short v, boolean big) { int16n(a, i, big ? v : Short.reverseBytes(v)); } + public void int16b(byte[] a, int i, short v) { int16n(a, i, v); } + public void int16l(byte[] a, int i, short v) { int16n(a, i, Short.reverseBytes(v)); } + + public char uint16(byte[] a, int i, boolean big) { return big ? uint16n(a, i) : Character.reverseBytes(uint16n(a, i)); } + public char uint16b(byte[] a, int i) { return uint16n(a, i); } + public char uint16l(byte[] a, int i) { return Character.reverseBytes(uint16n(a, i)); } + public void uint16(byte[] a, int i, char v, boolean big) { uint16n(a, i, big ? v : Character.reverseBytes(v)); } + public void uint16b(byte[] a, int i, char v) { uint16n(a, i, v); } + public void uint16l(byte[] a, int i, char v) { uint16n(a, i, Character.reverseBytes(v)); } + + public int int32(byte[] a, int i, boolean big) { return big ? int32n(a, i) : Integer.reverseBytes(int32n(a, i)); } + public int int32b(byte[] a, int i) { return int32n(a, i); } + public int int32l(byte[] a, int i) { return Integer.reverseBytes(int32n(a, i)); } + public void int32(byte[] a, int i, int v, boolean big) { int32n(a, i, big ? v : Integer.reverseBytes(v)); } + public void int32b(byte[] a, int i, int v) { int32n(a, i, v); } + public void int32l(byte[] a, int i, int v) { int32n(a, i, Integer.reverseBytes(v)); } + + public long int64(byte[] a, int i, boolean big) { return big ? int64n(a, i) : Long.reverseBytes(int64n(a, i)); } + public long int64b(byte[] a, int i) { return int64n(a, i); } + public long int64l(byte[] a, int i) { return Long.reverseBytes(int64n(a, i)); } + public void int64(byte[] a, int i, long v, boolean big) { int64n(a, i, big ? v : Long.reverseBytes(v)); } + public void int64b(byte[] a, int i, long v) { int64n(a, i, v); } + public void int64l(byte[] a, int i, long v) { int64n(a, i, Long.reverseBytes(v)); } + + public float float32b(byte[] a, int i) { return float32n(a, i); } + public float float32l(byte[] a, int i) { return Float.intBitsToFloat(int32l(a, i)); } + public void float32b(byte[] a, int i, float v) { float32n(a, i, v); } + public void float32l(byte[] a, int i, float v) { int32l(a, i, Float.floatToRawIntBits(v)); } + + public double float64b(byte[] a, int i) { return float64n(a, i); } + public double float64l(byte[] a, int i) { return Double.longBitsToDouble(int64l(a, i)); } + public void float64b(byte[] a, int i, double v) { float64n(a, i, v); } + public void float64l(byte[] a, int i, double v) { int64l(a, i, Double.doubleToRawLongBits(v)); } +} + + +final class UnsafeLittleMemoryAccessor extends UnsafeMemoryAccessor { + public short int16(byte[] a, int i, boolean big) { return big ? Short.reverseBytes(int16n(a, i)) : int16n(a, i); } + public short int16l(byte[] a, int i) { return int16n(a, i); } + public short int16b(byte[] a, int i) { return Short.reverseBytes(int16n(a, i)); } + public void int16(byte[] a, int i, short v, boolean big) { int16n(a, i, big ? Short.reverseBytes(v) : v); } + public void int16l(byte[] a, int i, short v) { int16n(a, i, v); } + public void int16b(byte[] a, int i, short v) { int16n(a, i, Short.reverseBytes(v)); } + + public char uint16(byte[] a, int i, boolean big) { return big ? Character.reverseBytes(uint16n(a, i)) : uint16n(a, i); } + public char uint16l(byte[] a, int i) { return uint16n(a, i); } + public char uint16b(byte[] a, int i) { return Character.reverseBytes(uint16n(a, i)); } + public void uint16(byte[] a, int i, char v, boolean big) { uint16n(a, i, big ? Character.reverseBytes(v) : v); } + public void uint16l(byte[] a, int i, char v) { uint16n(a, i, v); } + public void uint16b(byte[] a, int i, char v) { uint16n(a, i, Character.reverseBytes(v)); } + + public int int32(byte[] a, int i, boolean big) { return big ? Integer.reverseBytes(int32n(a, i)) : int32n(a, i); } + public int int32l(byte[] a, int i) { return int32n(a, i); } + public int int32b(byte[] a, int i) { return Integer.reverseBytes(int32n(a, i)); } + public void int32(byte[] a, int i, int v, boolean big) { int32n(a, i, big ? Integer.reverseBytes(v) : v); } + public void int32l(byte[] a, int i, int v) { int32n(a, i, v); } + public void int32b(byte[] a, int i, int v) { int32n(a, i, Integer.reverseBytes(v)); } + + public long int64(byte[] a, int i, boolean big) { return big ? Long.reverseBytes(int64n(a, i)) : int64n(a, i); } + public long int64l(byte[] a, int i) { return int64n(a, i); } + public long int64b(byte[] a, int i) { return Long.reverseBytes(int64n(a, i)); } + public void int64(byte[] a, int i, long v, boolean big) { int64n(a, i, big ? Long.reverseBytes(v) : v); } + public void int64l(byte[] a, int i, long v) { int64n(a, i, v); } + public void int64b(byte[] a, int i, long v) { int64n(a, i, Long.reverseBytes(v)); } + + public float float32l(byte[] a, int i) { return float32n(a, i); } + public float float32b(byte[] a, int i) { return Float.intBitsToFloat(int32b(a, i)); } + public void float32l(byte[] a, int i, float v) { float32n(a, i, v); } + public void float32b(byte[] a, int i, float v) { int32b(a, i, Float.floatToRawIntBits(v)); } + + public double float64l(byte[] a, int i) { return float64n(a, i); } + public double float64b(byte[] a, int i) { return Double.longBitsToDouble(int64b(a, i)); } + public void float64l(byte[] a, int i, double v) { float64n(a, i, v); } + public void float64b(byte[] a, int i, double v) { int64b(a, i, Double.doubleToRawLongBits(v)); } +} diff --git a/proto-bench/src/main/scala/ReadBenchmark.scala b/proto-bench/src/main/scala/ReadBenchmark.scala index 6f0c604..d917e97 100644 --- a/proto-bench/src/main/scala/ReadBenchmark.scala +++ b/proto-bench/src/main/scala/ReadBenchmark.scala @@ -28,12 +28,12 @@ class ReadBenchmark: testData = Files.readAllBytes(testDataFile) assert(testData.length == 159366, s"testData.length ${testData.length}") - @Benchmark - def array_google(bh: Blackhole): Unit = - val p = GPluginProtos.CodeGeneratorRequest.parseFrom(testData) - assert(p.getFileToGenerateList.size() == 2) - assert(p.getSourceFileDescriptorsList.size() == 2) - bh.consume(p) +// @Benchmark +// def array_google(bh: Blackhole): Unit = +// val p = GPluginProtos.CodeGeneratorRequest.parseFrom(testData) +// assert(p.getFileToGenerateList.size() == 2) +// assert(p.getSourceFileDescriptorsList.size() == 2) +// bh.consume(p) @Benchmark def array_perfio(bh: Blackhole): Unit = @@ -42,27 +42,27 @@ class ReadBenchmark: assert(p.getSourceFileDescriptorsList.size() == 2) bh.consume(p) - @Benchmark - def file_google(bh: Blackhole): Unit = - val in = new BufferedInputStream(new FileInputStream(testDataFile.toFile)) - val p = GPluginProtos.CodeGeneratorRequest.parseFrom(in) - assert(p.getFileToGenerateList.size() == 2) - assert(p.getSourceFileDescriptorsList.size() == 2) - bh.consume(p) - in.close() - - @Benchmark - def file_perfio(bh: Blackhole): Unit = - val in = BufferedInput.of(new FileInputStream(testDataFile.toFile)).order(ByteOrder.LITTLE_ENDIAN) - val p = PPluginProtos.CodeGeneratorRequest.parseFrom(in) - assert(p.getFileToGenerateList.size() == 2) - assert(p.getSourceFileDescriptorsList.size() == 2) - bh.consume(p) - in.close() - - @Benchmark - def file_perfio_mapped(bh: Blackhole): Unit = - val p = PPluginProtos.CodeGeneratorRequest.parseFrom(BufferedInput.ofMappedFile(testDataFile).order(ByteOrder.LITTLE_ENDIAN)) - assert(p.getFileToGenerateList.size() == 2) - assert(p.getSourceFileDescriptorsList.size() == 2) - bh.consume(p) +// @Benchmark +// def file_google(bh: Blackhole): Unit = +// val in = new BufferedInputStream(new FileInputStream(testDataFile.toFile)) +// val p = GPluginProtos.CodeGeneratorRequest.parseFrom(in) +// assert(p.getFileToGenerateList.size() == 2) +// assert(p.getSourceFileDescriptorsList.size() == 2) +// bh.consume(p) +// in.close() +// +// @Benchmark +// def file_perfio(bh: Blackhole): Unit = +// val in = BufferedInput.of(new FileInputStream(testDataFile.toFile)).order(ByteOrder.LITTLE_ENDIAN) +// val p = PPluginProtos.CodeGeneratorRequest.parseFrom(in) +// assert(p.getFileToGenerateList.size() == 2) +// assert(p.getSourceFileDescriptorsList.size() == 2) +// bh.consume(p) +// in.close() +// +// @Benchmark +// def file_perfio_mapped(bh: Blackhole): Unit = +// val p = PPluginProtos.CodeGeneratorRequest.parseFrom(BufferedInput.ofMappedFile(testDataFile).order(ByteOrder.LITTLE_ENDIAN)) +// assert(p.getFileToGenerateList.size() == 2) +// assert(p.getSourceFileDescriptorsList.size() == 2) +// bh.consume(p) diff --git a/proto-bench/src/main/scala/WriteBenchmark.scala b/proto-bench/src/main/scala/WriteBenchmark.scala index 0feec5d..5906ed8 100644 --- a/proto-bench/src/main/scala/WriteBenchmark.scala +++ b/proto-bench/src/main/scala/WriteBenchmark.scala @@ -66,11 +66,11 @@ class WriteBenchmark: pMessage.writeTo(out) out.close() - @Benchmark - def array_google(bh: Blackhole): Unit = - val baos = new ByteArrayOutputStream() - writeGoogle(baos) - bh.consume(baos.size()) +// @Benchmark +// def array_google(bh: Blackhole): Unit = +// val baos = new ByteArrayOutputStream() +// writeGoogle(baos) +// bh.consume(baos.size()) @Benchmark def array_perfio(bh: Blackhole): Unit = @@ -78,14 +78,14 @@ class WriteBenchmark: writePerfio(bo) bh.consume(bo.length()) - @Benchmark - def file_google(bh: Blackhole): Unit = - val out = new BufferedOutputStream(new FileOutputStream("/dev/null")) - writeGoogle(out) - out.close() - - @Benchmark - def file_perfio(bh: Blackhole): Unit = - val bo = BufferedOutput.ofFile(Path.of("/dev/null"), 8192) - writePerfio(bo) - bo.close() +// @Benchmark +// def file_google(bh: Blackhole): Unit = +// val out = new BufferedOutputStream(new FileOutputStream("/dev/null")) +// writeGoogle(out) +// out.close() +// +// @Benchmark +// def file_perfio(bh: Blackhole): Unit = +// val bo = BufferedOutput.ofFile(Path.of("/dev/null"), 8192) +// writePerfio(bo) +// bo.close()