clintropolis commented on a change in pull request #11853:
URL: https://github.com/apache/druid/pull/11853#discussion_r741501467



##########
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)

Review comment:
       added note to javadoc that mention that the contract of these methods is 
that at least max size bytes must be available in the buffer, which is 
acceptable for current callers who know their max limit




-- 
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]

Reply via email to