You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datasketches.apache.org by dc...@apache.org on 2021/08/19 22:18:24 UTC

svn commit: r49567 [8/14] - in /dev/datasketches/memory/2.0.0-RC1: ./ apache-datasketches-memory-2.0.0-src/ apache-datasketches-memory-2.0.0-src/datasketches-memory-java11/ apache-datasketches-memory-2.0.0-src/datasketches-memory-java11/src/ apache-dat...

Added: dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/WritableMemory.java
==============================================================================
--- dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/WritableMemory.java (added)
+++ dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/WritableMemory.java Thu Aug 19 22:18:24 2021
@@ -0,0 +1,641 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory;
+
+import static org.apache.datasketches.memory.internal.Util.negativeCheck;
+
+import java.io.File;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Objects;
+
+import org.apache.datasketches.memory.internal.BaseWritableMemoryImpl;
+import org.apache.datasketches.memory.internal.Prim;
+import org.apache.datasketches.memory.internal.UnsafeUtil;
+
+/**
+ * Defines the writable API for offset access to a resource.
+ *
+ * @author Lee Rhodes
+ */
+public interface WritableMemory extends Memory {
+
+  //BYTE BUFFER
+  /**
+   * Accesses the given <i>ByteBuffer</i> for write operations. The returned <i>WritableMemory</i> object has
+   * the same byte order, as the given <i>ByteBuffer</i>.
+   * @param byteBuffer the given <i>ByteBuffer</i>. It must be non-null, with capacity &ge; 0, and writable.
+   * @return a new <i>WritableMemory</i> for write operations on the given <i>ByteBuffer</i>.
+   */
+  static WritableMemory writableWrap(ByteBuffer byteBuffer) {
+    return writableWrap(byteBuffer, byteBuffer.order(), defaultMemReqSvr);
+  }
+
+  /**
+   * Accesses the given <i>ByteBuffer</i> for write operations. The returned <i>WritableMemory</i> object has
+   * the given byte order, ignoring the byte order of the given <i>ByteBuffer</i> for future writes and following reads.
+   * However, this does not change the byte order of data already in the <i>ByteBuffer</i>.
+   * @param byteBuffer the given <i>ByteBuffer</i>. It must be non-null, with capacity &ge; 0, and writable.
+   * @param byteOrder the byte order to be used. It must be non-null.
+   * @return a new <i>WritableMemory</i> for write operations on the given <i>ByteBuffer</i>.
+   */
+  static WritableMemory writableWrap(ByteBuffer byteBuffer, ByteOrder byteOrder) {
+    return writableWrap(byteBuffer, byteOrder, defaultMemReqSvr);
+  }
+
+  /**
+   * Accesses the given <i>ByteBuffer</i> for write operations. The returned <i>WritableMemory</i> object has
+   * the given byte order, ignoring the byte order of the given <i>ByteBuffer</i> for future reads and writes.
+   * However, this does not change the byte order of data already in the <i>ByteBuffer</i>.
+   * @param byteBuffer the given <i>ByteBuffer</i>. It must be non-null, with capacity &ge; 0, and writable.
+   * @param byteOrder the byte order to be used. It must be non-null.
+   * @param memReqSvr A user-specified <i>MemoryRequestServer</i>, which may be null.
+   * This is a callback mechanism for a user client to request a larger <i>WritableMemory</i>.
+   * @return a new <i>WritableMemory</i> for write operations on the given <i>ByteBuffer</i>.
+   */
+  static WritableMemory writableWrap(ByteBuffer byteBuffer, ByteOrder byteOrder, MemoryRequestServer memReqSvr) {
+    Objects.requireNonNull(byteBuffer, "byteBuffer must be non-null");
+    Objects.requireNonNull(byteOrder, "byteOrder must be non-null");
+    negativeCheck(byteBuffer.capacity(), "byteBuffer");
+    if (byteBuffer.isReadOnly()) { throw new ReadOnlyException("byteBuffer must be writable."); }
+    return BaseWritableMemoryImpl.wrapByteBuffer(byteBuffer, false, byteOrder, memReqSvr);
+  }
+
+  //MAP
+  /**
+   * Maps the entire given file into native-ordered WritableMemory for write operations
+   * Calling this method is equivalent to calling
+   * {@link #writableMap(File, long, long, ByteOrder) writableMap(file, 0, file.length(), ByteOrder.nativeOrder())}.
+   * @param file the given file to map. It must be non-null, with length &ge; 0, and writable.
+   * @return WritableMapHandle for managing the mapped Memory.
+   * Please read Javadocs for {@link Handle}.
+   */
+  static WritableMapHandle writableMap(File file) {
+    return writableMap(file, 0, file.length(), ByteOrder.nativeOrder());
+  }
+
+  /**
+   * Maps the specified portion of the given file into Memory for write operations.
+   *
+   * <p><b>Note:</b> Always qualify this method with the class name, e.g.,
+   * <i>WritableMemory.map(...)</i>.
+   * @param file the given file to map. It must be non-null, writable and length &ge; 0.
+   * @param fileOffsetBytes the position in the given file in bytes. It must not be negative.
+   * @param capacityBytes the size of the mapped Memory. It must not be negative.
+   * @param byteOrder the byte order to be used for the given file. It must be non-null.
+   * @return WritableMapHandle for managing the mapped Memory.
+   * Please read Javadocs for {@link Handle}.
+   */
+  static WritableMapHandle writableMap(File file, long fileOffsetBytes, long capacityBytes, ByteOrder byteOrder) {
+    Objects.requireNonNull(file, "file must be non-null.");
+    Objects.requireNonNull(byteOrder, "byteOrder must be non-null.");
+    if (!file.canWrite()) { throw new ReadOnlyException("file must be writable."); }
+    negativeCheck(file.length(), "file.length()");
+    negativeCheck(fileOffsetBytes, "fileOffsetBytes");
+    negativeCheck(capacityBytes, "capacityBytes");
+    return BaseWritableMemoryImpl.wrapMap(file, fileOffsetBytes, capacityBytes, false, byteOrder);
+  }
+
+  //ALLOCATE DIRECT
+  /**
+   * Allocates and provides access to capacityBytes directly in native (off-heap) memory.
+   * Native byte order is assumed.
+   * The allocated memory will be 8-byte aligned, but may not be page aligned.
+   *
+   * <p><b>NOTE:</b> Native/Direct memory acquired may have garbage in it.
+   * It is the responsibility of the using application to clear this memory, if required,
+   * and to call <i>close()</i> when done.</p>
+   *
+   * @param capacityBytes the size of the desired memory in bytes. It must be &ge; 0.
+   * @return WritableHandle for this off-heap resource.
+   * Please read Javadocs for {@link Handle}.
+   */
+  static WritableHandle allocateDirect(long capacityBytes) {
+    return allocateDirect(capacityBytes, ByteOrder.nativeOrder(), defaultMemReqSvr);
+  }
+
+  /**
+   * Allocates and provides access to capacityBytes directly in native (off-heap) memory.
+   * The allocated memory will be 8-byte aligned, but may not be page aligned.
+   *
+   * <p><b>NOTE:</b> Native/Direct memory acquired may have garbage in it.
+   * It is the responsibility of the using application to clear this memory, if required,
+   * and to call <i>close()</i> when done.</p>
+   *
+   * @param capacityBytes the size of the desired memory in bytes. It must be &ge; 0.
+   * @param byteOrder the given byte order. It must be non-null.
+   * @param memReqSvr A user-specified MemoryRequestServer, which may be null.
+   * This is a callback mechanism for a user client of direct memory to request more memory.
+   * @return WritableHandle for this off-heap resource.
+   * Please read Javadocs for {@link Handle}.
+   */
+  static WritableHandle allocateDirect(long capacityBytes, ByteOrder byteOrder, MemoryRequestServer memReqSvr) {
+    Objects.requireNonNull(byteOrder, "byteOrder must be non-null");
+    negativeCheck(capacityBytes, "capacityBytes");
+    return BaseWritableMemoryImpl.wrapDirect(capacityBytes, byteOrder, memReqSvr);
+  }
+
+  //REGIONS
+  /**
+   * A writable region is a writable view of this object.
+   * This returns a new <i>WritableMemory</i> representing the defined writable region with the
+   * given offsetBytes and capacityBytes.
+   * <ul>
+   * <li>Returned object's origin = this objects' origin + <i>offsetBytes</i></li>
+   * <li>Returned object's capacity = <i>capacityBytes</i></li>
+   * </ul>
+   *
+   * @param offsetBytes the starting offset with respect to this object. It must be &ge; 0.
+   * @param capacityBytes the capacity of the returned object in bytes. It must be &ge; 0.
+   * @return a new <i>WritableMemory</i> representing the defined writable region.
+   */
+  default WritableMemory writableRegion(long offsetBytes, long capacityBytes) {
+    return writableRegion(offsetBytes, capacityBytes, getTypeByteOrder());
+  }
+
+  /**
+   * A writable region is a writable view of this object.
+   * This returns a new <i>WritableMemory</i> representing the defined writable region with the
+   * given offsetBytes, capacityBytes and byte order.
+   * <ul>
+   * <li>Returned object's origin = this objects' origin + <i>offsetBytes</i></li>
+   * <li>Returned object's capacity = <i>capacityBytes</i></li>
+   * <li>Returned object's byte order = <i>byteOrder</i></li>
+   * </ul>
+   *
+   * @param offsetBytes the starting offset with respect to this object. It must be &ge; 0.
+   * @param capacityBytes the capacity of the returned object in bytes. It must be &ge; 0.
+   * @param byteOrder the given byte order. It must be non-null.
+   * @return a new <i>WritableMemory</i> representing the defined writable region.
+   */
+  WritableMemory writableRegion(long offsetBytes, long capacityBytes, ByteOrder byteOrder);
+
+  //AS WRITABLE BUFFER
+  /**
+   * Returns a new <i>WritableBuffer</i> with a writable view of this object.
+   * <ul>
+   * <li>Returned object's origin = this object's origin</li>
+   * <li>Returned object's <i>start</i> = 0</li>
+   * <li>Returned object's <i>position</i> = 0</li>
+   * <li>Returned object's <i>end</i> = this object's capacity</li>
+   * <li>Returned object's <i>capacity</i> = this object's capacity</li>
+   * <li>Returned object's <i>start</i>, <i>position</i> and <i>end</i> are mutable</li>
+   * </ul>
+   * @return a new <i>WritableBuffer</i> with a view of this WritableMemory
+   */
+  default WritableBuffer asWritableBuffer() {
+    return asWritableBuffer(getTypeByteOrder());
+  }
+
+  /**
+   * Returns a new <i>WritableBuffer</i> with a writable view of this object
+   * with the given byte order.
+   * <ul>
+   * <li>Returned object's origin = this object's origin</li>
+   * <li>Returned object's <i>start</i> = 0</li>
+   * <li>Returned object's <i>position</i> = 0</li>
+   * <li>Returned object's <i>end</i> = this object's capacity</li>
+   * <li>Returned object's <i>capacity</i> = this object's capacity</li>
+   * <li>Returned object's <i>start</i>, <i>position</i> and <i>end</i> are mutable</li>
+   * </ul>
+   * @param byteOrder the given byte order
+   * @return a new <i>WritableBuffer</i> with a view of this WritableMemory
+   */
+  WritableBuffer asWritableBuffer(ByteOrder byteOrder);
+
+
+  //ALLOCATE HEAP VIA AUTOMATIC BYTE ARRAY
+  /**
+   * Creates on-heap WritableMemory with the given capacity and the native byte order.
+   * @param capacityBytes the given capacity in bytes. It must be &ge; 0.
+   * @return a new WritableMemory for write operations on a new byte array.
+   */
+  static WritableMemory allocate(int capacityBytes) {
+    return allocate(capacityBytes, ByteOrder.nativeOrder(), defaultMemReqSvr);
+  }
+
+  /**
+   * Creates on-heap WritableMemory with the given capacity and the given byte order.
+   * @param capacityBytes the given capacity in bytes. It must be &ge; 0.
+   * @param byteOrder the given byte order to allocate new Memory object with. It must be non-null.
+   * @return a new WritableMemory for write operations on a new byte array.
+   */
+  static WritableMemory allocate(int capacityBytes, ByteOrder byteOrder) {
+    return allocate(capacityBytes, byteOrder, defaultMemReqSvr);
+  }
+
+  /**
+   * Creates on-heap WritableMemory with the given capacity and the given byte order.
+   * @param capacityBytes the given capacity in bytes. It must be &ge; 0.
+   * @param byteOrder the given byte order to allocate new Memory object with. It must be non-null.
+   * @param memReqSvr A user-specified <i>MemoryRequestServer</i>, which may be null.
+   * This is a callback mechanism for a user client to request a larger <i>WritableMemory</i>.
+   * @return a new WritableMemory for write operations on a new byte array.
+   */
+  static WritableMemory allocate(int capacityBytes, ByteOrder byteOrder, MemoryRequestServer memReqSvr) {
+    final byte[] arr = new byte[capacityBytes];
+    negativeCheck(capacityBytes, "capacityBytes");
+    return writableWrap(arr, 0, capacityBytes, byteOrder, memReqSvr);
+  }
+
+
+  //ACCESS PRIMITIVE HEAP ARRAYS for WRITE
+
+  /**
+   * Wraps the given primitive array for write operations assuming native byte order.
+   *
+   * <p><b>Note:</b> Always qualify this method with the class name, e.g.,
+   * <i>WritableMemory.wrap(...)</i>.
+   * @param array the given primitive array. It must be non-null.
+   * @return a new WritableMemory for write operations on the given primitive array.
+   */
+  static WritableMemory writableWrap(byte[] array) {
+    return writableWrap(array, 0, array.length, ByteOrder.nativeOrder(), defaultMemReqSvr);
+  }
+
+  /**
+   * Wraps the given primitive array for write operations with the given byte order.
+   *
+   * <p><b>Note:</b> Always qualify this method with the class name, e.g.,
+   * <i>WritableMemory.wrap(...)</i>.
+   * @param array the given primitive array. It must be non-null.
+   * @param byteOrder the byte order to be used. It must be non-null.
+   * @return a new WritableMemory for write operations on the given primitive array.
+   */
+  static WritableMemory writableWrap(byte[] array, ByteOrder byteOrder) {
+    return writableWrap(array, 0, array.length, byteOrder, defaultMemReqSvr);
+  }
+
+  /**
+   * Wraps the given primitive array for write operations with the given byte order.
+   *
+   * <p><b>Note:</b> Always qualify this method with the class name, e.g.,
+   * <i>WritableMemory.wrap(...)</i>.
+   * @param array the given primitive array. It must be non-null.
+   * @param offsetBytes the byte offset into the given array. It must be &ge; 0.
+   * @param lengthBytes the number of bytes to include from the given array. It must be &ge; 0.
+   * @param byteOrder the byte order to be used. It must be non-null.
+   * @return a new WritableMemory for write operations on the given primitive array.
+   */
+  static WritableMemory writableWrap(byte[] array, int offsetBytes, int lengthBytes, ByteOrder byteOrder) {
+    return writableWrap(array, offsetBytes, lengthBytes, byteOrder, defaultMemReqSvr);
+  }
+
+  /**
+   * Wraps the given primitive array for write operations with the given byte order. If the given
+   * lengthBytes is zero, backing storage, byte order and read-only status of the returned
+   * WritableMemory object are unspecified.
+   *
+   * <p><b>Note:</b> Always qualify this method with the class name, e.g.,
+   * <i>WritableMemory.wrap(...)</i>.
+   * @param array the given primitive array. It must be non-null.
+   * @param offsetBytes the byte offset into the given array. It must be &ge; 0.
+   * @param lengthBytes the number of bytes to include from the given array. It must be &ge; 0.
+   * @param byteOrder the byte order to be used. It must be non-null.
+   * @param memReqSvr A user-specified <i>MemoryRequestServer</i>, which may be null.
+   * This is a callback mechanism for a user client to request a larger <i>WritableMemory</i>.
+   * @return a new WritableMemory for write operations on the given primitive array.
+   */
+  static WritableMemory writableWrap(byte[] array, int offsetBytes, int lengthBytes, ByteOrder byteOrder,
+      MemoryRequestServer memReqSvr) {
+    Objects.requireNonNull(array, "array must be non-null");
+    Objects.requireNonNull(byteOrder, "byteOrder must be non-null");
+    negativeCheck(offsetBytes, "offsetBytes");
+    negativeCheck(lengthBytes, "lengthBytes");
+    UnsafeUtil.checkBounds(offsetBytes, lengthBytes, array.length);
+    return BaseWritableMemoryImpl.wrapHeapArray(array, offsetBytes, lengthBytes, false, byteOrder, memReqSvr);
+  }
+
+  /**
+   * Wraps the given primitive array for write operations assuming native byte order.
+   * @param array the given primitive array. It must be non-null.
+   * @return a new WritableMemory for write operations on the given primitive array.
+   */
+  static WritableMemory writableWrap(boolean[] array) {
+    Objects.requireNonNull(array, "array must be non-null");
+    final long lengthBytes = array.length << Prim.BOOLEAN.shift();
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0, lengthBytes, false, ByteOrder.nativeOrder(), null);
+  }
+
+  /**
+   * Wraps the given primitive array for write operations assuming native byte order.
+   * @param array the given primitive array.
+   * @return a new WritableMemory for write operations on the given primitive array.
+   */
+  static WritableMemory writableWrap(char[] array) {
+    Objects.requireNonNull(array, "array must be non-null");
+    final long lengthBytes = array.length << Prim.CHAR.shift();
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(), null);
+  }
+
+  /**
+   * Wraps the given primitive array for write operations assuming native byte order.
+   * @param array the given primitive array.
+   * @return a new WritableMemory for write operations on the given primitive array.
+   */
+  static WritableMemory writableWrap(short[] array) {
+    Objects.requireNonNull(array, "arr must be non-null");
+    final long lengthBytes = array.length << Prim.SHORT.shift();
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(), null);
+  }
+
+  /**
+   * Wraps the given primitive array for write operations assuming native byte order.
+   * @param array the given primitive array.
+   * @return a new WritableMemory for write operations on the given primitive array.
+   */
+  static WritableMemory writableWrap(int[] array) {
+    Objects.requireNonNull(array, "arr must be non-null");
+    final long lengthBytes = array.length << Prim.INT.shift();
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(), null);
+  }
+
+  /**
+   * Wraps the given primitive array for write operations assuming native byte order.
+   * @param array the given primitive array.
+   * @return a new WritableMemory for write operations on the given primitive array.
+   */
+  static WritableMemory writableWrap(long[] array) {
+    Objects.requireNonNull(array, "arr must be non-null");
+    final long lengthBytes = array.length << Prim.LONG.shift();
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(), null);
+  }
+
+  /**
+   * Wraps the given primitive array for write operations assuming native byte order.
+   * @param array the given primitive array.
+   * @return a new WritableMemory for write operations on the given primitive array.
+   */
+  static WritableMemory writableWrap(float[] array) {
+    Objects.requireNonNull(array, "arr must be non-null");
+    final long lengthBytes = array.length << Prim.FLOAT.shift();
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(), null);
+  }
+
+  /**
+   * Wraps the given primitive array for write operations assuming native byte order.
+   * @param array the given primitive array.
+   * @return a new WritableMemory for write operations on the given primitive array.
+   */
+  static WritableMemory writableWrap(double[] array) {
+    Objects.requireNonNull(array, "arr must be non-null");
+    final long lengthBytes = array.length << Prim.DOUBLE.shift();
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(), null);
+  }
+  //END OF CONSTRUCTOR-TYPE METHODS
+
+  //PRIMITIVE putX() and putXArray()
+  /**
+   * Puts the boolean value at the given offset
+   * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
+   * @param value the value to put
+   */
+  void putBoolean(long offsetBytes, boolean value);
+
+  /**
+   * Puts the boolean array at the given offset
+   * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
+   * @param srcArray The source array.
+   * @param srcOffsetBooleans offset in array units
+   * @param lengthBooleans number of array units to transfer
+   */
+  void putBooleanArray(long offsetBytes, boolean[] srcArray, int srcOffsetBooleans, int lengthBooleans);
+
+  /**
+   * Puts the byte value at the given offset
+   * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
+   * @param value the value to put
+   */
+  void putByte(long offsetBytes, byte value);
+
+  /**
+   * Puts the byte array at the given offset
+   * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
+   * @param srcArray The source array.
+   * @param srcOffsetBytes offset in array units
+   * @param lengthBytes number of array units to transfer
+   */
+  void putByteArray(long offsetBytes, byte[] srcArray, int srcOffsetBytes, int lengthBytes);
+
+  /**
+   * Puts the char value at the given offset
+   * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
+   * @param value the value to put
+   */
+  void putChar(long offsetBytes, char value);
+
+  /**
+   * Puts the char array at the given offset
+   * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
+   * @param srcArray The source array.
+   * @param srcOffsetChars offset in array units
+   * @param lengthChars number of array units to transfer
+   */
+  void putCharArray(long offsetBytes, char[] srcArray, int srcOffsetChars, int lengthChars);
+
+  /**
+   * Encodes characters from the given CharSequence into UTF-8 bytes and puts them into this
+   * <i>WritableMemory</i> begining at the given offsetBytes.
+   * This is specifically designed to reduce the production of intermediate objects (garbage),
+   * thus significantly reducing pressure on the JVM Garbage Collector.
+   * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
+   * @param src The source CharSequence to be encoded and put into this WritableMemory. It is
+   * the responsibility of the caller to provide sufficient capacity in this
+   * <i>WritableMemory</i> for the encoded Utf8 bytes. Characters outside the ASCII range can
+   * require 2, 3 or 4 bytes per character to encode.
+   * @return the number of bytes encoded
+   */
+  long putCharsToUtf8(long offsetBytes, CharSequence src);
+
+  /**
+   * Puts the double value at the given offset
+   * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
+   * @param value the value to put
+   */
+  void putDouble(long offsetBytes, double value);
+
+  /**
+   * Puts the double array at the given offset
+   * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
+   * @param srcArray The source array.
+   * @param srcOffsetDoubles offset in array units
+   * @param lengthDoubles number of array units to transfer
+   */
+  void putDoubleArray(long offsetBytes, double[] srcArray, int srcOffsetDoubles, int lengthDoubles);
+
+  /**
+   * Puts the float value at the given offset
+   * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
+   * @param value the value to put
+   */
+  void putFloat(long offsetBytes, float value);
+
+  /**
+   * Puts the float array at the given offset
+   * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
+   * @param srcArray The source array.
+   * @param srcOffsetFloats offset in array units
+   * @param lengthFloats number of array units to transfer
+   */
+  void putFloatArray(long offsetBytes, float[] srcArray, int srcOffsetFloats, int lengthFloats);
+
+  /**
+   * Puts the int value at the given offset
+   * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
+   * @param value the value to put
+   */
+  void putInt(long offsetBytes, int value);
+
+  /**
+   * Puts the int array at the given offset
+   * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
+   * @param srcArray The source array.
+   * @param srcOffsetInts offset in array units
+   * @param lengthInts number of array units to transfer
+   */
+  void putIntArray(long offsetBytes, int[] srcArray, int srcOffsetInts, int lengthInts);
+
+  /**
+   * Puts the long value at the given offset
+   * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
+   * @param value the value to put
+   */
+  void putLong(long offsetBytes, long value);
+
+  /**
+   * Puts the long array at the given offset
+   * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
+   * @param srcArray The source array.
+   * @param srcOffsetLongs offset in array units
+   * @param lengthLongs number of array units to transfer
+   */
+  void putLongArray(long offsetBytes, long[] srcArray, int srcOffsetLongs, int lengthLongs);
+
+  /**
+   * Puts the short value at the given offset
+   * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
+   * @param value the value to put
+   */
+  void putShort(long offsetBytes, short value);
+
+  /**
+   * Puts the short array at the given offset
+   * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
+   * @param srcArray The source array.
+   * @param srcOffsetShorts offset in array units
+   * @param lengthShorts number of array units to transfer
+   */
+  void putShortArray(long offsetBytes, short[] srcArray, int srcOffsetShorts, int lengthShorts);
+
+  //Atomic Methods
+  /**
+   * Atomically adds the given value to the long located at offsetBytes.
+   * @param offsetBytes offset bytes relative to this Memory start
+   * @param delta the amount to add
+   * @return the the previous value
+   */
+  long getAndAddLong(long offsetBytes, long delta);
+
+  /**
+   * Atomically sets the current value at the memory location to the given updated value
+   * if and only if the current value {@code ==} the expected value.
+   * @param offsetBytes offset bytes relative to this Memory start
+   * @param expect the expected value
+   * @param update the new value
+   * @return {@code true} if successful. False return indicates that
+   * the current value at the memory location was not equal to the expected value.
+   */
+  boolean compareAndSwapLong(long offsetBytes, long expect, long update);
+
+  /**
+   * Atomically exchanges the given value with the current value located at offsetBytes.
+   * @param offsetBytes offset bytes relative to this Memory start
+   * @param newValue new value
+   * @return the previous value
+   */
+  long getAndSetLong(long offsetBytes, long newValue);
+
+  //OTHER WRITE METHODS
+  /**
+   * Returns the primitive backing array, otherwise null.
+   * @return the primitive backing array, otherwise null.
+   */
+  Object getArray();
+
+  /**
+   * Clears all bytes of this Memory to zero
+   */
+  void clear();
+
+  /**
+   * Clears a portion of this Memory to zero.
+   * @param offsetBytes offset bytes relative to this Memory start
+   * @param lengthBytes the length in bytes
+   */
+  void clear(long offsetBytes, long lengthBytes);
+
+  /**
+   * Clears the bits defined by the bitMask
+   * @param offsetBytes offset bytes relative to this Memory start.
+   * @param bitMask the bits set to one will be cleared
+   */
+  void clearBits(long offsetBytes, byte bitMask);
+
+  /**
+   * Fills all bytes of this Memory region to the given byte value.
+   * @param value the given byte value
+   */
+  void fill(byte value);
+
+  /**
+   * Fills a portion of this Memory region to the given byte value.
+   * @param offsetBytes offset bytes relative to this Memory start
+   * @param lengthBytes the length in bytes
+   * @param value the given byte value
+   */
+  void fill(long offsetBytes, long lengthBytes, byte value);
+
+  /**
+   * Sets the bits defined by the bitMask
+   * @param offsetBytes offset bytes relative to this Memory start
+   * @param bitMask the bits set to one will be set
+   */
+  void setBits(long offsetBytes, byte bitMask);
+
+
+  //OTHER WRITABLE API METHODS
+  /**
+   * WritableMemory enables this for ByteBuffer, Heap and Direct Memory backed resources.
+   * Map backed resources will always return null.
+   * Gets the MemoryRequestServer object, if set, for the above resources to request additional memory.
+   * The user must customize the actions of the MemoryRequestServer by
+   * implementing the MemoryRequestServer interface and set using one of these methods:
+   * <ul><li>{@link WritableMemory#allocateDirect(long, ByteOrder, MemoryRequestServer)}</li>
+   * <li>{@link WritableMemory#allocate(int, ByteOrder, MemoryRequestServer)}</li>
+   * <li>{@link WritableMemory#writableWrap(ByteBuffer, ByteOrder, MemoryRequestServer)}</li>
+   * </ul>
+   * Simple implementation examples include the DefaultMemoryRequestServer in the main tree, as well as
+   * the ExampleMemoryRequestServerTest and the use with ByteBuffer documented in the DruidIssue11544Test
+   * in the test tree.
+   * @return the MemoryRequestServer object or null.
+   */
+  MemoryRequestServer getMemoryRequestServer();
+
+}

