clintropolis commented on a change in pull request #11853:
URL: https://github.com/apache/druid/pull/11853#discussion_r741503261
##########
File path: core/src/main/java/org/apache/druid/segment/column/Types.java
##########
@@ -112,4 +121,529 @@
return (typeSignature1 != null && typeSignature1.is(typeDescriptor)) ||
(typeSignature2 != null && typeSignature2.is(typeDescriptor));
}
+
+ /**
+ * Get an {@link ObjectByteStrategy} registered to some {@link
TypeSignature#getComplexTypeName()}.
+ */
+ @Nullable
+ public static ObjectByteStrategy<?> getStrategy(String type)
+ {
+ return STRATEGIES.get(type);
+ }
+
+ /**
+ * hmm... this might look familiar... (see ComplexMetrics)
+ *
+ * Register a complex type name -> {@link ObjectByteStrategy} mapping.
+ *
+ * If the specified type name or type id are already used and the supplied
{@link ObjectByteStrategy} is not of the
+ * same type as the existing value in the map for said key, an {@link ISE}
is thrown.
+ *
+ * @param strategy The {@link ObjectByteStrategy} object to be associated
with the 'type' in the map.
+ */
+ public static void registerStrategy(String typeName, ObjectByteStrategy<?>
strategy)
+ {
+ Preconditions.checkNotNull(typeName);
+ STRATEGIES.compute(typeName, (key, value) -> {
+ if (value == null) {
+ return strategy;
+ } else {
+ if (!value.getClass().getName().equals(strategy.getClass().getName()))
{
+ throw new ISE(
+ "Incompatible strategy for type[%s] already exists. Expected
[%s], found [%s].",
+ key,
+ strategy.getClass().getName(),
+ value.getClass().getName()
+ );
+ } else {
+ return value;
+ }
+ }
+ });
+ }
+
+ /**
+ * Clear and set the 'null' byte of a nullable value to {@link
NullHandling#IS_NULL_BYTE} to a {@link ByteBuffer} at
+ * the supplied position. This method does not change the buffer position,
limit, or mark.
+ *
+ * Nullable types are stored with a leading byte to indicate if the value is
null, followed by teh value bytes
+ * (if not null)
+ *
+ * layout: | null (byte) | value |
+ *
+ * @return number of bytes written (always 1)
+ */
+ public static int writeNull(ByteBuffer buffer, int offset)
+ {
+ buffer.put(offset, NullHandling.IS_NULL_BYTE);
+ return 1;
+ }
+
+ /**
+ * Checks if a 'nullable' value's null byte is set to {@link
NullHandling#IS_NULL_BYTE}. This method will mask the
+ * value of the null byte to only check if the null bit is set, meaning that
the higher bits can be utilized for
+ * flags as necessary (e.g. using high bits to indicate if the value has
been set or not for aggregators).
+ *
+ * Note that writing nullable values with the methods of {@link Types} will
always clear and set the null byte to
+ * either {@link NullHandling#IS_NULL_BYTE} or {@link
NullHandling#IS_NOT_NULL_BYTE}, losing any flag bits.
+ *
+ * layout: | null (byte) | value |
+ */
+ public static boolean isNullableNull(ByteBuffer buffer, int offset)
+ {
+ // use & so that callers can use the high bits of the null byte to pack
additional information if necessary
+ return (buffer.get(offset) & NullHandling.IS_NULL_BYTE) ==
NullHandling.IS_NULL_BYTE;
+ }
+
+ /**
+ * Write a non-null long value to a {@link ByteBuffer} at the supplied
offset. The first byte is always cleared and
+ * set to {@link NullHandling#IS_NOT_NULL_BYTE}, the long value is written
in the next 8 bytes.
+ *
+ * layout: | null (byte) | long |
+ *
+ * This method does not change the buffer position, limit, or mark.
+ *
+ * @return number of bytes written (always 9)
+ */
+ public static int writeNullableLong(ByteBuffer buffer, int offset, long
value)
+ {
+ buffer.put(offset++, NullHandling.IS_NOT_NULL_BYTE);
+ buffer.putLong(offset, value);
+ return NULLABLE_LONG_SIZE;
+ }
+
+ /**
+ * Reads a non-null long value from a {@link ByteBuffer} at the supplied
offset. This method should only be called
+ * if and only if {@link #isNullableNull} for the same offset returns false.
+ *
+ * layout: | null (byte) | long |
+ *
+ * This method does not change the buffer position, limit, or mark.
+ */
+ public static long readNullableLong(ByteBuffer buffer, int offset)
+ {
+ assert !isNullableNull(buffer, offset);
+ return buffer.getLong(offset + VALUE_OFFSET);
+ }
+
+ /**
+ * Write a non-null double value to a {@link ByteBuffer} at the supplied
offset. The first byte is always cleared and
+ * set to {@link NullHandling#IS_NOT_NULL_BYTE}, the double value is written
in the next 8 bytes.
+ *
+ * layout: | null (byte) | double |
+ *
+ * This method does not change the buffer position, limit, or mark.
+ *
+ * @return number of bytes written (always 9)
+ */
+ public static int writeNullableDouble(ByteBuffer buffer, int offset, double
value)
+ {
+ buffer.put(offset++, NullHandling.IS_NOT_NULL_BYTE);
+ buffer.putDouble(offset, value);
+ return NULLABLE_DOUBLE_SIZE;
+ }
+
+ /**
+ * Reads a non-null double value from a {@link ByteBuffer} at the supplied
offset. This method should only be called
+ * if and only if {@link #isNullableNull} for the same offset returns false.
+ *
+ * layout: | null (byte) | double |
+ *
+ * This method does not change the buffer position, limit, or mark.
+ */
+ public static double readNullableDouble(ByteBuffer buffer, int offset)
+ {
+ assert !isNullableNull(buffer, offset);
+ return buffer.getDouble(offset + VALUE_OFFSET);
+ }
+
+ /**
+ * Write a non-null float value to a {@link ByteBuffer} at the supplied
offset. The first byte is always cleared and
+ * set to {@link NullHandling#IS_NOT_NULL_BYTE}, the float value is written
in the next 4 bytes.
+ *
+ * layout: | null (byte) | float |
+ *
+ * This method does not change the buffer position, limit, or mark.
+ *
+ * @return number of bytes written (always 5)
+ */
+ public static int writeNullableFloat(ByteBuffer buffer, int offset, float
value)
+ {
+ buffer.put(offset++, NullHandling.IS_NOT_NULL_BYTE);
+ buffer.putFloat(offset, value);
+ return NULLABLE_FLOAT_SIZE;
+ }
+
+ /**
+ * Reads a non-null float value from a {@link ByteBuffer} at the supplied
offset. This method should only be called
+ * if and only if {@link #isNullableNull} for the same offset returns false.
+ *
+ * layout: | null (byte) | float |
+ *
+ * This method does not change the buffer position, limit, or mark.
+ */
+ public static float readNullableFloat(ByteBuffer buffer, int offset)
+ {
+ assert !isNullableNull(buffer, offset);
+ return buffer.getFloat(offset + VALUE_OFFSET);
+ }
+
+ /**
+ * Write a variably lengthed byte[] value to a {@link ByteBuffer} at the
supplied offset. The first byte is set to
+ * {@link NullHandling#IS_NULL_BYTE} or {@link
NullHandling#IS_NOT_NULL_BYTE} as appropriate, and if the byte[] value
+ * is not null, the size in bytes is written as an integer in the next 4
bytes, followed by the byte[] value itself.
+ *
+ * layout: | null (byte) | size (int) | byte[] |
+ *
+ * This method does not permanently change the buffer position, limit, or
mark.
+ *
+ * @return number of bytes written (1 if null, or 5 + size of byte[] if not)
+ */
+ public static int writeNullableVariableBlob(ByteBuffer buffer, int offset,
@Nullable byte[] value)
+ {
+ // | null (byte) | length (int) | bytes |
+ final int size;
+ if (value != null) {
+ buffer.put(offset++, NullHandling.IS_NOT_NULL_BYTE);
+ buffer.putInt(offset, value.length);
+ offset += Integer.BYTES;
+ final int oldPosition = buffer.position();
+ buffer.position(offset);
+ buffer.put(value, 0, value.length);
+ buffer.position(oldPosition);
+ size = 1 + Integer.BYTES + value.length;
+ } else {
+ size = writeNull(buffer, offset);
+ }
+ return size;
+ }
+
+ /**
+ * Reads a nullable variably lengthed byte[] value from a {@link ByteBuffer}
at the supplied offset. If the null byte
+ * is set to {@link NullHandling#IS_NULL_BYTE}, this method will return
null, else it will read the next 4 bytes to
+ * get the byte[] size followed by that many bytes to extract the value.
+ *
+ * layout: | null (byte) | size (int) | byte[] |
+ *
+ * This method does not change the buffer position, limit, or mark.
+ */
+ @Nullable
+ public static byte[] readNullableVariableBlob(ByteBuffer buffer, int offset)
+ {
+ // | null (byte) | length (int) | bytes |
+ final int length = buffer.getInt(offset + VALUE_OFFSET);
+ final byte[] blob = new byte[length];
+ final int oldPosition = buffer.position();
+ buffer.position(offset + VALUE_OFFSET + Integer.BYTES);
+ buffer.get(blob, 0, length);
+ buffer.position(oldPosition);
+ return blob;
+ }
+
+ /**
+ * Write a variably lengthed Long[] value to a {@link ByteBuffer} at the
supplied offset. The first byte is set to
+ * {@link NullHandling#IS_NULL_BYTE} or {@link
NullHandling#IS_NOT_NULL_BYTE} as appropriate, and if the Long[] value
+ * is not null, the size in bytes is written as an integer in the next 4
bytes. Elements of the array are each written
+ * out with {@link #writeNull} if null, or {@link #writeNullableLong} if
not, taking either 1 or 9 bytes each. If the
+ * total byte size of serializing the array is larger than the max size
parameter, this method will explode via a call
+ * to {@link #checkMaxBytes}.
+ *
+ * layout: | null (byte) | size (int) | {| null (byte) | long |, | null
(byte) |, ... |null (byte) | long |} |
+ *
+ *
+ * This method does not permanently change the buffer position, limit, or
mark.
+ *
+ * @return number of bytes written (1 if null, or 5 + size of Long[] if not)
+ */
+ public static int writeNullableLongArray(ByteBuffer buffer, int offset,
@Nullable Long[] array, int maxSizeBytes)
+ {
+ // | null (byte) | array length (int) | array bytes |
+ if (array == null) {
+ return writeNull(buffer, offset);
+ } else {
+ int sizeBytes = 1 + Integer.BYTES;
+
+ buffer.put(offset, NullHandling.IS_NOT_NULL_BYTE);
+ buffer.putInt(offset + 1, array.length);
+ for (Long element : array) {
+ if (element != null) {
+ checkMaxBytes(
+ ColumnType.LONG_ARRAY,
+ sizeBytes + 1 + Long.BYTES,
+ maxSizeBytes
+ );
+ sizeBytes += writeNullableLong(buffer, offset + sizeBytes, element);
+ } else {
+ checkMaxBytes(
+ ColumnType.LONG_ARRAY,
+ sizeBytes + 1,
+ maxSizeBytes
+ );
+ sizeBytes += writeNull(buffer, offset + sizeBytes);
+ }
+ }
+ return sizeBytes;
+ }
+ }
+
+ /**
+ * Reads a nullable variably lengthed Long[] value from a {@link ByteBuffer}
at the supplied offset. If the null byte
+ * is set to {@link NullHandling#IS_NULL_BYTE}, this method will return
null, else it will read the size of the array
+ * from the next 4 bytes and then read that many elements with {@link
#isNullableNull} and {@link #readNullableLong}.
+ *
+ * layout: | null (byte) | size (int) | {| null (byte) | long |, | null
(byte) |, ... |null (byte) | long |} |
+ *
+ * This method does not change the buffer position, limit, or mark.
+ */
+ @Nullable
+ public static Long[] readNullableLongArray(ByteBuffer buffer, int offset)
+ {
+ // | null (byte) | array length (int) | array bytes |
+ if (isNullableNull(buffer, offset++)) {
+ return null;
+ }
+ final int longArrayLength = buffer.getInt(offset);
+ offset += Integer.BYTES;
+ final Long[] longs = new Long[longArrayLength];
+ for (int i = 0; i < longArrayLength; i++) {
+ if (isNullableNull(buffer, offset)) {
+ longs[i] = null;
+ } else {
+ longs[i] = readNullableLong(buffer, offset);
+ offset += Long.BYTES;
+ }
+ offset++;
+ }
+ return longs;
+ }
+
+ /**
+ * Write a variably lengthed Double[] value to a {@link ByteBuffer} at the
supplied offset. The first byte is set to
+ * {@link NullHandling#IS_NULL_BYTE} or {@link
NullHandling#IS_NOT_NULL_BYTE} as appropriate, and if the Long[] value
+ * is not null, the size in bytes is written as an integer in the next 4
bytes. Elements of the array are each written
+ * out with {@link #writeNull} if null, or {@link #writeNullableDouble} if
not, taking either 1 or 9 bytes each. If
+ * the total byte size of serializing the array is larger than the max size
parameter, this method will explode via a
+ * call to {@link #checkMaxBytes}.
+ *
+ * layout: | null (byte) | size (int) | {| null (byte) | double |, | null
(byte) |, ... |null (byte) | double |} |
+ *
+ *
+ * This method does not permanently change the buffer position, limit, or
mark.
+ *
+ * @return number of bytes written (1 if null, or 5 + size of Double[] if
not)
+ */
+ public static int writeNullableDoubleArray(ByteBuffer buffer, int offset,
@Nullable Double[] array, int maxSizeBytes)
Review comment:
it is easier to be consistent across all types working in bytes, because
variably sized types like strings and string arrays become sort of hard to
reason about. The main reason here is that the expression aggregator has a
single max size bytes parameter (since that aggregator can potentially
aggregate any type)
##########
File path: core/src/main/java/org/apache/druid/segment/column/Types.java
##########
@@ -112,4 +121,529 @@
return (typeSignature1 != null && typeSignature1.is(typeDescriptor)) ||
(typeSignature2 != null && typeSignature2.is(typeDescriptor));
}
+
+ /**
+ * Get an {@link ObjectByteStrategy} registered to some {@link
TypeSignature#getComplexTypeName()}.
+ */
+ @Nullable
+ public static ObjectByteStrategy<?> getStrategy(String type)
+ {
+ return STRATEGIES.get(type);
+ }
+
+ /**
+ * hmm... this might look familiar... (see ComplexMetrics)
+ *
+ * Register a complex type name -> {@link ObjectByteStrategy} mapping.
+ *
+ * If the specified type name or type id are already used and the supplied
{@link ObjectByteStrategy} is not of the
+ * same type as the existing value in the map for said key, an {@link ISE}
is thrown.
+ *
+ * @param strategy The {@link ObjectByteStrategy} object to be associated
with the 'type' in the map.
+ */
+ public static void registerStrategy(String typeName, ObjectByteStrategy<?>
strategy)
+ {
+ Preconditions.checkNotNull(typeName);
+ STRATEGIES.compute(typeName, (key, value) -> {
+ if (value == null) {
+ return strategy;
+ } else {
+ if (!value.getClass().getName().equals(strategy.getClass().getName()))
{
+ throw new ISE(
+ "Incompatible strategy for type[%s] already exists. Expected
[%s], found [%s].",
+ key,
+ strategy.getClass().getName(),
+ value.getClass().getName()
+ );
+ } else {
+ return value;
+ }
+ }
+ });
+ }
+
+ /**
+ * Clear and set the 'null' byte of a nullable value to {@link
NullHandling#IS_NULL_BYTE} to a {@link ByteBuffer} at
+ * the supplied position. This method does not change the buffer position,
limit, or mark.
+ *
+ * Nullable types are stored with a leading byte to indicate if the value is
null, followed by teh value bytes
+ * (if not null)
+ *
+ * layout: | null (byte) | value |
+ *
+ * @return number of bytes written (always 1)
+ */
+ public static int writeNull(ByteBuffer buffer, int offset)
+ {
+ buffer.put(offset, NullHandling.IS_NULL_BYTE);
+ return 1;
+ }
+
+ /**
+ * Checks if a 'nullable' value's null byte is set to {@link
NullHandling#IS_NULL_BYTE}. This method will mask the
+ * value of the null byte to only check if the null bit is set, meaning that
the higher bits can be utilized for
+ * flags as necessary (e.g. using high bits to indicate if the value has
been set or not for aggregators).
+ *
+ * Note that writing nullable values with the methods of {@link Types} will
always clear and set the null byte to
+ * either {@link NullHandling#IS_NULL_BYTE} or {@link
NullHandling#IS_NOT_NULL_BYTE}, losing any flag bits.
+ *
+ * layout: | null (byte) | value |
+ */
+ public static boolean isNullableNull(ByteBuffer buffer, int offset)
+ {
+ // use & so that callers can use the high bits of the null byte to pack
additional information if necessary
+ return (buffer.get(offset) & NullHandling.IS_NULL_BYTE) ==
NullHandling.IS_NULL_BYTE;
+ }
+
+ /**
+ * Write a non-null long value to a {@link ByteBuffer} at the supplied
offset. The first byte is always cleared and
+ * set to {@link NullHandling#IS_NOT_NULL_BYTE}, the long value is written
in the next 8 bytes.
+ *
+ * layout: | null (byte) | long |
+ *
+ * This method does not change the buffer position, limit, or mark.
+ *
+ * @return number of bytes written (always 9)
+ */
+ public static int writeNullableLong(ByteBuffer buffer, int offset, long
value)
+ {
+ buffer.put(offset++, NullHandling.IS_NOT_NULL_BYTE);
+ buffer.putLong(offset, value);
+ return NULLABLE_LONG_SIZE;
+ }
+
+ /**
+ * Reads a non-null long value from a {@link ByteBuffer} at the supplied
offset. This method should only be called
+ * if and only if {@link #isNullableNull} for the same offset returns false.
+ *
+ * layout: | null (byte) | long |
+ *
+ * This method does not change the buffer position, limit, or mark.
+ */
+ public static long readNullableLong(ByteBuffer buffer, int offset)
+ {
+ assert !isNullableNull(buffer, offset);
+ return buffer.getLong(offset + VALUE_OFFSET);
+ }
+
+ /**
+ * Write a non-null double value to a {@link ByteBuffer} at the supplied
offset. The first byte is always cleared and
+ * set to {@link NullHandling#IS_NOT_NULL_BYTE}, the double value is written
in the next 8 bytes.
+ *
+ * layout: | null (byte) | double |
+ *
+ * This method does not change the buffer position, limit, or mark.
+ *
+ * @return number of bytes written (always 9)
+ */
+ public static int writeNullableDouble(ByteBuffer buffer, int offset, double
value)
+ {
+ buffer.put(offset++, NullHandling.IS_NOT_NULL_BYTE);
+ buffer.putDouble(offset, value);
+ return NULLABLE_DOUBLE_SIZE;
+ }
+
+ /**
+ * Reads a non-null double value from a {@link ByteBuffer} at the supplied
offset. This method should only be called
+ * if and only if {@link #isNullableNull} for the same offset returns false.
+ *
+ * layout: | null (byte) | double |
+ *
+ * This method does not change the buffer position, limit, or mark.
+ */
+ public static double readNullableDouble(ByteBuffer buffer, int offset)
+ {
+ assert !isNullableNull(buffer, offset);
+ return buffer.getDouble(offset + VALUE_OFFSET);
+ }
+
+ /**
+ * Write a non-null float value to a {@link ByteBuffer} at the supplied
offset. The first byte is always cleared and
+ * set to {@link NullHandling#IS_NOT_NULL_BYTE}, the float value is written
in the next 4 bytes.
+ *
+ * layout: | null (byte) | float |
+ *
+ * This method does not change the buffer position, limit, or mark.
+ *
+ * @return number of bytes written (always 5)
+ */
+ public static int writeNullableFloat(ByteBuffer buffer, int offset, float
value)
+ {
+ buffer.put(offset++, NullHandling.IS_NOT_NULL_BYTE);
+ buffer.putFloat(offset, value);
+ return NULLABLE_FLOAT_SIZE;
+ }
+
+ /**
+ * Reads a non-null float value from a {@link ByteBuffer} at the supplied
offset. This method should only be called
+ * if and only if {@link #isNullableNull} for the same offset returns false.
+ *
+ * layout: | null (byte) | float |
+ *
+ * This method does not change the buffer position, limit, or mark.
+ */
+ public static float readNullableFloat(ByteBuffer buffer, int offset)
+ {
+ assert !isNullableNull(buffer, offset);
+ return buffer.getFloat(offset + VALUE_OFFSET);
+ }
+
+ /**
+ * Write a variably lengthed byte[] value to a {@link ByteBuffer} at the
supplied offset. The first byte is set to
+ * {@link NullHandling#IS_NULL_BYTE} or {@link
NullHandling#IS_NOT_NULL_BYTE} as appropriate, and if the byte[] value
+ * is not null, the size in bytes is written as an integer in the next 4
bytes, followed by the byte[] value itself.
+ *
+ * layout: | null (byte) | size (int) | byte[] |
+ *
+ * This method does not permanently change the buffer position, limit, or
mark.
+ *
+ * @return number of bytes written (1 if null, or 5 + size of byte[] if not)
+ */
+ public static int writeNullableVariableBlob(ByteBuffer buffer, int offset,
@Nullable byte[] value)
+ {
+ // | null (byte) | length (int) | bytes |
+ final int size;
+ if (value != null) {
+ buffer.put(offset++, NullHandling.IS_NOT_NULL_BYTE);
+ buffer.putInt(offset, value.length);
+ offset += Integer.BYTES;
+ final int oldPosition = buffer.position();
+ buffer.position(offset);
+ buffer.put(value, 0, value.length);
+ buffer.position(oldPosition);
+ size = 1 + Integer.BYTES + value.length;
+ } else {
+ size = writeNull(buffer, offset);
+ }
+ return size;
+ }
+
+ /**
+ * Reads a nullable variably lengthed byte[] value from a {@link ByteBuffer}
at the supplied offset. If the null byte
+ * is set to {@link NullHandling#IS_NULL_BYTE}, this method will return
null, else it will read the next 4 bytes to
+ * get the byte[] size followed by that many bytes to extract the value.
+ *
+ * layout: | null (byte) | size (int) | byte[] |
+ *
+ * This method does not change the buffer position, limit, or mark.
+ */
+ @Nullable
+ public static byte[] readNullableVariableBlob(ByteBuffer buffer, int offset)
+ {
+ // | null (byte) | length (int) | bytes |
+ final int length = buffer.getInt(offset + VALUE_OFFSET);
+ final byte[] blob = new byte[length];
+ final int oldPosition = buffer.position();
+ buffer.position(offset + VALUE_OFFSET + Integer.BYTES);
+ buffer.get(blob, 0, length);
+ buffer.position(oldPosition);
+ return blob;
+ }
+
+ /**
+ * Write a variably lengthed Long[] value to a {@link ByteBuffer} at the
supplied offset. The first byte is set to
+ * {@link NullHandling#IS_NULL_BYTE} or {@link
NullHandling#IS_NOT_NULL_BYTE} as appropriate, and if the Long[] value
+ * is not null, the size in bytes is written as an integer in the next 4
bytes. Elements of the array are each written
+ * out with {@link #writeNull} if null, or {@link #writeNullableLong} if
not, taking either 1 or 9 bytes each. If the
+ * total byte size of serializing the array is larger than the max size
parameter, this method will explode via a call
+ * to {@link #checkMaxBytes}.
+ *
+ * layout: | null (byte) | size (int) | {| null (byte) | long |, | null
(byte) |, ... |null (byte) | long |} |
+ *
+ *
+ * This method does not permanently change the buffer position, limit, or
mark.
+ *
+ * @return number of bytes written (1 if null, or 5 + size of Long[] if not)
+ */
+ public static int writeNullableLongArray(ByteBuffer buffer, int offset,
@Nullable Long[] array, int maxSizeBytes)
+ {
+ // | null (byte) | array length (int) | array bytes |
+ if (array == null) {
+ return writeNull(buffer, offset);
+ } else {
+ int sizeBytes = 1 + Integer.BYTES;
+
+ buffer.put(offset, NullHandling.IS_NOT_NULL_BYTE);
+ buffer.putInt(offset + 1, array.length);
+ for (Long element : array) {
+ if (element != null) {
+ checkMaxBytes(
+ ColumnType.LONG_ARRAY,
+ sizeBytes + 1 + Long.BYTES,
+ maxSizeBytes
+ );
+ sizeBytes += writeNullableLong(buffer, offset + sizeBytes, element);
+ } else {
+ checkMaxBytes(
+ ColumnType.LONG_ARRAY,
+ sizeBytes + 1,
+ maxSizeBytes
+ );
+ sizeBytes += writeNull(buffer, offset + sizeBytes);
+ }
+ }
+ return sizeBytes;
+ }
+ }
+
+ /**
+ * Reads a nullable variably lengthed Long[] value from a {@link ByteBuffer}
at the supplied offset. If the null byte
+ * is set to {@link NullHandling#IS_NULL_BYTE}, this method will return
null, else it will read the size of the array
+ * from the next 4 bytes and then read that many elements with {@link
#isNullableNull} and {@link #readNullableLong}.
+ *
+ * layout: | null (byte) | size (int) | {| null (byte) | long |, | null
(byte) |, ... |null (byte) | long |} |
+ *
+ * This method does not change the buffer position, limit, or mark.
+ */
+ @Nullable
+ public static Long[] readNullableLongArray(ByteBuffer buffer, int offset)
+ {
+ // | null (byte) | array length (int) | array bytes |
+ if (isNullableNull(buffer, offset++)) {
+ return null;
+ }
+ final int longArrayLength = buffer.getInt(offset);
+ offset += Integer.BYTES;
+ final Long[] longs = new Long[longArrayLength];
+ for (int i = 0; i < longArrayLength; i++) {
+ if (isNullableNull(buffer, offset)) {
+ longs[i] = null;
+ } else {
+ longs[i] = readNullableLong(buffer, offset);
+ offset += Long.BYTES;
+ }
+ offset++;
+ }
+ return longs;
+ }
+
+ /**
+ * Write a variably lengthed Double[] value to a {@link ByteBuffer} at the
supplied offset. The first byte is set to
+ * {@link NullHandling#IS_NULL_BYTE} or {@link
NullHandling#IS_NOT_NULL_BYTE} as appropriate, and if the Long[] value
+ * is not null, the size in bytes is written as an integer in the next 4
bytes. Elements of the array are each written
+ * out with {@link #writeNull} if null, or {@link #writeNullableDouble} if
not, taking either 1 or 9 bytes each. If
+ * the total byte size of serializing the array is larger than the max size
parameter, this method will explode via a
+ * call to {@link #checkMaxBytes}.
+ *
+ * layout: | null (byte) | size (int) | {| null (byte) | double |, | null
(byte) |, ... |null (byte) | double |} |
+ *
+ *
+ * This method does not permanently change the buffer position, limit, or
mark.
+ *
+ * @return number of bytes written (1 if null, or 5 + size of Double[] if
not)
+ */
+ public static int writeNullableDoubleArray(ByteBuffer buffer, int offset,
@Nullable Double[] array, int maxSizeBytes)
+ {
+ // | null (byte) | array length (int) | array bytes |
+ if (array == null) {
+ return writeNull(buffer, offset);
+ } else {
Review comment:
:+1: fixed
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]