Skip to content

Commit

Permalink
Avoid allocation in BigDecimal serializer, new method for bytes in …
Browse files Browse the repository at this point in the history
…Input/Output .
  • Loading branch information
Wojtek Gdela committed Oct 14, 2023
1 parent c0cc9f9 commit 62bcd2d
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 27 deletions.
10 changes: 10 additions & 0 deletions src/com/esotericsoftware/kryo/io/ByteBufferInput.java
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,16 @@ public void readBytes (byte[] bytes, int offset, int count) throws KryoException
}
}

public long readBytesAsLong (int count) {
require(count);
position += count;
long bytes = byteBuffer.get();
for (int i = 1; i < count; i++) {
bytes = (bytes << 8) | (byteBuffer.get() & 0xFF);
}
return bytes;
}

// int:

public int readInt () throws KryoException {
Expand Down
8 changes: 8 additions & 0 deletions src/com/esotericsoftware/kryo/io/ByteBufferOutput.java
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,14 @@ public void writeBytes (byte[] bytes, int offset, int count) throws KryoExceptio
}
}

public void writeBytesFromLong (long bytes, int count) {
require(count);
position += count;
for (int i = count - 1; i >= 0; i--) {
byteBuffer.put((byte) (bytes >> (i << 3)));
}
}

// int:

public void writeInt (int value) throws KryoException {
Expand Down
12 changes: 12 additions & 0 deletions src/com/esotericsoftware/kryo/io/Input.java
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,18 @@ public void readBytes (byte[] bytes, int offset, int count) throws KryoException
}
}

/** Reads count bytes and returns them as long, the last byte read will be the lowest byte in the long. */
public long readBytesAsLong (int count) {
require(count);
int p = position;
position = p + count;
long bytes = buffer[p++];
for (int i = 1; i < count; i++) {
bytes = (bytes << 8) | (buffer[p++] & 0xFF);
}
return bytes;
}

// int:

/** Reads a 4 byte int. */
Expand Down
12 changes: 11 additions & 1 deletion src/com/esotericsoftware/kryo/io/Output.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
package com.esotericsoftware.kryo.io;

import com.esotericsoftware.kryo.KryoException;
import com.esotericsoftware.kryo.io.KryoBufferOverflowException;
import com.esotericsoftware.kryo.util.Pool.Poolable;
import com.esotericsoftware.kryo.util.Util;

Expand Down Expand Up @@ -274,6 +273,17 @@ public void writeBytes (byte[] bytes, int offset, int count) throws KryoExceptio
}
}

/** Writes count bytes from long, the last byte written is the lowest byte from the long.
* Note the number of bytes is not written. */
public void writeBytesFromLong (long bytes, int count) {
require(count);
int p = position;
position = p + count;
for (int i = count - 1; i >= 0; i--) {
buffer[p++] = (byte) (bytes >> (i << 3));
}
}

// int:

/** Writes a 4 byte int. */
Expand Down
37 changes: 11 additions & 26 deletions src/com/esotericsoftware/kryo/serializers/DefaultSerializers.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import static com.esotericsoftware.kryo.Kryo.*;
import static com.esotericsoftware.kryo.util.Util.*;
import static java.lang.Long.numberOfLeadingZeros;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.KryoException;
Expand Down Expand Up @@ -282,27 +283,15 @@ public void write (Kryo kryo, Output output, BigDecimal object) {
}

// compatible with writing unscaled value represented as BigInteger's bytes
private static void writeUnscaledLong(Output output, long unscaledLong) {
if (unscaledLong >>> 7 == 0) { // optimize for tiny values
output.writeVarInt(2, true);
output.writeByte((byte) unscaledLong);
} else {
byte[] bytes = new byte[8];
int pos = 8;
do {
bytes[--pos] = (byte) (unscaledLong & 0xFF);
unscaledLong >>= 8;
} while (unscaledLong != 0 && unscaledLong != -1); // out of bits

if (((bytes[pos] ^ unscaledLong) & 0x80) != 0) {
// sign bit didn't fit in previous byte, need to add another byte
bytes[--pos] = (byte) unscaledLong;
}
private static void writeUnscaledLong (Output output, long unscaledLong) {
int insignificantBits = unscaledLong >= 0
? numberOfLeadingZeros(unscaledLong)
: numberOfLeadingZeros(~unscaledLong);
int significantBits = (64 - insignificantBits) + 1; // one more bit is for the sign
int length = (significantBits + (8 - 1)) >> 3; // how many bytes are needed (rounded up)

int length = 8 - pos;
output.writeVarInt(length + 1, true);
output.writeBytes(bytes, pos, length);
}
output.writeByte(length + 1);
output.writeBytesFromLong(unscaledLong, length);
}

public BigDecimal read (Kryo kryo, Input input, Class<? extends BigDecimal> type) {
Expand All @@ -313,15 +302,11 @@ public BigDecimal read (Kryo kryo, Input input, Class<? extends BigDecimal> type
if (length == NULL) return null;
length--;

byte[] bytes = input.readBytes(length);
if (length > 8) {
byte[] bytes = input.readBytes(length);
unscaledBig = new BigInteger(bytes);
} else {
unscaledLong = bytes[0];
for (int i = 1; i < bytes.length; i++) {
unscaledLong <<= 8;
unscaledLong |= (bytes[i] & 0xFF);
}
unscaledLong = input.readBytesAsLong(length);
}

int scale = input.readInt(false);
Expand Down

0 comments on commit 62bcd2d

Please sign in to comment.