Added: dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/XxHash.java
==============================================================================
--- dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/XxHash.java (added)
+++ dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/XxHash.java Thu Aug 19 22:18:24 2021
@@ -0,0 +1,192 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory;
+
+import static org.apache.datasketches.memory.internal.XxHash64.hash;
+import static org.apache.datasketches.memory.internal.XxHash64.hashBooleans;
+import static org.apache.datasketches.memory.internal.XxHash64.hashBytes;
+import static org.apache.datasketches.memory.internal.XxHash64.hashChars;
+import static org.apache.datasketches.memory.internal.XxHash64.hashDoubles;
+import static org.apache.datasketches.memory.internal.XxHash64.hashFloats;
+import static org.apache.datasketches.memory.internal.XxHash64.hashInts;
+import static org.apache.datasketches.memory.internal.XxHash64.hashLongs;
+import static org.apache.datasketches.memory.internal.XxHash64.hashShorts;
+
+/**
+ * The XxHash is a fast, non-cryptographic, 64-bit hash function that has
+ * excellent avalanche and 2-way bit independence properties.
+ * This java version adapted  the C++ version and the OpenHFT/Zero-Allocation-Hashing implementation
+ * referenced below as inspiration.
+ *
+ * <p>The C++ source repository:
+ * <a href="https://github.com/Cyan4973/xxHash">
+ * https://github.com/Cyan4973/xxHash</a>. It has a BSD 2-Clause License:
+ * <a href="http://www.opensource.org/licenses/bsd-license.php">
+ * http://www.opensource.org/licenses/bsd-license.php</a>.  See LICENSE.
+ *
+ * <p>Portions of this code were adapted from
+ * <a href="https://github.com/OpenHFT/Zero-Allocation-Hashing/blob/master/src/main/java/net/openhft/hashing/XxHash.java">
+ * OpenHFT/Zero-Allocation-Hashing</a>, which has an Apache 2 license as does this site. See LICENSE.
+ *
+ * @author Lee Rhodes
+ */
+public final class XxHash {
+
+  private XxHash() { /* singleton */ }
+
+  /**
+   * Hash the given arr starting at the given offset and continuing for the given length using the
+   * given seed.
+   * @param arr the given array
+   * @param offsetBooleans starting at this offset
+   * @param lengthBooleans continuing for this length
+   * @param seed the given seed
+   * @return the hash
+   */
+  public static long hashBooleanArr(final boolean[] arr, final long offsetBooleans,
+      final long lengthBooleans, final long seed) {
+    return hashBooleans(arr, offsetBooleans, lengthBooleans, seed);
+  }
+
+  /**
+   * Hash the given arr starting at the given offset and continuing for the given length using the
+   * given seed.
+   * @param arr the given array
+   * @param offsetBytes starting at this offset
+   * @param lengthBytes continuing for this length
+   * @param seed the given seed
+   * @return the hash
+   */
+  public static long hashByteArr(final byte[] arr, final long offsetBytes,
+      final long lengthBytes, final long seed) {
+    return hashBytes(arr, offsetBytes, lengthBytes, seed);
+  }
+
+  /**
+   * Hash the given arr starting at the given offset and continuing for the given length using the
+   * given seed.
+   * @param arr the given array
+   * @param offsetShorts starting at this offset
+   * @param lengthShorts continuing for this length
+   * @param seed the given seed
+   * @return the hash
+   */
+  public static long hashShortArr(final short[] arr, final long offsetShorts,
+      final long lengthShorts, final long seed) {
+    return hashShorts(arr, offsetShorts, lengthShorts, seed);
+  }
+
+  /**
+   * Hash the given arr starting at the given offset and continuing for the given length using the
+   * given seed.
+   * @param arr the given array
+   * @param offsetChars starting at this offset
+   * @param lengthChars continuing for this length
+   * @param seed the given seed
+   * @return the hash
+   */
+  public static long hashCharArr(final char[] arr, final long offsetChars,
+      final long lengthChars, final long seed) {
+    return hashChars(arr, offsetChars, lengthChars, seed);
+  }
+
+  /**
+   * Hash the given arr starting at the given offset and continuing for the given length using the
+   * given seed.
+   * @param arr the given array
+   * @param offsetInts starting at this offset
+   * @param lengthInts continuing for this length
+   * @param seed the given seed
+   * @return the hash
+   */
+  public static long hashIntArr(final int[] arr, final long offsetInts,
+      final long lengthInts, final long seed) {
+    return hashInts(arr, offsetInts, lengthInts, seed);
+  }
+
+  /**
+   * Hash the given arr starting at the given offset and continuing for the given length using the
+   * given seed.
+   * @param arr the given array
+   * @param offsetLongs starting at this offset
+   * @param lengthLongs continuing for this length
+   * @param seed the given seed
+   * @return the hash
+   */
+  public static long hashLongArr(final long[] arr, final long offsetLongs,
+      final long lengthLongs, final long seed) {
+    return hashLongs(arr, offsetLongs, lengthLongs, seed);
+  }
+
+  /**
+   * Returns a 64-bit hash from a single long. This method has been optimized for speed when only
+   * a single hash of a long is required.
+   * @param in A long.
+   * @param seed A long valued seed.
+   * @return the hash.
+   */
+  public static long hashLong(final long in, final long seed) {
+    return hash(in, seed);
+  }
+
+  /**
+   * Hash the given arr starting at the given offset and continuing for the given length using the
+   * given seed.
+   * @param arr the given array
+   * @param offsetFloats starting at this offset
+   * @param lengthFloats continuing for this length
+   * @param seed the given seed
+   * @return the hash
+   */
+  public static long hashFloatArr(final float[] arr, final long offsetFloats,
+      final long lengthFloats, final long seed) {
+    return hashFloats(arr, offsetFloats, lengthFloats, seed);
+  }
+
+  /**
+   * Hash the given arr starting at the given offset and continuing for the given length using the
+   * given seed.
+   * @param arr the given array
+   * @param offsetDoubles starting at this offset
+   * @param lengthDoubles continuing for this length
+   * @param seed the given seed
+   * @return the hash
+   */
+  public static long hashDoubleArr(final double[] arr, final long offsetDoubles,
+      final long lengthDoubles, final long seed) {
+    return hashDoubles(arr, offsetDoubles, lengthDoubles, seed);
+  }
+
+  /**
+   * Hash the given arr starting at the given offset and continuing for the given length using the
+   * given seed.
+   * @param str the given string
+   * @param offsetChars starting at this offset
+   * @param lengthChars continuing for this length
+   * @param seed the given seed
+   * @return the hash
+   */
+  public static long hashString(final String str, final long offsetChars,
+      final long lengthChars, final long seed) {
+    return org.apache.datasketches.memory.internal.XxHash64.hashString(str, offsetChars, lengthChars, seed);
+  }
+
+}
+

