This is an automated email from the ASF dual-hosted git repository.
xiangfu0 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git
The following commit(s) were added to refs/heads/master by this push:
new c5eeb91e388 Let OBJECT codecs serialize payloads into caller buffers
(#19836)
c5eeb91e388 is described below
commit c5eeb91e388ab5cc697a8262881ccbd3b668e076
Author: Xiang Fu <[email protected]>
AuthorDate: Fri Oct 16 11:40:22 2026 -0700
Let OBJECT codecs serialize payloads into caller buffers (#19836)
* Let OBJECT codecs serialize payloads into caller buffers
Roaring, UltraLogLog, and primitive-list codecs now own direct writes
alongside their existing byte-array API. Call getSerializedSize before buffer
serialization; unsupported codecs keep the legacy fallback, and all 198
combined tests pass.
* Centralize OBJECT byte-array allocation
Keep typed forwarding calls so legacy serializers retain their allocation
behavior while sharing the default implementation.
* Clarify caller-buffer serialization contracts
Document sufficient remaining capacity, codec override requirements and the
intended caller. Cover excess buffer space in the existing serialization tests.
---
.../apache/pinot/core/common/ObjectSerDeUtils.java | 213 +++++++++++++++++----
.../pinot/core/common/ObjectSerDeUtilsTest.java | 163 ++++++++++++++++
2 files changed, 338 insertions(+), 38 deletions(-)
diff --git
a/pinot-core/src/main/java/org/apache/pinot/core/common/ObjectSerDeUtils.java
b/pinot-core/src/main/java/org/apache/pinot/core/common/ObjectSerDeUtils.java
index c5427f76065..b3c17dc809c 100644
---
a/pinot-core/src/main/java/org/apache/pinot/core/common/ObjectSerDeUtils.java
+++
b/pinot-core/src/main/java/org/apache/pinot/core/common/ObjectSerDeUtils.java
@@ -56,9 +56,12 @@ import it.unimi.dsi.fastutil.objects.ObjectSet;
import java.io.IOException;
import java.lang.foreign.MemorySegment;
import java.math.BigDecimal;
+import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.nio.IntBuffer;
+import java.nio.ReadOnlyBufferException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -325,11 +328,36 @@ public class ObjectSerDeUtils {
/// Serializer/De-serializer for a specific type of object.
///
+ /// Implementations must override either the byte-array serializer or both
[#getSerializedSize(Object)] and
+ /// the buffer serializer [#serialize(Object, ByteBuffer)]. This contract is
enforced by convention; the serializer
+ /// defaults delegate to each other.
+ ///
/// @param <T> Type of the object
public interface ObjectSerDe<T> {
/// Serializes a value into a byte array.
- byte[] serialize(T value);
+ /// Typed forwarding overrides preserve receiver specialization when
invoking this default.
+ default byte[] serialize(T value) {
+ byte[] bytes = new byte[getSerializedSize(value)];
+ serialize(value, ByteBuffer.wrap(bytes));
+ return bytes;
+ }
+
+ /// Returns the exact size of a representable payload, or `-1` when
allocation-free sizing is unsupported.
+ /// This method must not serialize the value or allocate a payload array.
The value must remain unchanged between
+ /// sizing and serialization. The destination must have at least this many
bytes remaining.
+ default int getSerializedSize(T value) {
+ return -1;
+ }
+
+ /// Writes the canonical payload at the destination's current position and
advances it by the payload size.
+ /// Supports heap and direct buffers, preserves the destination's limit
and byte order, and does not retain the
+ /// buffer. Direct-writing overrides must not mutate the value. A
read-only destination or insufficient remaining
+ /// space fails before any write. The default implementation preserves the
legacy serializer behavior and
+ /// serializes once into a temporary array; codecs can override it for
direct writes.
+ default void serialize(T value, ByteBuffer destination) {
+ destination.put(serialize(value));
+ }
/// De-serializes a value from a byte array.
T deserialize(byte[] bytes);
@@ -413,17 +441,31 @@ public class ObjectSerDeUtils {
public static final ObjectSerDe<IntArrayList> INT_ARRAY_LIST_SER_DE = new
ObjectSerDe<IntArrayList>() {
+ @Override
+ public int getSerializedSize(IntArrayList intArrayList) {
+ return Math.addExact(Integer.BYTES,
Math.multiplyExact(intArrayList.size(), Integer.BYTES));
+ }
+
@Override
public byte[] serialize(IntArrayList intArrayList) {
- int size = intArrayList.size();
- byte[] bytes = new byte[Integer.BYTES + size * Integer.BYTES];
- ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
- byteBuffer.putInt(size);
- int[] values = intArrayList.elements();
- for (int i = 0; i < size; i++) {
- byteBuffer.putInt(values[i]);
+ return ObjectSerDe.super.serialize(intArrayList);
+ }
+
+ @Override
+ public void serialize(IntArrayList intArrayList, ByteBuffer destination) {
+ checkSerializationBuffer(destination, getSerializedSize(intArrayList));
+ ByteOrder originalOrder = destination.order();
+ destination.order(ByteOrder.BIG_ENDIAN);
+ try {
+ int size = intArrayList.size();
+ destination.putInt(size);
+ int[] values = intArrayList.elements();
+ for (int i = 0; i < size; i++) {
+ destination.putInt(values[i]);
+ }
+ } finally {
+ destination.order(originalOrder);
}
- return bytes;
}
@Override
@@ -450,17 +492,31 @@ public class ObjectSerDeUtils {
public static final ObjectSerDe<LongArrayList> LONG_ARRAY_LIST_SER_DE = new
ObjectSerDe<LongArrayList>() {
+ @Override
+ public int getSerializedSize(LongArrayList longArrayList) {
+ return Math.addExact(Integer.BYTES,
Math.multiplyExact(longArrayList.size(), Long.BYTES));
+ }
+
@Override
public byte[] serialize(LongArrayList longArrayList) {
- int size = longArrayList.size();
- byte[] bytes = new byte[Integer.BYTES + size * Long.BYTES];
- ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
- byteBuffer.putInt(size);
- long[] values = longArrayList.elements();
- for (int i = 0; i < size; i++) {
- byteBuffer.putLong(values[i]);
+ return ObjectSerDe.super.serialize(longArrayList);
+ }
+
+ @Override
+ public void serialize(LongArrayList longArrayList, ByteBuffer destination)
{
+ checkSerializationBuffer(destination, getSerializedSize(longArrayList));
+ ByteOrder originalOrder = destination.order();
+ destination.order(ByteOrder.BIG_ENDIAN);
+ try {
+ int size = longArrayList.size();
+ destination.putInt(size);
+ long[] values = longArrayList.elements();
+ for (int i = 0; i < size; i++) {
+ destination.putLong(values[i]);
+ }
+ } finally {
+ destination.order(originalOrder);
}
- return bytes;
}
@Override
@@ -487,17 +543,31 @@ public class ObjectSerDeUtils {
public static final ObjectSerDe<FloatArrayList> FLOAT_ARRAY_LIST_SER_DE =
new ObjectSerDe<FloatArrayList>() {
+ @Override
+ public int getSerializedSize(FloatArrayList floatArrayList) {
+ return Math.addExact(Integer.BYTES,
Math.multiplyExact(floatArrayList.size(), Float.BYTES));
+ }
+
@Override
public byte[] serialize(FloatArrayList floatArrayList) {
- int size = floatArrayList.size();
- byte[] bytes = new byte[Integer.BYTES + size * Float.BYTES];
- ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
- byteBuffer.putInt(size);
- float[] values = floatArrayList.elements();
- for (int i = 0; i < size; i++) {
- byteBuffer.putFloat(values[i]);
+ return ObjectSerDe.super.serialize(floatArrayList);
+ }
+
+ @Override
+ public void serialize(FloatArrayList floatArrayList, ByteBuffer
destination) {
+ checkSerializationBuffer(destination, getSerializedSize(floatArrayList));
+ ByteOrder originalOrder = destination.order();
+ destination.order(ByteOrder.BIG_ENDIAN);
+ try {
+ int size = floatArrayList.size();
+ destination.putInt(size);
+ float[] values = floatArrayList.elements();
+ for (int i = 0; i < size; i++) {
+ destination.putInt(Float.floatToRawIntBits(values[i]));
+ }
+ } finally {
+ destination.order(originalOrder);
}
- return bytes;
}
@Override
@@ -524,17 +594,31 @@ public class ObjectSerDeUtils {
public static final ObjectSerDe<DoubleArrayList> DOUBLE_ARRAY_LIST_SER_DE =
new ObjectSerDe<DoubleArrayList>() {
+ @Override
+ public int getSerializedSize(DoubleArrayList doubleArrayList) {
+ return Math.addExact(Integer.BYTES,
Math.multiplyExact(doubleArrayList.size(), Double.BYTES));
+ }
+
@Override
public byte[] serialize(DoubleArrayList doubleArrayList) {
- int size = doubleArrayList.size();
- byte[] bytes = new byte[Integer.BYTES + size * Double.BYTES];
- ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
- byteBuffer.putInt(size);
- double[] values = doubleArrayList.elements();
- for (int i = 0; i < size; i++) {
- byteBuffer.putDouble(values[i]);
+ return ObjectSerDe.super.serialize(doubleArrayList);
+ }
+
+ @Override
+ public void serialize(DoubleArrayList doubleArrayList, ByteBuffer
destination) {
+ checkSerializationBuffer(destination,
getSerializedSize(doubleArrayList));
+ ByteOrder originalOrder = destination.order();
+ destination.order(ByteOrder.BIG_ENDIAN);
+ try {
+ int size = doubleArrayList.size();
+ destination.putInt(size);
+ double[] values = doubleArrayList.elements();
+ for (int i = 0; i < size; i++) {
+ destination.putLong(Double.doubleToRawLongBits(values[i]));
+ }
+ } finally {
+ destination.order(originalOrder);
}
- return bytes;
}
@Override
@@ -1280,9 +1364,30 @@ public class ObjectSerDeUtils {
public static final ObjectSerDe<RoaringBitmap> ROARING_BITMAP_SER_DE = new
ObjectSerDe<RoaringBitmap>() {
+ @Override
+ public int getSerializedSize(RoaringBitmap bitmap) {
+ int size = bitmap.serializedSizeInBytes();
+ Preconditions.checkArgument(size >= 0, "Serialized bitmap exceeds the
maximum buffer size");
+ return size;
+ }
+
@Override
public byte[] serialize(RoaringBitmap bitmap) {
- return RoaringBitmapUtils.serialize(bitmap);
+ return ObjectSerDe.super.serialize(bitmap);
+ }
+
+ @Override
+ public void serialize(RoaringBitmap bitmap, ByteBuffer destination) {
+ // Recompute the size to validate standalone writes; mutable bitmaps
cannot safely cache it across calls.
+ checkSerializationBuffer(destination, getSerializedSize(bitmap));
+ ByteOrder originalOrder = destination.order();
+ // Roaring uses little-endian wire bytes; restore the caller's byte
order after writing.
+ destination.order(ByteOrder.LITTLE_ENDIAN);
+ try {
+ RoaringBitmapUtils.serialize(bitmap, destination);
+ } finally {
+ destination.order(originalOrder);
+ }
}
@Override
@@ -1729,12 +1834,21 @@ public class ObjectSerDeUtils {
public static final ObjectSerDe<UltraLogLog> ULTRA_LOG_LOG_OBJECT_SER_DE =
new ObjectSerDe<UltraLogLog>() {
+ @Override
+ public int getSerializedSize(UltraLogLog value) {
+ return Math.addExact(1, value.getState().length);
+ }
+
@Override
public byte[] serialize(UltraLogLog value) {
- ByteBuffer buff = ByteBuffer.wrap(new byte[(1 << value.getP()) + 1]);
- buff.put((byte) value.getP());
- buff.put(value.getState());
- return buff.array();
+ return ObjectSerDe.super.serialize(value);
+ }
+
+ @Override
+ public void serialize(UltraLogLog value, ByteBuffer destination) {
+ checkSerializationBuffer(destination, getSerializedSize(value));
+ destination.put((byte) value.getP());
+ destination.put(value.getState());
}
@Override
@@ -1984,6 +2098,29 @@ public class ObjectSerDeUtils {
return SER_DES[objectTypeValue].serialize(value);
}
+ /// Returns the codec's exact size for a representable payload, or `-1` if
allocation-free sizing is unavailable.
+ /// Intended for callers writing OBJECT payloads into an existing transport
buffer, such as an Arrow vector.
+ /// A result of `-1` selects the legacy byte-array fallback. The value must
remain unchanged until serialization ends.
+ public static int getSerializedSize(Object value, int objectTypeValue) {
+ return SER_DES[objectTypeValue].getSerializedSize(value);
+ }
+
+ /// Writes the payload through its type's codec, advancing the destination
position and preserving its byte order.
+ /// The destination must have sufficient remaining space; its limit does not
need to match the payload size.
+ /// The codec uses a temporary payload array when it does not support direct
serialization.
+ public static void serialize(Object value, int objectTypeValue, ByteBuffer
destination) {
+ SER_DES[objectTypeValue].serialize(value, destination);
+ }
+
+ private static void checkSerializationBuffer(ByteBuffer destination, int
size) {
+ if (destination.isReadOnly()) {
+ throw new ReadOnlyBufferException();
+ }
+ if (destination.remaining() < size) {
+ throw new BufferOverflowException();
+ }
+ }
+
public static <T> T deserialize(CustomObject customObject) {
return (T)
SER_DES[customObject.getType()].deserialize(customObject.getBuffer());
}
diff --git
a/pinot-core/src/test/java/org/apache/pinot/core/common/ObjectSerDeUtilsTest.java
b/pinot-core/src/test/java/org/apache/pinot/core/common/ObjectSerDeUtilsTest.java
index c7932fcbf02..41c969962a5 100644
---
a/pinot-core/src/test/java/org/apache/pinot/core/common/ObjectSerDeUtilsTest.java
+++
b/pinot-core/src/test/java/org/apache/pinot/core/common/ObjectSerDeUtilsTest.java
@@ -32,10 +32,14 @@ import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet;
+import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.ReadOnlyBufferException;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
+import java.util.HexFormat;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
@@ -49,6 +53,9 @@ import org.apache.datasketches.tuple.TupleSketch;
import org.apache.datasketches.tuple.aninteger.IntegerSummary;
import org.apache.datasketches.tuple.aninteger.IntegerSummarySetOperations;
import org.apache.datasketches.tuple.aninteger.IntegerTupleSketch;
+import org.apache.pinot.common.utils.RoaringBitmapUtils;
+import org.apache.pinot.core.common.ObjectSerDeUtils.ObjectSerDe;
+import org.apache.pinot.core.common.ObjectSerDeUtils.ObjectType;
import
org.apache.pinot.core.query.aggregation.function.PercentileEstAggregationFunction;
import
org.apache.pinot.core.query.aggregation.function.PercentileTDigestAggregationFunction;
import org.apache.pinot.core.query.aggregation.function.funnel.FunnelStepEvent;
@@ -69,10 +76,12 @@ import
org.apache.pinot.segment.local.customobject.tdigest.TDigest;
import org.apache.pinot.segment.local.customobject.tdigest.TDigest.Centroid;
import org.apache.pinot.segment.local.customobject.tdigest.TDigestAccumulator;
import org.apache.pinot.segment.local.utils.UltraLogLogUtils;
+import org.roaringbitmap.RoaringBitmap;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
import static org.testng.Assert.assertThrows;
import static org.testng.Assert.assertTrue;
@@ -101,6 +110,160 @@ public class ObjectSerDeUtilsTest {
+
"QUChLz+AAABBXvGHP4AAAEGCsOA/gAAAQZutuD+AAABBvS/yP4AAAEHr7EA/gAAAQhhGxT+AAABCTlsKP4AAAEKWasI/gAAAQvfH"
+ "yz+AAABDgpJvP4AAAESXLNE=";
+ @DataProvider(name = "directSerializationValues")
+ public Object[][] directSerializationValues() {
+ RoaringBitmap runBitmap = new RoaringBitmap();
+ runBitmap.add(100L, 10000L);
+ runBitmap.runOptimize();
+ return new Object[][]{
+ {new IntArrayList(), ObjectType.IntArrayList,
HexFormat.of().parseHex("00000000")},
+ {IntArrayList.wrap(new int[]{Integer.MIN_VALUE, Integer.MAX_VALUE, 0,
99}, 3), ObjectType.IntArrayList,
+ HexFormat.of().parseHex("00000003800000007fffffff00000000")},
+ {new LongArrayList(), ObjectType.LongArrayList,
HexFormat.of().parseHex("00000000")},
+ {LongArrayList.wrap(new long[]{Long.MIN_VALUE, Long.MAX_VALUE, 0, 99},
3), ObjectType.LongArrayList,
+
HexFormat.of().parseHex("0000000380000000000000007fffffffffffffff0000000000000000")},
+ {new FloatArrayList(), ObjectType.FloatArrayList,
HexFormat.of().parseHex("00000000")},
+ {FloatArrayList.wrap(new float[]{Float.intBitsToFloat(0x7fa12345),
-0.0f, Float.POSITIVE_INFINITY,
+ Float.NEGATIVE_INFINITY, 99}, 4), ObjectType.FloatArrayList,
+
HexFormat.of().parseHex("000000047fa12345800000007f800000ff800000")},
+ {new DoubleArrayList(), ObjectType.DoubleArrayList,
HexFormat.of().parseHex("00000000")},
+ {DoubleArrayList.wrap(new
double[]{Double.longBitsToDouble(0x7ff0123456789abcL), -0.0d,
+ Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, 99}, 4),
ObjectType.DoubleArrayList,
+
HexFormat.of().parseHex("000000047ff0123456789abc80000000000000007ff0000000000000fff0000000000000")},
+ {UltraLogLog.create(3), ObjectType.UltraLogLog,
HexFormat.of().parseHex("030000000000000000")},
+ {UltraLogLog.wrap(new byte[]{0, 1, 2, 3, 4, 5, 6, 7}),
ObjectType.UltraLogLog,
+ HexFormat.of().parseHex("030001020304050607")},
+ {new RoaringBitmap(), ObjectType.RoaringBitmap,
HexFormat.of().parseHex("3a30000000000000")},
+ {RoaringBitmap.bitmapOf(1, 3), ObjectType.RoaringBitmap,
+
HexFormat.of().parseHex("3a30000001000000000001001000000001000300")},
+ {runBitmap, ObjectType.RoaringBitmap,
RoaringBitmapUtils.serialize(runBitmap)}
+ };
+ }
+
+ @Test(dataProvider = "directSerializationValues")
+ public void testSerializeIntoBuffer(Object value, ObjectType type, byte[]
expected) {
+ int typeId = type.getValue();
+ Object inputState = copyInputState(value);
+ assertEquals(ObjectSerDeUtils.getSerializedSize(value, typeId),
expected.length);
+ assertEquals(ObjectSerDeUtils.serialize(value, typeId), expected);
+ for (boolean direct : new boolean[]{false, true}) {
+ for (ByteOrder order : new ByteOrder[]{ByteOrder.BIG_ENDIAN,
ByteOrder.LITTLE_ENDIAN}) {
+ for (int extraRemaining : new int[]{0, 5}) {
+ ByteBuffer destination = direct ?
ByteBuffer.allocateDirect(expected.length + 10)
+ : ByteBuffer.allocate(expected.length + 10);
+ while (destination.hasRemaining()) {
+ destination.put((byte) 0x5a);
+ }
+ destination.position(5).limit(5 + expected.length + extraRemaining);
+ destination.order(order);
+ ObjectSerDeUtils.serialize(value, typeId, destination);
+ assertEquals(destination.position(), 5 + expected.length);
+ assertEquals(destination.limit(), 5 + expected.length +
extraRemaining);
+ assertSame(destination.order(), order);
+ destination.clear();
+ for (int i = 0; i < 5; i++) {
+ assertEquals(destination.get(), (byte) 0x5a);
+ }
+ byte[] actual = new byte[expected.length];
+ destination.get(actual);
+ assertEquals(actual, expected);
+ while (destination.hasRemaining()) {
+ assertEquals(destination.get(), (byte) 0x5a);
+ }
+ }
+ }
+ }
+ Object decoded = ObjectSerDeUtils.deserialize(expected, type);
+ assertEquals(ObjectSerDeUtils.serialize(decoded, typeId), expected);
+ assertEquals(copyInputState(value), inputState);
+ assertEquals(ObjectSerDeUtils.getSerializedSize(value, typeId),
expected.length);
+ assertEquals(ObjectSerDeUtils.serialize(value, typeId), expected);
+ }
+
+ @Test(dataProvider = "directSerializationValues")
+ public void testSerializeIntoInvalidBuffer(Object value, ObjectType type,
byte[] expected) {
+ ByteBuffer tooSmall = ByteBuffer.allocate(expected.length +
10).order(ByteOrder.LITTLE_ENDIAN);
+ Arrays.fill(tooSmall.array(), (byte) 0x5a);
+ byte[] before = tooSmall.array().clone();
+ tooSmall.position(5).limit(5 + expected.length - 1);
+ assertThrows(BufferOverflowException.class, () ->
ObjectSerDeUtils.serialize(value, type.getValue(), tooSmall));
+ assertEquals(tooSmall.position(), 5);
+ assertSame(tooSmall.order(), ByteOrder.LITTLE_ENDIAN);
+ assertEquals(tooSmall.array(), before);
+
+ ByteBuffer readOnly = ByteBuffer.allocateDirect(expected.length +
5).asReadOnlyBuffer();
+ readOnly.position(5).order(ByteOrder.LITTLE_ENDIAN);
+ assertThrows(ReadOnlyBufferException.class, () ->
ObjectSerDeUtils.serialize(value, type.getValue(), readOnly));
+ assertEquals(readOnly.position(), 5);
+ assertSame(readOnly.order(), ByteOrder.LITTLE_ENDIAN);
+ }
+
+ @Test
+ public void testDefaultBufferSerialization() {
+ int[] serializationCount = {0};
+ ObjectSerDe<Integer> codec = new ObjectSerDe<>() {
+ @Override
+ public byte[] serialize(Integer value) {
+ serializationCount[0]++;
+ return new byte[]{value.byteValue()};
+ }
+
+ @Override
+ public Integer deserialize(byte[] bytes) {
+ return (int) bytes[0];
+ }
+
+ @Override
+ public Integer deserialize(ByteBuffer byteBuffer) {
+ return (int) byteBuffer.get();
+ }
+ };
+ assertEquals(codec.getSerializedSize(42), -1);
+ assertEquals(serializationCount[0], 0);
+ ByteBuffer destination =
ByteBuffer.allocateDirect(3).order(ByteOrder.LITTLE_ENDIAN);
+ destination.position(1).limit(2);
+ codec.serialize(42, destination);
+ assertEquals(serializationCount[0], 1);
+ assertEquals(destination.position(), 2);
+ assertEquals(destination.limit(), 2);
+ assertSame(destination.order(), ByteOrder.LITTLE_ENDIAN);
+ assertEquals(destination.get(1), (byte) 42);
+
+ assertEquals(ObjectSerDeUtils.getSerializedSize("abc",
ObjectType.String.getValue()), -1);
+ ByteBuffer stringDestination = ByteBuffer.allocate(3);
+ ObjectSerDeUtils.serialize("abc", ObjectType.String.getValue(),
stringDestination);
+ assertEquals(stringDestination.array(), new byte[]{'a', 'b', 'c'});
+ }
+
+ private static Object copyInputState(Object value) {
+ if (value instanceof IntArrayList list) {
+ return list.elements().clone();
+ }
+ if (value instanceof LongArrayList list) {
+ return list.elements().clone();
+ }
+ if (value instanceof FloatArrayList list) {
+ float[] elements = list.elements();
+ int[] bits = new int[elements.length];
+ for (int i = 0; i < elements.length; i++) {
+ bits[i] = Float.floatToRawIntBits(elements[i]);
+ }
+ return bits;
+ }
+ if (value instanceof DoubleArrayList list) {
+ double[] elements = list.elements();
+ long[] bits = new long[elements.length];
+ for (int i = 0; i < elements.length; i++) {
+ bits[i] = Double.doubleToRawLongBits(elements[i]);
+ }
+ return bits;
+ }
+ if (value instanceof UltraLogLog sketch) {
+ return sketch.getState().clone();
+ }
+ return ((RoaringBitmap) value).clone();
+ }
+
@Test
public void testString() {
for (int i = 0; i < NUM_ITERATIONS; i++) {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]