Added: dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AccessByteBuffer.java
==============================================================================
--- dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AccessByteBuffer.java (added)
+++ dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AccessByteBuffer.java Thu Aug 19 22:18:24 2021
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.apache.datasketches.memory.internal.UnsafeUtil.unsafe;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Acquires access to a ByteBuffer.
+ *
+ * @author Lee Rhodes
+ * @author Praveenkumar Venkatesan
+ * @author Roman Leventov
+ */
+@SuppressWarnings("restriction")
+final class AccessByteBuffer {
+
+  static final ByteBuffer ZERO_READ_ONLY_DIRECT_BYTE_BUFFER =
+      ByteBuffer.allocateDirect(0).asReadOnlyBuffer();
+
+  private static final long NIO_BUFFER_ADDRESS_FIELD_OFFSET =
+      UnsafeUtil.getFieldOffset(java.nio.Buffer.class, "address");
+  private static final long NIO_BUFFER_CAPACITY_FIELD_OFFSET =
+      UnsafeUtil.getFieldOffset(java.nio.Buffer.class, "capacity");
+  private static final long BYTE_BUFFER_HB_FIELD_OFFSET =
+      UnsafeUtil.getFieldOffset(java.nio.ByteBuffer.class, "hb");
+  private static final long BYTE_BUFFER_OFFSET_FIELD_OFFSET =
+      UnsafeUtil.getFieldOffset(java.nio.ByteBuffer.class, "offset");
+
+  final long nativeBaseOffset;
+  final long capacityBytes;
+  final long regionOffset;
+  final Object unsafeObj;
+  final boolean resourceReadOnly;
+  final ByteOrder byteOrder; //not used externally, here for reference.
+
+  /**
+   * The given ByteBuffer may be either readOnly or writable
+   * @param byteBuf the given ByteBuffer
+   */
+  AccessByteBuffer(final ByteBuffer byteBuf) {
+    capacityBytes = byteBuf.capacity();
+    resourceReadOnly = byteBuf.isReadOnly();
+    byteOrder = byteBuf.order();
+    final boolean direct = byteBuf.isDirect();
+    if (direct) {
+      nativeBaseOffset = ((sun.nio.ch.DirectBuffer) byteBuf).address();
+      unsafeObj = null;
+      regionOffset = 0L; //address() is already adjusted for direct slices, so regionOffset = 0
+    } else {
+      nativeBaseOffset = 0L;
+      // ByteBuffer.arrayOffset() and ByteBuffer.array() throw ReadOnlyBufferException if
+      // ByteBuffer is read-only. This uses reflection for both writable and read-only cases.
+      // Includes the slice() offset for heap.
+      regionOffset = unsafe.getInt(byteBuf, BYTE_BUFFER_OFFSET_FIELD_OFFSET);
+      unsafeObj = unsafe.getObject(byteBuf, BYTE_BUFFER_HB_FIELD_OFFSET);
+    }
+  }
+
+  /**
+   * This method is adapted from
+   * https://github.com/odnoklassniki/one-nio/blob/master/src/one/nio/mem/DirectMemory.java
+   * : wrap(...). See LICENSE.
+   */
+  static ByteBuffer getDummyReadOnlyDirectByteBuffer(final long address, final int capacity) {
+    final ByteBuffer buf = ZERO_READ_ONLY_DIRECT_BYTE_BUFFER.duplicate();
+    unsafe.putLong(buf, NIO_BUFFER_ADDRESS_FIELD_OFFSET, address);
+    unsafe.putInt(buf, NIO_BUFFER_CAPACITY_FIELD_OFFSET, capacity);
+    buf.limit(capacity);
+    return buf;
+  }
+
+}

Added: dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirect.java
==============================================================================
--- dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirect.java (added)
+++ dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirect.java Thu Aug 19 22:18:24 2021
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.apache.datasketches.memory.internal.UnsafeUtil.unsafe;
+
+import java.util.logging.Logger;
+
+/**
+ * Provides access to direct (native) memory.
+ *
+ * @author Roman Leventov
+ * @author Lee Rhodes
+ */
+@SuppressWarnings("restriction")
+final class AllocateDirect {
+  static final Logger LOG = Logger.getLogger(AllocateDirect.class.getCanonicalName());
+
+  private final Deallocator deallocator;
+  private final long nativeBaseOffset;
+  private final MemoryCleaner cleaner;
+
+  /**
+   * Base Constructor for allocate native memory.
+   *
+   * <p>Allocates and provides access to capacityBytes directly in native (off-heap) memory
+   * leveraging the MemoryImpl interface.
+   * The allocated memory will be 8-byte aligned, but may not be page aligned.
+   * @param capacityBytes the the requested capacity of off-heap memory. Cannot be zero.
+   */
+  AllocateDirect(final long capacityBytes) {
+    final boolean pageAligned = NioBits.isPageAligned();
+    final long pageSize = NioBits.pageSize();
+    final long allocationSize = capacityBytes + (pageAligned ? pageSize : 0);
+    NioBits.reserveMemory(allocationSize, capacityBytes);
+
+    final long nativeAddress;
+    try {
+      nativeAddress = unsafe.allocateMemory(allocationSize);
+    } catch (final OutOfMemoryError err) {
+      NioBits.unreserveMemory(allocationSize, capacityBytes);
+      throw new RuntimeException(err);
+    }
+    if (pageAligned && ((nativeAddress % pageSize) != 0)) {
+      //Round up to page boundary
+      nativeBaseOffset = (nativeAddress & ~(pageSize - 1L)) + pageSize;
+    } else {
+      nativeBaseOffset = nativeAddress;
+    }
+    deallocator = new Deallocator(nativeAddress, allocationSize, capacityBytes);
+    cleaner = new MemoryCleaner(this, deallocator);
+  }
+
+  boolean doClose() {
+    try {
+      if (deallocator.deallocate(false)) {
+        // This Cleaner.clean() call effectively just removes the Cleaner from the internal linked
+        // list of all cleaners. It will delegate to Deallocator.deallocate() which will be a no-op
+        // because the valid state is already changed.
+        cleaner.clean();
+        return true;
+      }
+      return false;
+    } finally {
+      BaseStateImpl.reachabilityFence(this);
+    }
+  }
+
+  long getNativeBaseOffset() {
+    return nativeBaseOffset;
+  }
+
+  StepBoolean getValid() {
+    return deallocator.getValid();
+  }
+
+  static final class Deallocator implements Runnable {
+    //This is the only place the actual native address is kept for use by unsafe.freeMemory();
+    private final long nativeAddress;
+    private final long allocationSize;
+    private final long capacity;
+    private final StepBoolean valid = new StepBoolean(true); //only place for this
+
+    Deallocator(final long nativeAddress, final long allocationSize, final long capacity) {
+      BaseStateImpl.currentDirectMemoryAllocations_.incrementAndGet();
+      BaseStateImpl.currentDirectMemoryAllocated_.addAndGet(capacity);
+      this.nativeAddress = nativeAddress;
+      this.allocationSize = allocationSize;
+      this.capacity = capacity;
+      assert (nativeAddress != 0);
+    }
+
+    StepBoolean getValid() {
+      return valid;
+    }
+
+    @Override
+    public void run() {
+      deallocate(true);
+    }
+
+    boolean deallocate(final boolean calledFromCleaner) {
+      if (valid.change()) {
+        if (calledFromCleaner) {
+          // Warn about non-deterministic resource cleanup.
+          LOG.warning("A WritableHandle was not closed manually");
+        }
+        unsafe.freeMemory(nativeAddress);
+        NioBits.unreserveMemory(allocationSize, capacity);
+        BaseStateImpl.currentDirectMemoryAllocations_.decrementAndGet();
+        BaseStateImpl.currentDirectMemoryAllocated_.addAndGet(-capacity);
+        return true;
+      }
+      return false;
+    }
+  }
+
+}

Added: dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirectMap.java
==============================================================================
--- dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirectMap.java (added)
+++ dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirectMap.java Thu Aug 19 22:18:24 2021
@@ -0,0 +1,317 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.apache.datasketches.memory.internal.UnsafeUtil.unsafe;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.logging.Logger;
+
+import org.apache.datasketches.memory.Map;
+import org.apache.datasketches.memory.MemoryCloseException;
+
+import sun.nio.ch.FileChannelImpl;
+
+/**
+ * Allocates direct memory used to memory map files for read operations.
+ * (including those &gt; 2GB).
+ *
+ * <p>To understand how it works, reference native code for map0, unmap0:
+ * <a href="http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/f940e7a48b72/src/solaris/native/sun/nio/ch/FileChannelImpl.c">
+ * FileChannelImpl.c</a></p>
+ *
+ * <p>To understand how it works, reference native code for load0(), isLoaded0(), and force0():
+ * <a href="http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/f940e7a48b72/src/solaris/native/java/nio/MappedByteBuffer.c">
+ * MappedByteBuffer.c</a></p>
+ *
+ * @author Roman Leventov
+ * @author Lee Rhodes
+ * @author Praveenkumar Venkatesan
+ */
+@SuppressWarnings("restriction")
+class AllocateDirectMap implements Map {
+  static final Logger LOG = Logger.getLogger(AllocateDirectMap.class.getCanonicalName());
+
+  private static final int MAP_RO = 0;
+  private static final int MAP_RW = 1;
+
+  private static final Method FILE_CHANNEL_IMPL_MAP0_METHOD;
+  static final Method FILE_CHANNEL_IMPL_UNMAP0_METHOD;
+
+  private static final Method MAPPED_BYTE_BUFFER_LOAD0_METHOD;
+  private static final Method MAPPED_BYTE_BUFFER_ISLOADED0_METHOD;
+  static final Method MAPPED_BYTE_BUFFER_FORCE0_METHOD;
+
+  static {
+    try { //The FileChannelImpl methods map0 and unmap0 still exist in 16
+      FILE_CHANNEL_IMPL_MAP0_METHOD = FileChannelImpl.class
+          .getDeclaredMethod("map0", int.class, long.class, long.class); //JDK14 add boolean.class
+      FILE_CHANNEL_IMPL_MAP0_METHOD.setAccessible(true);
+
+      FILE_CHANNEL_IMPL_UNMAP0_METHOD = FileChannelImpl.class
+          .getDeclaredMethod("unmap0", long.class, long.class); //OK through jDK16
+      FILE_CHANNEL_IMPL_UNMAP0_METHOD.setAccessible(true);
+
+
+      //The MappedByteBuffer methods load0, isLoaded0 and force0 are removed in 15
+      MAPPED_BYTE_BUFFER_LOAD0_METHOD = MappedByteBuffer.class
+          .getDeclaredMethod("load0", long.class, long.class); //JDK15 removed
+      MAPPED_BYTE_BUFFER_LOAD0_METHOD.setAccessible(true);
+
+      MAPPED_BYTE_BUFFER_ISLOADED0_METHOD = MappedByteBuffer.class
+          .getDeclaredMethod("isLoaded0", long.class, long.class, int.class); //JDK15 removed
+      MAPPED_BYTE_BUFFER_ISLOADED0_METHOD.setAccessible(true);
+
+      MAPPED_BYTE_BUFFER_FORCE0_METHOD = MappedByteBuffer.class
+          .getDeclaredMethod("force0", FileDescriptor.class, long.class, long.class); //JDK15 removed
+      MAPPED_BYTE_BUFFER_FORCE0_METHOD.setAccessible(true);
+    } catch (final SecurityException | NoSuchMethodException e) {
+      throw new RuntimeException("Could not reflect static methods: " + e);
+    }
+  }
+
+  private final Deallocator deallocator;
+  private final MemoryCleaner cleaner;
+
+  final long capacityBytes;
+  final RandomAccessFile raf;
+  final long nativeBaseOffset;
+  final boolean resourceReadOnly;
+
+  //called from AllocateDirectWritableMap constructor
+  @SuppressWarnings("resource")
+  AllocateDirectMap(final File file, final long fileOffsetBytes, final long capacityBytes,
+      final boolean localReadOnly) {
+    this.capacityBytes = capacityBytes;
+    resourceReadOnly = isFileReadOnly(file);
+    final long fileLength = file.length();
+    if ((localReadOnly || resourceReadOnly) && fileOffsetBytes + capacityBytes > fileLength) {
+      throw new IllegalArgumentException(
+          "Read-only mode and requested map length is greater than current file length: "
+          + "Requested Length = " + (fileOffsetBytes + capacityBytes)
+          + ", Current File Length = " + fileLength);
+    }
+    raf = mapper(file, fileOffsetBytes, capacityBytes, resourceReadOnly);
+    nativeBaseOffset = map(raf.getChannel(), resourceReadOnly, fileOffsetBytes, capacityBytes);
+    deallocator = new Deallocator(nativeBaseOffset, capacityBytes, raf);
+    cleaner = new MemoryCleaner(this, deallocator);
+  }
+
+  //Map Interface
+
+  @Override
+  public void load() {
+    madvise();
+    // Performance optimization. Read a byte from each page to bring it into memory.
+    final int ps = NioBits.pageSize();
+    final int count = NioBits.pageCount(capacityBytes);
+    long offset = nativeBaseOffset;
+    for (int i = 0; i < count; i++) {
+      unsafe.getByte(offset);
+      offset += ps;
+    }
+  }
+
+  @Override
+  public boolean isLoaded() {
+    try {
+      final int pageCount = NioBits.pageCount(capacityBytes);
+      return (boolean) MAPPED_BYTE_BUFFER_ISLOADED0_METHOD
+          //isLoaded0 is effectively static, so ZERO_READ_ONLY_DIRECT_BYTE_BUFFER is not modified
+          .invoke(AccessByteBuffer.ZERO_READ_ONLY_DIRECT_BYTE_BUFFER,
+              nativeBaseOffset,
+              capacityBytes,
+              pageCount);
+    } catch (final  IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(
+              String.format("Encountered %s exception while loading", e.getClass()));
+    }
+  }
+  // End Map Interface
+
+  @Override
+  public void close() {
+    doClose("AllocateDirectMap");
+  }
+
+  boolean doClose(final String resource) {
+    try {
+      if (deallocator.deallocate(false)) {
+        // This Cleaner.clean() call effectively just removes the Cleaner from the internal linked
+        // list of all cleaners. It will delegate to Deallocator.deallocate() which will be a no-op
+        // because the valid state is already changed.
+        cleaner.clean();
+        return true;
+      }
+      return false;
+    } catch (final Exception e) {
+        throw new MemoryCloseException(resource);
+    } finally {
+      BaseStateImpl.reachabilityFence(this);
+    }
+  }
+
+  StepBoolean getValid() {
+    return deallocator.getValid();
+  }
+
+  // Private methods
+  /**
+   * called by load(). Calls the native method load0 in MappedByteBuffer.java, implemented
+   * in MappedByteBuffer.c. See reference at top of class. load0 allows setting a mapping length
+   * of greater than 2GB.
+   */
+  private void madvise() {
+    try {
+      MAPPED_BYTE_BUFFER_LOAD0_METHOD
+        //load0 is effectively static, so ZERO_READ_ONLY_DIRECT_BYTE_BUFFER is not modified
+        .invoke(AccessByteBuffer.ZERO_READ_ONLY_DIRECT_BYTE_BUFFER,
+            nativeBaseOffset,
+            capacityBytes);
+    } catch (final  IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(
+          String.format("Encountered %s exception while loading", e.getClass()));
+    }
+  }
+
+  //Does the actual mapping work, resourceReadOnly must already be set
+  private static RandomAccessFile mapper(final File file, final long fileOffset,
+      final long capacityBytes, final boolean resourceReadOnly)  {
+
+    final String mode = resourceReadOnly ? "r" : "rw";
+    final RandomAccessFile raf;
+    try {
+      raf = new RandomAccessFile(file, mode);
+      if (fileOffset + capacityBytes > raf.length()) {
+        raf.setLength(fileOffset + capacityBytes);
+      }
+    } catch (final IOException e) {
+      throw new RuntimeException(e);
+    }
+    return raf;
+  }
+
+  /**
+   * Creates a mapping of the FileChannel starting at position and of size length to pages
+   * in the OS. This may throw OutOfMemory error if you have exhausted memory.
+   * You can try to force garbage collection and re-attempt.
+   *
+   * <p>map0 is a native method of FileChannelImpl.java implemented in FileChannelImpl.c.
+   * See reference at top of class.</p>
+   *
+   * @param fileChannel the FileChannel
+   * @param position the offset in bytes into the FileChannel
+   * @param lengthBytes the length in bytes
+   * @return the native base offset address
+   * @throws RuntimeException Encountered an exception while mapping
+   */
+  private static long map(final FileChannel fileChannel, final boolean resourceReadOnly,
+      final long position, final long lengthBytes) {
+    final int pagePosition = (int) (position % unsafe.pageSize());
+    final long mapPosition = position - pagePosition;
+    final long mapSize = lengthBytes + pagePosition;
+    final int mapMode = resourceReadOnly ? MAP_RO : MAP_RW;
+    //final boolean isSync = true; //required as of JDK14, but it is more complex
+    try {
+      final long nativeBaseOffset = //JDK14 add isSync
+        (long) FILE_CHANNEL_IMPL_MAP0_METHOD.invoke(fileChannel, mapMode, mapPosition, mapSize);
+      return nativeBaseOffset;
+    } catch (final InvocationTargetException e) {
+      throw new RuntimeException("Exception while mapping", e.getTargetException());
+    } catch (final IllegalAccessException e) {
+      throw new RuntimeException("Exception while mapping", e);
+    }
+  }
+
+  public static boolean isFileReadOnly(final File file) {
+    return (!file.canWrite());
+  }
+
+  private static final class Deallocator implements Runnable {
+    private final RandomAccessFile myRaf;
+    private final FileChannel myFc;
+    //This is the only place the actual native offset is kept for use by unsafe.freeMemory();
+    private final long actualNativeBaseOffset;
+    private final long myCapacity;
+    private final StepBoolean valid = new StepBoolean(true); //only place for this
+
+    Deallocator(final long nativeBaseOffset, final long capacityBytes,
+        final RandomAccessFile raf) {
+      BaseStateImpl.currentDirectMemoryMapAllocations_.incrementAndGet();
+      BaseStateImpl.currentDirectMemoryMapAllocated_.addAndGet(capacityBytes);
+      myRaf = raf;
+      assert myRaf != null;
+      myFc = myRaf.getChannel();
+      actualNativeBaseOffset = nativeBaseOffset;
+      assert actualNativeBaseOffset != 0;
+      myCapacity = capacityBytes;
+      assert myCapacity != 0;
+    }
+
+    StepBoolean getValid() {
+      return valid;
+    }
+
+    @Override
+    public void run() {
+      deallocate(true);
+    }
+
+    boolean deallocate(final boolean calledFromCleaner) {
+      if (valid.change()) {
+        if (calledFromCleaner) {
+          // Warn about non-deterministic resource cleanup.
+          LOG.warning("A WritableMapHandleImpl was not closed manually");
+        }
+        try {
+          unmap();
+        }
+        finally {
+          BaseStateImpl.currentDirectMemoryMapAllocations_.decrementAndGet();
+          BaseStateImpl.currentDirectMemoryMapAllocated_.addAndGet(-myCapacity);
+        }
+        return true;
+      }
+      return false;
+    }
+
+    /**
+     * Removes existing mapping.  <i>unmap0</i> is a native method in FileChannelImpl.c. See
+     * reference at top of class.
+     */
+    private void unmap() throws RuntimeException {
+      try {
+        FILE_CHANNEL_IMPL_UNMAP0_METHOD.invoke(myFc, actualNativeBaseOffset, myCapacity);
+        myRaf.close();
+      } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException | IOException e) {
+        throw new RuntimeException(
+            String.format("Encountered %s exception while freeing memory", e.getClass()));
+      }
+    }
+  } //End of class Deallocator
+
+}

Added: dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirectWritableMap.java
==============================================================================
--- dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirectWritableMap.java (added)
+++ dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/AllocateDirectWritableMap.java Thu Aug 19 22:18:24 2021
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+
+import org.apache.datasketches.memory.ReadOnlyException;
+import org.apache.datasketches.memory.WritableMap;
+
+/**
+ * Allocates direct memory used to memory map files for write operations
+ * (including those &gt; 2GB).
+ *
+ * @author Lee Rhodes
+ * @author Roman Leventov
+ * @author Praveenkumar Venkatesan
+ */
+//Called from WritableMemoryImpl, implements combo of WritableMemoryImpl with WritableMap resource
+final class AllocateDirectWritableMap extends AllocateDirectMap implements WritableMap {
+
+  AllocateDirectWritableMap(final File file, final long fileOffsetBytes,
+      final long capacityBytes, final boolean localReadOnly) {
+    super(file, fileOffsetBytes, capacityBytes, localReadOnly);
+  }
+
+  //Added by WritableMap Interface
+
+  @Override
+  public void force() {
+    if (resourceReadOnly) {
+      throw new ReadOnlyException("MemoryImpl Mapped File is Read Only.");
+    }
+    try {
+      MAPPED_BYTE_BUFFER_FORCE0_METHOD
+          //force0 is effectively static, so ZERO_READ_ONLY_DIRECT_BYTE_BUFFER is not modified
+          .invoke(AccessByteBuffer.ZERO_READ_ONLY_DIRECT_BYTE_BUFFER,
+              raf.getFD(),
+              nativeBaseOffset,
+              capacityBytes);
+    } catch (final IOException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(String.format("Encountered %s exception in force. " + e.getClass()));
+    }
+  }
+}

Added: dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableBufferImpl.java
==============================================================================
--- dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableBufferImpl.java (added)
+++ dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableBufferImpl.java Thu Aug 19 22:18:24 2021
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableBuffer;
+
+/**
+ * Implementation of {@link WritableBuffer} for ByteBuffer, non-native byte order.
+ *
+ * @author Roman Leventov
+ * @author Lee Rhodes
+ */
+final class BBNonNativeWritableBufferImpl extends NonNativeWritableBufferImpl {
+  private static final int id = BUFFER | NONNATIVE | BYTEBUF;
+  private final Object unsafeObj;
+  private final long nativeBaseOffset; //used to compute cumBaseOffset
+  private final ByteBuffer byteBuf; //holds a reference to a ByteBuffer until we are done with it.
+  private final MemoryRequestServer memReqSvr;
+  private final byte typeId;
+
+  BBNonNativeWritableBufferImpl(
+      final Object unsafeObj,
+      final long nativeBaseOffset,
+      final long regionOffset,
+      final long capacityBytes,
+      final int typeId,
+      final ByteBuffer byteBuf,
+      final MemoryRequestServer memReqSvr) {
+    super(unsafeObj, nativeBaseOffset, regionOffset, capacityBytes);
+    this.unsafeObj = unsafeObj;
+    this.nativeBaseOffset = nativeBaseOffset;
+    this.byteBuf = byteBuf;
+    this.memReqSvr = memReqSvr;
+    this.typeId = (byte) (id | (typeId & 0x7));
+  }
+
+  @Override
+  BaseWritableBufferImpl toWritableRegion(final long offsetBytes, final long capacityBytes,
+      final boolean readOnly, final ByteOrder byteOrder) {
+    final int type = setReadOnlyType(typeId, readOnly) | REGION;
+    return Util.isNativeByteOrder(byteOrder)
+        ? new BBWritableBufferImpl(
+          unsafeObj, nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, byteBuf, memReqSvr)
+        : new BBNonNativeWritableBufferImpl(
+          unsafeObj, nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, byteBuf, memReqSvr);
+  }
+
+  @Override
+  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
+    final int type = setReadOnlyType(typeId, readOnly) | DUPLICATE;
+    return Util.isNativeByteOrder(byteOrder)
+        ? new BBWritableBufferImpl(
+            unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(), type, byteBuf, memReqSvr)
+        : new BBNonNativeWritableBufferImpl(
+            unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(), type, byteBuf, memReqSvr);
+  }
+
+  @Override
+  BaseWritableMemoryImpl toWritableMemory(final boolean readOnly, final ByteOrder byteOrder) {
+    final int type = setReadOnlyType(typeId, readOnly);
+    return Util.isNativeByteOrder(byteOrder)
+        ? new BBWritableMemoryImpl(
+            unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(), type, byteBuf, memReqSvr)
+        : new BBNonNativeWritableMemoryImpl(
+            unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(), type, byteBuf, memReqSvr);
+  }
+
+  @Override
+  public ByteBuffer getByteBuffer() {
+    assertValid();
+    return byteBuf;
+  }
+
+  @Override
+  public MemoryRequestServer getMemoryRequestServer() {
+    assertValid();
+    return memReqSvr;
+  }
+
+  @Override
+  long getNativeBaseOffset() {
+    return nativeBaseOffset;
+  }
+
+  @Override
+  int getTypeId() {
+    return typeId & 0xff;
+  }
+
+  @Override
+  Object getUnsafeObject() {
+    assertValid();
+    return unsafeObj;
+  }
+
+}

Added: dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableMemoryImpl.java
==============================================================================
--- dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableMemoryImpl.java (added)
+++ dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableMemoryImpl.java Thu Aug 19 22:18:24 2021
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableMemory;
+
+/**
+ * Implementation of {@link WritableMemory} for ByteBuffer, non-native byte order.
+ *
+ * @author Roman Leventov
+ * @author Lee Rhodes
+ */
+final class BBNonNativeWritableMemoryImpl extends NonNativeWritableMemoryImpl {
+  private static final int id = MEMORY | NONNATIVE | BYTEBUF;
+  private final Object unsafeObj;
+  private final long nativeBaseOffset; //used to compute cumBaseOffset
+  private final ByteBuffer byteBuf; //holds a reference to a ByteBuffer until we are done with it.
+  private final MemoryRequestServer memReqSvr;
+  private final byte typeId;
+
+  BBNonNativeWritableMemoryImpl(
+      final Object unsafeObj,
+      final long nativeBaseOffset,
+      final long regionOffset,
+      final long capacityBytes,
+      final int typeId,
+      final ByteBuffer byteBuf,
+      final MemoryRequestServer memReqSvr) {
+    super(unsafeObj, nativeBaseOffset, regionOffset, capacityBytes);
+    this.unsafeObj = unsafeObj;
+    this.nativeBaseOffset = nativeBaseOffset;
+    this.byteBuf = byteBuf;
+    this.memReqSvr = memReqSvr;
+    this.typeId = (byte) (id | (typeId & 0x7));
+  }
+
+  @Override
+  BaseWritableMemoryImpl toWritableRegion(final long offsetBytes, final long capacityBytes,
+      final boolean readOnly, final ByteOrder byteOrder) {
+    final int type = setReadOnlyType(typeId, readOnly) | REGION;
+    return Util.isNativeByteOrder(byteOrder)
+        ? new BBWritableMemoryImpl(
+            unsafeObj, nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, getByteBuffer(), memReqSvr)
+        : new BBNonNativeWritableMemoryImpl(
+            unsafeObj, nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, getByteBuffer(), memReqSvr);
+  }
+
+  @Override
+  BaseWritableBufferImpl toWritableBuffer(final boolean readOnly, final ByteOrder byteOrder) {
+    final int type = setReadOnlyType(typeId, readOnly);
+    return Util.isNativeByteOrder(byteOrder)
+        ? new BBWritableBufferImpl(
+            unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(), type, byteBuf, memReqSvr)
+        : new BBNonNativeWritableBufferImpl(
+            unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(), type, byteBuf, memReqSvr);
+  }
+
+  @Override
+  public ByteBuffer getByteBuffer() {
+    assertValid();
+    return byteBuf;
+  }
+
+  @Override
+  public MemoryRequestServer getMemoryRequestServer() {
+    assertValid();
+    return memReqSvr;
+  }
+
+  @Override
+  long getNativeBaseOffset() {
+    return nativeBaseOffset;
+  }
+
+  @Override
+  int getTypeId() {
+    return typeId & 0xff;
+  }
+
+  @Override
+  Object getUnsafeObject() {
+    assertValid();
+    return unsafeObj;
+  }
+
+}

Added: dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBWritableBufferImpl.java
==============================================================================
--- dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBWritableBufferImpl.java (added)
+++ dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBWritableBufferImpl.java Thu Aug 19 22:18:24 2021
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableBuffer;
+
+/**
+ * Implementation of {@link WritableBuffer} for ByteBuffer, native byte order.
+ *
+ * @author Roman Leventov
+ * @author Lee Rhodes
+ */
+final class BBWritableBufferImpl extends NativeWritableBufferImpl {
+  private static final int id = BUFFER | NATIVE | BYTEBUF;
+  private final Object unsafeObj;
+  private final long nativeBaseOffset; //used to compute cumBaseOffset
+  private final ByteBuffer byteBuf; //holds a reference to a ByteBuffer until we are done with it.
+  private final MemoryRequestServer memReqSvr;
+  private final byte typeId;
+
+  BBWritableBufferImpl(
+      final Object unsafeObj,
+      final long nativeBaseOffset,
+      final long regionOffset,
+      final long capacityBytes,
+      final int typeId,
+      final ByteBuffer byteBuf,
+      final MemoryRequestServer memReqSvr) {
+    super(unsafeObj, nativeBaseOffset, regionOffset, capacityBytes);
+    this.unsafeObj = unsafeObj;
+    this.nativeBaseOffset = nativeBaseOffset;
+    this.byteBuf = byteBuf;
+    this.memReqSvr = memReqSvr;
+    this.typeId = (byte) (id | (typeId & 0x7));
+  }
+
+  @Override
+  BaseWritableBufferImpl toWritableRegion(final long offsetBytes, final long capacityBytes,
+      final boolean readOnly, final ByteOrder byteOrder) {
+    final int type = setReadOnlyType(typeId, readOnly) | REGION;
+    return Util.isNativeByteOrder(byteOrder)
+        ? new BBWritableBufferImpl(
+            unsafeObj, nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, byteBuf, memReqSvr)
+        : new BBNonNativeWritableBufferImpl(
+            unsafeObj, nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, byteBuf, memReqSvr);
+  }
+
+  @Override
+  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
+    final int type = setReadOnlyType(typeId, readOnly) | DUPLICATE;
+    return Util.isNativeByteOrder(byteOrder)
+        ? new BBWritableBufferImpl(
+            unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(), type, byteBuf, memReqSvr)
+        : new BBNonNativeWritableBufferImpl(
+            unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(), type, byteBuf, memReqSvr);
+  }
+
+  @Override
+  BaseWritableMemoryImpl toWritableMemory(final boolean readOnly, final ByteOrder byteOrder) {
+    final int type = setReadOnlyType(typeId, readOnly);
+    return Util.isNativeByteOrder(byteOrder)
+        ? new BBWritableMemoryImpl(
+            unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(), type, byteBuf, memReqSvr)
+        : new BBNonNativeWritableMemoryImpl(
+            unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(), type, byteBuf, memReqSvr);
+  }
+
+  @Override
+  public ByteBuffer getByteBuffer() {
+    assertValid();
+    return byteBuf;
+  }
+
+  @Override
+  public MemoryRequestServer getMemoryRequestServer() {
+    assertValid();
+    return memReqSvr;
+  }
+
+  @Override
+  long getNativeBaseOffset() {
+    return nativeBaseOffset;
+  }
+
+  @Override
+  int getTypeId() {
+    return typeId & 0xff;
+  }
+
+  @Override
+  Object getUnsafeObject() {
+    assertValid();
+    return unsafeObj;
+  }
+
+}

Added: dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBWritableMemoryImpl.java
==============================================================================
--- dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBWritableMemoryImpl.java (added)
+++ dev/datasketches/memory/2.0.0-RC1/apache-datasketches-memory-2.0.0-src/datasketches-memory-java8/src/main/java/org/apache/datasketches/memory/internal/BBWritableMemoryImpl.java Thu Aug 19 22:18:24 2021
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableMemory;
+
+/**
+ * Implementation of {@link WritableMemory} for ByteBuffer, native byte order.
+ *
+ * @author Roman Leventov
+ * @author Lee Rhodes
+ */
+final class BBWritableMemoryImpl extends NativeWritableMemoryImpl {
+  private static final int id = MEMORY | NATIVE | BYTEBUF;
+  private final Object unsafeObj;
+  private final long nativeBaseOffset; //used to compute cumBaseOffset
+  private final ByteBuffer byteBuf; //holds a reference to a ByteBuffer until we are done with it.
+  private final MemoryRequestServer memReqSvr;
+  private final byte typeId;
+
+  BBWritableMemoryImpl(
+      final Object unsafeObj,
+      final long nativeBaseOffset,
+      final long regionOffset,
+      final long capacityBytes,
+      final int typeId,
+      final ByteBuffer byteBuf,
+      final MemoryRequestServer memReqSvr) {
+    super(unsafeObj, nativeBaseOffset, regionOffset, capacityBytes);
+    this.unsafeObj = unsafeObj;
+    this.nativeBaseOffset = nativeBaseOffset;
+    this.byteBuf = byteBuf;
+    this.memReqSvr = memReqSvr;
+    this.typeId = (byte) (id | (typeId & 0x7));
+  }
+
+  @Override
+  BaseWritableMemoryImpl toWritableRegion(final long offsetBytes, final long capacityBytes,
+      final boolean readOnly, final ByteOrder byteOrder) {
+    final int type = setReadOnlyType(typeId, readOnly) | REGION;
+    return Util.isNativeByteOrder(byteOrder)
+        ? new BBWritableMemoryImpl(
+            unsafeObj, nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, getByteBuffer(), memReqSvr)
+        : new BBNonNativeWritableMemoryImpl(
+            unsafeObj, nativeBaseOffset, getRegionOffset(offsetBytes), capacityBytes, type, getByteBuffer(), memReqSvr);
+  }
+
+  @Override
+  BaseWritableBufferImpl toWritableBuffer(final boolean readOnly, final ByteOrder byteOrder) {
+    final int type = setReadOnlyType(typeId, readOnly);
+    return Util.isNativeByteOrder(byteOrder)
+        ? new BBWritableBufferImpl(
+            unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(), type, byteBuf, memReqSvr)
+        : new BBNonNativeWritableBufferImpl(
+            unsafeObj, nativeBaseOffset, getRegionOffset(), getCapacity(), type, byteBuf, memReqSvr);
+  }
+
+  @Override
+  public ByteBuffer getByteBuffer() {
+    assertValid();
+    return byteBuf;
+  }
+
+  @Override
+  public MemoryRequestServer getMemoryRequestServer() {
+    assertValid();
+    return memReqSvr;
+  }
+
+  @Override
+  long getNativeBaseOffset() {
+    return nativeBaseOffset;
+  }
+
+  @Override
+  int getTypeId() {
+    return typeId & 0xff;
+  }
+
+  @Override
+  Object getUnsafeObject() {
+    assertValid();
+    return unsafeObj;
+  }
+
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datasketches.apache.org
For additional commands, e-mail: commits-help@datasketches.apache.org