Interim 3 Tests loaded so far do run.
diff --git a/src/main/java/org/apache/datasketches/memory/BaseState.java b/src/main/java/org/apache/datasketches/memory/BaseState.java
index e54f4dd..c9c8503 100644
--- a/src/main/java/org/apache/datasketches/memory/BaseState.java
+++ b/src/main/java/org/apache/datasketches/memory/BaseState.java
@@ -212,13 +212,14 @@
   //TO STRING
 
   /**
-   * Returns a formatted hex string of a range of this object.
-   * Used primarily for testing.
-   * @param header a descriptive header
+   * Returns a description of this object with an optional formatted hex string of the data
+   * for the specified a range. Used primarily for testing.
+   * @param comment a description
    * @param offsetBytes offset bytes relative to this object start
    * @param lengthBytes number of bytes to convert to a hex string
-   * @return a formatted hex string in a human readable array
+   * @param withData include output listing of byte data in the given range
+   * @return a description and hex output in a human readable format.
    */
-  String toHexString(String header, long offsetBytes, int lengthBytes);
+  String toHexString(String comment, long offsetBytes, int lengthBytes, boolean withData);
 
 }
diff --git a/src/main/java/org/apache/datasketches/memory/Buffer.java b/src/main/java/org/apache/datasketches/memory/Buffer.java
index 1a8cdbe..7c5661d 100644
--- a/src/main/java/org/apache/datasketches/memory/Buffer.java
+++ b/src/main/java/org/apache/datasketches/memory/Buffer.java
@@ -19,7 +19,6 @@
 
 package org.apache.datasketches.memory;
 
-import java.io.File;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.Objects;
@@ -36,11 +35,12 @@
   //BYTE BUFFER
   /**
    * Provides a view of the given <i>ByteBuffer</i> for read-only operations.
-   * The returned <i>Buffer</i> will use the native <i>ByteOrder</i>,
-   * ignoring the byte order of the given <i>ByteBuffer</i>.
-   * This does not change the byte order of data already in the <i>ByteBuffer</i>.
-   * The view starts relative to the buffer's position (inclusive)
-   * and ends relative to the buffer's limit (exclusive).
+   * The view is of the entire ByteBuffer independent of position and limit.
+   * However, the returned <i>WritableBuffer</i> will have a position and end set to the
+   * ByteBuffer's position and limit, respectively.
+   * The returned WritableBuffer will use the native <i>ByteOrder</i>,
+   * ignoring the ByteOrder of the given ByteBuffer.
+   * This does not affect the ByteOrder of data already in the ByteBuffer.
    * @param byteBuffer the given ByteBuffer, must not be null.
    * @return a new <i>Buffer</i> for read-only operations on the given ByteBuffer.
    */
@@ -50,10 +50,12 @@
 
   /**
    * Provides a view of the given <i>ByteBuffer</i> for read-only operations.
-   * The returned <i>Buffer</i> will use the given <i>ByteOrder</i>,
-   * ignoring the byte order of the given <i>ByteBuffer</i>.
-   * The view starts relative to the ByteBuffer's position (inclusive)
-   * and ends relative to the ByteBuffer's limit (exclusive).
+   * The view is of the entire ByteBuffer independent of position and limit.
+   * However, the returned <i>WritableBuffer</i> will have a position and end set to the
+   * ByteBuffer's position and limit, respectively.
+   * The returned WritableBuffer will use the native <i>ByteOrder</i>,
+   * ignoring the ByteOrder of the given ByteBuffer.
+   * This does not affect the ByteOrder of data already in the ByteBuffer.
    * @param byteBuffer the given ByteBuffer, must not be null
    * @param byteOrder the ByteOrder to be used. It must be non-null.
    * @return a new <i>Buffer</i> for read-only operations on the given ByteBuffer.
@@ -61,8 +63,7 @@
   static Buffer wrap(ByteBuffer byteBuffer, ByteOrder byteOrder) {
     Objects.requireNonNull(byteBuffer, "byteBuffer must not be null");
     Objects.requireNonNull(byteOrder, "byteOrder must not be null");
-    ByteBuffer byteBuf = byteBuffer.asReadOnlyBuffer();
-    return BaseWritableBufferImpl.wrapByteBuffer(byteBuf, true, byteOrder);
+    return BaseWritableBufferImpl.wrapByteBuffer(byteBuffer, true, byteOrder);
   }
 
   //DUPLICATES
@@ -102,36 +103,8 @@
    */
   Buffer duplicate(ByteOrder byteOrder);
 
-  //MAP
-  /**
-   * Maps the given file into <i>Buffer</i> for read operations
-   * Calling this method is equivalent to calling
-   * {@link #map(File, long, long, ByteOrder) map(file, 0, file.length(), ByteOrder.nativeOrder())}.
-   * @param file the given file to map. It must be non-null, length &ge; 0, and readable.
-   * @return mapped Buffer.
-   * @throws Exception
-   */
-  static Buffer map(File file) throws Exception {
-    return map(file, 0, file.length(), ByteOrder.nativeOrder());
-  }
-
-  /**
-   * Maps the specified portion of the given file into <i>Buffer</i> for read operations.
-   * @param file the given file to map. It must be non-null,readable 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 be &ge; 0.
-   * @param byteOrder the byte order to be used.  It must be non-null.
-   * @return Buffer
-   * @throws Exception
-
-   */
-  static Buffer map(File file, long fileOffsetBytes, long capacityBytes, ByteOrder byteOrder)
-      throws Exception {
-    Objects.requireNonNull(file, "file must be non-null.");
-    Objects.requireNonNull(byteOrder, "byteOrder must be non-null.");
-    if (!file.canRead()) { throw new IllegalArgumentException("file must be readable."); }
-    return BaseWritableBufferImpl.wrapMap(file, fileOffsetBytes, capacityBytes, true, byteOrder);
-  }
+  //NO MAP use Memory
+  //NO ALLOCATE DIRECT, makes no sense
 
   //REGIONS
   /**
@@ -193,7 +166,10 @@
    */
   Memory asMemory(ByteOrder byteOrder);
 
-  //NO WRAP - ACCESS PRIMITIVE HEAP ARRAYS for readOnly
+  //NO ALLOCATE HEAP BYTE ARRAYS, makes no sense. Use WritableMemory
+  //NO WRAP - ACCESS PRIMITIVE HEAP ARRAYS for readOnly.
+  //  Because of the ambiguity of positional API with the multibyte primitives. Use Memory instead.
+  //END OF CONSTRUCTOR-TYPE METHODS
 
   //PRIMITIVE getX() and getXArray()
 
@@ -365,7 +341,9 @@
    */
   void getShortArray(short[] dstArray, int dstOffsetShorts, int lengthShorts);
 
-  //SPECIAL PRIMITIVE READ METHODS: compareTo
+  //SPECIAL PRIMITIVE READ METHODS: compareTo.
+  //   No copyTo, No writeTo. Use Memory for that.
+
   /**
    * Compares the bytes of this Buffer to <i>that</i> Buffer.
    * This uses absolute offsets not the start, position and end.
diff --git a/src/main/java/org/apache/datasketches/memory/Memory.java b/src/main/java/org/apache/datasketches/memory/Memory.java
index ad003da..07e3135 100644
--- a/src/main/java/org/apache/datasketches/memory/Memory.java
+++ b/src/main/java/org/apache/datasketches/memory/Memory.java
@@ -30,6 +30,7 @@
 import org.apache.datasketches.memory.internal.Util;
 
 import jdk.incubator.foreign.MemorySegment;
+import jdk.incubator.foreign.ResourceScope;
 
 /**
  * Defines the read-only API for offset access to a resource.
@@ -41,8 +42,10 @@
   //BYTE BUFFER
   /**
    * Provides a view of the given <i>ByteBuffer</i> for read-only operations.
-   * The returned <i>Memory</i> will use the native <i>ByteOrder</i>,
-   * ignoring the byte order of the given <i>ByteBuffer</i>.
+   * The view is of the entire ByteBuffer independent of position and limit.
+   * The returned <i>WritableMemory</i> will use the native <i>ByteOrder</i>,
+   * independent of the ByteOrder of the given ByteBuffer.
+   * This does not affect the ByteOrder of data already in the ByteBuffer.
    * @param byteBuffer the given <i>ByteBuffer</i>. It must be non-null.
    * @return a new <i>Memory</i> for read-only operations on the given <i>ByteBuffer</i>.
    */
@@ -52,10 +55,10 @@
 
   /**
    * Provides a view of the given <i>ByteBuffer</i> for read-only operations.
-   * The returned <i>Memory</i> will use the given byte order,
-   * ignoring the byte order of the given <i>ByteBuffer</i>.
-   * This does not change the byte order of data already in the <i>ByteBuffer</i>.
-   * The view starts at zero (inclusive) and ends at the ByteBuffer's capacity (exclusive).
+   * The view is of the entire ByteBuffer independent of position and limit.
+   * The returned <i>WritableMemory</i> will use the native <i>ByteOrder</i>,
+   * independent of the ByteOrder of the given ByteBuffer.
+   * This does not affect the ByteOrder of data already in the ByteBuffer.
    * @param byteBuffer the given <i>ByteBuffer</i>. It must be non-null.
    * @param byteOrder the byte order to be used.  It must be non-null.
    * @return a new <i>Memory</i> for read-only operations on the given <i>ByteBuffer</i>.
@@ -63,42 +66,49 @@
   static Memory wrap(ByteBuffer byteBuffer, ByteOrder byteOrder) {
     Objects.requireNonNull(byteBuffer, "byteBuffer must not be null");
     Objects.requireNonNull(byteOrder, "byteOrder must not be null");
-    ByteBuffer byteBuf = byteBuffer.position(0).limit(byteBuffer.capacity()).asReadOnlyBuffer();
-    return BaseWritableMemoryImpl.wrapByteBuffer(byteBuf, true, byteOrder);
+    return BaseWritableMemoryImpl.wrapByteBuffer(byteBuffer, true, byteOrder);
   }
 
+  //Duplicates make no sense here
+
   //MAP
   /**
    * Maps the given file into <i>Memory</i> for read operations
    * Calling this method is equivalent to calling
-   * {@link #map(File, long, long, ByteOrder) map(file, 0, file.length(), ByteOrder.nativeOrder())}.
-   * @param file the given file to map. It must be non-null, length &ge; 0, and readable.
+   * {@link #map(File, long, long, ResourceScope, ByteOrder) map(file, 0, file.length(), scope, ByteOrder.nativeOrder())}.
+   * @param file the given file to map. It must be non-null with a non-negative length and readable.
+   * @param scope the given ResourceScope. It must be non-null.
    * @return mapped Memory.
    * @throws Exception
    */
-  static Memory map(File file) throws Exception {
-    return map(file, 0, file.length(), ByteOrder.nativeOrder());
+  static Memory map(File file, ResourceScope scope) throws Exception {
+    return map(file, 0, file.length(), scope, ByteOrder.nativeOrder());
   }
 
   /**
    * Maps the specified portion of the given file into <i>Memory</i> for read operations.
    * @param file the given file to map. It must be non-null,readable 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 be &ge; 0.
+   * @param capacityBytes the size of the mapped memory. It must not be negative..
+   * @param scope the given ResourceScope. It must be non-null.
    * @param byteOrder the byte order to be used.  It must be non-null.
-   * @return Memory
+   * @return mapped Memory
    * @throws Exception
    */
-  static Memory map(File file, long fileOffsetBytes, long capacityBytes, ByteOrder byteOrder)
+  @SuppressWarnings("resource")
+  static Memory map(File file, long fileOffsetBytes, long capacityBytes, ResourceScope scope, ByteOrder byteOrder)
       throws Exception {
-    Objects.requireNonNull(file, "file must be non-null.");
-    Objects.requireNonNull(byteOrder, "byteOrder must be non-null.");
+    Objects.requireNonNull(file, "File must be non-null.");
+    Objects.requireNonNull(byteOrder, "ByteOrder must be non-null.");
+    Objects.requireNonNull(scope, "ResourceScope must be non-null.");
     Util.negativeCheck(fileOffsetBytes, "fileOffsetBytes");
     Util.negativeCheck(capacityBytes, "capacityBytes");
-    if (!file.canRead()) { throw new IllegalArgumentException("file must be readable."); }
-    return BaseWritableMemoryImpl.wrapMap(file, fileOffsetBytes, capacityBytes, true, byteOrder);
+    if (!file.canRead()) { throw new IllegalArgumentException("File must be readable."); }
+    return BaseWritableMemoryImpl.wrapMap(file, fileOffsetBytes, capacityBytes, scope, true, byteOrder);
   }
 
+  //NO ALLOCATE DIRECT, makes no sense
+
   //REGIONS
   /**
    * A region is a read-only view of this object.
@@ -163,6 +173,8 @@
    */
   Buffer asBuffer(ByteOrder byteOrder);
 
+  //NO ALLOCATE HEAP BYTE ARRAYS, makes no sense
+
   //WRAP - ACCESS PRIMITIVE HEAP ARRAYS for readOnly
   /**
    * Wraps the given primitive array for read operations assuming native byte order.
@@ -195,8 +207,7 @@
   static Memory wrap(byte[] array, int offsetBytes, int lengthBytes, ByteOrder byteOrder) {
     Objects.requireNonNull(array, "array must be non-null");
     final MemorySegment slice = MemorySegment.ofArray(array).asSlice(offsetBytes, lengthBytes).asReadOnly();
-    return BaseWritableMemoryImpl.wrapSegment(slice, ByteOrder.nativeOrder(), null);
-
+    return BaseWritableMemoryImpl.wrapSegmentAsArray(slice, ByteOrder.nativeOrder(), null);
   }
 
   /**
@@ -207,7 +218,7 @@
   static Memory wrap(char[] array) {
     Objects.requireNonNull(array, "array must be non-null");
     final MemorySegment slice = MemorySegment.ofArray(array).asReadOnly();
-    return BaseWritableMemoryImpl.wrapSegment(slice, ByteOrder.nativeOrder(), null);
+    return BaseWritableMemoryImpl.wrapSegmentAsArray(slice, ByteOrder.nativeOrder(), null);
   }
 
   /**
@@ -218,7 +229,7 @@
   static Memory wrap(short[] array) {
     Objects.requireNonNull(array, "arr must be non-null");
     final MemorySegment slice = MemorySegment.ofArray(array).asReadOnly();
-    return BaseWritableMemoryImpl.wrapSegment(slice, ByteOrder.nativeOrder(), null);
+    return BaseWritableMemoryImpl.wrapSegmentAsArray(slice, ByteOrder.nativeOrder(), null);
   }
 
   /**
@@ -229,7 +240,7 @@
   static Memory wrap(int[] array) {
     Objects.requireNonNull(array, "arr must be non-null");
     final MemorySegment slice = MemorySegment.ofArray(array).asReadOnly();
-    return BaseWritableMemoryImpl.wrapSegment(slice, ByteOrder.nativeOrder(), null);
+    return BaseWritableMemoryImpl.wrapSegmentAsArray(slice, ByteOrder.nativeOrder(), null);
   }
 
   /**
@@ -240,7 +251,7 @@
   static Memory wrap(long[] array) {
     Objects.requireNonNull(array, "arr must be non-null");
     final MemorySegment slice = MemorySegment.ofArray(array).asReadOnly();
-    return BaseWritableMemoryImpl.wrapSegment(slice, ByteOrder.nativeOrder(), null);
+    return BaseWritableMemoryImpl.wrapSegmentAsArray(slice, ByteOrder.nativeOrder(), null);
   }
 
   /**
@@ -251,7 +262,7 @@
   static Memory wrap(float[] array) {
     Objects.requireNonNull(array, "arr must be non-null");
     final MemorySegment slice = MemorySegment.ofArray(array).asReadOnly();
-    return BaseWritableMemoryImpl.wrapSegment(slice, ByteOrder.nativeOrder(), null);
+    return BaseWritableMemoryImpl.wrapSegmentAsArray(slice, ByteOrder.nativeOrder(), null);
   }
 
   /**
@@ -262,8 +273,9 @@
   static Memory wrap(double[] array) {
     Objects.requireNonNull(array, "arr must be non-null");
     final MemorySegment slice = MemorySegment.ofArray(array).asReadOnly();
-    return BaseWritableMemoryImpl.wrapSegment(slice, ByteOrder.nativeOrder(), null);
+    return BaseWritableMemoryImpl.wrapSegmentAsArray(slice, ByteOrder.nativeOrder(), null);
   }
+  //END OF CONSTRUCTOR-TYPE METHODS
 
   //PRIMITIVE getX() and getXArray()
 
@@ -380,6 +392,7 @@
   void getShortArray(long offsetBytes, short[] dstArray, int dstOffsetShorts, int lengthShorts);
 
   //SPECIAL PRIMITIVE READ METHODS: compareTo, copyTo, writeTo
+
   /**
    * Compares the bytes of this Memory to <i>that</i> Memory.
    * Returns <i>(this &lt; that) ? (some negative value) : (this &gt; that) ? (some positive value)
diff --git a/src/main/java/org/apache/datasketches/memory/MemoryRequestServer.java b/src/main/java/org/apache/datasketches/memory/MemoryRequestServer.java
index e2ca235..6bef2c6 100644
--- a/src/main/java/org/apache/datasketches/memory/MemoryRequestServer.java
+++ b/src/main/java/org/apache/datasketches/memory/MemoryRequestServer.java
@@ -31,11 +31,11 @@
    * Request new WritableMemory with the given capacity. The current Writable Memory will be used to
    * determine the byte order of the returned WritableMemory and other checks.
    * @param currentWritableMemory the current writableMemory of the client. It must be non-null.
-   * @param capacityBytes The capacity being requested. It must be &ge; 0.
+   * @param newCapacityBytes The capacity being requested. It must be &ge; 0.
    *
    * @return new WritableMemory with the given capacity.
    */
-  WritableMemory request(WritableMemory currentWritableMemory, long capacityBytes);
+  WritableMemory request(WritableMemory currentWritableMemory, long newCapacityBytes);
 
   /**
    * Request close the AutoCloseable resource. This only applies to resources allocated using
diff --git a/src/main/java/org/apache/datasketches/memory/WritableBuffer.java b/src/main/java/org/apache/datasketches/memory/WritableBuffer.java
index b0695cf..362a38e 100644
--- a/src/main/java/org/apache/datasketches/memory/WritableBuffer.java
+++ b/src/main/java/org/apache/datasketches/memory/WritableBuffer.java
@@ -36,11 +36,12 @@
   //BYTE BUFFER
   /**
    * Provides a view of the given <i>ByteBuffer</i> for write operations.
-   * The returned <i>WritableBuffer</i> will use the native <i>ByteOrder</i>,
-   * ignoring the byte order of the given <i>ByteBuffer</i>.
-   * This does not change the byte order of data already in the <i>ByteBuffer</i>.
-   * The view starts relative to the ByteBuffer's position (inclusive)
-   * and ends relative to the ByteBuffer's limit (exclusive).
+   * The view is of the entire ByteBuffer independent of position and limit.
+   * However, the returned <i>WritableBuffer</i> will have a position and end set to the
+   * ByteBuffer's position and limit, respectively.
+   * The returned WritableBuffer will use the native <i>ByteOrder</i>,
+   * ignoring the ByteOrder of the given ByteBuffer.
+   * This does not affect the ByteOrder of data already in the ByteBuffer.
    * @param byteBuffer the given ByteBuffer. It must be non-null and writable.
    * @return a new <i>WritableBuffer</i> for write operations on the given <i>ByteBuffer</i>.
    */
@@ -50,11 +51,12 @@
 
   /**
    * Provides a view of the given <i>ByteBuffer</i> for write operations.
-   * The returned <i>WritableBuffer</i> will use the given <i>ByteOrder</i>,
-   * ignoring the byte order of the given <i>ByteBuffer</i>.
-   * However, this does not change the byte order of data already in the <i>ByteBuffer</i>.
-   * The view starts relative to the ByteBuffer's position (inclusive)
-   * and ends relative to the ByteBuffer's limit (exclusive).
+   * The view is of the entire ByteBuffer independent of position and limit.
+   * However, the returned <i>WritableBuffer</i> will have a position and end set to the
+   * ByteBuffer's position and limit, respectively.
+   * The returned WritableBuffer will use the native <i>ByteOrder</i>,
+   * ignoring the ByteOrder of the given ByteBuffer.
+   * This does not affect the ByteOrder of data already in the ByteBuffer.
    * @param byteBuffer the given ByteBuffer. It must be non-null and writable.
    * @param byteOrder the byte order to be used.  It must be non-null.
    * @return a new <i>WritableBuffer</i> for write operations on the given <i>ByteBuffer</i>.
@@ -66,9 +68,6 @@
     return BaseWritableBufferImpl.wrapByteBuffer(byteBuffer, false, byteOrder);
   }
 
-  // NO MAP
-  // NO ALLOCATE DIRECT
-
   //DUPLICATES
   /**
    * Returns a duplicate writable view of this Buffer with the same but independent values of
@@ -105,6 +104,9 @@
    */
   WritableBuffer writableDuplicate(ByteOrder byteOrder);
 
+  // NO MAP use WritableMemory
+  // NO ALLOCATE DIRECT use WritableMemory
+
   //REGIONS
   /**
    * A writable region is a writable view of this object.
@@ -166,9 +168,10 @@
    */
   WritableMemory asWritableMemory(ByteOrder byteOrder);
 
-  //NO ALLOCATE HEAP VIA AUTOMATIC BYTE ARRAY
-
+  //NO ALLOCATE HEAP BYTE ARRAY use WritableMemory
+  //NO WRITABLE WRAP -- ACCESS PRIMITIVE HEAP ARRAYS for WRITE
   //NO ACCESS PRIMITIVE HEAP ARRAYS for WRITE
+  //END OF CONSTRUCTOR-TYPE METHODS
 
   //PRIMITIVE putX() and putXArray()
 
@@ -362,6 +365,6 @@
 
   //NO setBits(...)
 
-  //OTHER WRITABLE API METHODS
+  //NO OTHER WRITABLE API METHODS
 
 }
diff --git a/src/main/java/org/apache/datasketches/memory/WritableMemory.java b/src/main/java/org/apache/datasketches/memory/WritableMemory.java
index 4e6d4a5..73b0ca0 100644
--- a/src/main/java/org/apache/datasketches/memory/WritableMemory.java
+++ b/src/main/java/org/apache/datasketches/memory/WritableMemory.java
@@ -25,6 +25,7 @@
 import java.util.Objects;
 
 import org.apache.datasketches.memory.internal.BaseWritableMemoryImpl;
+import org.apache.datasketches.memory.internal.Util;
 
 import jdk.incubator.foreign.MemorySegment;
 import jdk.incubator.foreign.ResourceScope;
@@ -39,8 +40,10 @@
   //BYTE BUFFER
   /**
    * Provides a view of the given <i>ByteBuffer</i> for write operations.
+   * The view is of the entire ByteBuffer independent of position and limit.
    * The returned <i>WritableMemory</i> will use the native <i>ByteOrder</i>,
-   * ignoring the byte order of the given <i>ByteBuffer</i>.
+   * independent of the ByteOrder of the given ByteBuffer.
+   * This does not affect the ByteOrder of data already in the ByteBuffer.
    * @param byteBuffer the given <i>ByteBuffer</i>. It must be non-null and writable.
    * @return a new <i>WritableMemory</i> for write operations on the given <i>ByteBuffer</i>.
    */
@@ -50,10 +53,10 @@
 
   /**
    * Provides a view of the given <i>ByteBuffer</i> for write operations.
-   * The returned <i>WritableMemory</i> will use the given byte order,
-   * ignoring the byte order of the given <i>ByteBuffer</i>.
-   * This does not change the byte order of data already in the <i>ByteBuffer</i>.
-   * The view starts at zero (inclusive) and ends at the ByteBuffer's capacity (exclusive).
+   * The view is of the entire ByteBuffer independent of position and limit.
+   * The returned <i>WritableMemory</i> will use the native <i>ByteOrder</i>,
+   * independent of the ByteOrder of the given ByteBuffer.
+   * This does not affect the ByteOrder of data already in the ByteBuffer.
    * @param byteBuffer the given <i>ByteBuffer</i>. It must be non-null 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>.
@@ -66,40 +69,47 @@
     return BaseWritableMemoryImpl.wrapByteBuffer(byteBuf, false, byteOrder);
   }
 
+  //Duplicates make no sense here
+
   //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 and writable.
+   * {@link #writableMap(File, long, long, ResourceScope, ByteOrder)
+   *   writableMap(file, 0, file.length(), scope, ByteOrder.nativeOrder())}.
+   * @param file the given file to map. It must be non-null with a non-negative length and writable.
+   * @param scope the give Resource Scope. It must be non-null.
    * @return mapped WritableMemory
    * @throws Exception
    */
-  static WritableMemory writableMap(File file) throws Exception {
-    return writableMap(file, 0, file.length(), ByteOrder.nativeOrder());
+  static WritableMemory writableMap(File file, ResourceScope scope) throws Exception {
+    return writableMap(file, 0, file.length(), scope, 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 and writable.
+   * @param file the given file to map. It must be non-null with a non-negative length and writable.
    * @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 be &ge; 0.
+   * @param scope the give Resource Scope. It must be non-null.
    * @param byteOrder the byte order to be used.  It must be non-null.
    * @return mapped WritableMemory.
    * @throws Exception
    */
-  static WritableMemory writableMap(File file, long fileOffsetBytes, long capacityBytes, ByteOrder byteOrder)
-      throws Exception {
+  @SuppressWarnings("resource")
+  static WritableMemory writableMap(File file, long fileOffsetBytes, long capacityBytes, ResourceScope scope,
+      ByteOrder byteOrder) throws Exception {
     Objects.requireNonNull(file, "File must be non-null.");
     Objects.requireNonNull(byteOrder, "ByteOrder must be non-null.");
+    Objects.requireNonNull(scope, "ResourceScope must be non-null.");
+    Util.negativeCheck(fileOffsetBytes, "fileOffsetBytes");
+    Util.negativeCheck(capacityBytes, "capacityBytes");
     if (!file.canWrite()) { throw new ReadOnlyException("file must be writable."); }
-    return BaseWritableMemoryImpl.wrapMap(file, fileOffsetBytes, capacityBytes, false, byteOrder);
+    return BaseWritableMemoryImpl.wrapMap(file, fileOffsetBytes, capacityBytes, scope, false, byteOrder);
   }
 
   //ALLOCATE DIRECT
+
   /**
    * Allocates and provides access to capacityBytes directly in native (off-heap) memory.
    * Native byte order is assumed.
@@ -108,12 +118,13 @@
    * <p><b>NOTICE:</b> It is the responsibility of the using application to call <i>close()</i> when done.</p>
    *
    * @param capacityBytes the size of the desired memory in bytes.
+   * @param scope the given ResourceScope. It must be non-null.
    * @param memReqSvr A user-specified MemoryRequestServer, which may be null.
    * @return WritableMemory for this off-heap, native resource.
    */
   @SuppressWarnings("resource")
-  static WritableMemory allocateDirect(long capacityBytes, MemoryRequestServer memReqSvr) {
-    return allocateDirect(capacityBytes, 8, ResourceScope.newConfinedScope(), ByteOrder.nativeOrder(), memReqSvr);
+  static WritableMemory allocateDirect(long capacityBytes, ResourceScope scope, MemoryRequestServer memReqSvr) {
+    return allocateDirect(capacityBytes, 8, scope, ByteOrder.nativeOrder(), memReqSvr);
   }
 
   /**
@@ -125,8 +136,7 @@
    *
    * @param capacityBytes the size of the desired memory in bytes.
    * @param alignmentBytes requested segment alignment. Typically 1, 2, 4 or 8.
-   * @param scope ResourceScope for the backing MemorySegment.
-   * Typically <i>ResourceScope.newConfinedScope()</i>.
+   * @param scope the given ResourceScope. It must be non-null.
    * @param byteOrder the byte order to be used.  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.
@@ -212,8 +222,8 @@
    */
   WritableBuffer asWritableBuffer(ByteOrder byteOrder);
 
+  //ALLOCATE HEAP BYTE ARRAYS
 
-  //ALLOCATE HEAP VIA AUTOMATIC BYTE ARRAY
   /**
    * Creates on-heap WritableMemory with the given capacity and the native byte order.
    * This will utilize the MemoryRequestServer if it has been configured.
@@ -247,8 +257,7 @@
     return writableWrap(arr, 0, capacityBytes, byteOrder, memReqSvr);
   }
 
-
-  //ACCESS PRIMITIVE HEAP ARRAYS for WRITE
+  //WRITABLE WRAP - ACCESS PRIMITIVE HEAP ARRAYS for WRITE
 
   /**
    * Wraps the given primitive array for write operations assuming native byte order.
@@ -307,8 +316,7 @@
     Objects.requireNonNull(array, "array must be non-null");
     Objects.requireNonNull(byteOrder, "byteOrder must be non-null");
     final MemorySegment slice = MemorySegment.ofArray(array).asSlice(offsetBytes, lengthBytes);
-    return BaseWritableMemoryImpl.wrapSegment(slice, ByteOrder.nativeOrder(), memReqSvr);
-
+    return BaseWritableMemoryImpl.wrapSegmentAsArray(slice, byteOrder, memReqSvr);
   }
 
   /**
@@ -319,7 +327,7 @@
   static WritableMemory writableWrap(char[] array) {
     Objects.requireNonNull(array, "array must be non-null");
     final MemorySegment seg = MemorySegment.ofArray(array);
-    return BaseWritableMemoryImpl.wrapSegment(seg, ByteOrder.nativeOrder(), null);
+    return BaseWritableMemoryImpl.wrapSegmentAsArray(seg, ByteOrder.nativeOrder(), null);
   }
 
   /**
@@ -330,7 +338,7 @@
   static WritableMemory writableWrap(short[] array) {
     Objects.requireNonNull(array, "array must be non-null");
     final MemorySegment seg = MemorySegment.ofArray(array);
-    return BaseWritableMemoryImpl.wrapSegment(seg, ByteOrder.nativeOrder(), null);
+    return BaseWritableMemoryImpl.wrapSegmentAsArray(seg, ByteOrder.nativeOrder(), null);
   }
 
   /**
@@ -341,7 +349,7 @@
   static WritableMemory writableWrap(int[] array) {
     Objects.requireNonNull(array, "array must be non-null");
     final MemorySegment seg = MemorySegment.ofArray(array);
-    return BaseWritableMemoryImpl.wrapSegment(seg, ByteOrder.nativeOrder(), null);
+    return BaseWritableMemoryImpl.wrapSegmentAsArray(seg, ByteOrder.nativeOrder(), null);
   }
 
   /**
@@ -352,7 +360,7 @@
   static WritableMemory writableWrap(long[] array) {
     Objects.requireNonNull(array, "array must be non-null");
     final MemorySegment seg = MemorySegment.ofArray(array);
-    return BaseWritableMemoryImpl.wrapSegment(seg, ByteOrder.nativeOrder(), null);
+    return BaseWritableMemoryImpl.wrapSegmentAsArray(seg, ByteOrder.nativeOrder(), null);
   }
 
   /**
@@ -363,7 +371,7 @@
   static WritableMemory writableWrap(float[] array) {
     Objects.requireNonNull(array, "array must be non-null");
     final MemorySegment seg = MemorySegment.ofArray(array);
-    return BaseWritableMemoryImpl.wrapSegment(seg, ByteOrder.nativeOrder(), null);
+    return BaseWritableMemoryImpl.wrapSegmentAsArray(seg, ByteOrder.nativeOrder(), null);
   }
 
   /**
@@ -374,7 +382,7 @@
   static WritableMemory writableWrap(double[] array) {
     Objects.requireNonNull(array, "array must be non-null");
     final MemorySegment seg = MemorySegment.ofArray(array);
-    return BaseWritableMemoryImpl.wrapSegment(seg, ByteOrder.nativeOrder(), null);
+    return BaseWritableMemoryImpl.wrapSegmentAsArray(seg, ByteOrder.nativeOrder(), null);
   }
   //END OF CONSTRUCTOR-TYPE METHODS
 
diff --git a/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableBufferImpl.java b/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableBufferImpl.java
index bf65f09..222168b 100644
--- a/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableBufferImpl.java
+++ b/src/main/java/org/apache/datasketches/memory/internal/BBNonNativeWritableBufferImpl.java
@@ -19,8 +19,6 @@
 
 package org.apache.datasketches.memory.internal;
 
-import java.nio.ByteOrder;
-
 import org.apache.datasketches.memory.WritableBuffer;
 
 import jdk.incubator.foreign.MemorySegment;
@@ -39,14 +37,4 @@
     super(seg, typeId);
   }
 
-  //DUPLICATE
-
-  @Override
-  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | DUPLICATE;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new BBWritableBufferImpl(seg, type)
-        : new BBNonNativeWritableBufferImpl(seg, type);
-  }
-
 }
diff --git a/src/main/java/org/apache/datasketches/memory/internal/BBWritableBufferImpl.java b/src/main/java/org/apache/datasketches/memory/internal/BBWritableBufferImpl.java
index d9bbebd..bf83a41 100644
--- a/src/main/java/org/apache/datasketches/memory/internal/BBWritableBufferImpl.java
+++ b/src/main/java/org/apache/datasketches/memory/internal/BBWritableBufferImpl.java
@@ -19,8 +19,6 @@
 
 package org.apache.datasketches.memory.internal;
 
-import java.nio.ByteOrder;
-
 import org.apache.datasketches.memory.WritableBuffer;
 
 import jdk.incubator.foreign.MemorySegment;
@@ -39,14 +37,4 @@
     super(seg, typeId);
   }
 
-  //DUPLICATE
-
-  @Override
-  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | DUPLICATE;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new BBWritableBufferImpl(seg, type)
-        : new BBNonNativeWritableBufferImpl(seg, type);
-  }
-
 }
diff --git a/src/main/java/org/apache/datasketches/memory/internal/BaseStateImpl.java b/src/main/java/org/apache/datasketches/memory/internal/BaseStateImpl.java
index c8e9a00..2159ef5 100644
--- a/src/main/java/org/apache/datasketches/memory/internal/BaseStateImpl.java
+++ b/src/main/java/org/apache/datasketches/memory/internal/BaseStateImpl.java
@@ -27,6 +27,7 @@
 import org.apache.datasketches.memory.BaseState;
 import org.apache.datasketches.memory.MemoryRequestServer;
 
+import jdk.incubator.foreign.MemoryAddress;
 import jdk.incubator.foreign.MemorySegment;
 import jdk.incubator.foreign.ResourceScope;
 
@@ -237,21 +238,27 @@
 
   @Override
   public final boolean isSameResource(final Object that) {
-    return (this == that);
+    if (this == that) { return true; }
+    final MemoryAddress myAdd = seg.address();
+    if (that instanceof BaseStateImpl) {
+      final MemoryAddress thatAdd = ((BaseStateImpl)that).seg.address();
+      return (myAdd.equals(thatAdd));
+    }
+    return false;
   }
 
   //TYPE ID Management
 
   @Override
   public final boolean isReadOnly() {
-    return (getTypeId() & READONLY) > 0;
+    return ((getTypeId() & READONLY) > 0) || seg.isReadOnly();
   }
 
   final static int setReadOnlyType(final int type, final boolean readOnly) {
     return (type & ~READONLY) | (readOnly ? READONLY : 0);
   }
 
-  final boolean isRegionType() {
+  final boolean isRegionType() { //
     return (getTypeId() & REGION) > 0;
   }
 
@@ -259,15 +266,15 @@
     return (getTypeId() & DUPLICATE) > 0;
   }
 
-  final boolean isMemoryType() {
+  final boolean isMemoryType() { //
     return (getTypeId() & BUFFER) == 0;
   }
 
-  final boolean isBufferType() {
+  final boolean isBufferType() { //
     return (getTypeId() & BUFFER) > 0;
   }
 
-  final boolean isNativeType() {
+  final boolean isNativeType() { //
     return (getTypeId() & NONNATIVE) == 0;
   }
 
@@ -275,15 +282,15 @@
     return (getTypeId() & NONNATIVE) > 0;
   }
 
-  final boolean isHeapType() {
+  final boolean isHeapType() { //
     return (getTypeId() >>> 3 & 3) == 0;
   }
 
-  final boolean isDirectType() {
+  final boolean isDirectType() { //
     return (getTypeId() & DIRECT) > 0;
   }
 
-  final boolean isMapType() {
+  final boolean isMapType() { //
     return (getTypeId() & MAP) > 0;
   }
 
@@ -301,27 +308,30 @@
     final StringBuilder sb = new StringBuilder();
     final int group1 = typeId & 0x7;
     switch (group1) {
-      case 1 : sb.append("ReadOnly, "); break;
-      case 2 : sb.append("Region, "); break;
-      case 3 : sb.append("ReadOnly Region, "); break;
-      case 4 : sb.append("Duplicate, "); break;
-      case 5 : sb.append("ReadOnly Duplicate, "); break;
-      case 6 : sb.append("Region Duplicate, "); break;
-      case 7 : sb.append("ReadOnly Region Duplicate, "); break;
+      case 0 : sb.append("Writable:\t"); break;
+      case 1 : sb.append("ReadOnly:\t"); break;
+      case 2 : sb.append("Writable:\tRegion:\t"); break;
+      case 3 : sb.append("ReadOnly:\tRegion:\t"); break;
+      case 4 : sb.append("Writable:\tDuplicate:\t"); break;
+      case 5 : sb.append("ReadOnly:\tDuplicate:\t"); break;
+      case 6 : sb.append("Writable:\tRegion:\tDuplicate:\t"); break;
+      case 7 : sb.append("ReadOnly:\tRegion:\tDuplicate:\t"); break;
       default: break;
     }
     final int group2 = (typeId >>> 3) & 0x3;
     switch (group2) {
-      case 0 : sb.append("Heap, "); break;
-      case 1 : sb.append("Direct, "); break;
-      case 2 : sb.append("Map, "); break;
+      case 0 : sb.append("Heap:\t"); break;
+      case 1 : sb.append("Direct:\t"); break;
+      case 2 : sb.append("Map:\t"); break;
+      case 3 : sb.append("Direct:\tMap:\t"); break;
       default: break;
     }
-    if ((typeId & BYTEBUF) > 0) { sb.append("ByteBuffer, "); }
+    if ((typeId & BYTEBUF) > 0) { sb.append("ByteBuffer:\t"); }
+
     final int group3 = (typeId >>> 5) & 0x1;
     switch (group3) {
-      case 0 : sb.append("Native, "); break;
-      case 1 : sb.append("NonNative, "); break;
+      case 0 : sb.append("NativeOrder:\t"); break;
+      case 1 : sb.append("NonNativeOrder:\t"); break;
       default: break;
     }
     final int group4 = (typeId >>> 6) & 0x1;
@@ -334,57 +344,57 @@
   }
 
   @Override
-  public final String toHexString(final String header, final long offsetBytes,
-      final int lengthBytes) {
-    final String klass = this.getClass().getSimpleName();
-    final String s1 = String.format("(..., %d, %d)", offsetBytes, lengthBytes);
-    final long hcode = hashCode() & 0XFFFFFFFFL;
-    final String call = ".toHexString" + s1 + ", hashCode: " + hcode;
-    final StringBuilder sb = new StringBuilder();
-    sb.append("### ").append(klass).append(" SUMMARY ###").append(LS);
-    sb.append("Header Comment      : ").append(header).append(LS);
-    sb.append("Call Parameters     : ").append(call);
-    return toHex(this, sb.toString(), offsetBytes, lengthBytes);
+  public final String toHexString(final String comment, final long offsetBytes, final int lengthBytes,
+      final boolean withData) {
+    return toHex(this, comment, offsetBytes, lengthBytes, withData);
   }
 
   /**
    * Returns a formatted hex string of an area of this object.
    * Used primarily for testing.
    * @param state the BaseStateImpl
-   * @param preamble a descriptive header
+   * @param comment optional unique description
    * @param offsetBytes offset bytes relative to the MemoryImpl start
    * @param lengthBytes number of bytes to convert to a hex string
    * @return a formatted hex string in a human readable array
    */
-  static final String toHex(final BaseStateImpl state, final String preamble, final long offsetBytes,
-      final int lengthBytes) {
+  static final String toHex(final BaseStateImpl state, final String comment, final long offsetBytes,
+      final int lengthBytes, final boolean withData) {
     final MemorySegment seg = state.seg;
     final long capacity = seg.byteSize();
     checkBounds(offsetBytes, lengthBytes, capacity);
     final StringBuilder sb = new StringBuilder();
-    final String segHCStr = "" + (seg.hashCode() & 0XFFFFFFFFL);
+    final String theComment = (comment != null) ? comment : "";
+    final String addHCStr = "" + Integer.toHexString(seg.address().hashCode());
     final MemoryRequestServer memReqSvr = state.getMemoryRequestServer();
     final String memReqStr = memReqSvr != null
-        ? memReqSvr.getClass().getSimpleName() + ", " + (memReqSvr.hashCode() & 0XFFFFFFFFL)
+        ? memReqSvr.getClass().getSimpleName() + ", " + Integer.toHexString(memReqSvr.hashCode())
         : "null";
-    sb.append(preamble).append(LS);
-    sb.append("MemorySegment hashCode : ").append(segHCStr).append(LS);
+
+    sb.append(LS + "### DataSketches Memory Component SUMMARY ###").append(LS);
+    sb.append("Optional Comment       : ").append(theComment).append(LS);
+    sb.append("TypeId String          : ").append(typeDecode(state.typeId)).append(LS);
+    sb.append("OffsetBytes            : ").append(offsetBytes).append(LS);
+    sb.append("LengthBytes            : ").append(lengthBytes).append(LS);
     sb.append("Capacity               : ").append(capacity).append(LS);
+    sb.append("MemoryAddress hashCode : ").append(addHCStr).append(LS);
     sb.append("MemReqSvr, hashCode    : ").append(memReqStr).append(LS);
     sb.append("Read Only              : ").append(state.isReadOnly()).append(LS);
     sb.append("Type Byte Order        : ").append(state.getTypeByteOrder().toString()).append(LS);
     sb.append("Native Byte Order      : ").append(ByteOrder.nativeOrder().toString()).append(LS);
     sb.append("JDK Runtime Version    : ").append(JDK).append(LS);
     //Data detail
-    sb.append("Data, littleEndian  :  0  1  2  3  4  5  6  7");
-
-    for (long i = 0; i < lengthBytes; i++) {
-      final int b = getByteAtOffset(seg, offsetBytes + i) & 0XFF;
-      if (i % 8 == 0) { //row header
-        sb.append(String.format("%n%20s: ", offsetBytes + i));
+    if (withData) {
+      sb.append("Data, LittleEndian     :  0  1  2  3  4  5  6  7");
+      for (long i = 0; i < lengthBytes; i++) {
+        final int b = getByteAtOffset(seg, offsetBytes + i) & 0XFF;
+        if (i % 8 == 0) { //row header
+          sb.append(String.format("%n%23s: ", offsetBytes + i));
+        }
+        sb.append(String.format("%02x ", b));
       }
-      sb.append(String.format("%02x ", b));
     }
+    sb.append(LS + "### END SUMMARY ###");
     sb.append(LS);
 
     return sb.toString();
diff --git a/src/main/java/org/apache/datasketches/memory/internal/BaseWritableBufferImpl.java b/src/main/java/org/apache/datasketches/memory/internal/BaseWritableBufferImpl.java
index 532f296..7fd1b77 100644
--- a/src/main/java/org/apache/datasketches/memory/internal/BaseWritableBufferImpl.java
+++ b/src/main/java/org/apache/datasketches/memory/internal/BaseWritableBufferImpl.java
@@ -19,14 +19,8 @@
 
 package org.apache.datasketches.memory.internal;
 
-import static java.nio.channels.FileChannel.MapMode.READ_ONLY;
-import static java.nio.channels.FileChannel.MapMode.READ_WRITE;
-
-import java.io.File;
-import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
-import java.nio.channels.FileChannel;
 import java.util.Objects;
 
 import org.apache.datasketches.memory.Buffer;
@@ -38,7 +32,6 @@
 
 import jdk.incubator.foreign.MemoryAccess;
 import jdk.incubator.foreign.MemorySegment;
-import jdk.incubator.foreign.ResourceScope;
 
 /*
  * Developer notes: The heavier methods, such as put/get arrays, duplicate, region, clear, fill,
@@ -60,16 +53,16 @@
 @SuppressWarnings("restriction")
 public abstract class BaseWritableBufferImpl extends BaseBufferImpl implements WritableBuffer {
 
-  //Pass-through ctor
+  //Pass-through constructor
   BaseWritableBufferImpl(
       final MemorySegment seg,
       final int typeId) {
     super(seg, typeId);
   }
 
-  //HEAP
+  //HEAP ARRAYS
 
-  public static WritableBuffer wrapSegment(
+  public static WritableBuffer wrapSegmentAsArray(
       final MemorySegment seg,
       final ByteOrder byteOrder,
       final MemoryRequestServer memReqSvr) {
@@ -90,54 +83,28 @@
       final ByteBuffer byteBuffer,
       final boolean localReadOnly,
       final ByteOrder byteOrder) {
-    ByteBuffer byteBuf = localReadOnly ? byteBuffer.asReadOnlyBuffer() : byteBuffer;
-    MemorySegment seg = MemorySegment.ofByteBuffer(byteBuf); //from Position to limit
+    final ByteBuffer byteBuf = localReadOnly ? byteBuffer.asReadOnlyBuffer() : byteBuffer.duplicate();
+    byteBuf.clear(); //resets position to zero and limit to capacity. Does not clear data.
+    MemorySegment seg = MemorySegment.ofByteBuffer(byteBuf); //from 0 to capacity
     int type = BUFFER | BYTEBUF
         | (localReadOnly ? READONLY : 0)
         | (seg.isMapped() ? MAP : 0)
         | (seg.isNative() ? DIRECT : 0);
     if (byteOrder == ByteOrder.nativeOrder()) {
       type |= NATIVE;
-      return new BBWritableBufferImpl(seg, type);
+      final WritableBuffer wbuf = new BBWritableBufferImpl(seg, type);
+      wbuf.setStartPositionEnd(0, byteBuffer.position(), byteBuffer.limit());
+      return wbuf;
     }
     type |= NONNATIVE;
-    return new BBNonNativeWritableBufferImpl(seg, type);
+    final WritableBuffer wbuf = new BBNonNativeWritableBufferImpl(seg, type);
+    wbuf.setStartPositionEnd(0, byteBuffer.position(), byteBuffer.limit());
+    return wbuf;
   }
 
-  //MAP
-  /**
-   * The static constructor that chooses the correct Map leaf node based on the byte order.
-   * @param file the file being wrapped. It must be non-null with length &gt; 0.
-   * @param fileOffsetBytes the file offset bytes
-   * @param capacityBytes the requested capacity of the memory mapped region. It must be &gt; 0
-   * @param localReadOnly the requested read-only state
-   * @param byteOrder the requested byte-order
-   * @return this class constructed via the leaf node.
-   * @throws Exception
-   */
-  @SuppressWarnings("resource")
-  public static WritableBuffer wrapMap(final File file, final long fileOffsetBytes,
-      final long capacityBytes, final boolean localReadOnly, final ByteOrder byteOrder)
-      throws Exception {
-    Objects.requireNonNull(file, "File must be non-null");
-    Objects.requireNonNull(byteOrder, "ByteOrder must be non-null");
-    FileChannel.MapMode mapMode = (localReadOnly) ? READ_ONLY : READ_WRITE;
-    MemorySegment seg;
-    try {
-      seg = MemorySegment.mapFile(file.toPath(), fileOffsetBytes, capacityBytes, mapMode,
-            ResourceScope.newConfinedScope()); }
-    catch (final IllegalArgumentException | IllegalStateException | UnsupportedOperationException
-        | IOException | SecurityException e) { throw e; }
-    final boolean nativeBOType = Util.isNativeByteOrder(byteOrder);
-    final int type = BUFFER | MAP | DIRECT
-        | (localReadOnly ? READONLY : 0)
-        | (nativeBOType ? NATIVE : NONNATIVE);
-    return Util.isNativeByteOrder(byteOrder)
-        ? new MapWritableBufferImpl(seg, type)
-        : new MapNonNativeWritableBufferImpl(seg, type);
-  }
-
+  //NO MAP
   //NO DIRECTS
+
   //REGIONS
 
   @Override
@@ -158,9 +125,12 @@
       final long capacityBytes,
       final boolean localReadOnly,
       final ByteOrder byteOrder) {
+    if (!this.isAlive()) { throw new IllegalStateException("This Buffer is not alive."); }
     Objects.requireNonNull(byteOrder, "byteOrder must be non-null.");
-    final boolean readOnly = isReadOnly() || localReadOnly || seg.isReadOnly();
-    final MemorySegment slice = seg.asSlice(offsetBytes, capacityBytes);
+    final boolean readOnly = isReadOnly() || localReadOnly;
+    final MemorySegment slice = (readOnly && !seg.isReadOnly())
+        ? seg.asSlice(offsetBytes, capacityBytes).asReadOnly()
+        : seg.asSlice(offsetBytes, capacityBytes);
     final boolean duplicateType = isDuplicateType();
     final boolean mapType = seg.isMapped();
     final boolean directType = seg.isNative();
@@ -193,12 +163,12 @@
   //DUPLICATES
   @Override
   public Buffer duplicate() {
-    return writableDuplicateImpl(true, getTypeByteOrder());
+    return toWritableDuplicateImpl(true, getTypeByteOrder());
   }
 
   @Override
   public Buffer duplicate(final ByteOrder byteOrder) {
-    return writableDuplicateImpl(true, byteOrder);
+    return toWritableDuplicateImpl(true, byteOrder);
   }
 
   @Override
@@ -206,7 +176,7 @@
     if (isReadOnly()) {
       throw new ReadOnlyException("Cannot create a writable duplicate from a read-only Buffer.");
     }
-    return writableDuplicateImpl(false, getTypeByteOrder());
+    return toWritableDuplicateImpl(false, getTypeByteOrder());
   }
 
   @Override
@@ -214,22 +184,63 @@
     if (isReadOnly()) {
       throw new ReadOnlyException("Cannot create a writable duplicate from a read-only Buffer.");
     }
-    return writableDuplicateImpl(false, byteOrder);
+    return toWritableDuplicateImpl(false, byteOrder);
   }
 
-  private WritableBuffer writableDuplicateImpl(final boolean localReadOnly, final ByteOrder byteOrder) {
+  private WritableBuffer toWritableDuplicateImpl(final boolean localReadOnly, final ByteOrder byteOrder) {
+    if (!this.isAlive()) { throw new IllegalStateException("This Memory is not alive."); }
     final boolean readOnly = isReadOnly() || localReadOnly;
-    final WritableBuffer wbuf = toDuplicate(readOnly, byteOrder);
+    final MemorySegment seg2 = (readOnly && !seg.isReadOnly()) ? seg.asReadOnly() : seg;
+    final boolean duplicateType = true;
+    final boolean mapType = seg.isMapped();
+    final boolean directType = seg.isNative();
+    final boolean nativeBOType = Util.isNativeByteOrder(byteOrder);
+    final boolean byteBufferType = isByteBufferType();
+    final int type = BUFFER
+        | (readOnly ? READONLY : 0)
+        | (duplicateType ? DUPLICATE : 0)
+        | (mapType ? MAP : 0)
+        | (directType ? DIRECT : 0)
+        | (nativeBOType ? NATIVE : NONNATIVE)
+        | (byteBufferType ? BYTEBUF : 0);
+
+    WritableBuffer wbuf;
+    if (byteBufferType) {
+      if (nativeBOType) {
+        wbuf = new BBWritableBufferImpl(seg2, type);
+      } else {
+        wbuf = new BBNonNativeWritableBufferImpl(seg2, type);
+      }
+    }
+    if (mapType) {
+      if (nativeBOType) {
+        wbuf = new MapWritableBufferImpl(seg2, type);
+      } else {
+        wbuf = new MapNonNativeWritableBufferImpl(seg2, type);
+      }
+    }
+    if (directType) {
+      if (nativeBOType) {
+        wbuf = new DirectWritableBufferImpl(seg2, type, memReqSvr);
+      } else {
+        wbuf = new DirectNonNativeWritableBufferImpl(seg2, type, memReqSvr);
+      }
+    }
+    //else heap type
+    if (nativeBOType) {
+      wbuf = new HeapWritableBufferImpl(seg2, type, memReqSvr);
+    } else {
+      wbuf = new HeapNonNativeWritableBufferImpl(seg2, type, memReqSvr);
+    }
     wbuf.setStartPositionEnd(getStart(), getPosition(), getEnd());
     return wbuf;
   }
 
-  abstract BaseWritableBufferImpl toDuplicate(boolean readOnly, ByteOrder byteOrder);
-
   //AS MEMORY
+
   @Override
   public Memory asMemory(final ByteOrder byteOrder) {
-    return asWritableMemory(true, byteOrder);
+    return asWritableMemoryImpl(true, byteOrder);
   }
 
   @Override
@@ -238,12 +249,14 @@
       throw new ReadOnlyException(
           "Cannot create a writable Memory from a read-only Buffer.");
     }
-    return asWritableMemory(false, byteOrder);
+    return asWritableMemoryImpl(false, byteOrder);
   }
 
-  private WritableMemory asWritableMemory(final boolean localReadOnly, final ByteOrder byteOrder) {
+  private WritableMemory asWritableMemoryImpl(final boolean localReadOnly, final ByteOrder byteOrder) {
+    if (!this.isAlive()) { throw new IllegalStateException("This Buffer is not alive."); }
     Objects.requireNonNull(byteOrder, "byteOrder must be non-null");
     final boolean readOnly = isReadOnly() || localReadOnly;
+    final MemorySegment seg2 = (readOnly && !seg.isReadOnly()) ? seg.asReadOnly() : seg;
     final boolean duplicateType = isDuplicateType();
     final boolean mapType = seg.isMapped();
     final boolean directType = seg.isNative();
@@ -259,30 +272,30 @@
     WritableMemory wmem;
     if (byteBufferType) {
       if (nativeBOType) {
-        wmem = new BBWritableMemoryImpl(seg, type);
+        wmem = new BBWritableMemoryImpl(seg2, type);
       } else {
-        wmem = new BBNonNativeWritableMemoryImpl(seg, type);
+        wmem = new BBNonNativeWritableMemoryImpl(seg2, type);
       }
     }
     if (mapType) {
       if (nativeBOType) {
-        wmem = new MapWritableMemoryImpl(seg, type);
+        wmem = new MapWritableMemoryImpl(seg2, type);
       } else {
-        wmem = new MapNonNativeWritableMemoryImpl(seg, type);
+        wmem = new MapNonNativeWritableMemoryImpl(seg2, type);
       }
     }
     if (directType) {
       if (nativeBOType) {
-        wmem = new DirectWritableMemoryImpl(seg, type, memReqSvr);
+        wmem = new DirectWritableMemoryImpl(seg2, type, memReqSvr);
       } else {
-        wmem = new DirectNonNativeWritableMemoryImpl(seg, type, memReqSvr);
+        wmem = new DirectNonNativeWritableMemoryImpl(seg2, type, memReqSvr);
       }
     }
     //else heap type
     if (nativeBOType) {
-      wmem = new HeapWritableMemoryImpl(seg, type, memReqSvr);
+      wmem = new HeapWritableMemoryImpl(seg2, type, memReqSvr);
     } else {
-      wmem = new HeapNonNativeWritableMemoryImpl(seg, type, memReqSvr);
+      wmem = new HeapNonNativeWritableMemoryImpl(seg2, type, memReqSvr);
     }
     return wmem;
   }
@@ -312,53 +325,8 @@
     setPosition(pos + lengthBytes);
   }
 
-  //PRIMITIVE getX() Native Endian (used by both endians)
+  //OTHER PRIMITIVE READ METHODS: copyTo, compareTo. No writeTo
 
-  final char getNativeOrderedChar() {
-    final long pos = getPosition();
-    final char aChar = MemoryAccess.getCharAtOffset(seg, pos);
-    setPosition(pos + Character.BYTES);
-    return aChar;
-  }
-
-  final char getNativeOrderedChar(final long offsetBytes) {
-    return MemoryAccess.getCharAtOffset(seg, offsetBytes);
-  }
-
-  final int getNativeOrderedInt() {
-    final long pos = getPosition();
-    final int anInt = MemoryAccess.getIntAtOffset(seg, pos);
-    setPosition(pos + Integer.BYTES);
-    return anInt;
-  }
-
-  final int getNativeOrderedInt(final long offsetBytes) {
-    return MemoryAccess.getIntAtOffset(seg, offsetBytes);
-  }
-
-  final long getNativeOrderedLong() {
-    final long pos = getPosition();
-    final long aLong = MemoryAccess.getLongAtOffset(seg, pos);
-    setPosition(pos + Long.BYTES);
-    return aLong;
-  }
-
-  final long getNativeOrderedLong(final long offsetBytes) {
-    return MemoryAccess.getLongAtOffset(seg, offsetBytes);
-  }
-
-  final short getNativeOrderedShort() {
-    final long pos = getPosition();
-    final short aShort = MemoryAccess.getShortAtOffset(seg, pos);
-    setPosition(pos + Short.BYTES);
-    return aShort;
-  }
-
-  final short getNativeOrderedShort(final long offsetBytes) {
-    return MemoryAccess.getShortAtOffset(seg, offsetBytes);
-  }
-
-  //OTHER PRIMITIVE READ METHODS: copyTo, compareTo
   @Override
   public final int compareTo(final long thisOffsetBytes, final long thisLengthBytes,
       final Buffer that, final long thatOffsetBytes, final long thatLengthBytes) {
@@ -367,8 +335,8 @@
   }
 
   /*
-   * Develper notes: There is no copyTo for Buffers because of the ambiguity of what to do with
-   * the positional values. Switch to MemoryImpl view to do copyTo.
+   * Developer notes: There is no copyTo for Buffers because of the ambiguity of what to do with
+   * the positional values. Switch to asMemory view to do copyTo.
    */
 
   //PRIMITIVE putX() and putXArray() implementations
@@ -395,47 +363,6 @@
     setPosition(pos + lengthBytes);
   }
 
-  //PRIMITIVE putX() Native Endian (used by both endians)
-  final void putNativeOrderedChar(final char value) {
-    final long pos = getPosition();
-    MemoryAccess.setCharAtOffset(seg, pos, value);
-    setPosition(pos + Character.BYTES);
-  }
-
-  final void putNativeOrderedChar(final long offsetBytes, final char value) {
-    MemoryAccess.setCharAtOffset(seg, offsetBytes, value);
-  }
-
-  final void putNativeOrderedInt(final int value) {
-    final long pos = getPosition();
-    MemoryAccess.setIntAtOffset(seg, pos, value);
-    setPosition(pos + Integer.BYTES);
-  }
-
-  final void putNativeOrderedInt(final long offsetBytes, final int value) {
-    MemoryAccess.setIntAtOffset(seg, offsetBytes, value);
-  }
-
-  final void putNativeOrderedLong(final long value) {
-    final long pos = getPosition();
-    MemoryAccess.setLongAtOffset(seg, pos, value);
-    setPosition(pos + Long.BYTES);
-  }
-
-  final void putNativeOrderedLong(final long offsetBytes, final long value) {
-    MemoryAccess.setLongAtOffset(seg, offsetBytes, value);
-  }
-
-  final void putNativeOrderedShort(final short value) {
-    final long pos = getPosition();
-    MemoryAccess.setShortAtOffset(seg, pos, value);
-    setPosition(pos + Short.BYTES);
-  }
-
-  final void putNativeOrderedShort(final long offsetBytes, final short value) {
-    MemoryAccess.setShortAtOffset(seg, offsetBytes, value);
-  }
-
   //OTHER
 
   @Override
diff --git a/src/main/java/org/apache/datasketches/memory/internal/BaseWritableMemoryImpl.java b/src/main/java/org/apache/datasketches/memory/internal/BaseWritableMemoryImpl.java
index 7953d7c..d9454a0 100644
--- a/src/main/java/org/apache/datasketches/memory/internal/BaseWritableMemoryImpl.java
+++ b/src/main/java/org/apache/datasketches/memory/internal/BaseWritableMemoryImpl.java
@@ -66,9 +66,9 @@
     super(seg, typeId);
   }
 
-  //HEAP
+  //HEAP ARRAYS
 
-  public static WritableMemory wrapSegment(
+  public static WritableMemory wrapSegmentAsArray(
       final MemorySegment seg,
       final ByteOrder byteOrder,
       final MemoryRequestServer memReqSvr) {
@@ -88,8 +88,9 @@
       final ByteBuffer byteBuffer,
       final boolean localReadOnly,
       final ByteOrder byteOrder) {
-    byteBuffer.position(0).limit(byteBuffer.capacity());
-    MemorySegment seg = MemorySegment.ofByteBuffer(byteBuffer); //from 0 to capacity
+    final ByteBuffer byteBuf = localReadOnly ? byteBuffer.asReadOnlyBuffer() : byteBuffer.duplicate();
+    byteBuf.clear(); //resets position to zero and limit to capacity. Does not clear data.
+    MemorySegment seg = MemorySegment.ofByteBuffer(byteBuf); //from 0 to capacity
     int type = MEMORY | BYTEBUF
         | (localReadOnly ? READONLY : 0)
         | (seg.isMapped() ? MAP : 0)
@@ -105,24 +106,34 @@
   //MAP
 
   /**
-   * The static constructor that chooses the correct Map leaf node based on the byte order.
+   * Maps the specified portion of the given file into Memory for write operations.
+   * This chooses the correct Map leaf node based on the byte order.
    * @param file the file being wrapped. It must be non-null with length &gt; 0.
-   * @param fileOffsetBytes the file offset bytes
-   * @param capacityBytes the requested capacity of the memory mapped region. It must be &gt; 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 be &ge; 0.
+   * @param scope the given ResourceScope. It must be non-null.
    * @param localReadOnly the requested read-only state
-   * @param byteOrder the requested byte-order
-   * @return this class constructed via the leaf node.
+   * @param byteOrder the byte order to be used.  It must be non-null.
+   * @return mapped WritableMemory.
    * @throws Exception
    */
   @SuppressWarnings("resource")
-  public static WritableMemory wrapMap(final File file, final long fileOffsetBytes,
-      final long capacityBytes, final boolean localReadOnly, final ByteOrder byteOrder)
-      throws Exception {
+  public static WritableMemory wrapMap(
+      final File file,
+      final long fileOffsetBytes,
+      final long capacityBytes,
+      final ResourceScope scope,
+      final boolean localReadOnly,
+      final ByteOrder byteOrder) throws Exception {
     FileChannel.MapMode mapMode = (localReadOnly) ? READ_ONLY : READ_WRITE;
     MemorySegment seg;
     try {
-      seg = MemorySegment.mapFile(file.toPath(), fileOffsetBytes, capacityBytes, mapMode,
-            ResourceScope.newConfinedScope()); }
+      seg = MemorySegment.mapFile(
+          file.toPath(),
+          fileOffsetBytes,
+          capacityBytes,
+          mapMode,
+          scope); }
     catch (final IllegalArgumentException | IllegalStateException | UnsupportedOperationException
         | IOException | SecurityException e) { throw e; }
     final boolean nativeBOType = Util.isNativeByteOrder(byteOrder);
@@ -186,9 +197,12 @@
       final long capacityBytes,
       final boolean localReadOnly,
       final ByteOrder byteOrder) {
+    if (!this.isAlive()) { throw new IllegalStateException("This Memory is not alive."); }
     Objects.requireNonNull(byteOrder, "byteOrder must be non-null.");
-    final boolean readOnly = isReadOnly() || localReadOnly || seg.isReadOnly();
-    final MemorySegment slice = seg.asSlice(offsetBytes, capacityBytes);
+    final boolean readOnly = isReadOnly() || localReadOnly;
+    final MemorySegment slice = (readOnly && !seg.isReadOnly())
+        ? seg.asSlice(offsetBytes, capacityBytes).asReadOnly()
+        : seg.asSlice(offsetBytes, capacityBytes);
     final boolean duplicateType = isDuplicateType();
     final boolean mapType = seg.isMapped();
     final boolean directType = seg.isNative();
@@ -222,7 +236,7 @@
 
   @Override
   public Buffer asBuffer(final ByteOrder byteOrder) {
-    return asWritableBuffer(true, byteOrder);
+    return asWritableBufferImpl(true, byteOrder);
   }
 
   @Override
@@ -231,12 +245,14 @@
       throw new ReadOnlyException(
           "Cannot create a writable buffer from a read-only Memory.");
     }
-    return asWritableBuffer(false, byteOrder);
+    return asWritableBufferImpl(false, byteOrder);
   }
 
-  private WritableBuffer asWritableBuffer(final boolean localReadOnly, final ByteOrder byteOrder) {
+  private WritableBuffer asWritableBufferImpl(final boolean localReadOnly, final ByteOrder byteOrder) {
+    if (!this.isAlive()) { throw new IllegalStateException("This Memory is not alive."); }
     Objects.requireNonNull(byteOrder, "byteOrder must be non-null");
     final boolean readOnly = isReadOnly() || localReadOnly;
+    final MemorySegment seg2 = (readOnly && !seg.isReadOnly()) ? seg.asReadOnly() : seg;
     final boolean duplicateType = isDuplicateType();
     final boolean mapType = seg.isMapped();
     final boolean directType = seg.isNative();
@@ -252,30 +268,30 @@
     WritableBuffer wbuf;
     if (byteBufferType) {
       if (nativeBOType) {
-        wbuf = new BBWritableBufferImpl(seg, type);
+        wbuf = new BBWritableBufferImpl(seg2, type);
       } else {
-        wbuf = new BBNonNativeWritableBufferImpl(seg, type);
+        wbuf = new BBNonNativeWritableBufferImpl(seg2, type);
       }
     }
     if (mapType) {
       if (nativeBOType) {
-        wbuf = new MapWritableBufferImpl(seg, type);
+        wbuf = new MapWritableBufferImpl(seg2, type);
       } else {
-        wbuf = new MapNonNativeWritableBufferImpl(seg, type);
+        wbuf = new MapNonNativeWritableBufferImpl(seg2, type);
       }
     }
     if (directType) {
       if (nativeBOType) {
-        wbuf = new DirectWritableBufferImpl(seg, type, memReqSvr);
+        wbuf = new DirectWritableBufferImpl(seg2, type, memReqSvr);
       } else {
-        wbuf = new DirectNonNativeWritableBufferImpl(seg, type, memReqSvr);
+        wbuf = new DirectNonNativeWritableBufferImpl(seg2, type, memReqSvr);
       }
     }
     //else heap type
     if (nativeBOType) {
-      wbuf = new HeapWritableBufferImpl(seg, type, memReqSvr);
+      wbuf = new HeapWritableBufferImpl(seg2, type, memReqSvr);
     } else {
-      wbuf = new HeapNonNativeWritableBufferImpl(seg, type, memReqSvr);
+      wbuf = new HeapNonNativeWritableBufferImpl(seg2, type, memReqSvr);
     }
     wbuf.setStartPositionEnd(0, 0, getCapacity());
     return wbuf;
@@ -297,8 +313,8 @@
     dstSlice.copyFrom(srcSlice);
   }
 
+  //OTHER PRIMITIVE READ METHODS: compareTo, copyTo, writeTo
 
-  //OTHER PRIMITIVE READ METHODS: compareTo, copyTo, equals
   @Override
   public final int compareTo(final long thisOffsetBytes, final long thisLengthBytes,
       final Memory that, final long thatOffsetBytes, final long thatLengthBytes) {
diff --git a/src/main/java/org/apache/datasketches/memory/internal/DirectNonNativeWritableBufferImpl.java b/src/main/java/org/apache/datasketches/memory/internal/DirectNonNativeWritableBufferImpl.java
index a409b66..ea2c5db 100644
--- a/src/main/java/org/apache/datasketches/memory/internal/DirectNonNativeWritableBufferImpl.java
+++ b/src/main/java/org/apache/datasketches/memory/internal/DirectNonNativeWritableBufferImpl.java
@@ -19,8 +19,6 @@
 
 package org.apache.datasketches.memory.internal;
 
-import java.nio.ByteOrder;
-
 import org.apache.datasketches.memory.MemoryRequestServer;
 import org.apache.datasketches.memory.WritableBuffer;
 
@@ -40,15 +38,6 @@
       final MemoryRequestServer memReqSvr) {
     super(seg, typeId);
     if (memReqSvr != null) { setMemoryRequestServer(memReqSvr); }
-
-  }
-
-  @Override
-  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | DUPLICATE;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new DirectWritableBufferImpl(seg, type, memReqSvr)
-        : new DirectNonNativeWritableBufferImpl(seg, type, memReqSvr);
   }
 
 }
diff --git a/src/main/java/org/apache/datasketches/memory/internal/DirectWritableBufferImpl.java b/src/main/java/org/apache/datasketches/memory/internal/DirectWritableBufferImpl.java
index 26a4d56..3b03b6c 100644
--- a/src/main/java/org/apache/datasketches/memory/internal/DirectWritableBufferImpl.java
+++ b/src/main/java/org/apache/datasketches/memory/internal/DirectWritableBufferImpl.java
@@ -19,8 +19,6 @@
 
 package org.apache.datasketches.memory.internal;
 
-import java.nio.ByteOrder;
-
 import org.apache.datasketches.memory.MemoryRequestServer;
 import org.apache.datasketches.memory.WritableBuffer;
 
@@ -42,12 +40,4 @@
     if (memReqSvr != null) { setMemoryRequestServer(memReqSvr); }
   }
 
-  @Override
-  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | DUPLICATE;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new DirectWritableBufferImpl(seg, type, memReqSvr)
-        : new DirectNonNativeWritableBufferImpl(seg, type, memReqSvr);
-  }
-
 }
diff --git a/src/main/java/org/apache/datasketches/memory/internal/HeapNonNativeWritableBufferImpl.java b/src/main/java/org/apache/datasketches/memory/internal/HeapNonNativeWritableBufferImpl.java
index fe46aae..be661c7 100644
--- a/src/main/java/org/apache/datasketches/memory/internal/HeapNonNativeWritableBufferImpl.java
+++ b/src/main/java/org/apache/datasketches/memory/internal/HeapNonNativeWritableBufferImpl.java
@@ -19,8 +19,6 @@
 
 package org.apache.datasketches.memory.internal;
 
-import java.nio.ByteOrder;
-
 import org.apache.datasketches.memory.MemoryRequestServer;
 import org.apache.datasketches.memory.WritableBuffer;
 
@@ -42,12 +40,4 @@
     if (memReqSvr != null) { setMemoryRequestServer(memReqSvr); }
   }
 
-  @Override
-  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | DUPLICATE;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new HeapWritableBufferImpl(seg, type, memReqSvr)
-        : new HeapNonNativeWritableBufferImpl(seg, type, memReqSvr);
-  }
-
 }
diff --git a/src/main/java/org/apache/datasketches/memory/internal/HeapWritableBufferImpl.java b/src/main/java/org/apache/datasketches/memory/internal/HeapWritableBufferImpl.java
index 972dc37..e389389 100644
--- a/src/main/java/org/apache/datasketches/memory/internal/HeapWritableBufferImpl.java
+++ b/src/main/java/org/apache/datasketches/memory/internal/HeapWritableBufferImpl.java
@@ -19,8 +19,6 @@
 
 package org.apache.datasketches.memory.internal;
 
-import java.nio.ByteOrder;
-
 import org.apache.datasketches.memory.MemoryRequestServer;
 import org.apache.datasketches.memory.WritableBuffer;
 
@@ -42,12 +40,4 @@
     if (memReqSvr != null) { setMemoryRequestServer(memReqSvr); }
   }
 
-  @Override
-  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | DUPLICATE;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new HeapWritableBufferImpl(seg, type, memReqSvr)
-        : new HeapNonNativeWritableBufferImpl(seg, type, memReqSvr);
-  }
-
 }
diff --git a/src/main/java/org/apache/datasketches/memory/internal/MapNonNativeWritableBufferImpl.java b/src/main/java/org/apache/datasketches/memory/internal/MapNonNativeWritableBufferImpl.java
index 9c3a1a9..94a8d1c 100644
--- a/src/main/java/org/apache/datasketches/memory/internal/MapNonNativeWritableBufferImpl.java
+++ b/src/main/java/org/apache/datasketches/memory/internal/MapNonNativeWritableBufferImpl.java
@@ -19,8 +19,6 @@
 
 package org.apache.datasketches.memory.internal;
 
-import java.nio.ByteOrder;
-
 import org.apache.datasketches.memory.WritableBuffer;
 
 import jdk.incubator.foreign.MemorySegment;
@@ -39,12 +37,4 @@
     super(seg, typeId);
   }
 
-  @Override
-  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | DUPLICATE;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new MapWritableBufferImpl(seg, type)
-        : new MapNonNativeWritableBufferImpl(seg, type);
-  }
-
 }
diff --git a/src/main/java/org/apache/datasketches/memory/internal/MapWritableBufferImpl.java b/src/main/java/org/apache/datasketches/memory/internal/MapWritableBufferImpl.java
index b0fcf29..376a29c 100644
--- a/src/main/java/org/apache/datasketches/memory/internal/MapWritableBufferImpl.java
+++ b/src/main/java/org/apache/datasketches/memory/internal/MapWritableBufferImpl.java
@@ -19,8 +19,6 @@
 
 package org.apache.datasketches.memory.internal;
 
-import java.nio.ByteOrder;
-
 import org.apache.datasketches.memory.WritableBuffer;
 
 import jdk.incubator.foreign.MemorySegment;
@@ -39,12 +37,4 @@
     super(seg, typeId);
   }
 
-  @Override
-  BaseWritableBufferImpl toDuplicate(final boolean readOnly, final ByteOrder byteOrder) {
-    final int type = setReadOnlyType(typeId, readOnly) | DUPLICATE;
-    return Util.isNativeByteOrder(byteOrder)
-        ? new MapWritableBufferImpl(seg, type)
-        : new MapNonNativeWritableBufferImpl(seg, type);
-  }
-
 }
diff --git a/src/main/java/org/apache/datasketches/memory/internal/NativeWritableBufferImpl.java b/src/main/java/org/apache/datasketches/memory/internal/NativeWritableBufferImpl.java
index c2a34fe..cc298e7 100644
--- a/src/main/java/org/apache/datasketches/memory/internal/NativeWritableBufferImpl.java
+++ b/src/main/java/org/apache/datasketches/memory/internal/NativeWritableBufferImpl.java
@@ -110,8 +110,7 @@
   }
 
   @Override
-  public void getFloatArray(final float[] dstArray, final int dstOffsetFloats,
-      final int lengthFloats) {
+  public void getFloatArray(final float[] dstArray, final int dstOffsetFloats, final int lengthFloats) {
     final long pos = getPosition();
     final long copyBytes = ((long) lengthFloats) << FLOAT_SHIFT;
     MemorySegment srcSlice = seg.asSlice(pos, copyBytes);
@@ -177,8 +176,7 @@
   }
 
   @Override
-  public void getShortArray(final short[] dstArray, final int dstOffsetShorts,
-      final int lengthShorts) {
+  public void getShortArray(final short[] dstArray, final int dstOffsetShorts, final int lengthShorts) {
     final long pos = getPosition();
     final long copyBytes = ((long) lengthShorts) << SHORT_SHIFT;
     MemorySegment srcSlice = seg.asSlice(pos, copyBytes);
@@ -245,8 +243,7 @@
   }
 
   @Override
-  public void putFloatArray(final float[] srcArray, final int srcOffsetFloats,
-      final int lengthFloats) {
+  public void putFloatArray(final float[] srcArray, final int srcOffsetFloats, final int lengthFloats) {
     final long pos = getPosition();
     final long copyBytes = ((long) lengthFloats) << FLOAT_SHIFT;
     MemorySegment srcSlice = MemorySegment.ofArray(srcArray).asSlice(srcOffsetFloats << FLOAT_SHIFT, copyBytes);
diff --git a/src/main/java/org/apache/datasketches/memory/internal/Util.java b/src/main/java/org/apache/datasketches/memory/internal/Util.java
index 195ab77..8d0e68d 100644
--- a/src/main/java/org/apache/datasketches/memory/internal/Util.java
+++ b/src/main/java/org/apache/datasketches/memory/internal/Util.java
@@ -60,6 +60,7 @@
    * @param byteOrder the given byte order
    * @return true if the given byteOrder is the same as the native byte order.
    */
+  //TODO Duplicate in BaseStateImpl
   public static boolean isNativeByteOrder(final ByteOrder byteOrder) {
     if (byteOrder == null) {
       throw new IllegalArgumentException("ByteOrder parameter cannot be null.");
diff --git a/src/test/java/org/apache/datasketches/memory/AllocateDirectMapMemoryTest.java b/src/test/java/org/apache/datasketches/memory/AllocateDirectMapMemoryTest.java
index f82b810..5b8b0e7 100644
--- a/src/test/java/org/apache/datasketches/memory/AllocateDirectMapMemoryTest.java
+++ b/src/test/java/org/apache/datasketches/memory/AllocateDirectMapMemoryTest.java
@@ -44,7 +44,8 @@
     File file = getResourceFile("GettysburgAddress.txt");
     file.setReadOnly();
     Memory mem = null;
-    try (ResourceScope scope = (mem = Memory.map(file)).scope()) {
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      mem = Memory.map(file, scope);
     }
     assertFalse(mem.isAlive());
   }
@@ -53,14 +54,16 @@
   public void testIllegalArguments() throws Exception {
     File file = getResourceFile("GettysburgAddress.txt");
     Memory mem = null;
-    try (ResourceScope scope = (mem = Memory.map(file, -1, Integer.MAX_VALUE, ByteOrder.nativeOrder())).scope()) {
-      fail("Failed: testIllegalArgumentException: Position was negative.");
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      mem = Memory.map(file, -1, Integer.MAX_VALUE, scope, ByteOrder.nativeOrder());
+      fail("Failed: test IllegalArgumentException: Position was negative.");
       mem.getCapacity();
-    } catch (IllegalArgumentException e) {
+    }
+    catch (IllegalArgumentException e) {
       //ok
     }
-
-    try (ResourceScope scope =  (mem = Memory.map(file, 0, -1, ByteOrder.nativeOrder())).scope()) {
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      mem = Memory.map(file, 0, -1, scope, ByteOrder.nativeOrder());
       fail("Failed: testIllegalArgumentException: Size was negative.");
     } catch (IllegalArgumentException e) {
       //ok
@@ -72,13 +75,13 @@
     File file = getResourceFile("GettysburgAddress.txt");
     long memCapacity = file.length();
     Memory mem = null;
-    try (ResourceScope scope = (mem = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder())).scope()) {
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      mem = Memory.map(file, 0, memCapacity, scope, ByteOrder.nativeOrder());
       assertEquals(memCapacity, mem.getCapacity());
-      //mem.close(); //close inside the TWR block with throw excption
-      // when the TWR block ends
+      //mem.close(); //a close inside the TWR block will throw excption when the TWR block ends
     }
-    mem.close(); //multiple closes outside the TWR block are OK
-    mem.close(); // but unnecessary
+    mem.close(); //multiple closes outside the TWR block are OK, but unnecessary
+    mem.close();
   }
 
   @Test
@@ -86,11 +89,11 @@
     File file = getResourceFile("GettysburgAddress.txt");
     long memCapacity = file.length();
     Memory mem = null;
-    try (ResourceScope scope = (mem = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder())).scope()) {
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      mem = Memory.map(file, 0, memCapacity, scope, ByteOrder.nativeOrder());
       mem.load();
       assertTrue(mem.isLoaded());
     }
-    mem.close(); //OK
   }
 
   @SuppressWarnings("resource")
@@ -98,8 +101,9 @@
   public void testHandleHandoff() throws Exception {
     File file = getResourceFile("GettysburgAddress.txt");
     long memCapacity = file.length();
-    Memory mem = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder());
-    ResourceScope.Handle handle = mem.scope().acquire();
+    ResourceScope scope = ResourceScope.newConfinedScope();
+    Memory mem = Memory.map(file, 0, memCapacity, scope, ByteOrder.nativeOrder());
+    ResourceScope.Handle handle = scope.acquire();
     try {
       mem.load();
       assertTrue(mem.isLoaded());
diff --git a/src/test/java/org/apache/datasketches/memory/AllocateDirectMemoryTest.java b/src/test/java/org/apache/datasketches/memory/AllocateDirectMemoryTest.java
index 4a318dc..6c61ac3 100644
--- a/src/test/java/org/apache/datasketches/memory/AllocateDirectMemoryTest.java
+++ b/src/test/java/org/apache/datasketches/memory/AllocateDirectMemoryTest.java
@@ -35,17 +35,17 @@
   public void simpleAllocateDirect() {
     int longs = 32;
     WritableMemory wMem = null;
-    try (ResourceScope scope = (wMem = WritableMemory.allocateDirect(longs << 3, memReqSvr)).scope()) {
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      wMem = WritableMemory.allocateDirect(longs << 3, scope, memReqSvr);
       for (int i = 0; i<longs; i++) {
         wMem.putLong(i << 3, i);
         assertEquals(wMem.getLong(i << 3), i);
       }
-      //inside the TWR block the memory scope should be alive
+      //inside the TWR block the memory scope will be alive
       assertTrue(wMem.isAlive());
     }
     //The TWR block has exited, so the memory should be invalid
     assertFalse(wMem.isAlive());
-    wMem.close();
   }
 
   @Test
@@ -53,13 +53,14 @@
     int longs1 = 32;
     int bytes1 = longs1 << 3;
     WritableMemory wmem = null;
-    try (ResourceScope scope = (wmem = WritableMemory.allocateDirect(bytes1, memReqSvr)).scope()) {
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      wmem = WritableMemory.allocateDirect(bytes1, scope, memReqSvr);
 
       for (int i = 0; i < longs1; i++) { //puts data in origWmem
         wmem.putLong(i << 3, i);
         assertEquals(wmem.getLong(i << 3), i);
       }
-      println(wmem.toHexString("Test", 0, 32 * 8));
+      println(wmem.toHexString("Test", 0, 32 * 8, true));
 
       int longs2 = 64;
       int bytes2 = longs2 << 3;
@@ -67,43 +68,37 @@
       if (memReqSvr == null) {
         memReqSvr = new DefaultMemoryRequestServer();
       }
-      WritableMemory newWmem = memReqSvr.request(wmem, bytes2);
+      WritableMemory newWmem = memReqSvr.request(wmem, bytes2); //on the heap
       assertFalse(newWmem.isDirect()); //on heap by default
       for (int i = 0; i < longs2; i++) {
           newWmem.putLong(i << 3, i);
           assertEquals(newWmem.getLong(i << 3), i);
       }
-      memReqSvr.requestClose(wmem, newWmem);
-      //The default MRS doesn't actually release because it could be easily misused.
-    } // So we let the TWR release it here
+      memReqSvr.requestClose(wmem, newWmem); //The default MRS doesn't close.
+    } // So we let the TWR close it here
   }
 
   @SuppressWarnings("resource")
   @Test
   public void checkNonNativeDirect() {
     WritableMemory wmem = null;
-    try (ResourceScope scope = (wmem =
-        WritableMemory.allocateDirect(
-            128,
-            8,
-            ResourceScope.newConfinedScope(),
-            BaseState.NON_NATIVE_BYTE_ORDER,
-            memReqSvr)).scope()) {
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      wmem = WritableMemory.allocateDirect( 128, 8, scope,
+          BaseState.NON_NATIVE_BYTE_ORDER,
+          memReqSvr);
       wmem.putChar(0, (char) 1);
       assertEquals(wmem.getByte(1), (byte) 1);
     }
   }
 
+  @SuppressWarnings("resource")
   @Test
   public void checkExplicitCloseNoTWR() {
     final long cap = 128;
     WritableMemory wmem = null;
-    try {
-      wmem = WritableMemory.allocateDirect(cap, memReqSvr);
-      wmem.close(); //explicit close
-    } catch (final Exception e) {
-      throw e;
-    }
+    ResourceScope scope = ResourceScope.newConfinedScope();
+    wmem = WritableMemory.allocateDirect(cap, scope, memReqSvr);
+    wmem.close(); //explicit close
   }
 
   @Test
diff --git a/src/test/java/org/apache/datasketches/memory/AllocateDirectWritableMapMemoryTest.java b/src/test/java/org/apache/datasketches/memory/AllocateDirectWritableMapMemoryTest.java
new file mode 100644
index 0000000..266c195
--- /dev/null
+++ b/src/test/java/org/apache/datasketches/memory/AllocateDirectWritableMapMemoryTest.java
@@ -0,0 +1,230 @@
+/*
+ * 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.
+ */
+
+/*
+ * Note: Lincoln's Gettysburg Address is in the public domain. See LICENSE.
+ */
+
+package org.apache.datasketches.memory;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.apache.datasketches.memory.internal.Util.getResourceFile;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteOrder;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+public class AllocateDirectWritableMapMemoryTest {
+  private static final String LS = System.getProperty("line.separator");
+  private static final MemoryRequestServer memReqSvr = new DefaultMemoryRequestServer();
+
+  @BeforeClass
+  public void setReadOnly() {
+    UtilTest.setGettysburgAddressFileToReadOnly();
+  }
+
+  @Test
+  public void simpleMap() throws Exception {
+    File file = getResourceFile("GettysburgAddress.txt");
+    Memory mem = null;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      mem = Memory.map(file,scope);
+      byte[] byteArr = new byte[(int)mem.getCapacity()];
+      mem.getByteArray(0, byteArr, 0, byteArr.length);
+      String text = new String(byteArr, UTF_8);
+      println(text);
+      assertTrue(mem.isReadOnly());
+    }
+  }
+
+  @Test
+  public void copyOffHeapToMemoryMappedFile() throws Exception {
+    long numBytes = 1L << 10; //small for unit tests.  Make it larger than 2GB if you like.
+    long numLongs = numBytes >>> 3;
+
+    File file = new File("TestFile.bin"); //create a dummy file
+    if (file.exists()) {
+      try {
+        java.nio.file.Files.delete(file.toPath());
+      } catch (IOException e) {
+        throw new RuntimeException(e);
+      }
+    }
+    assertTrue(file.createNewFile());
+    assertTrue (file.setWritable(true, false)); //writable=true, ownerOnly=false
+    assertTrue (file.isFile());
+    file.deleteOnExit();  //comment out if you want to examine the file.
+
+    WritableMemory  dstMem = null;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) { //this scope manages two Memory objects
+      dstMem = WritableMemory.writableMap(file, 0, numBytes, scope, ByteOrder.nativeOrder());
+
+      WritableMemory srcMem
+        = WritableMemory.allocateDirect(numBytes, 8, scope, ByteOrder.nativeOrder(), memReqSvr);
+
+      //load source with consecutive longs
+      for (long i = 0; i < numLongs; i++) {
+        srcMem.putLong(i << 3, i);
+      }
+      //off-heap to off-heap copy
+      srcMem.copyTo(0, dstMem, 0, srcMem.getCapacity());
+      dstMem.force(); //push any remaining to the file
+      //check end value
+      assertEquals(dstMem.getLong(numLongs - 1L << 3), numLongs - 1L);
+    } //both map and direct closed here
+  }
+
+  @Test
+  public void checkNonNativeFile() throws Exception {
+    File file = new File("TestFile2.bin");
+    if (file.exists()) {
+      try {
+        java.nio.file.Files.delete(file.toPath());
+      } catch (IOException e) {
+        throw new RuntimeException(e);
+      }
+    }
+    assertTrue(file.createNewFile());
+    assertTrue(file.setWritable(true, false)); //writable=true, ownerOnly=false
+    assertTrue(file.isFile());
+    file.deleteOnExit();  //comment out if you want to examine the file.
+
+    final long bytes = 8;
+    WritableMemory wmem = null;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      wmem = WritableMemory.writableMap(file, 0L, bytes, scope, BaseState.NON_NATIVE_BYTE_ORDER);
+      wmem.putChar(0, (char) 1);
+      assertEquals(wmem.getByte(1), (byte) 1);
+    }
+  }
+
+  @SuppressWarnings("resource")
+  @Test
+  public void testMapExceptionNoTWR() throws Exception {
+    File dummy = createFile("dummy.txt", ""); //zero length
+    ResourceScope scope = ResourceScope.newConfinedScope();
+    Memory.map(dummy, 0, dummy.length(), scope, ByteOrder.nativeOrder());
+    scope.close();
+  }
+
+  @Test(expectedExceptions = ReadOnlyException.class)
+  public void simpleMap2() throws Exception {
+    File file = getResourceFile("GettysburgAddress.txt");
+    assertTrue(file.canRead());
+    assertFalse(file.canWrite());
+    WritableMemory wmem = null;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      wmem = WritableMemory.writableMap(file, scope);
+      //throws ReadOnlyException
+      wmem.getCapacity();
+    }
+  }
+
+  @Test(expectedExceptions = ReadOnlyException.class)
+  public void checkReadException() throws Exception  {
+    File file = getResourceFile("GettysburgAddress.txt");
+    WritableMemory wmem = null;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      wmem = WritableMemory.writableMap(file, 0, 1 << 20, scope, ByteOrder.nativeOrder());
+      //throws ReadOnlyException
+      wmem.getCapacity();
+    }
+  }
+
+  @Test
+  public void testForce() throws Exception {
+    String origStr = "Corectng spellng mistks";
+    File origFile = createFile("force_original.txt", origStr); //23
+    assertTrue(origFile.setWritable(true, false));
+    long origBytes = origFile.length();
+    String correctStr = "Correcting spelling mistakes"; //28
+    byte[] correctByteArr = correctStr.getBytes(UTF_8);
+    long correctBytesLen = correctByteArr.length;
+
+    Memory mem = null;
+    WritableMemory wmem = null;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      mem = Memory.map(origFile, 0, origBytes, scope, ByteOrder.nativeOrder());
+      mem.load();
+      assertTrue(mem.isLoaded());
+      //confirm orig string
+      byte[] buf = new byte[(int)origBytes];
+      mem.getByteArray(0, buf, 0, (int)origBytes);
+      String bufStr = new String(buf, UTF_8);
+      assertEquals(bufStr, origStr);
+
+      wmem = WritableMemory.writableMap(origFile, 0, correctBytesLen, scope, ByteOrder.nativeOrder());
+      wmem.load();
+      assertTrue(wmem.isLoaded());
+      // over write content
+      wmem.putByteArray(0, correctByteArr, 0, (int)correctBytesLen);
+      wmem.force();
+      //confirm correct string
+      byte[] buf2 = new byte[(int)correctBytesLen];
+      wmem.getByteArray(0, buf2, 0, (int)correctBytesLen);
+      String bufStr2 = new String(buf2, UTF_8);
+      assertEquals(bufStr2, correctStr);
+    }
+  }
+
+  private static File createFile(String fileName, String text) throws FileNotFoundException {
+    File file = new File(fileName);
+    file.deleteOnExit();
+    PrintWriter writer;
+    try {
+      writer = new PrintWriter(file, UTF_8.name());
+      writer.print(text);
+      writer.close();
+    } catch (UnsupportedEncodingException e) {
+      e.printStackTrace();
+    }
+    return file;
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  static void println(final Object o) {
+    if (o == null) { print(LS); }
+    else { print(o.toString() + LS); }
+  }
+
+  /**
+   * @param o value to print
+   */
+  static void print(final Object o) {
+    if (o != null) {
+      //System.out.print(o.toString()); //disable here
+    }
+  }
+
+}
diff --git a/src/test/java/org/apache/datasketches/memory/BaseBufferTest.java b/src/test/java/org/apache/datasketches/memory/BaseBufferTest.java
new file mode 100644
index 0000000..625b1d8
--- /dev/null
+++ b/src/test/java/org/apache/datasketches/memory/BaseBufferTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.testng.Assert.fail;
+
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+/**
+ * @author Lee Rhodes
+ */
+public class BaseBufferTest {
+  private final MemoryRequestServer memReqSvr = new DefaultMemoryRequestServer();
+
+  @Test
+  public void checkLimits() {
+    Buffer buf = Memory.wrap(new byte[100]).asBuffer();
+    buf.setStartPositionEnd(40, 45, 50);
+    buf.setStartPositionEnd(0, 0, 100);
+    try {
+      buf.setStartPositionEnd(0, 0, 101);
+      fail();
+    } catch (AssertionError e) {
+      //ok
+    }
+  }
+
+  @Test
+  public void checkLimitsAndCheck() {
+    Buffer buf = Memory.wrap(new byte[100]).asBuffer();
+    buf.setAndCheckStartPositionEnd(40, 45, 50);
+    buf.setAndCheckStartPositionEnd(0, 0, 100);
+    try {
+      buf.setAndCheckStartPositionEnd(0, 0, 101);
+      fail();
+    } catch (IllegalArgumentException e) {
+      //ok
+    }
+    buf.setAndCheckPosition(100);
+    try {
+      buf.setAndCheckPosition(101);
+      fail();
+    } catch (IllegalArgumentException e) {
+      //ok
+    }
+    buf.setPosition(99);
+    buf.incrementAndCheckPosition(1L);
+    try {
+      buf.incrementAndCheckPosition(1L);
+      fail();
+    } catch (IllegalArgumentException e) {
+      //ok
+    }
+  }
+
+  @Test
+  public void checkCheckNotValidAfterTWR() {
+    WritableMemory wmem;
+    Buffer buf;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      wmem = WritableMemory.allocateDirect(100, scope, memReqSvr);
+      buf = wmem.asBuffer();
+    }
+    try {
+      buf.asMemory(); //not alive
+    } catch (IllegalStateException e) { }
+  }
+}
diff --git a/src/test/java/org/apache/datasketches/memory/BaseStateTest.java b/src/test/java/org/apache/datasketches/memory/BaseStateTest.java
new file mode 100644
index 0000000..b848065
--- /dev/null
+++ b/src/test/java/org/apache/datasketches/memory/BaseStateTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.internal.BaseStateImpl;
+import org.testng.annotations.Test;
+
+public class BaseStateTest {
+
+  @Test
+  public void checkIsSameResource() {
+    WritableMemory wmem = WritableMemory.allocate(16);
+    Memory mem = wmem;
+    assertFalse(wmem.isSameResource(null));
+    assertTrue(wmem.isSameResource(mem));
+
+    WritableBuffer wbuf = wmem.asWritableBuffer();
+    Buffer buf = wbuf;
+    assertFalse(wbuf.isSameResource(null));
+    assertTrue(wbuf.isSameResource(buf));
+  }
+
+  @Test
+  public void checkNotEqualTo() {
+    byte[] arr = new byte[8];
+    Memory mem = Memory.wrap(arr);
+    assertFalse(mem.equalTo(0, arr, 0, 8));
+  }
+
+  @Test
+  public void checkIsByteOrderCompatible() {
+    WritableMemory wmem = WritableMemory.allocate(8);
+    assertTrue(wmem.isByteOrderCompatible(ByteOrder.nativeOrder()));
+  }
+
+  @Test(expectedExceptions = IllegalArgumentException.class)
+  public void checkByteOrderNull() {
+    BaseStateImpl.isNativeByteOrder(null);
+    fail();
+  }
+
+  @Test
+  public void checkIsNativeByteOrder() {
+    assertTrue(BaseStateImpl.isNativeByteOrder(ByteOrder.nativeOrder()));
+    try {
+      BaseStateImpl.isNativeByteOrder(null);
+      fail();
+    } catch (final IllegalArgumentException e) {}
+  }
+
+  @Test
+  public void checkXxHash64() {
+    WritableMemory mem = WritableMemory.allocate(8);
+    long out = mem.xxHash64(mem.getLong(0), 1L);
+    assertTrue(out != 0);
+  }
+
+  @Test
+  public void checkTypeDecode() {
+    for (int i = 0; i < 256; i++) {
+      String str = BaseStateImpl.typeDecode(i);
+      println(i + "\t" + str);
+    }
+  }
+
+  @Test
+  public void checkToHexString() {
+    WritableMemory mem = WritableMemory.writableWrap(new byte[16]);
+    println(mem.toHexString("baseMem", 0, 16, true));
+    for (int i = 0; i < 16; i++) { mem.putByte(i, (byte)i); }
+    Buffer buf = mem.asBuffer();
+    println(buf.toHexString("buffer", 0, 16, true));
+  }
+
+
+
+  /********************/
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void println(String s) {
+    //System.out.println(s); //disable here
+  }
+
+}
diff --git a/src/test/java/org/apache/datasketches/memory/Buffer2Test.java b/src/test/java/org/apache/datasketches/memory/Buffer2Test.java
new file mode 100644
index 0000000..f0729c9
--- /dev/null
+++ b/src/test/java/org/apache/datasketches/memory/Buffer2Test.java
@@ -0,0 +1,426 @@
+/*
+ * 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.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.testng.annotations.Test;
+
+public class Buffer2Test {
+
+  @Test
+  public void testWrapByteBuf() {
+    ByteBuffer bb = ByteBuffer.allocate(64).order(ByteOrder.nativeOrder());
+
+    Byte b = 0;
+    while (bb.hasRemaining()) {
+      bb.put(b);
+      b++;
+    }
+    bb.position(0);
+
+    Buffer buffer = Buffer.wrap(bb.asReadOnlyBuffer().order(ByteOrder.nativeOrder()));
+    while (buffer.hasRemaining()) {
+      assertEquals(bb.get(), buffer.getByte());
+    }
+    assertEquals(true, buffer.hasByteBuffer());
+  }
+
+  @Test
+  public void testWrapDirectBB() {
+    ByteBuffer bb = ByteBuffer.allocateDirect(64).order(ByteOrder.nativeOrder());
+
+    Byte b = 0;
+    while (bb.hasRemaining()) {
+      bb.put(b);
+      b++;
+    }
+    bb.position(0);
+
+    Buffer buffer = Buffer.wrap(bb);
+    while (buffer.hasRemaining()) {
+      assertEquals(bb.get(), buffer.getByte());
+    }
+
+    assertEquals(true, buffer.hasByteBuffer());
+  }
+
+  @Test
+  public void testWrapByteArray() {
+    byte[] byteArray = new byte[64];
+
+    for (byte i = 0; i < 64; i++) {
+      byteArray[i] = i;
+    }
+
+    Buffer buffer = Memory.wrap(byteArray).asBuffer();
+    int i = 0;
+    while (buffer.hasRemaining()) {
+      assertEquals(byteArray[i++], buffer.getByte());
+    }
+
+    buffer.setPosition(0);
+    byte[] copyByteArray = new byte[64];
+    buffer.getByteArray(copyByteArray, 0, 64);
+    assertEquals(byteArray, copyByteArray);
+
+    assertEquals(false, buffer.hasByteBuffer());
+  }
+
+  @Test
+  public void testWrapCharArray() {
+    char[] charArray = new char[64];
+
+    for (char i = 0; i < 64; i++) {
+      charArray[i] = i;
+    }
+
+    Buffer buffer = Memory.wrap(charArray).asBuffer();
+    int i = 0;
+    while (buffer.hasRemaining()) {
+      assertEquals(charArray[i++], buffer.getChar());
+    }
+
+    buffer.setPosition(0);
+    char[] copyCharArray = new char[64];
+    buffer.getCharArray(copyCharArray, 0, 64);
+    assertEquals(charArray, copyCharArray);
+  }
+
+  @Test
+  public void testWrapShortArray() {
+    short[] shortArray = new short[64];
+
+    for (short i = 0; i < 64; i++) {
+      shortArray[i] = i;
+    }
+
+    Buffer buffer = Memory.wrap(shortArray).asBuffer();
+    int i = 0;
+    while (buffer.hasRemaining()) {
+      assertEquals(shortArray[i++], buffer.getShort());
+    }
+
+    buffer.setPosition(0);
+    short[] copyShortArray = new short[64];
+    buffer.getShortArray(copyShortArray, 0, 64);
+    assertEquals(shortArray, copyShortArray);
+  }
+
+  @Test
+  public void testWrapIntArray() {
+    int[] intArray = new int[64];
+
+    for (int i = 0; i < 64; i++) {
+      intArray[i] = i;
+    }
+
+    Buffer buffer = Memory.wrap(intArray).asBuffer();
+    int i = 0;
+    while (buffer.hasRemaining()) {
+      assertEquals(intArray[i++], buffer.getInt());
+    }
+
+    buffer.setPosition(0);
+    int[] copyIntArray = new int[64];
+    buffer.getIntArray(copyIntArray, 0, 64);
+    assertEquals(intArray, copyIntArray);
+  }
+
+  @Test
+  public void testWrapLongArray() {
+    long[] longArray = new long[64];
+
+    for (int i = 0; i < 64; i++) {
+      longArray[i] = i;
+    }
+
+    Buffer buffer = Memory.wrap(longArray).asBuffer();
+    int i = 0;
+    while (buffer.hasRemaining()) {
+      assertEquals(longArray[i++], buffer.getLong());
+    }
+
+    buffer.setPosition(0);
+    long[] copyLongArray = new long[64];
+    buffer.getLongArray(copyLongArray, 0, 64);
+    assertEquals(longArray, copyLongArray);
+  }
+
+  @Test
+  public void testWrapFloatArray() {
+    float[] floatArray = new float[64];
+
+    for (int i = 0; i < 64; i++) {
+      floatArray[i] = i;
+    }
+
+    Buffer buffer = Memory.wrap(floatArray).asBuffer();
+    int i = 0;
+    while (buffer.hasRemaining()) {
+      assertEquals(floatArray[i++], buffer.getFloat());
+    }
+
+    buffer.setPosition(0);
+    float[] copyFloatArray = new float[64];
+    buffer.getFloatArray(copyFloatArray, 0, 64);
+    assertEquals(floatArray, copyFloatArray);
+  }
+
+  @Test
+  public void testWrapDoubleArray() {
+    double[] doubleArray = new double[64];
+
+    for (int i = 0; i < 64; i++) {
+      doubleArray[i] = i;
+    }
+
+    Buffer buffer = Memory.wrap(doubleArray).asBuffer();
+    int i = 0;
+    while (buffer.hasRemaining()) {
+      assertEquals(doubleArray[i++], buffer.getDouble());
+    }
+
+    buffer.setPosition(0);
+    double[] copyDoubleArray = new double[64];
+    buffer.getDoubleArray(copyDoubleArray, 0, 64);
+    assertEquals(doubleArray, copyDoubleArray);
+  }
+
+  @Test
+  public void testByteBufferPositionPreservation() {
+    ByteBuffer bb = ByteBuffer.allocate(64).order(ByteOrder.nativeOrder());
+
+    Byte b = 0;
+    while (bb.hasRemaining()) {
+      bb.put(b);
+      b++;
+    }
+    bb.position(10);
+
+    Buffer buffer = Buffer.wrap(bb);
+    while (buffer.hasRemaining()) {
+      assertEquals(bb.get(), buffer.getByte());
+    }
+  }
+
+  @Test
+  public void testGetAndHasRemaining() {
+    ByteBuffer bb = ByteBuffer.allocate(64).order(ByteOrder.nativeOrder());
+
+    Byte b = 0;
+    while (bb.hasRemaining()) {
+      bb.put(b);
+      b++;
+    }
+    bb.position(10);
+
+    Buffer buffer = Buffer.wrap(bb);
+    assertEquals(bb.hasRemaining(), buffer.hasRemaining());
+    assertEquals(bb.remaining(), buffer.getRemaining());
+  }
+
+  @Test
+  public void testGetSetIncResetPosition() {
+    ByteBuffer bb = ByteBuffer.allocate(64).order(ByteOrder.nativeOrder());
+
+    byte b = 0;
+    while (bb.hasRemaining()) {
+      bb.put(b);
+      b++;
+    }
+    bb.position(10);
+
+    Buffer buffer = Buffer.wrap(bb);
+    assertEquals(bb.position(), buffer.getPosition());
+    assertEquals(30, buffer.setPosition(30).getPosition());
+    assertEquals(40, buffer.incrementPosition(10).getPosition());
+    assertEquals(0, buffer.resetPosition().getPosition());
+  }
+
+  @Test
+  public void testByteBufferSlice() {
+    ByteBuffer bb = ByteBuffer.allocate(64).order(ByteOrder.nativeOrder());
+
+    Byte b = 0;
+    while (bb.hasRemaining()) {
+      bb.put(b);
+      b++;
+    }
+    bb.position(10);
+
+    Buffer buffer = Buffer.wrap(bb.slice().order(ByteOrder.nativeOrder()));
+    while (buffer.hasRemaining()) {
+      assertEquals(bb.get(), buffer.getByte());
+    }
+
+    assertEquals(bb.position(), buffer.getPosition() + 10);
+    assertEquals(30, buffer.setPosition(30).getPosition());
+    assertEquals(40, buffer.incrementPosition(10).getPosition());
+    assertEquals(0, buffer.resetPosition().getPosition());
+  }
+
+  @Test
+  public void testDuplicateAndRegion() {
+    ByteBuffer bb = ByteBuffer.allocate(64).order(ByteOrder.nativeOrder());
+
+    Byte b = 0;
+    while (bb.hasRemaining()) {
+      bb.put(b);
+      b++;
+    }
+    bb.position(10);
+
+    Buffer buffer = Buffer.wrap(bb.slice().order(ByteOrder.nativeOrder())); //slice = 54
+    buffer.setPosition(30);//remaining = 24
+    Buffer dupBuffer = buffer.duplicate(); //all 54
+    Buffer regionBuffer = buffer.region(); //24
+
+    assertEquals(dupBuffer.getStart(), buffer.getStart());
+    assertEquals(regionBuffer.getStart(), buffer.getStart());
+    assertEquals(dupBuffer.getEnd(), buffer.getEnd());
+    assertEquals(regionBuffer.getEnd(), buffer.getRemaining());
+    assertEquals(dupBuffer.getPosition(), buffer.getPosition());
+    assertEquals(regionBuffer.getPosition(), 0);
+    assertEquals(dupBuffer.getCapacity(), buffer.getCapacity());
+    assertEquals(regionBuffer.getCapacity(), buffer.getCapacity() - 30);
+  }
+
+  @Test
+  public void checkRORegions() {
+    int n = 16;
+    int n2 = n / 2;
+    long[] arr = new long[n];
+    for (int i = 0; i < n; i++) { arr[i] = i; }
+    Memory mem = Memory.wrap(arr);
+    Buffer buf = mem.asBuffer();
+    Buffer reg = buf.region(n2 * 8, n2 * 8, buf.getTypeByteOrder()); //top half
+    for (int i = 0; i < n2; i++) {
+      long v = reg.getLong(i * 8);
+      long e = i + n2;
+      assertEquals(v, e);
+    }
+  }
+
+  @Test
+  public void testAsMemory() {
+    ByteBuffer bb = ByteBuffer.allocate(64).order(ByteOrder.nativeOrder());
+
+    Byte b = 0;
+    while (bb.hasRemaining()) {
+      bb.put(b);
+      b++;
+    }
+    bb.position(10);
+
+    Buffer buffer = Buffer.wrap(bb);
+    Memory memory = buffer.asMemory();
+
+    assertEquals(buffer.getCapacity(), memory.getCapacity());
+
+    while(buffer.hasRemaining()){
+      assertEquals(memory.getByte(buffer.getPosition()), buffer.getByte());
+    }
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testROByteBuffer() {
+    byte[] arr = new byte[64];
+    ByteBuffer roBB = ByteBuffer.wrap(arr).asReadOnlyBuffer();
+    Buffer buf = Buffer.wrap(roBB);
+    WritableBuffer wbuf = (WritableBuffer) buf;
+    wbuf.putByte(0, (byte) 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testROByteBuffer2() {
+    byte[] arr = new byte[64];
+    ByteBuffer roBB = ByteBuffer.wrap(arr).asReadOnlyBuffer();
+    Buffer buf = Buffer.wrap(roBB);
+    WritableBuffer wbuf = (WritableBuffer) buf;
+    wbuf.putByteArray(arr, 0, 64);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testIllegalFill() {
+    byte[] arr = new byte[64];
+    ByteBuffer roBB = ByteBuffer.wrap(arr).asReadOnlyBuffer();
+    Buffer buf = Buffer.wrap(roBB);
+    WritableBuffer wbuf = (WritableBuffer) buf;
+    wbuf.fill((byte)0);
+  }
+
+  @Test
+  public void checkWritableWrap() {
+    ByteBuffer bb = ByteBuffer.allocate(16);
+    WritableBuffer buf = WritableBuffer.writableWrap(bb, ByteOrder.nativeOrder());
+    assertNotNull(buf);
+  }
+
+  @Test
+  public void testWritableDuplicate() {
+    WritableMemory wmem = WritableMemory.writableWrap(new byte[1]);
+    WritableBuffer wbuf = wmem.asWritableBuffer();
+    WritableBuffer wbuf2 = wbuf.writableDuplicate();
+    assertEquals(wbuf2.getCapacity(), 1);
+    Buffer buf = wmem.asBuffer();
+    assertEquals(buf.getCapacity(), 1);
+  }
+
+  @Test
+  public void checkIndependence() {
+    int cap = 64;
+    WritableMemory wmem = WritableMemory.allocate(cap);
+    WritableBuffer wbuf1 = wmem.asWritableBuffer();
+    WritableBuffer wbuf2 = wmem.asWritableBuffer();
+    assertFalse(wbuf1 == wbuf2);
+    assertTrue(wbuf1.isSameResource(wbuf2));
+
+    WritableMemory reg1 = wmem.writableRegion(0, cap);
+    WritableMemory reg2 = wmem.writableRegion(0, cap);
+    assertFalse(reg1 == reg2);
+    assertTrue(reg1.isSameResource(reg2));
+
+
+    WritableBuffer wbuf3 = wbuf1.writableRegion();
+    WritableBuffer wbuf4 = wbuf1.writableRegion();
+    assertFalse(wbuf3 == wbuf4);
+    assertTrue(wbuf3.isSameResource(wbuf4));
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void println(String s) {
+    //System.out.println(s); //disable here
+  }
+
+}
diff --git a/src/test/java/org/apache/datasketches/memory/BufferBoundaryCheckTest.java b/src/test/java/org/apache/datasketches/memory/BufferBoundaryCheckTest.java
new file mode 100644
index 0000000..b90d685
--- /dev/null
+++ b/src/test/java/org/apache/datasketches/memory/BufferBoundaryCheckTest.java
@@ -0,0 +1,182 @@
+/*
+ * 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 org.testng.annotations.Test;
+
+public class BufferBoundaryCheckTest {
+
+  private final WritableMemory writableMemory = WritableMemory.allocate(8);
+
+  @Test
+  public void testGetByte() {
+    writableMemory.getByte(7);
+    try {
+      writableMemory.getByte(8);
+      throw new RuntimeException("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutByte() {
+    writableMemory.putByte(7, (byte) 1);
+    try {
+      writableMemory.putByte(8, (byte) 1);
+      throw new RuntimeException("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetChar() {
+    writableMemory.getChar(6);
+    try {
+      writableMemory.getChar(7);
+      throw new RuntimeException("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutChar() {
+    writableMemory.putChar(6, 'a');
+    try {
+      writableMemory.putChar(7, 'a');
+      throw new RuntimeException("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetShort() {
+    writableMemory.getShort(6);
+    try {
+      writableMemory.getShort(7);
+      throw new RuntimeException("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutShort() {
+    writableMemory.putShort(6, (short) 1);
+    try {
+      writableMemory.putShort(7, (short) 1);
+      throw new RuntimeException("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetInt() {
+    writableMemory.getInt(4);
+    try {
+      writableMemory.getInt(5);
+      throw new RuntimeException("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutInt() {
+    writableMemory.putInt(4, 1);
+    try {
+      writableMemory.putInt(5, 1);
+      throw new RuntimeException("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetFloat() {
+    writableMemory.getFloat(4);
+    try {
+      writableMemory.getFloat(5);
+      throw new RuntimeException("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutFloat() {
+    writableMemory.putFloat(4, 1f);
+    try {
+      writableMemory.putFloat(5, 1f);
+      throw new RuntimeException("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetLong() {
+    writableMemory.getLong(0);
+    try {
+      writableMemory.getLong(1);
+      throw new RuntimeException("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutLong() {
+    writableMemory.putLong(0, 1L);
+    try {
+      writableMemory.putLong(1, 1L);
+      throw new RuntimeException("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetDouble() {
+    writableMemory.getDouble(0);
+    try {
+      writableMemory.getDouble(1);
+      throw new RuntimeException("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutDouble() {
+    writableMemory.putDouble(0, 1d);
+    try {
+      writableMemory.putDouble(1, 1d);
+      throw new RuntimeException("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+}
diff --git a/src/test/java/org/apache/datasketches/memory/BufferInvariantsTest.java b/src/test/java/org/apache/datasketches/memory/BufferInvariantsTest.java
new file mode 100644
index 0000000..36e1ff9
--- /dev/null
+++ b/src/test/java/org/apache/datasketches/memory/BufferInvariantsTest.java
@@ -0,0 +1,340 @@
+/*
+ * 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.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+import java.nio.ByteBuffer;
+
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+/**
+ * @author Lee Rhodes
+ */
+public class BufferInvariantsTest {
+  private static final MemoryRequestServer memReqSvr = new DefaultMemoryRequestServer();
+
+  @Test
+  public void testRegion() {
+    ByteBuffer byteBuffer = ByteBuffer.allocate(10);
+    byteBuffer.limit(7);
+    Buffer buff = Buffer.wrap(byteBuffer); //assuming buff has cap of 8
+    assertEquals(buff.getCapacity(), 10); //wrong should be 8
+    buff.getByte(); //pos moves to 1
+    Buffer copyBuff = buff.region(); //pos: 0, start: 0, end: 6: cap: 7
+    assertEquals(copyBuff.getEnd(), 6);
+    assertEquals(copyBuff.getCapacity(), 6);
+    assertEquals(copyBuff.getStart(), 0);
+    assertEquals(copyBuff.getPosition(), 0);
+
+    buff.setStartPositionEnd(1, 1, 5);
+    buff.getByte();
+    Buffer copyBuff2 = buff.region();
+    assertEquals(copyBuff2.getEnd(), 3);
+    assertEquals(copyBuff2.getCapacity(), 3);
+    assertEquals(copyBuff2.getStart(), 0);
+    assertEquals(copyBuff2.getPosition(), 0);
+  }
+
+  @Test
+  public void testBB() {
+    int n = 25;
+    ByteBuffer bb = ByteBuffer.allocate(n);
+    for (byte i = 0; i < n; i++) { bb.put(i, i); }
+    assertEquals(bb.position(), 0);
+    assertEquals(bb.limit(), n);
+    assertEquals(bb.get(0), 0);
+//    print("Orig : ");
+//    printbb(bb);
+
+    bb.limit(20);
+    bb.position(5);
+    assertEquals(bb.remaining(), 15);
+//    print("Set  : ");
+//    printbb(bb);
+
+    ByteBuffer dup = bb.duplicate();
+    assertEquals(dup.position(), 5);
+    assertEquals(dup.limit(), 20);
+    assertEquals(dup.capacity(), 25);
+//    print("Dup  : ");
+//    printbb(dup);
+
+    ByteBuffer sl = bb.slice();
+    assertEquals(sl.position(), 0);
+    assertEquals(sl.limit(), 15);
+    assertEquals(sl.capacity(), 15);
+//    print("Slice: ");
+//    printbb(sl);
+  }
+
+  @Test
+  public void testBuf() {
+    int n = 25;
+    WritableBuffer buf = WritableMemory.allocate(n).asWritableBuffer();
+    for (byte i = 0; i < n; i++) { buf.putByte(i); }
+    buf.setPosition(0);
+    assertEquals(buf.getPosition(), 0);
+    assertEquals(buf.getEnd(), 25);
+    assertEquals(buf.getCapacity(), 25);
+//    print("Orig  : ");
+//    printbuf(buf);
+
+    buf.setStartPositionEnd(0, 5, 20);
+    assertEquals(buf.getRemaining(), 15);
+    assertEquals(buf.getCapacity(), 25);
+    assertEquals(buf.getByte(), 5);
+    buf.setPosition(5);
+//    print("Set   : ");
+//    printbuf(buf);
+
+    Buffer dup = buf.duplicate();
+    assertEquals(dup.getRemaining(), 15);
+    assertEquals(dup.getCapacity(), 25);
+    assertEquals(dup.getByte(), 5);
+    dup.setPosition(5);
+//    print("Dup   : ");
+//    printbuf(dup);
+
+
+    Buffer reg = buf.region();
+    assertEquals(reg.getPosition(), 0);
+    assertEquals(reg.getEnd(), 15);
+    assertEquals(reg.getRemaining(), 15);
+    assertEquals(reg.getCapacity(), 15);
+    assertEquals(reg.getByte(), 5);
+    reg.setPosition(0);
+//    print("Region: ");
+//    printbuf(reg);
+  }
+
+  @Test
+  public void testBufWrap() {
+    int n = 25;
+    ByteBuffer bb = ByteBuffer.allocate(n);
+    for (byte i = 0; i < n; i++) { bb.put(i, i); }
+
+    bb.position(5);
+    bb.limit(20);
+
+    Buffer buf = Buffer.wrap(bb);
+    assertEquals(buf.getPosition(), 5);
+    assertEquals(buf.getEnd(), 20);
+    assertEquals(buf.getRemaining(), 15);
+    assertEquals(buf.getCapacity(), 25);
+    assertEquals(buf.getByte(), 5);
+    buf.setPosition(5);
+//    print("Buf.wrap: ");
+//    printbuf(buf);
+
+    Buffer reg = buf.region();
+    assertEquals(reg.getPosition(), 0);
+    assertEquals(reg.getEnd(), 15);
+    assertEquals(reg.getRemaining(), 15);
+    assertEquals(reg.getCapacity(), 15);
+    assertEquals(reg.getByte(), 5);
+    reg.setPosition(0);
+//    print("Buf.region: ");
+//    printbuf(reg);
+  }
+
+  @Test
+  public void checkLimitsDirect() throws Exception {
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory wmem = WritableMemory.allocateDirect(100, scope, memReqSvr);
+      Buffer buf = wmem.asBuffer();
+      buf.setStartPositionEnd(40, 45, 50);
+      buf.setStartPositionEnd(0, 0, 100);
+      try {
+        buf.setStartPositionEnd(0, 0, 101);
+        fail();
+      } catch (AssertionError e) {
+        //
+      }
+    }
+  }
+
+  @Test
+  public void testRegionDirect() {
+    ByteBuffer byteBuffer = ByteBuffer.allocate(10);
+    byteBuffer.limit(7);
+    Buffer buff = Buffer.wrap(byteBuffer); //assuming buff has cap of 8
+    assertEquals(buff.getCapacity(), 10); //wrong should be 8
+    buff.getByte(); //pos moves to 1
+    Buffer copyBuff = buff.region(); //pos: 0, start: 0, end: 6: cap: 7
+    assertEquals(copyBuff.getEnd(), 6);
+    assertEquals(copyBuff.getCapacity(), 6);
+    assertEquals(copyBuff.getStart(), 0);
+    assertEquals(copyBuff.getPosition(), 0);
+
+    buff.setStartPositionEnd(1, 1, 5);
+    buff.getByte();
+    Buffer copyBuff2 = buff.region();
+    assertEquals(copyBuff2.getEnd(), 3);
+    assertEquals(copyBuff2.getCapacity(), 3);
+    assertEquals(copyBuff2.getStart(), 0);
+    assertEquals(copyBuff2.getPosition(), 0);
+  }
+
+  @Test
+  public void testBBDirect() {
+    int n = 25;
+    ByteBuffer bb = ByteBuffer.allocateDirect(n);
+    for (byte i = 0; i < n; i++) { bb.put(i, i); }
+    assertEquals(bb.position(), 0);
+    assertEquals(bb.limit(), n);
+    assertEquals(bb.get(0), 0);
+//    print("Orig : ");
+//    printbb(bb);
+
+    bb.limit(20);
+    bb.position(5);
+    assertEquals(bb.remaining(), 15);
+//    print("Set  : ");
+//    printbb(bb);
+
+    ByteBuffer dup = bb.duplicate();
+    assertEquals(dup.position(), 5);
+    assertEquals(dup.limit(), 20);
+    assertEquals(dup.capacity(), 25);
+//    print("Dup  : ");
+//    printbb(dup);
+
+    ByteBuffer sl = bb.slice();
+    assertEquals(sl.position(), 0);
+    assertEquals(sl.limit(), 15);
+    assertEquals(sl.capacity(), 15);
+//    print("Slice: ");
+//    printbb(sl);
+  }
+
+  @Test
+  public void testBufDirect() throws Exception {
+    int n = 25;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+    WritableMemory wmem = WritableMemory.allocateDirect(n, scope, memReqSvr);
+    WritableBuffer buf = wmem.asWritableBuffer();
+    for (byte i = 0; i < n; i++) { buf.putByte(i); }
+    buf.setPosition(0);
+    assertEquals(buf.getPosition(), 0);
+    assertEquals(buf.getEnd(), 25);
+    assertEquals(buf.getCapacity(), 25);
+//    print("Orig  : ");
+//    printbuf(buf);
+
+    buf.setStartPositionEnd(0, 5, 20);
+    assertEquals(buf.getRemaining(), 15);
+    assertEquals(buf.getCapacity(), 25);
+    assertEquals(buf.getByte(), 5);
+    buf.setPosition(5);
+//    print("Set   : ");
+//    printbuf(buf);
+
+    Buffer dup = buf.duplicate();
+    assertEquals(dup.getRemaining(), 15);
+    assertEquals(dup.getCapacity(), 25);
+    assertEquals(dup.getByte(), 5);
+    dup.setPosition(5);
+//    print("Dup   : ");
+//    printbuf(dup);
+
+
+    Buffer reg = buf.region();
+    assertEquals(reg.getPosition(), 0);
+    assertEquals(reg.getEnd(), 15);
+    assertEquals(reg.getRemaining(), 15);
+    assertEquals(reg.getCapacity(), 15);
+    assertEquals(reg.getByte(), 5);
+    reg.setPosition(0);
+//    print("Region: ");
+//    printbuf(reg);
+    }
+  }
+
+  @Test
+  public void testBufWrapDirect() {
+    int n = 25;
+    ByteBuffer bb = ByteBuffer.allocateDirect(n);
+    for (byte i = 0; i < n; i++) { bb.put(i, i); }
+
+    bb.position(5);
+    bb.limit(20);
+
+    Buffer buf = Buffer.wrap(bb);
+    assertEquals(buf.getPosition(), 5);
+    assertEquals(buf.getEnd(), 20);
+    assertEquals(buf.getRemaining(), 15);
+    assertEquals(buf.getCapacity(), 25);
+    assertEquals(buf.getByte(), 5);
+    buf.setPosition(5);
+//    print("Buf.wrap: ");
+//    printbuf(buf);
+
+    Buffer reg = buf.region();
+    assertEquals(reg.getPosition(), 0);
+    assertEquals(reg.getEnd(), 15);
+    assertEquals(reg.getRemaining(), 15);
+    assertEquals(reg.getCapacity(), 15);
+    assertEquals(reg.getByte(), 5);
+    reg.setPosition(0);
+//    print("Buf.region: ");
+//    printbuf(reg);
+  }
+
+
+  static void printbb(ByteBuffer bb) {
+    println("pos: " + bb.position() + ", lim: " + bb.limit() + ", cap: " + bb.capacity());
+    int rem = bb.remaining();
+    int pos = bb.position();
+    int i;
+    for (i = 0; i < (rem-1); i++) {
+      print(bb.get(i+ pos) + ", ");
+    }
+    println(bb.get(i + pos) + "\n");
+  }
+
+  static void printbuf(Buffer buf) {
+    println("pos: " + buf.getPosition() + ", end: " + buf.getEnd() + ", cap: " + buf.getCapacity());
+    long rem = buf.getRemaining();
+    long pos = buf.getPosition();
+    int i;
+    for (i = 0; i < (rem-1); i++) {
+      print(buf.getByte(i+ pos) + ", ");
+    }
+    println(buf.getByte(i + pos) + "\n");
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void println(String s) {
+    //System.out.println(s); //disable here
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void print(String s) {
+    //System.out.print(s); //disable here
+  }
+}
diff --git a/src/test/java/org/apache/datasketches/memory/BufferReadWriteSafetyTest.java b/src/test/java/org/apache/datasketches/memory/BufferReadWriteSafetyTest.java
new file mode 100644
index 0000000..8588b14
--- /dev/null
+++ b/src/test/java/org/apache/datasketches/memory/BufferReadWriteSafetyTest.java
@@ -0,0 +1,177 @@
+/*
+ * 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 java.nio.ByteBuffer;
+
+import org.testng.annotations.Test;
+
+public class BufferReadWriteSafetyTest {
+
+  // Test various operations with read-only Buffer
+
+  private final WritableBuffer buf = (WritableBuffer) Buffer.wrap(ByteBuffer.allocate(8));
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutByte() {
+    buf.setPosition(0);
+    buf.putByte(0, (byte) 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutBytePositional() {
+    buf.setPosition(0);
+    buf.putByte((byte) 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutShort() {
+    buf.setPosition(0);
+    buf.putShort(0, (short) 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutShortPositional() {
+    buf.setPosition(0);
+    buf.putShort((short) 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutChar() {
+    buf.setPosition(0);
+    buf.putChar(0, (char) 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutCharPositional() {
+    buf.setPosition(0);
+    buf.putChar((char) 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutInt() {
+    buf.setPosition(0);
+    buf.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutIntPositional() {
+    buf.setPosition(0);
+    buf.putInt(1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutLong() {
+    buf.setPosition(0);
+    buf.putLong(0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutLongPositional() {
+    buf.setPosition(0);
+    buf.putLong(1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutFloat() {
+    buf.setPosition(0);
+    buf.putFloat(0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutFloatPositional() {
+    buf.setPosition(0);
+    buf.putFloat(1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutDouble() {
+    buf.setPosition(0);
+    buf.putDouble(0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutDoublePositional() {
+    buf.setPosition(0);
+    buf.putDouble(1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutByteArray() {
+    buf.setPosition(0);
+    buf.putByteArray(new byte[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutShortArray() {
+    buf.setPosition(0);
+    buf.putShortArray(new short[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutCharArray() {
+    buf.setPosition(0);
+    buf.putCharArray(new char[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutIntArray() {
+    buf.setPosition(0);
+    buf.putIntArray(new int[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutLongArray() {
+    buf.setPosition(0);
+    buf.putLongArray(new long[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutFloatArray() {
+    buf.setPosition(0);
+    buf.putFloatArray(new float[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testDoubleByteArray() {
+    buf.setPosition(0);
+    buf.putDoubleArray(new double[] {1}, 0, 1);
+  }
+
+  // Now, test that various ways to obtain a read-only buffer produce a read-only buffer indeed
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testWritableMemoryAsBuffer() {
+    WritableBuffer buf1 = (WritableBuffer) WritableMemory.allocate(8).asBuffer();
+    buf1.putInt(1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testWritableBufferRegion() {
+    WritableBuffer buf1 = (WritableBuffer) WritableMemory.allocate(8).asWritableBuffer().region();
+    buf1.putInt(1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testWritableBufferDuplicate() {
+    WritableBuffer buf1 = (WritableBuffer) WritableMemory.allocate(8).asWritableBuffer().duplicate();
+    buf1.putInt(1);
+  }
+}
diff --git a/src/test/java/org/apache/datasketches/memory/BufferTest.java b/src/test/java/org/apache/datasketches/memory/BufferTest.java
new file mode 100644
index 0000000..dcc794f
--- /dev/null
+++ b/src/test/java/org/apache/datasketches/memory/BufferTest.java
@@ -0,0 +1,322 @@
+/*
+ * 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.testng.Assert.assertEquals;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.List;
+
+import org.testng.annotations.Test;
+import org.testng.collections.Lists;
+
+import jdk.incubator.foreign.ResourceScope;
+
+public class BufferTest {
+  private final MemoryRequestServer memReqSvr = new DefaultMemoryRequestServer();
+
+  @Test
+  public void checkDirectRoundTrip() throws Exception {
+    int n = 1024; //longs
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+    WritableMemory wmem = WritableMemory.allocateDirect(n * 8, scope, memReqSvr);
+      WritableBuffer wbuf = wmem.asWritableBuffer();
+      for (int i = 0; i < n; i++) {
+        wbuf.putLong(i);
+      }
+      wbuf.resetPosition();
+      for (int i = 0; i < n; i++) {
+        long v = wbuf.getLong();
+        assertEquals(v, i);
+      }
+    }
+  }
+
+  @Test
+  public void checkAutoHeapRoundTrip() {
+    int n = 1024; //longs
+    WritableBuffer wbuf = WritableMemory.allocate(n * 8).asWritableBuffer();
+    for (int i = 0; i < n; i++) {
+      wbuf.putLong(i);
+    }
+    wbuf.resetPosition();
+    for (int i = 0; i < n; i++) {
+      long v = wbuf.getLong();
+      assertEquals(v, i);
+    }
+  }
+
+  @Test
+  public void checkArrayWrap() {
+    int n = 1024; //longs
+    byte[] arr = new byte[n * 8];
+    WritableBuffer wbuf = WritableMemory.writableWrap(arr).asWritableBuffer();
+    for (int i = 0; i < n; i++) {
+      wbuf.putLong(i);
+    }
+    wbuf.resetPosition();
+    for (int i = 0; i < n; i++) {
+      long v = wbuf.getLong();
+      assertEquals(v, i);
+    }
+    Buffer buf = Memory.wrap(arr).asBuffer();
+    buf.resetPosition();
+    for (int i = 0; i < n; i++) {
+      long v = buf.getLong();
+      assertEquals(v, i);
+    }
+    // Check Zero length array wraps
+    Memory mem = Memory.wrap(new byte[0]);
+    Buffer buffZeroLengthArrayWrap = mem.asBuffer();
+    assertEquals(buffZeroLengthArrayWrap.getCapacity(), 0);
+    // check 0 length array wraps
+    List<Buffer> buffersToCheck = Lists.newArrayList();
+    buffersToCheck.add(WritableMemory.allocate(0).asBuffer());
+    buffersToCheck.add(WritableBuffer.writableWrap(ByteBuffer.allocate(0)));
+    buffersToCheck.add(Buffer.wrap(ByteBuffer.allocate(0)));
+    buffersToCheck.add(Memory.wrap(new byte[0]).asBuffer());
+    buffersToCheck.add(Memory.wrap(new char[0]).asBuffer());
+    buffersToCheck.add(Memory.wrap(new short[0]).asBuffer());
+    buffersToCheck.add(Memory.wrap(new int[0]).asBuffer());
+    buffersToCheck.add(Memory.wrap(new long[0]).asBuffer());
+    buffersToCheck.add(Memory.wrap(new float[0]).asBuffer());
+    buffersToCheck.add(Memory.wrap(new double[0]).asBuffer());
+    //Check the buffer lengths
+    for (Buffer buffer : buffersToCheck) {
+      assertEquals(buffer.getCapacity(), 0);
+    }
+  }
+
+  @Test
+  public void simpleBBTest() {
+    int n = 1024; //longs
+    byte[] arr = new byte[n * 8];
+    ByteBuffer bb = ByteBuffer.wrap(arr);
+    bb.order(ByteOrder.nativeOrder());
+
+    WritableBuffer wbuf = WritableBuffer.writableWrap(bb);
+    for (int i = 0; i < n; i++) { //write to wbuf
+      wbuf.putLong(i);
+    }
+    wbuf.resetPosition();
+    for (int i = 0; i < n; i++) { //read from wbuf
+      long v = wbuf.getLong();
+      assertEquals(v, i);
+    }
+    for (int i = 0; i < n; i++) { //read from BB
+      long v = bb.getLong();
+      assertEquals(v, i);
+    }
+  }
+
+  @Test
+  public void checkByteBufHeap() {
+    int n = 1024; //longs
+    byte[] arr = new byte[n * 8];
+    ByteBuffer bb = ByteBuffer.wrap(arr);
+    bb.order(ByteOrder.nativeOrder());
+
+    WritableBuffer wbuf = WritableBuffer.writableWrap(bb);
+    for (int i = 0; i < n; i++) { //write to wbuf
+      wbuf.putLong(i);
+    }
+    wbuf.resetPosition();
+    for (int i = 0; i < n; i++) { //read from wbuf
+      long v = wbuf.getLong();
+      assertEquals(v, i);
+    }
+    for (int i = 0; i < n; i++) { //read from BB
+      long v = bb.getLong(i * 8);
+      assertEquals(v, i);
+    }
+    Buffer buf1 = Memory.wrap(arr).asBuffer();
+    for (int i = 0; i < n; i++) { //read from wrapped arr
+      long v = buf1.getLong();
+      assertEquals(v, i);
+    }
+    //convert to wbuf to RO
+    Buffer buf = wbuf;
+    buf.resetPosition();
+    for (int i = 0; i < n; i++) {
+      long v = buf.getLong();
+      assertEquals(v, i);
+    }
+  }
+
+  @Test
+  public void checkByteBufDirect() {
+    int n = 1024; //longs
+    ByteBuffer bb = ByteBuffer.allocateDirect(n * 8);
+    bb.order(ByteOrder.nativeOrder());
+
+    WritableBuffer wbuf = WritableBuffer.writableWrap(bb);
+    for (int i = 0; i < n; i++) { //write to wmem
+      wbuf.putLong(i);
+    }
+    wbuf.resetPosition();
+    for (int i = 0; i < n; i++) { //read from wmem
+      long v = wbuf.getLong();
+      assertEquals(v, i);
+    }
+    for (int i = 0; i < n; i++) { //read from BB
+      long v = bb.getLong(i * 8);
+      assertEquals(v, i);
+    }
+    Buffer buf1 = Buffer.wrap(bb);
+    for (int i = 0; i < n; i++) { //read from wrapped bb RO
+      long v = buf1.getLong();
+      assertEquals(v, i);
+    }
+    //convert to RO
+    Buffer buf = wbuf;
+    buf.resetPosition();
+    for (int i = 0; i < n; i++) {
+      long v = buf.getLong();
+      assertEquals(v, i);
+    }
+  }
+
+  @Test
+  public void checkByteBufBigEndianOrder() {
+    int n = 1024; //longs
+    ByteBuffer bb = ByteBuffer.allocate(n * 8);
+    bb.order(BaseState.NON_NATIVE_BYTE_ORDER);
+    Buffer buf = Buffer.wrap(bb);
+    assertEquals(buf.getTypeByteOrder(), ByteOrder.nativeOrder());
+  }
+
+  @Test
+  public void checkReadOnlyHeapByteBuffer() {
+    ByteBuffer bb = ByteBuffer.allocate(128);
+    bb.order(ByteOrder.nativeOrder());
+    for (int i = 0; i < 128; i++) { bb.put(i, (byte)i); }
+
+    bb.position(64);
+    ByteBuffer slice = bb.slice().asReadOnlyBuffer();
+    slice.order(ByteOrder.nativeOrder());
+
+    Buffer buf = Buffer.wrap(slice);
+    for (int i = 0; i < 64; i++) {
+      assertEquals(buf.getByte(), 64 + i);
+    }
+    buf.toHexString("slice", 0, slice.capacity(), true);
+    //println(s);
+  }
+
+  @Test
+  public void checkPutGetArraysHeap() {
+    int n = 1024; //longs
+    long[] arr = new long[n];
+    for (int i = 0; i < n; i++) { arr[i] = i; }
+
+    WritableBuffer wbuf = WritableMemory.allocate(n * 8).asWritableBuffer();
+    wbuf.putLongArray(arr, 0, n);
+    long[] arr2 = new long[n];
+    wbuf.resetPosition();
+    wbuf.getLongArray(arr2, 0, n);
+    for (int i = 0; i < n; i++) {
+      assertEquals(arr2[i], i);
+    }
+  }
+
+  @Test
+  public void checkRORegions() {
+    int n = 16;
+    int n2 = n / 2;
+    long[] arr = new long[n];
+    for (int i = 0; i < n; i++) { arr[i] = i; }
+
+    Buffer buf = Memory.wrap(arr).asBuffer();
+    buf.setPosition(n2 * 8);
+    Buffer reg = buf.region();
+    for (int i = 0; i < n2; i++) {
+      long v = reg.getLong();
+      assertEquals(v, i + n2);
+      //println("" + v);
+    }
+  }
+
+  @Test
+  public void checkWRegions() {
+    int n = 16;
+    int n2 = n / 2;
+    long[] arr = new long[n];
+    for (int i = 0; i < n; i++) { arr[i] = i; }
+    WritableBuffer wbuf = WritableMemory.writableWrap(arr).asWritableBuffer();
+    for (int i = 0; i < n; i++) {
+      assertEquals(wbuf.getLong(), i); //write all
+      //println("" + wmem.getLong(i * 8));
+    }
+    //println("");
+    wbuf.setPosition(n2 * 8);
+    WritableBuffer reg = wbuf.writableRegion();
+    for (int i = 0; i < n2; i++) { reg.putLong(i); } //rewrite top half
+    wbuf.resetPosition();
+    for (int i = 0; i < n; i++) {
+      assertEquals(wbuf.getLong(), i % 8);
+      //println("" + wmem.getLong(i * 8));
+    }
+  }
+
+  @SuppressWarnings("resource")
+  @Test(expectedExceptions = IllegalStateException.class)
+  public void checkParentUseAfterFree() throws Exception {
+    int bytes = 64 * 8;
+    WritableMemory wmem = WritableMemory.allocateDirect(bytes, ResourceScope.newConfinedScope(), memReqSvr);
+    WritableBuffer wbuf = wmem.asWritableBuffer();
+    wbuf.close();
+    //with -ea assert: Memory not valid.
+    //with -da sometimes segfaults, sometimes passes!
+    wbuf.getLong();
+  }
+
+  @SuppressWarnings("resource")
+  @Test(expectedExceptions = IllegalStateException.class)
+  public void checkRegionUseAfterFree() throws Exception {
+    int bytes = 64;
+    WritableMemory wmem = WritableMemory.allocateDirect(bytes, ResourceScope.newConfinedScope(), memReqSvr);
+    Buffer region = wmem.asBuffer().region();
+    region.close();
+    //with -ea assert: Memory not valid.
+    //with -da sometimes segfaults, sometimes passes!
+    region.getByte();
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void checkBaseBufferInvariants() {
+    WritableBuffer wbuf = WritableMemory.allocate(64).asWritableBuffer();
+    wbuf.setStartPositionEnd(1, 0, 2); //out of order
+  }
+
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  /**
+   * @param s String to print
+   */
+  static void println(final String s) {
+    //System.out.println(s);
+  }
+
+}
diff --git a/src/test/java/org/apache/datasketches/memory/CommonBufferTest.java b/src/test/java/org/apache/datasketches/memory/CommonBufferTest.java
new file mode 100644
index 0000000..e6e24df
--- /dev/null
+++ b/src/test/java/org/apache/datasketches/memory/CommonBufferTest.java
@@ -0,0 +1,417 @@
+/*
+ * 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.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+public class CommonBufferTest {
+  private final MemoryRequestServer memReqSvr = new DefaultMemoryRequestServer();
+
+  @Test
+  public void checkSetGet() throws Exception {
+    int memCapacity = 60; //must be at least 60
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      WritableBuffer buf = mem.asWritableBuffer();
+      assertEquals(buf.getCapacity(), memCapacity);
+      setGetTests(buf);
+      setGetTests2(buf);
+    }
+  }
+
+  public static void setGetTests(WritableBuffer buf) {
+    buf.putByte((byte) -1);
+    buf.putByte((byte) 0);
+    buf.putChar('A');
+    buf.putChar('Z');
+    buf.putShort(Short.MAX_VALUE);
+    buf.putShort(Short.MIN_VALUE);
+    buf.putInt(Integer.MAX_VALUE);
+    buf.putInt(Integer.MIN_VALUE);
+    buf.putFloat(Float.MAX_VALUE);
+    buf.putFloat(Float.MIN_VALUE);
+    buf.putLong(Long.MAX_VALUE);
+    buf.putLong(Long.MIN_VALUE);
+    buf.putDouble(Double.MAX_VALUE);
+    buf.putDouble(Double.MIN_VALUE);
+
+    buf.resetPosition();
+
+    assertEquals(buf.getByte(buf.getPosition()), (byte) -1);
+    assertEquals(buf.getByte(), (byte) -1);
+    assertEquals(buf.getByte(buf.getPosition()), (byte)0);
+    assertEquals(buf.getByte(), (byte)0);
+    assertEquals(buf.getChar(buf.getPosition()), 'A');
+    assertEquals(buf.getChar(), 'A');
+    assertEquals(buf.getChar(buf.getPosition()), 'Z');
+    assertEquals(buf.getChar(), 'Z');
+    assertEquals(buf.getShort(buf.getPosition()), Short.MAX_VALUE);
+    assertEquals(buf.getShort(), Short.MAX_VALUE);
+    assertEquals(buf.getShort(buf.getPosition()), Short.MIN_VALUE);
+    assertEquals(buf.getShort(), Short.MIN_VALUE);
+    assertEquals(buf.getInt(buf.getPosition()), Integer.MAX_VALUE);
+    assertEquals(buf.getInt(), Integer.MAX_VALUE);
+    assertEquals(buf.getInt(buf.getPosition()), Integer.MIN_VALUE);
+    assertEquals(buf.getInt(), Integer.MIN_VALUE);
+    assertEquals(buf.getFloat(buf.getPosition()), Float.MAX_VALUE);
+    assertEquals(buf.getFloat(), Float.MAX_VALUE);
+    assertEquals(buf.getFloat(buf.getPosition()), Float.MIN_VALUE);
+    assertEquals(buf.getFloat(), Float.MIN_VALUE);
+    assertEquals(buf.getLong(buf.getPosition()), Long.MAX_VALUE);
+    assertEquals(buf.getLong(), Long.MAX_VALUE);
+    assertEquals(buf.getLong(buf.getPosition()), Long.MIN_VALUE);
+    assertEquals(buf.getLong(), Long.MIN_VALUE);
+    assertEquals(buf.getDouble(buf.getPosition()), Double.MAX_VALUE);
+    assertEquals(buf.getDouble(), Double.MAX_VALUE);
+    assertEquals(buf.getDouble(buf.getPosition()), Double.MIN_VALUE);
+    assertEquals(buf.getDouble(), Double.MIN_VALUE);
+  }
+
+  public static void setGetTests2(WritableBuffer buf) {
+    buf.putByte(2, (byte) -1);
+    buf.putByte(3, (byte) 0);
+    buf.putChar(4,'A');
+    buf.putChar(6,'Z');
+    buf.putShort(8, Short.MAX_VALUE);
+    buf.putShort(10, Short.MIN_VALUE);
+    buf.putInt(12, Integer.MAX_VALUE);
+    buf.putInt(16, Integer.MIN_VALUE);
+    buf.putFloat(20, Float.MAX_VALUE);
+    buf.putFloat(24, Float.MIN_VALUE);
+    buf.putLong(28, Long.MAX_VALUE);
+    buf.putLong(36, Long.MIN_VALUE);
+    buf.putDouble(44, Double.MAX_VALUE);
+    buf.putDouble(52, Double.MIN_VALUE);
+
+    assertEquals(buf.getByte(2), (byte) -1);
+    assertEquals(buf.getByte(3), (byte)0);
+    assertEquals(buf.getChar(4), 'A');
+    assertEquals(buf.getChar(6), 'Z');
+    assertEquals(buf.getShort(8), Short.MAX_VALUE);
+    assertEquals(buf.getShort(10), Short.MIN_VALUE);
+    assertEquals(buf.getInt(12), Integer.MAX_VALUE);
+    assertEquals(buf.getInt(16), Integer.MIN_VALUE);
+    assertEquals(buf.getFloat(20), Float.MAX_VALUE);
+    assertEquals(buf.getFloat(24), Float.MIN_VALUE);
+    assertEquals(buf.getLong(28), Long.MAX_VALUE);
+    assertEquals(buf.getLong(36), Long.MIN_VALUE);
+    assertEquals(buf.getDouble(44), Double.MAX_VALUE);
+    assertEquals(buf.getDouble(52), Double.MIN_VALUE);
+  }
+
+  @Test
+  public void checkSetGetArrays() throws Exception {
+    int memCapacity = 32;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      WritableBuffer buf = mem.asWritableBuffer();
+      assertEquals(buf.getCapacity(), memCapacity);
+      setGetArraysTests(buf);
+    }
+  }
+
+  public static void setGetArraysTests(WritableBuffer buf) {
+    int words = 4;
+
+    byte[] srcArray2 = { 1, -2, 3, -4 };
+    byte[] dstArray2 = new byte[4];
+    buf.resetPosition();
+    buf.putByteArray(srcArray2, 0, words);
+    buf.resetPosition();
+    buf.getByteArray(dstArray2, 0, words);
+    for (int i=0; i<words; i++) {
+      assertEquals(dstArray2[i], srcArray2[i]);
+    }
+
+    char[] srcArray3 = { 'A', 'B', 'C', 'D' };
+    char[] dstArray3 = new char[words];
+    buf.resetPosition();
+    buf.putCharArray(srcArray3, 0, words);
+    buf.resetPosition();
+    buf.getCharArray(dstArray3, 0, words);
+    for (int i=0; i<words; i++) {
+      assertEquals(dstArray3[i], srcArray3[i]);
+    }
+
+    double[] srcArray4 = { 1.0, -2.0, 3.0, -4.0 };
+    double[] dstArray4 = new double[words];
+    buf.resetPosition();
+    buf.putDoubleArray(srcArray4, 0, words);
+    buf.resetPosition();
+    buf.getDoubleArray(dstArray4, 0, words);
+    for (int i=0; i<words; i++) {
+      assertEquals(dstArray4[i], srcArray4[i], 0.0);
+    }
+
+    float[] srcArray5 = { 1.0F, -2.0F, 3.0F, -4.0F };
+    float[] dstArray5 = new float[words];
+    buf.resetPosition();
+    buf.putFloatArray(srcArray5, 0, words);
+    buf.resetPosition();
+    buf.getFloatArray(dstArray5, 0, words);
+    for (int i=0; i<words; i++) {
+      assertEquals(dstArray5[i], srcArray5[i], 0.0);
+    }
+
+    int[] srcArray6 = { 1, -2, 3, -4 };
+    int[] dstArray6 = new int[words];
+    buf.resetPosition();
+    buf.putIntArray(srcArray6, 0, words);
+    buf.resetPosition();
+    buf.getIntArray(dstArray6, 0, words);
+    for (int i=0; i<words; i++) {
+      assertEquals(dstArray6[i], srcArray6[i]);
+    }
+
+    long[] srcArray7 = { 1, -2, 3, -4 };
+    long[] dstArray7 = new long[words];
+    buf.resetPosition();
+    buf.putLongArray(srcArray7, 0, words);
+    buf.resetPosition();
+    buf.getLongArray(dstArray7, 0, words);
+    for (int i=0; i<words; i++) {
+      assertEquals(dstArray7[i], srcArray7[i]);
+    }
+
+    short[] srcArray8 = { 1, -2, 3, -4 };
+    short[] dstArray8 = new short[words];
+    buf.resetPosition();
+    buf.putShortArray(srcArray8, 0, words);
+    buf.resetPosition();
+    buf.getShortArray(dstArray8, 0, words);
+    for (int i=0; i<words; i++) {
+      assertEquals(dstArray8[i], srcArray8[i]);
+    }
+  }
+
+  @Test
+  public void checkSetGetPartialArraysWithOffset() throws Exception {
+    int memCapacity = 32;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      WritableBuffer buf = mem.asWritableBuffer();
+      assertEquals(buf.getCapacity(), memCapacity);
+      setGetPartialArraysWithOffsetTests(buf);
+    }
+  }
+
+  public static void setGetPartialArraysWithOffsetTests(WritableBuffer buf) {
+    int items= 4;
+
+    byte[] srcArray2 = { 1, -2, 3, -4 };
+    byte[] dstArray2 = new byte[items];
+    buf.resetPosition();
+    buf.putByteArray(srcArray2, 2, items/2);
+    buf.resetPosition();
+    buf.getByteArray(dstArray2, 2, items/2);
+    for (int i=2; i<items; i++) {
+      assertEquals(dstArray2[i], srcArray2[i]);
+    }
+
+    char[] srcArray3 = { 'A', 'B', 'C', 'D' };
+    char[] dstArray3 = new char[items];
+    buf.resetPosition();
+    buf.putCharArray(srcArray3, 2, items/2);
+    buf.resetPosition();
+    buf.getCharArray(dstArray3, 2, items/2);
+    for (int i=2; i<items; i++) {
+      assertEquals(dstArray3[i], srcArray3[i]);
+    }
+
+    double[] srcArray4 = { 1.0, -2.0, 3.0, -4.0 };
+    double[] dstArray4 = new double[items];
+    buf.resetPosition();
+    buf.putDoubleArray(srcArray4, 2, items/2);
+    buf.resetPosition();
+    buf.getDoubleArray(dstArray4, 2, items/2);
+    for (int i=2; i<items; i++) {
+      assertEquals(dstArray4[i], srcArray4[i], 0.0);
+    }
+
+    float[] srcArray5 = { 1.0F, -2.0F, 3.0F, -4.0F };
+    float[] dstArray5 = new float[items];
+    buf.resetPosition();
+    buf.putFloatArray(srcArray5, 2, items/2);
+    buf.resetPosition();
+    buf.getFloatArray(dstArray5, 2, items/2);
+    for (int i=2; i<items; i++) {
+      assertEquals(dstArray5[i], srcArray5[i], 0.0);
+    }
+
+    int[] srcArray6 = { 1, -2, 3, -4 };
+    int[] dstArray6 = new int[items];
+    buf.resetPosition();
+    buf.putIntArray(srcArray6, 2, items/2);
+    buf.resetPosition();
+    buf.getIntArray(dstArray6, 2, items/2);
+    for (int i=2; i<items; i++) {
+      assertEquals(dstArray6[i], srcArray6[i]);
+    }
+
+    long[] srcArray7 = { 1, -2, 3, -4 };
+    long[] dstArray7 = new long[items];
+    buf.resetPosition();
+    buf.putLongArray(srcArray7, 2, items/2);
+    buf.resetPosition();
+    buf.getLongArray(dstArray7, 2, items/2);
+    for (int i=2; i<items; i++) {
+      assertEquals(dstArray7[i], srcArray7[i]);
+    }
+
+    short[] srcArray8 = { 1, -2, 3, -4 };
+    short[] dstArray8 = new short[items];
+    buf.resetPosition();
+    buf.putShortArray(srcArray8, 2, items/2);
+    buf.resetPosition();
+    buf.getShortArray(dstArray8, 2, items/2);
+    for (int i=2; i<items; i++) {
+      assertEquals(dstArray8[i], srcArray8[i]);
+    }
+  }
+
+  @Test
+  public void checkSetClearMemoryRegions() throws Exception {
+    int memCapacity = 64; //must be 64
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      WritableBuffer buf = mem.asWritableBuffer();
+      assertEquals(buf.getCapacity(), memCapacity);
+
+      setClearMemoryRegionsTests(buf); //requires println enabled to visually check
+      buf.resetPosition();
+      for (int i = 0; i < memCapacity; i++) {
+        assertEquals(mem.getByte(i), 0);
+      }
+    }
+  }
+
+  //enable println statements to visually check
+  public static void setClearMemoryRegionsTests(WritableBuffer buf) {
+    int accessCapacity = (int)buf.getCapacity();
+
+  //define regions
+    int reg1Start = 0;
+    int reg1Len = 28;
+    int reg2Start = 28;
+    int reg2Len = 32;
+
+    //set region 1
+    byte b1 = 5;
+    buf.setStartPositionEnd(reg1Start, reg1Start, reg1Len);
+    buf.fill(b1);
+    buf.resetPosition();
+    for (int i=reg1Start; i<(reg1Len+reg1Start); i++) {
+      assertEquals(buf.getByte(), b1);
+    }
+    //println(buf.toHexString("Region1 to 5", reg1Start, reg1Len));
+
+    //set region 2
+    byte b2 = 7;
+    buf.setStartPositionEnd(reg2Start, reg2Start, reg2Start + reg2Len);
+    buf.fill(b2);
+    //println(mem.toHexString("Fill", 0, (int)mem.getCapacity()));
+    buf.resetPosition();
+    for (int i=reg2Start; i<(reg2Start+reg2Len); i++) {
+      assertEquals(buf.getByte(), b2);
+    }
+    //println(buf.toHexString("Region2 to 7", reg2Start, reg2Len));
+
+    //clear region 1
+    byte zeroByte = 0;
+    buf.setStartPositionEnd(reg1Start, reg1Start, reg2Len);
+    buf.resetPosition();
+    buf.clear();
+    buf.resetPosition();
+    for (int i=reg1Start; i<(reg1Start+reg1Len); i++) {
+      assertEquals(buf.getByte(), zeroByte);
+    }
+    //println(buf.toHexString("Region1 cleared", reg1Start, reg1Len));
+
+    //clear region 2
+    buf.setStartPositionEnd(reg2Start, reg2Start, reg2Start + reg2Len);
+    buf.resetPosition();
+    buf.clear();
+    buf.resetPosition();
+    for (int i=reg2Start; i<(reg2Len+reg2Start); i++) {
+      assertEquals(buf.getByte(), zeroByte);
+    }
+    //println(buf.toHexString("Region2 cleared", reg2Start, reg2Len));
+
+    //set all to ones
+    buf.setStartPositionEnd(reg1Start, reg1Start, accessCapacity);
+    byte b4 = 127;
+    buf.resetPosition();
+    buf.fill(b4);
+    buf.resetPosition();
+    for (int i=0; i<accessCapacity; i++) {
+      assertEquals(buf.getByte(), b4);
+    }
+    //println(buf.toHexString("Region1 + Region2 all ones", 0, accessCapacity));
+
+    //clear all
+    buf.resetPosition();
+    buf.clear();
+    buf.resetPosition();
+    for (int i=0; i<accessCapacity; i++) {
+      assertEquals(buf.getByte(), zeroByte);
+    }
+    //println(buf.toHexString("Region1 + Region2 cleared", 0, accessCapacity));
+  }
+
+  @Test
+  public void checkToHexStringAllMem() throws Exception {
+    int memCapacity = 48; //must be 48
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      WritableBuffer buf = mem.asWritableBuffer();
+      assertEquals(buf.getCapacity(), memCapacity);
+      toHexStringAllMemTests(buf); //requires println enabled to visually check
+    }
+  }
+
+  //enable println to visually check
+  public static void toHexStringAllMemTests(WritableBuffer buf) {
+    int memCapacity = (int)buf.getCapacity();
+
+    for (int i=0; i<memCapacity; i++) {
+      buf.putByte((byte)i);
+    }
+
+    //println(buf.toHexString("Check toHexString(0, 48) to integers", 0, memCapacity));
+    //println(buf.toHexString("Check toHexString(8, 40)", 8, 40));
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void println(String s) {
+    //System.out.println(s); //disable here
+  }
+
+}
diff --git a/src/test/java/org/apache/datasketches/memory/CommonMemoryTest.java b/src/test/java/org/apache/datasketches/memory/CommonMemoryTest.java
new file mode 100644
index 0000000..43c3c32
--- /dev/null
+++ b/src/test/java/org/apache/datasketches/memory/CommonMemoryTest.java
@@ -0,0 +1,369 @@
+/*
+ * 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.isAllBitsClear;
+import static org.apache.datasketches.memory.internal.Util.isAllBitsSet;
+import static org.apache.datasketches.memory.internal.Util.isAnyBitsClear;
+import static org.apache.datasketches.memory.internal.Util.isAnyBitsSet;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+public class CommonMemoryTest {
+  private final MemoryRequestServer memReqSvr = new DefaultMemoryRequestServer();
+
+  @Test
+  public void checkSetGet() throws Exception {
+    int memCapacity = 16; //must be at least 8
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      assertEquals(mem.getCapacity(), memCapacity);
+      setGetTests(mem);
+    }
+  }
+
+  public static void setGetTests(WritableMemory mem) {
+
+    mem.putByte(0, (byte) -1);
+    assertEquals(mem.getByte(0), (byte) -1);
+    mem.putByte(0, (byte) 0);
+    assertEquals(mem.getByte(0), (byte) 0);
+
+    mem.putChar(0, 'A');
+    assertEquals(mem.getChar(0), 'A');
+    mem.putChar(0, 'Z');
+    assertEquals(mem.getChar(0), 'Z');
+
+    mem.putShort(0, Short.MAX_VALUE);
+    assertEquals(mem.getShort(0), Short.MAX_VALUE);
+    mem.putShort(0, Short.MIN_VALUE);
+    assertEquals(mem.getShort(0), Short.MIN_VALUE);
+
+    mem.putInt(0, Integer.MAX_VALUE);
+    assertEquals(mem.getInt(0), Integer.MAX_VALUE);
+    mem.putInt(0, Integer.MIN_VALUE);
+    assertEquals(mem.getInt(0), Integer.MIN_VALUE);
+
+    mem.putFloat(0, Float.MAX_VALUE);
+    assertEquals(mem.getFloat(0), Float.MAX_VALUE);
+    mem.putFloat(0, Float.MIN_VALUE);
+    assertEquals(mem.getFloat(0), Float.MIN_VALUE);
+
+    mem.putLong(0, Long.MAX_VALUE);
+    assertEquals(mem.getLong(0), Long.MAX_VALUE);
+    mem.putLong(0, Long.MIN_VALUE);
+    assertEquals(mem.getLong(0), Long.MIN_VALUE);
+
+    mem.putDouble(0, Double.MAX_VALUE);
+    assertEquals(mem.getDouble(0), Double.MAX_VALUE);
+    mem.putDouble(0, Double.MIN_VALUE);
+    assertEquals(mem.getDouble(0), Double.MIN_VALUE);
+  }
+
+  @Test
+  public void checkSetGetArrays() throws Exception {
+    int memCapacity = 32;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      assertEquals(memCapacity, mem.getCapacity());
+      setGetArraysTests(mem);
+    }
+  }
+
+  public static void setGetArraysTests(WritableMemory mem) {
+    int words = 4;
+
+    byte[] srcArray2 = { 1, -2, 3, -4 };
+    byte[] dstArray2 = new byte[4];
+    mem.putByteArray(0, srcArray2, 0, words);
+    mem.getByteArray(0, dstArray2, 0, words);
+    for (int i = 0; i < words; i++) {
+      assertEquals(dstArray2[i], srcArray2[i]);
+    }
+
+    char[] srcArray3 = { 'A', 'B', 'C', 'D' };
+    char[] dstArray3 = new char[words];
+    mem.putCharArray(0, srcArray3, 0, words);
+    mem.getCharArray(0, dstArray3, 0, words);
+    for (int i = 0; i < words; i++) {
+      assertEquals(dstArray3[i], srcArray3[i]);
+    }
+
+    double[] srcArray4 = { 1.0, -2.0, 3.0, -4.0 };
+    double[] dstArray4 = new double[words];
+    mem.putDoubleArray(0, srcArray4, 0, words);
+    mem.getDoubleArray(0, dstArray4, 0, words);
+    for (int i = 0; i < words; i++) {
+      assertEquals(dstArray4[i], srcArray4[i], 0.0);
+    }
+
+    float[] srcArray5 = { (float)1.0, (float)-2.0, (float)3.0, (float)-4.0 };
+    float[] dstArray5 = new float[words];
+    mem.putFloatArray(0, srcArray5, 0, words);
+    mem.getFloatArray(0, dstArray5, 0, words);
+    for (int i = 0; i < words; i++) {
+      assertEquals(dstArray5[i], srcArray5[i], 0.0);
+    }
+
+    int[] srcArray6 = { 1, -2, 3, -4 };
+    int[] dstArray6 = new int[words];
+    mem.putIntArray(0, srcArray6, 0, words);
+    mem.getIntArray(0, dstArray6, 0, words);
+    for (int i = 0; i < words; i++) {
+      assertEquals(dstArray6[i], srcArray6[i]);
+    }
+
+    long[] srcArray7 = { 1, -2, 3, -4 };
+    long[] dstArray7 = new long[words];
+    mem.putLongArray(0, srcArray7, 0, words);
+    mem.getLongArray(0, dstArray7, 0, words);
+    for (int i = 0; i < words; i++) {
+      assertEquals(dstArray7[i], srcArray7[i]);
+    }
+
+    short[] srcArray8 = { 1, -2, 3, -4 };
+    short[] dstArray8 = new short[words];
+    mem.putShortArray(0, srcArray8, 0, words);
+    mem.getShortArray(0, dstArray8, 0, words);
+    for (int i = 0; i < words; i++) {
+      assertEquals(dstArray8[i], srcArray8[i]);
+    }
+  }
+
+  @Test
+  public void checkSetGetPartialArraysWithOffset() throws Exception {
+    int memCapacity = 32;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      assertEquals(memCapacity, mem.getCapacity());
+      setGetPartialArraysWithOffsetTests(mem);
+    }
+  }
+
+  public static void setGetPartialArraysWithOffsetTests(WritableMemory mem) {
+    int items= 4;
+
+    byte[] srcArray2 = { 1, -2, 3, -4 };
+    byte[] dstArray2 = new byte[items];
+    mem.putByteArray(0, srcArray2, 2, items/2);
+    mem.getByteArray(0, dstArray2, 2, items/2);
+    for (int i = 2; i < items; i++) {
+      assertEquals(dstArray2[i], srcArray2[i]);
+    }
+
+    char[] srcArray3 = { 'A', 'B', 'C', 'D' };
+    char[] dstArray3 = new char[items];
+    mem.putCharArray(0, srcArray3, 2, items/2);
+    mem.getCharArray(0, dstArray3, 2, items/2);
+    for (int i = 2; i < items; i++) {
+      assertEquals(dstArray3[i], srcArray3[i]);
+    }
+
+    double[] srcArray4 = { 1.0, -2.0, 3.0, -4.0 };
+    double[] dstArray4 = new double[items];
+    mem.putDoubleArray(0, srcArray4, 2, items/2);
+    mem.getDoubleArray(0, dstArray4, 2, items/2);
+    for (int i = 2; i < items; i++) {
+      assertEquals(dstArray4[i], srcArray4[i], 0.0);
+    }
+
+    float[] srcArray5 = { (float)1.0, (float)-2.0, (float)3.0, (float)-4.0 };
+    float[] dstArray5 = new float[items];
+    mem.putFloatArray(0, srcArray5, 2, items/2);
+    mem.getFloatArray(0, dstArray5, 2, items/2);
+    for (int i = 2; i < items; i++) {
+      assertEquals(dstArray5[i], srcArray5[i], 0.0);
+    }
+
+    int[] srcArray6 = { 1, -2, 3, -4 };
+    int[] dstArray6 = new int[items];
+    mem.putIntArray(0, srcArray6, 2, items/2);
+    mem.getIntArray(0, dstArray6, 2, items/2);
+    for (int i = 2; i < items; i++) {
+      assertEquals(dstArray6[i], srcArray6[i]);
+    }
+
+    long[] srcArray7 = { 1, -2, 3, -4 };
+    long[] dstArray7 = new long[items];
+    mem.putLongArray(0, srcArray7, 2, items/2);
+    mem.getLongArray(0, dstArray7, 2, items/2);
+    for (int i = 2; i < items; i++) {
+      assertEquals(dstArray7[i], srcArray7[i]);
+    }
+
+    short[] srcArray8 = { 1, -2, 3, -4 };
+    short[] dstArray8 = new short[items];
+    mem.putShortArray(0, srcArray8, 2, items/2);
+    mem.getShortArray(0, dstArray8, 2, items/2);
+    for (int i = 2; i < items; i++) {
+      assertEquals(dstArray8[i], srcArray8[i]);
+    }
+  }
+
+  @Test
+  public void checkSetClearIsBits() throws Exception {
+    int memCapacity = 8;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      assertEquals(memCapacity, mem.getCapacity());
+      mem.clear();
+      setClearIsBitsTests(mem);
+    }
+  }
+
+  public static void setClearIsBitsTests(WritableMemory mem) {
+  //single bits
+    for (int i = 0; i < 8; i++) {
+      long bitMask = (1 << i);
+      long v = mem.getByte(0) & 0XFFL;
+      assertTrue(isAnyBitsClear(v, bitMask));
+      mem.setBits(0, (byte) bitMask);
+      v = mem.getByte(0) & 0XFFL;
+      assertTrue(isAnyBitsSet(v, bitMask));
+      mem.clearBits(0, (byte) bitMask);
+      v = mem.getByte(0) & 0XFFL;
+      assertTrue(isAnyBitsClear(v, bitMask));
+    }
+
+    //multiple bits
+    for (int i = 0; i < 7; i++) {
+      long bitMask1 = (1 << i);
+      long bitMask2 = (3 << i);
+      long v = mem.getByte(0) & 0XFFL;
+      assertTrue(isAnyBitsClear(v, bitMask1));
+      assertTrue(isAnyBitsClear(v, bitMask2));
+      mem.setBits(0, (byte) bitMask1); //set one bit
+      v = mem.getByte(0) & 0XFFL;
+      assertTrue(isAnyBitsSet(v, bitMask2));
+      assertTrue(isAnyBitsClear(v, bitMask2));
+      assertFalse(isAllBitsSet(v, bitMask2));
+      assertFalse(isAllBitsClear(v, bitMask2));
+    }
+  }
+
+  @Test
+  public void checkSetClearMemoryRegions() throws Exception {
+    int memCapacity = 64; //must be 64
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+
+      setClearMemoryRegionsTests(mem); //requires println enabled to visually check
+      for (int i = 0; i < memCapacity; i++) {
+        assertEquals(mem.getByte(i), 0);
+      }
+    }
+  }
+
+  //enable println stmts to visually check
+  public static void setClearMemoryRegionsTests(WritableMemory mem) {
+    int accessCapacity = (int)mem.getCapacity();
+
+  //define regions
+    int reg1Start = 0;
+    int reg1Len = 28;
+    int reg2Start = 28;
+    int reg2Len = 32;
+
+    //set region 1
+    byte b1 = 5;
+    mem.fill(reg1Start, reg1Len, b1);
+    for (int i = reg1Start; i < (reg1Len+reg1Start); i++) {
+      assertEquals(mem.getByte(i), b1);
+    }
+    //println(mem.toHexString("Region1 to 5", reg1Start, reg1Len));
+
+    //set region 2
+    byte b2 = 7;
+    mem.fill(reg2Start, reg2Len, b2);
+    //println(mem.toHexString("Fill", 0, (int)mem.getCapacity()));
+    for (int i = reg2Start; i < (reg2Len+reg2Start); i++) {
+      assertEquals(mem.getByte(i), b2);
+    }
+    //println(mem.toHexString("Region2 to 7", reg2Start, reg2Len));
+
+    //clear region 1
+    byte zeroByte = 0;
+    mem.clear(reg1Start, reg1Len);
+    for (int i = reg1Start; i < (reg1Len+reg1Start); i++) {
+      assertEquals(mem.getByte(i), zeroByte);
+    }
+    //println(mem.toHexString("Region1 cleared", reg1Start, reg1Len));
+
+    //clear region 2
+    mem.clear(reg2Start, reg2Len);
+    for (int i = reg2Start; i < (reg2Len+reg2Start); i++) {
+      assertEquals(mem.getByte(i), zeroByte);
+    }
+    //println(mem.toHexString("Region2 cleared", reg2Start, reg2Len));
+
+    //set all to ones
+    byte b4 = 127;
+    mem.fill(b4);
+    for (int i=0; i<accessCapacity; i++) {
+      assertEquals(mem.getByte(i), b4);
+    }
+    //println(mem.toHexString("Region1 + Region2 all ones", 0, accessCapacity));
+
+    //clear all
+    mem.clear();
+    for (int i = 0; i < accessCapacity; i++) {
+      assertEquals(mem.getByte(i), zeroByte);
+    }
+    //println(mem.toHexString("Region1 + Region2 cleared", 0, accessCapacity));
+  }
+
+  @Test
+  public void checkToHexStringAllMem() throws Exception {
+    int memCapacity = 48; //must be 48
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      toHexStringAllMemTests(mem); //requires println enabled to visually check
+    }
+  }
+
+  //enable println to visually check
+  public static void toHexStringAllMemTests(WritableMemory mem) {
+    int memCapacity = (int)mem.getCapacity();
+
+    for (int i = 0; i < memCapacity; i++) {
+      mem.putByte(i, (byte)i);
+    }
+
+    //println(mem.toHexString("Check toHexString(0, 48) to integers", 0, memCapacity));
+    //println(mem.toHexString("Check toHexString(8, 40)", 8, 40));
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void println(String s) {
+    //System.out.println(s); //disable here
+  }
+}
diff --git a/src/test/java/org/apache/datasketches/memory/CopyMemoryOverlapTest.java b/src/test/java/org/apache/datasketches/memory/CopyMemoryOverlapTest.java
new file mode 100644
index 0000000..f89847d
--- /dev/null
+++ b/src/test/java/org/apache/datasketches/memory/CopyMemoryOverlapTest.java
@@ -0,0 +1,184 @@
+/*
+ * 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.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+/**
+ * @author Lee Rhodes
+ */
+public class CopyMemoryOverlapTest {
+
+  @Test
+  public void checkOverlapUsingMemory() throws Exception {
+    long copyLongs = 1 << 20;
+    double overlap = 0.5;
+    long start_mS = System.currentTimeMillis();
+
+    copyUsingDirectMemory(copyLongs, overlap, true);
+    long end1_mS = System.currentTimeMillis();
+
+    copyUsingDirectMemory(copyLongs, overlap, false);
+    long end2_mS = System.currentTimeMillis();
+
+    println("CopyUp Time Sec: " + ((end1_mS - start_mS)/1000.0));
+    println("CopyDn Time Sec: " + ((end2_mS - end1_mS)/1000.0));
+  }
+
+  @Test
+  public void checkOverlapUsingRegions() throws Exception {
+    long copyLongs = 1 << 20;
+    double overlap = 0.5;
+    long start_mS = System.currentTimeMillis();
+
+    copyUsingDirectRegions(copyLongs, overlap, true);
+    long end1_mS = System.currentTimeMillis();
+
+    copyUsingDirectRegions(copyLongs, overlap, false);
+    long end2_mS = System.currentTimeMillis();
+
+    println("CopyUp Time Sec: " + ((end1_mS - start_mS)/1000.0));
+    println("CopyDn Time Sec: " + ((end2_mS - end1_mS)/1000.0));
+  }
+
+  private static final void copyUsingDirectMemory(long copyLongs, double overlap, boolean copyUp) throws Exception {
+    final MemoryRequestServer memReqSvr = new DefaultMemoryRequestServer();
+    println("Copy Using Direct Memory");
+    long overlapLongs = (long) (overlap * copyLongs);
+    long backingLongs = (2 * copyLongs) - overlapLongs;
+
+    long fromOffsetLongs;
+    long toOffsetLongs;
+    //long deltaLongs;
+
+    if (copyUp) {
+      fromOffsetLongs = 0;
+      toOffsetLongs = copyLongs - overlapLongs;
+      //deltaLongs = toOffsetLongs - fromOffsetLongs;
+    } else {
+      fromOffsetLongs = copyLongs - overlapLongs;
+      toOffsetLongs = 0;
+      //deltaLongs = toOffsetLongs - fromOffsetLongs;
+    }
+
+    long backingBytes = backingLongs << 3;
+    long copyBytes = copyLongs << 3;
+    long fromOffsetBytes = fromOffsetLongs << 3;
+    long toOffsetBytes = toOffsetLongs << 3;
+    //long deltaBytes = deltaLongs << 3;
+    println("Copy longs   : " + copyLongs    + "\t bytes: " + copyBytes);
+    println("Overlap      : " + (overlap * 100.0) + "%");
+    println("CopyUp       : " + copyUp);
+    println("Backing longs: " + backingLongs + "\t bytes: " + backingBytes);
+
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory backingMem = WritableMemory.allocateDirect(backingBytes, scope, memReqSvr);
+      fill(backingMem); //fill mem with 0 thru copyLongs -1
+      //listMem(backingMem, "Original");
+      backingMem.copyTo(fromOffsetBytes, backingMem, toOffsetBytes, copyBytes);
+      //listMem(backingMem, "After");
+      checkMemLongs(backingMem, fromOffsetLongs, toOffsetLongs, copyLongs);
+    }
+    println("");
+  }
+
+  private static final void copyUsingDirectRegions(long copyLongs, double overlap, boolean copyUp) throws Exception {
+    final MemoryRequestServer memReqSvr = new DefaultMemoryRequestServer();
+    println("Copy Using Direct Memory");
+    long overlapLongs = (long) (overlap * copyLongs);
+    long backingLongs = (2 * copyLongs) - overlapLongs;
+
+    long fromOffsetLongs;
+    long toOffsetLongs;
+    //long deltaLongs;
+
+    if (copyUp) {
+      fromOffsetLongs = 0;
+      toOffsetLongs = copyLongs - overlapLongs;
+      //deltaLongs = toOffsetLongs - fromOffsetLongs;
+    } else {
+      fromOffsetLongs = copyLongs - overlapLongs;
+      toOffsetLongs = 0;
+      //deltaLongs = toOffsetLongs - fromOffsetLongs;
+    }
+
+    long backingBytes = backingLongs << 3;
+    long copyBytes = copyLongs << 3;
+    long fromOffsetBytes = fromOffsetLongs << 3;
+    long toOffsetBytes = toOffsetLongs << 3;
+    //long deltaBytes = deltaLongs << 3;
+    println("Copy longs   : " + copyLongs    + "\t bytes: " + copyBytes);
+    println("Overlap      : " + (overlap * 100.0) + "%");
+    println("CopyUp       : " + copyUp);
+    println("Backing longs: " + backingLongs + "\t bytes: " + backingBytes);
+
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory backingMem = WritableMemory.allocateDirect(backingBytes, scope, memReqSvr);
+      fill(backingMem); //fill mem with 0 thru copyLongs -1
+      //listMem(backingMem, "Original");
+      WritableMemory reg1 = backingMem.writableRegion(fromOffsetBytes, copyBytes);
+      WritableMemory reg2 = backingMem.writableRegion(toOffsetBytes, copyBytes);
+
+      reg1.copyTo(0, reg2, 0, copyBytes);
+      //listMem(backingMem, "After");
+      checkMemLongs(reg2, fromOffsetLongs, 0, copyLongs);
+    }
+    println("");
+  }
+
+  private static final void fill(WritableMemory wmem) {
+    long longs = wmem.getCapacity() >>> 3;
+    for (long i = 0; i < longs; i++) { wmem.putLong(i << 3, i); } //fill with 0 .. (longs - 1)
+    //checkMemLongs(wmem, 0L, 0L, longs);
+  }
+
+  private static final void checkMemLongs(Memory mem, long fromOffsetLongs, long toOffsetLongs, long copyLongs) {
+    for (long i = 0; i < copyLongs; i++) {
+      long memVal = mem.getLong((toOffsetLongs + i) << 3);
+      assertEquals(memVal, fromOffsetLongs + i);
+    }
+  }
+
+  @SuppressWarnings("unused")
+  private static final void listMem(Memory mem, String comment) {
+    println(comment);
+    println("Idx\tValue");
+    long longs = mem.getCapacity() >>> 3;
+    for (long i = 0; i < longs; i++) {
+      println(i + "\t" + mem.getLong(i << 3));
+    }
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void println(String s) {
+    //System.out.println(s); //disable here
+  }
+}
diff --git a/src/test/java/org/apache/datasketches/memory/CopyMemoryTest.java b/src/test/java/org/apache/datasketches/memory/CopyMemoryTest.java
new file mode 100644
index 0000000..7665b14
--- /dev/null
+++ b/src/test/java/org/apache/datasketches/memory/CopyMemoryTest.java
@@ -0,0 +1,178 @@
+/*
+ * 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.testng.Assert.assertEquals;
+
+import java.util.concurrent.ThreadLocalRandom;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+public class CopyMemoryTest {
+
+  @Test
+  public void heapWSource() {
+    int k1 = 1 << 20; //longs
+    int k2 = 2 * k1;
+    WritableMemory srcMem = genMem(k1, false); //!empty
+    //println(srcMem.toHexString("src: ", 0, k1 << 3));
+    WritableMemory dstMem = genMem(k2, true);
+    srcMem.copyTo(0, dstMem, k1 << 3, k1 << 3);
+    //println(dstMem.toHexString("dst: ", 0, k2 << 3));
+    check(dstMem, k1, k1, 1);
+  }
+
+  @Test
+  public void heapROSource() {
+    int k1 = 1 << 20; //longs
+    int k2 = 2 * k1;
+    Memory srcMem = genMem(k1, false); //!empty
+    WritableMemory dstMem = genMem(k2, true);
+    srcMem.copyTo(0, dstMem, k1 << 3, k1 << 3);
+    check(dstMem, k1, k1, 1);
+  }
+
+  @Test
+  public void directWSource() throws Exception {
+    int k1 = 1 << 20; //longs
+    int k2 = 2 * k1;
+    WritableMemory srcMem = genWmem(k1, false);
+    WritableMemory dstMem = genMem(k2, true);
+    srcMem.copyTo(0, dstMem, k1 << 3, k1 << 3);
+    check(dstMem, k1, k1, 1);
+    srcMem.close();
+  }
+
+  @Test
+  public void directROSource() throws Exception {
+    int k1 = 1 << 20; //longs
+    int k2 = 2 * k1;
+    Memory srcMem = genWmem(k1, false);
+    WritableMemory dstMem = genMem(k2, true);
+    srcMem.copyTo(0, dstMem, k1 << 3, k1 << 3);
+    check(dstMem, k1, k1, 1);
+    srcMem.close();
+  }
+
+  @Test
+  public void heapWSrcRegion() {
+    int k1 = 1 << 20; //longs
+    //gen baseMem of k1 longs w data
+    WritableMemory baseMem = genMem(k1, false); //!empty
+    //gen src region of k1/2 longs, off= k1/2
+    WritableMemory srcReg = baseMem.writableRegion((k1/2) << 3, (k1/2) << 3);
+    WritableMemory dstMem = genMem(2 * k1, true); //empty
+    srcReg.copyTo(0, dstMem, k1 << 3, (k1/2) << 3);
+    //println(dstMem.toHexString("dstMem: ", k1 << 3, (k1/2) << 3));
+    check(dstMem, k1, k1/2, (k1/2) + 1);
+  }
+
+  @Test
+  public void heapROSrcRegion() {
+    int k1 = 1 << 20; //longs
+    //gen baseMem of k1 longs w data
+    WritableMemory baseMem = genMem(k1, false); //!empty
+    //gen src region of k1/2 longs, off= k1/2
+    Memory srcReg = baseMem.region((k1/2) << 3, (k1/2) << 3);
+    WritableMemory dstMem = genMem(2 * k1, true); //empty
+    srcReg.copyTo(0, dstMem, k1 << 3, (k1/2) << 3);
+    check(dstMem, k1, k1/2, (k1/2) + 1);
+  }
+
+  @Test
+  public void directROSrcRegion() throws Exception {
+    int k1 = 1 << 20; //longs
+    //gen baseMem of k1 longs w data, direct
+    Memory baseMem = genWmem(k1, false);
+    //gen src region of k1/2 longs, off= k1/2
+    Memory srcReg = baseMem.region((k1/2) << 3, (k1/2) << 3);
+
+    WritableMemory dstMem = genMem(2 * k1, true); //empty
+    srcReg.copyTo(0, dstMem, k1 << 3, (k1/2) << 3);
+    check(dstMem, k1, k1/2, (k1/2) + 1);
+    baseMem.close();
+  }
+
+  @Test
+  public void testOverlappingCopyLeftToRight() {
+    byte[] bytes = new byte[(((1 << 20) * 5) / 2) + 1];
+    ThreadLocalRandom.current().nextBytes(bytes);
+    byte[] referenceBytes = bytes.clone();
+    Memory referenceMem = Memory.wrap(referenceBytes);
+    WritableMemory mem = WritableMemory.writableWrap(bytes);
+    long copyLen = (1 << 20) * 2;
+    mem.copyTo(0, mem, (1 << 20) / 2, copyLen);
+    Assert.assertEquals(0, mem.compareTo((1 << 20) / 2, copyLen, referenceMem, 0, copyLen));
+  }
+
+  @Test
+  public void testOverlappingCopyRightToLeft() {
+    byte[] bytes = new byte[(((1 << 20) * 5) / 2) + 1];
+    ThreadLocalRandom.current().nextBytes(bytes);
+    byte[] referenceBytes = bytes.clone();
+    Memory referenceMem = Memory.wrap(referenceBytes);
+    WritableMemory mem = WritableMemory.writableWrap(bytes);
+    long copyLen = (1 << 20) * 2;
+    mem.copyTo((1 << 20) / 2, mem, 0, copyLen);
+    Assert.assertEquals(0, mem.compareTo(0, copyLen, referenceMem, (1 << 20) / 2, copyLen));
+  }
+
+  private static void check(Memory mem, int offsetLongs, int lengthLongs, int startValue) {
+    int offBytes = offsetLongs << 3;
+    for (long i = 0; i < lengthLongs; i++) {
+      assertEquals(mem.getLong(offBytes + (i << 3)), i + startValue);
+    }
+  }
+
+  @SuppressWarnings("resource")
+  private static WritableMemory genWmem(int longs, boolean empty) {
+    final MemoryRequestServer memReqSvr = new DefaultMemoryRequestServer();
+    WritableMemory wmem = WritableMemory.allocateDirect(longs << 3, ResourceScope.newConfinedScope(), memReqSvr);
+    if (empty) {
+      wmem.clear();
+    } else {
+      for (int i = 0; i < longs; i++) { wmem.putLong(i << 3, i + 1); }
+    }
+    return wmem;
+  }
+
+  private static WritableMemory genMem(int longs, boolean empty) {
+    WritableMemory mem = WritableMemory.allocate(longs << 3);
+    if (!empty) {
+      for (int i = 0; i < longs; i++) { mem.putLong(i << 3, i + 1); }
+    }
+    return mem;
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void println(String s) {
+    //System.out.println(s); //disable here
+  }
+}
diff --git a/src/test/java/org/apache/datasketches/memory/DruidIssue11544Test.java b/src/test/java/org/apache/datasketches/memory/DruidIssue11544Test.java
new file mode 100644
index 0000000..911606b
--- /dev/null
+++ b/src/test/java/org/apache/datasketches/memory/DruidIssue11544Test.java
@@ -0,0 +1,104 @@
+/*
+ * 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.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.testng.annotations.Test;
+
+/**
+ * The original design provided the MemoryRequestServer callback only for Memory segments allocated via
+ * <i>WritableMemory.allocateDirect(...)</i> calls.  Memory segments allocated via
+ * <i>WritableMemory.wrap(ByteBuffer)</i> did not have this capability.  This was a major oversight since
+ * all off-heap memory in Druid is allocated using ByteBuffers!  It is unusual that no one has
+ * uncovered this until August 2021.  Nonetheless, the fix involves instrumenting all the paths involved
+ * in providing this callback mechanism for wrapped ByteBuffers.
+ *
+ * This issues was first identified in Druid Issue #11544 and then posted as DataSketches-java Issue #358.
+ * But the actual source of the problem was in Memory.
+ *
+ * This test mimics the Druid issue but at a much smaller scale.
+ *
+ * @author Lee Rhodes
+ *
+ */
+public class DruidIssue11544Test {
+
+  @Test
+  public void withByteBuffer() {
+    int initialLongs = 1000;
+    int size1 = initialLongs * 8;
+
+    //Start with a ByteBuffer
+    ByteBuffer bb = ByteBuffer.allocateDirect(size1);
+    bb.order(ByteOrder.nativeOrder());
+
+    //Wrap bb into WritableMemory
+    WritableMemory mem1 = WritableMemory.writableWrap(bb);
+    assertTrue(mem1.isDirect()); //confirm mem1 is off-heap
+
+    MemoryRequestServer svr = mem1.getMemoryRequestServer();
+    if (svr == null) {
+      svr = new DefaultMemoryRequestServer();
+    }
+    assertNotNull(svr);
+
+    //Request Bigger Memory
+    int size2 = size1 * 2;
+    WritableMemory mem2 = svr.request(mem1, size2);
+
+    //Confirm that mem2 is on the heap (the default) and 2X size1
+    assertFalse(mem2.isDirect());
+    assertEquals(mem2.getCapacity(), size2);
+
+    //Move data to new memory
+    mem1.copyTo(0, mem2, 0, size1);
+
+    //Prepare to request deallocation
+    //In the DefaultMemoryRequestServer, this is a no-op, so nothing is actually deallocated.
+    svr.requestClose(mem1, mem2);
+    assertTrue(mem1.isAlive());
+    assertTrue(mem2.isAlive());
+
+    //Now we are on the heap and need to grow again:
+    int size3 = size2 * 2;
+    WritableMemory mem3 = svr.request(mem2, size3);
+
+    //Confirm that mem3 is still on the heap and 2X of size2
+    assertFalse(mem3.isDirect());
+    assertEquals(mem3.getCapacity(), size3);
+
+    //Move data to new memory
+    mem2.copyTo(0, mem3, 0, size2);
+
+    //Prepare to request deallocation
+
+    svr.requestClose(mem2, mem3); //No-op
+    assertTrue(mem2.isAlive());
+    assertTrue(mem3.isAlive());
+  }
+
+}
diff --git a/src/test/java/org/apache/datasketches/memory/ExampleMemoryRequestServerTest.java b/src/test/java/org/apache/datasketches/memory/ExampleMemoryRequestServerTest.java
new file mode 100644
index 0000000..25fa2ee
--- /dev/null
+++ b/src/test/java/org/apache/datasketches/memory/ExampleMemoryRequestServerTest.java
@@ -0,0 +1,136 @@
+/*
+ * 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 java.nio.ByteOrder;
+
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+/**
+ * Examples of how to use the MemoryRequestServer with a memory hungry client.
+ * @author Lee Rhodes
+ */
+public class ExampleMemoryRequestServerTest {
+
+  /**
+   * This version is without a TWR block. All of the memory allocations are done through the MemoryRequestServer
+   * and each is closed by the MemoryClient when it is done with each.
+   * @throws Exception
+   */
+  @SuppressWarnings("resource")
+  @Test
+  public void checkExampleMemoryRequestServer1() throws Exception {
+    int bytes = 8;
+    ExampleMemoryRequestServer svr = new ExampleMemoryRequestServer(true);
+    WritableMemory memStart = null;
+    ResourceScope scope = ResourceScope.newConfinedScope();
+    memStart = WritableMemory.allocateDirect(bytes, 8, scope, ByteOrder.nativeOrder(), svr);
+    MemoryClient client = new MemoryClient(memStart);
+    client.process();
+  }
+
+  /**
+   * This little client is never happy with how much memory it has been allocated and keeps
+   * requesting for more. When it does ask for more, it must copy its old data into the new
+   * memory, release the prior memory, and then continue working from there.
+   *
+   * <p>In reality, these memory requests should be quite rare.</p>
+   */
+  static class MemoryClient {
+    WritableMemory smallMem;
+    MemoryRequestServer svr;
+
+    MemoryClient(WritableMemory memStart) {
+      smallMem = memStart;
+      svr = memStart.getMemoryRequestServer();
+    }
+
+    void process() {
+      long cap1 = smallMem.getCapacity();
+      smallMem.fill((byte) 1);                //fill it, but not big enough
+      println(smallMem.toHexString("Small", 0, (int)cap1, true));
+
+      WritableMemory bigMem = svr.request(smallMem, 2 * cap1); //get bigger mem
+      long cap2 = bigMem.getCapacity();
+      smallMem.copyTo(0, bigMem, 0, cap1);    //copy data from small to big
+      svr.requestClose(smallMem, bigMem);     //done with smallMem, release it, if offheap
+
+      bigMem.fill(cap1, cap1, (byte) 2);      //fill the rest of bigMem, still not big enough
+      println(bigMem.toHexString("Big", 0, (int)cap2, true));
+
+      WritableMemory giantMem = svr.request(bigMem, 2 * cap2); //get giant mem
+      long cap3 = giantMem.getCapacity();
+      bigMem.copyTo(0, giantMem, 0, cap2);    //copy data from small to big
+      svr.requestClose(bigMem, giantMem);     //done with bigMem, release it, if offheap
+
+      giantMem.fill(cap2, cap2, (byte) 3);    //fill the rest of giantMem
+      println(giantMem.toHexString("Giant", 0, (int)cap3, true));
+      svr.requestClose(giantMem, null);       //done with giantMem, release it
+    }
+  }
+
+  /**
+   * This example MemoryRequestServer is simplistic but demonstrates one of many ways to
+   * possibly manage the continuous requests for larger memory.
+   */
+  public static class ExampleMemoryRequestServer implements MemoryRequestServer {
+    final boolean offHeap;
+
+    public ExampleMemoryRequestServer(final boolean offHeap) {
+      this.offHeap = offHeap;
+    }
+
+    @SuppressWarnings("resource")
+    @Override
+    public WritableMemory request(WritableMemory currentWMem, long newCapacityBytes) {
+     ByteOrder order = currentWMem.getTypeByteOrder();
+     WritableMemory wmem;
+     if (offHeap) {
+       wmem = WritableMemory.allocateDirect(newCapacityBytes, 8, ResourceScope.newConfinedScope(), order, this);
+     } else {
+       if (newCapacityBytes > Integer.MAX_VALUE) {
+         throw new IllegalArgumentException("Requested capacity exceeds Integer.MAX_VALUE.");
+       }
+       wmem = WritableMemory.allocate((int)newCapacityBytes, order, this);
+     }
+     return wmem;
+    }
+
+    @Override
+    //here we actually release it, in reality it might be a lot more complex.
+    public void requestClose(WritableMemory memToRelease, WritableMemory newMemory) {
+      memToRelease.close();
+    }
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  /**
+   * @param o value to print
+   */
+  static void println(Object o) {
+    System.out.println(o); //disable here
+  }
+}
diff --git a/src/test/java/org/apache/datasketches/memory/IgnoredArrayOverflowTest.java b/src/test/java/org/apache/datasketches/memory/IgnoredArrayOverflowTest.java
new file mode 100644
index 0000000..bdae1bb
--- /dev/null
+++ b/src/test/java/org/apache/datasketches/memory/IgnoredArrayOverflowTest.java
@@ -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;
+
+import java.nio.ByteOrder;
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+public class IgnoredArrayOverflowTest {
+  private final MemoryRequestServer memReqSvr = new DefaultMemoryRequestServer();
+
+  private WritableMemory memory;
+  private static final long MAX_SIZE = (1L << 10); // use 1L << 31 to test int overrange
+
+  @SuppressWarnings("resource")
+  @BeforeClass
+  public void allocate() {
+    ResourceScope scope = ResourceScope.newConfinedScope();
+    memory = WritableMemory.allocateDirect(MAX_SIZE, 8L, scope, ByteOrder.nativeOrder(), memReqSvr);
+  }
+
+  @AfterClass
+  public void close() throws Exception {
+    memory.close();
+  }
+
+  @Test
+  public void testCharArray() {
+    int size = (int) (memory.getCapacity() / 2);
+    char[] array = new char[size];
+    memory.getCharArray(0, array, 0, size);
+    memory.asBuffer().getCharArray(array, 0, size);
+    memory.putCharArray(0, array, 0, size);
+    memory.asWritableBuffer().putCharArray(array, 0, size);
+  }
+
+  @Test
+  public void testShortArray() {
+    int size = (int) (memory.getCapacity() / 2);
+    short[] array = new short[size];
+    memory.getShortArray(0, array, 0, size);
+    memory.asBuffer().getShortArray(array, 0, size);
+    memory.putShortArray(0, array, 0, size);
+    memory.asWritableBuffer().putShortArray(array, 0, size);
+  }
+
+  @Test
+  public void testIntArray() {
+    int size = (int) (memory.getCapacity() / 4);
+    int[] array = new int[size];
+    memory.getIntArray(0, array, 0, size);
+    memory.asBuffer().getIntArray(array, 0, size);
+    memory.putIntArray(0, array, 0, size);
+    memory.asWritableBuffer().putIntArray(array, 0, size);
+  }
+
+  @Test
+  public void testFloatArray() {
+    int size = (int) (memory.getCapacity() / 4);
+    float[] array = new float[size];
+    memory.getFloatArray(0, array, 0, size);
+    memory.asBuffer().getFloatArray(array, 0, size);
+    memory.putFloatArray(0, array, 0, size);
+    memory.asWritableBuffer().putFloatArray(array, 0, size);
+  }
+
+  @Test
+  public void testLongArray() {
+    int size = (int) (memory.getCapacity() / 8);
+    long[] array = new long[size];
+    memory.getLongArray(0, array, 0, size);
+    memory.asBuffer().getLongArray(array, 0, size);
+    memory.putLongArray(0, array, 0, size);
+    memory.asWritableBuffer().putLongArray(array, 0, size);
+  }
+
+  @Test
+  public void testDoubleArray() {
+    int size = (int) (memory.getCapacity() / 8);
+    double[] array = new double[size];
+    memory.getDoubleArray(0, array, 0, size);
+    memory.asBuffer().getDoubleArray(array, 0, size);
+    memory.putDoubleArray(0, array, 0, size);
+    memory.asWritableBuffer().putDoubleArray(array, 0, size);
+  }
+}
diff --git a/src/test/java/org/apache/datasketches/memory/LeafImplTest.java b/src/test/java/org/apache/datasketches/memory/LeafImplTest.java
new file mode 100644
index 0000000..c397452
--- /dev/null
+++ b/src/test/java/org/apache/datasketches/memory/LeafImplTest.java
@@ -0,0 +1,259 @@
+/*
+ * 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.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+/**
+ * @author Lee Rhodes
+ */
+public class LeafImplTest {
+  private static final ByteOrder NBO = ByteOrder.nativeOrder();
+  private static final ByteOrder NNBO = BaseState.NON_NATIVE_BYTE_ORDER;
+  private static final MemoryRequestServer dummyMemReqSvr = new DummyMemoryRequestServer();
+
+  static class DummyMemoryRequestServer implements MemoryRequestServer {
+    @Override
+    public WritableMemory request(WritableMemory currentWMem, long capacityBytes) { return null; }
+    @Override
+    public void requestClose(WritableMemory memToClose, WritableMemory newMemory) { }
+  }
+
+  public static ByteOrder otherByteOrder(final ByteOrder order) {
+    return (order == ByteOrder.nativeOrder()) ? NNBO : ByteOrder.nativeOrder();
+  }
+
+  @Test
+  public void checkDirectLeafs() throws Exception {
+    long off = 0;
+    long cap = 128;
+    // Off Heap, Native order, No ByteBuffer, has MemReqSvr
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory memNO = WritableMemory.allocateDirect(cap, 8, scope, NBO, dummyMemReqSvr);
+      memNO.putShort(0, (short) 1);
+      assertTrue(memNO.isDirect());
+      checkCombinations(memNO, off, cap, memNO.isDirect(), NBO, false, true);
+    }
+    // Off Heap, Non Native order, No ByteBuffer, has MemReqSvr
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory memNNO = WritableMemory.allocateDirect(cap, 8, scope, NNBO, dummyMemReqSvr);
+      memNNO.putShort(0, (short) 1);
+      assertTrue(memNNO.isDirect());
+      checkCombinations(memNNO, off, cap, memNNO.isDirect(), NNBO, false, true);
+    }
+  }
+
+  @Test
+  public void checkByteBufferLeafs() {
+    long off = 0;
+    long cap = 128;
+    //BB on heap, native order, has ByteBuffer, has MemReqSvr
+    ByteBuffer bb = ByteBuffer.allocate((int)cap);
+    bb.order(NBO);
+    bb.putShort(0, (short) 1);
+    WritableMemory mem = WritableMemory.writableWrap(bb, NBO);
+    assertEquals(bb.isDirect(), mem.isDirect());
+
+    checkCombinations(mem, off, cap, mem.isDirect(), mem.getTypeByteOrder(), true, false);
+
+    //BB off heap, native order, has ByteBuffer, has MemReqSvr
+    ByteBuffer dbb = ByteBuffer.allocateDirect((int)cap);
+    dbb.order(NBO);
+    dbb.putShort(0, (short) 1);
+    mem = WritableMemory.writableWrap(dbb, NBO);
+    assertEquals(dbb.isDirect(), mem.isDirect());
+
+    checkCombinations(mem, off, cap,  mem.isDirect(), mem.getTypeByteOrder(), true, false);
+
+    //BB on heap, non native order, has ByteBuffer, has MemReqSvr
+    bb = ByteBuffer.allocate((int)cap);
+    bb.order(NNBO);
+    bb.putShort(0, (short) 1);
+    mem = WritableMemory.writableWrap(bb, NNBO);
+    assertEquals(bb.isDirect(), mem.isDirect());
+
+    checkCombinations(mem, off, cap, mem.isDirect(), mem.getTypeByteOrder(), true, false);
+
+    //BB off heap, non native order, has ByteBuffer, has MemReqSvr
+    dbb = ByteBuffer.allocateDirect((int)cap);
+    dbb.order(NNBO);
+    dbb.putShort(0, (short) 1);
+    mem = WritableMemory.writableWrap(dbb, NNBO);
+    assertEquals(dbb.isDirect(), mem.isDirect());
+
+    checkCombinations(mem, off, cap,  mem.isDirect(), mem.getTypeByteOrder(), true, false);
+  }
+
+  @Test
+  public void checkMapLeafs() throws Exception {
+    long off = 0;
+    long cap = 128;
+    File file = new File("TestFile2.bin");
+    if (file.exists()) {
+      try {
+        java.nio.file.Files.delete(file.toPath());
+      } catch (IOException e) {
+        throw new RuntimeException(e);
+      }
+    }
+    assertTrue(file.createNewFile());
+    assertTrue(file.setWritable(true, false)); //writable=true, ownerOnly=false
+    assertTrue(file.isFile());
+    file.deleteOnExit();  //comment out if you want to examine the file.
+    // Off Heap, Native order, No ByteBuffer, No MemReqSvr
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory memNO = WritableMemory.writableMap(file, off, cap, scope, NBO);
+      memNO.putShort(0, (short) 1);
+      assertTrue(memNO.isDirect());
+      checkCombinations(memNO, off, cap, memNO.isDirect(), NBO, false, false);
+    }
+    // Off heap, Non Native order, No ByteBuffer, no MemReqSvr
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory memNNO = WritableMemory.writableMap(file, off, cap, scope, NNBO);
+      memNNO.putShort(0, (short) 1);
+      assertTrue(memNNO.isDirect());
+      checkCombinations(memNNO, off, cap, memNNO.isDirect(), NNBO, false, false);
+    }
+  }
+
+  @Test
+  public void checkHeapLeafs() {
+    long off = 0;
+    long cap = 128;
+    // On Heap, Native order, No ByteBuffer, MemReqSvr
+    WritableMemory memNO = WritableMemory.allocate((int)cap, NBO, dummyMemReqSvr); //assumes NBO
+    memNO.putShort(0, (short) 1);
+    assertFalse(memNO.isDirect());
+    checkCombinations(memNO, off, cap, memNO.isDirect(), NBO, false, true);
+
+    // On Heap, Non-native order, No ByteBuffer, MemReqSvr
+    WritableMemory memNNO = WritableMemory.allocate((int)cap, NNBO, dummyMemReqSvr);
+    memNNO.putShort(0, (short) 1);
+    assertFalse(memNNO.isDirect());
+    checkCombinations(memNNO, off, cap, memNNO.isDirect(), NNBO, false, true);
+  }
+
+  private static void checkCombinations(WritableMemory mem, long off, long cap,
+      boolean direct, ByteOrder bo, boolean fromByteBuffer, boolean hasMemReqSvr) {
+    ByteOrder oo = otherByteOrder(bo);
+
+    //### Start with given mem
+    assertEquals(mem.writableRegion(off, cap, bo).getShort(0), 1);
+    assertEquals(mem.writableRegion(off, cap, oo).getShort(0), 256);
+    assertEquals(mem.asWritableBuffer(bo).getShort(0), 1);
+    assertEquals(mem.asWritableBuffer(oo).getShort(0), 256);
+    assertTrue(mem.getTypeByteOrder() == bo);
+
+    if (fromByteBuffer) { assertTrue(mem.hasByteBuffer()); }
+    else { assertFalse(mem.hasByteBuffer()); }
+
+    if (hasMemReqSvr) {
+      assertTrue(mem.hasMemoryRequestServer());
+      assertTrue(mem.getMemoryRequestServer() instanceof DummyMemoryRequestServer);
+    }
+
+    if (direct) {
+      assertTrue(mem.isDirect());
+    } else {
+      assertFalse(mem.isDirect());
+    }
+    assertTrue(mem.isAlive() == true);
+
+    //### Convert to writable buffer
+    WritableBuffer buf = mem.asWritableBuffer();
+
+    assertEquals(buf.writableRegion(off, cap, bo).getShort(0), 1);
+    assertEquals(buf.writableRegion(off, cap, oo).getShort(0), 256);
+    assertEquals(buf.writableDuplicate(bo).getShort(0), 1);
+    assertEquals(buf.writableDuplicate(oo).getShort(0), 256);
+    assertTrue(buf.getTypeByteOrder() == bo);
+
+    if (fromByteBuffer) { assertTrue(buf.hasByteBuffer()); }
+
+    if (hasMemReqSvr) {
+      assertTrue(buf.hasMemoryRequestServer());
+      assertTrue(buf.getMemoryRequestServer() instanceof DummyMemoryRequestServer);
+    }
+
+    if (direct) {
+      assertTrue(buf.isDirect());
+    } else {
+      assertFalse(buf.isDirect());
+    }
+    assertTrue(buf.isAlive() == true);
+
+    //### Convert to non native writable Region
+    WritableMemory nnMem = mem.writableRegion(off, cap, oo);
+
+    assertEquals(nnMem.writableRegion(off, cap, bo).getShort(0), 1);
+    assertEquals(nnMem.writableRegion(off, cap, oo).getShort(0), 256);
+    assertEquals(nnMem.asWritableBuffer(bo).getShort(0), 1);
+    assertEquals(nnMem.asWritableBuffer(oo).getShort(0), 256);
+
+    assertTrue(nnMem.getTypeByteOrder() == oo);
+
+    if (fromByteBuffer) { assertTrue(nnMem.hasByteBuffer()); }
+
+    if (hasMemReqSvr) {
+      assertTrue(nnMem.hasMemoryRequestServer());
+      assertTrue(nnMem.getMemoryRequestServer() instanceof DummyMemoryRequestServer);
+    }
+
+    if (direct) {
+      assertTrue(nnMem.isDirect());
+    } else {
+      assertFalse(nnMem.isDirect());
+    }
+    assertTrue(nnMem.isAlive() == true);
+
+    //### Convert to non native buffer
+    WritableBuffer nnBuf = mem.asWritableBuffer(oo);
+
+    assertEquals(nnBuf.writableRegion(off, cap, bo).getShort(0), 1);
+    assertEquals(nnBuf.writableRegion(off, cap, oo).getShort(0), 256);
+    assertEquals(nnBuf.writableDuplicate(bo).getShort(0), 1);
+    assertEquals(nnBuf.writableDuplicate(oo).getShort(0), 256);
+
+    assertTrue(nnBuf.getTypeByteOrder() == oo);
+
+    if (fromByteBuffer) { assertTrue(nnBuf.hasByteBuffer()); }
+
+    if (hasMemReqSvr) { assertTrue(nnBuf.getMemoryRequestServer() instanceof DummyMemoryRequestServer); }
+
+    if (direct) {
+      assertTrue(nnBuf.isDirect());
+    } else {
+      assertFalse(nnBuf.isDirect());
+    }
+    assertTrue(nnBuf.isAlive() == true);
+  }
+
+}
diff --git a/src/test/java/org/apache/datasketches/memory/UtilTest.java b/src/test/java/org/apache/datasketches/memory/UtilTest.java
new file mode 100644
index 0000000..46bffa4
--- /dev/null
+++ b/src/test/java/org/apache/datasketches/memory/UtilTest.java
@@ -0,0 +1,204 @@
+/*
+ * 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.
+ */
+
+/*
+ * Note: Lincoln's Gettysburg Address is in the public domain. See LICENSE.
+ */
+
+package org.apache.datasketches.memory;
+
+import static org.apache.datasketches.memory.internal.Util.characterPad;
+import static org.apache.datasketches.memory.internal.Util.getResourceBytes;
+import static org.apache.datasketches.memory.internal.Util.getResourceFile;
+import static org.apache.datasketches.memory.internal.Util.negativeCheck;
+import static org.apache.datasketches.memory.internal.Util.nullCheck;
+import static org.apache.datasketches.memory.internal.Util.zeroCheck;
+import static org.apache.datasketches.memory.internal.Util.zeroPad;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.attribute.PosixFileAttributeView;
+import java.nio.file.attribute.PosixFileAttributes;
+import java.nio.file.attribute.PosixFilePermissions;
+
+import org.apache.datasketches.memory.internal.Util;
+import org.testng.annotations.Test;
+
+public class UtilTest {
+  private static final String LS = System.getProperty("line.separator");
+
+  //Binary Search
+  @Test
+  public void checkBinarySearch() {
+    int k = 1024; //longs
+    WritableMemory wMem = WritableMemory.allocate(k << 3); //1024 longs
+    for (int i = 0; i < k; i++) { wMem.putLong(i << 3, i); }
+    long idx = Util.binarySearchLongs(wMem, 0, k - 1, k / 2);
+    long val = wMem.getLong(idx << 3);
+    assertEquals(idx, k/2);
+    assertEquals(val, k/2);
+
+    idx = Util.binarySearchLongs(wMem, 0, k - 1, k);
+    assertEquals(idx, -1024);
+  }
+
+//  @Test(expectedExceptions = IllegalArgumentException.class)
+//  public void checkBoundsTest() {
+//    UnsafeUtil.checkBounds(999, 2, 1000);
+//  }
+
+  @Test
+  public void checkPadding() {
+    String s = "123";
+    String t = zeroPad(s, 4);
+    assertTrue(t.startsWith("0"));
+
+    t = characterPad(s, 4, '0', true);
+    assertTrue(t.endsWith("0"));
+
+    t = characterPad(s, 3, '0', false);
+    assertEquals(s, t);
+  }
+
+  @Test
+  public void checkNullZeroNegativeChecks() {
+    Object obj = null;
+    try {
+      nullCheck(obj, "Test Object");
+      fail();
+    } catch (IllegalArgumentException e) {
+      //OK
+    }
+    try {
+      zeroCheck(0, "Test Long");
+      fail();
+    } catch (IllegalArgumentException e) {
+      //OK
+    }
+    try {
+      negativeCheck(-1L, "Test Long");
+      fail();
+    } catch (IllegalArgumentException e) {
+      //OK
+    }
+  }
+
+  @Test
+  public void checkCodePointArr() {
+    final Util.RandomCodePoints rvcp = new Util.RandomCodePoints(true);
+    final int n = 1000;
+    final int[] cpArr = new int[n];
+    rvcp.fillCodePointArray(cpArr);
+    for (int i = 0; i < n; i++) {
+      int cp = cpArr[i];
+      if ((cp >= Character.MIN_SURROGATE) && (cp <= Character.MAX_SURROGATE)) {
+        fail();
+      }
+    }
+  }
+
+  @Test
+  public void checkCodePoint() {
+    final Util.RandomCodePoints rvcp = new Util.RandomCodePoints(true);
+    final int n = 1000;
+    for (int i = 0; i < n; i++) {
+      int cp = rvcp.getCodePoint();
+      if ((cp >= Character.MIN_SURROGATE) && (cp <= Character.MAX_SURROGATE)) {
+        fail();
+      }
+    }
+  }
+
+  static final String getFileAttributes(File file) {
+    try {
+    PosixFileAttributes attrs = Files.getFileAttributeView(
+        file.toPath(), PosixFileAttributeView.class, new LinkOption[0]).readAttributes();
+    String s = String.format("%s: %s %s %s%n",
+        file.getPath(),
+        attrs.owner().getName(),
+        attrs.group().getName(),
+        PosixFilePermissions.toString(attrs.permissions()));
+    return s;
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  static final void setGettysburgAddressFileToReadOnly() {
+    File file = getResourceFile("GettysburgAddress.txt");
+    try {
+    Files.setPosixFilePermissions(file.toPath(), PosixFilePermissions.fromString("r--r--r--"));
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  //Resources
+
+  @Test
+  public void resourceFileExits() {
+    final String shortFileName = "GettysburgAddress.txt";
+    final File file = getResourceFile(shortFileName);
+    assertTrue(file.exists());
+  }
+
+  @Test(expectedExceptions = NullPointerException.class)
+  public void resourceFileNotFound() {
+    final String shortFileName = "GettysburgAddress.txt";
+    getResourceFile(shortFileName + "123");
+  }
+
+  @Test
+  public void resourceBytesCorrect() {
+    final String shortFileName = "GettysburgAddress.txt";
+    final byte[] bytes = getResourceBytes(shortFileName);
+    assertTrue(bytes.length == 1541);
+  }
+
+  @Test(expectedExceptions = NullPointerException.class)
+  public void resourceBytesFileNotFound() {
+    final String shortFileName = "GettysburgAddress.txt";
+    getResourceBytes(shortFileName + "123");
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  static void println(final Object o) {
+    if (o == null) { print(LS); }
+    else { print(o.toString() + LS); }
+  }
+
+  /**
+   * @param o value to print
+   */
+  static void print(final Object o) {
+    if (o != null) {
+      //System.out.print(o.toString()); //disable here
+    }
+  }
+
+}
diff --git a/src/test/java/org/apache/datasketches/memory/test/ReflectUtil.java b/src/test/java/org/apache/datasketches/memory/test/ReflectUtil.java
new file mode 100644
index 0000000..f57a49c
--- /dev/null
+++ b/src/test/java/org/apache/datasketches/memory/test/ReflectUtil.java
@@ -0,0 +1,399 @@
+/*
+ * 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.test;
+
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.MemoryRequestServer;
+
+public final class ReflectUtil {
+
+  private ReflectUtil() {}
+
+  static final Class<?> BASE_STATE;
+  static final Class<?> BASE_WRITABLE_MEMORY_IMPL;
+  static final Class<?> ALLOCATE_DIRECT_MAP;
+  static final Class<?> NIO_BITS;
+
+  static final Method CHECK_VALID; //BaseStateImpl
+  static final Method GET_DIRECT_ALLOCATIONS_COUNT; //NioBits
+  static final Method GET_MAX_DIRECT_BYTE_BUFFER_MEMORY; //NioBits
+  static final Method GET_NATIVE_BASE_OFFSET; //BaseStateImpl
+  static final Method GET_RESERVED_MEMORY; //NioBits
+  static final Method GET_TOTAL_CAPACITY; //NioBits
+  static final Method GET_UNSAFE_OBJECT; //BaseStateImpl
+  static final Method IS_BB_TYPE; //BaseStateImpl
+  static final Method IS_BUFFER_TYPE; //BaseStateImpl
+  static final Method IS_DIRECT_TYPE; //BaseStateImpl
+  static final Method IS_DUPLICATE_TYPE; //BaseStateImpl
+  static final Method IS_FILE_READ_ONLY; //AllocateDirectMap
+  static final Method IS_HEAP_TYPE; //BaseStateImpl
+  static final Method IS_MAP_TYPE; //BaseStateImpl
+  static final Method IS_NON_NATIVE_TYPE; //BaseStateImpl
+  static final Method IS_PAGE_ALIGHED; //NioBits
+  static final Method IS_READ_ONLY_TYPE; //BaseStateImpl
+  static final Method IS_REGION_TYPE; //BaseStateImpl
+  static final Method PAGE_COUNT; //NioBits
+  static final Method PAGE_SIZE; //NioBits
+  static final Method RESERVE_MEMORY; //NioBits
+  static final Method UNRESERVE_MEMORY; //NioBits
+  static final Method WRAP_DIRECT; //BaseWritableMemoryImpl
+
+  static {
+    BASE_STATE =
+        getClass("org.apache.datasketches.memory.internal.BaseStateImpl");
+    BASE_WRITABLE_MEMORY_IMPL =
+        getClass("org.apache.datasketches.memory.internal.BaseWritableMemoryImpl");
+    ALLOCATE_DIRECT_MAP =
+        getClass("org.apache.datasketches.memory.internal.AllocateDirectMap");
+    NIO_BITS =
+        getClass("org.apache.datasketches.memory.internal.NioBits");
+
+    CHECK_VALID =
+        getMethod(BASE_STATE, "checkValid", (Class<?>[])null); //not static
+    GET_DIRECT_ALLOCATIONS_COUNT =
+        getMethod(NIO_BITS, "getDirectAllocationsCount", (Class<?>[])null); //static
+    GET_MAX_DIRECT_BYTE_BUFFER_MEMORY =
+        getMethod(NIO_BITS, "getMaxDirectByteBufferMemory", (Class<?>[])null); //static
+    GET_NATIVE_BASE_OFFSET =
+        getMethod(BASE_STATE, "getNativeBaseOffset", (Class<?>[])null);
+    GET_RESERVED_MEMORY =
+        getMethod(NIO_BITS, "getReservedMemory", (Class<?>[])null); //static
+    GET_TOTAL_CAPACITY =
+        getMethod(NIO_BITS, "getTotalCapacity", (Class<?>[])null); //static
+    GET_UNSAFE_OBJECT =
+        getMethod(BASE_STATE, "getUnsafeObject", (Class<?>[])null); //not static
+    IS_BB_TYPE =
+        getMethod(BASE_STATE, "isBBType", (Class<?>[])null); //not static
+    IS_BUFFER_TYPE =
+        getMethod(BASE_STATE, "isBufferType", (Class<?>[])null); //not static
+    IS_DIRECT_TYPE =
+        getMethod(BASE_STATE, "isDirectType", (Class<?>[])null); //not static
+    IS_DUPLICATE_TYPE =
+        getMethod(BASE_STATE, "isDuplicateType", (Class<?>[])null); //not static
+    IS_FILE_READ_ONLY =
+        getMethod(ALLOCATE_DIRECT_MAP, "isFileReadOnly", File.class);
+    IS_HEAP_TYPE =
+        getMethod(BASE_STATE, "isHeapType", (Class<?>[])null); //not static
+    IS_MAP_TYPE =
+        getMethod(BASE_STATE, "isMapType", (Class<?>[])null); //not static
+    IS_NON_NATIVE_TYPE =
+        getMethod(BASE_STATE, "isNonNativeType", (Class<?>[])null); //not static
+    IS_PAGE_ALIGHED =
+        getMethod(NIO_BITS, "isPageAligned", (Class<?>[])null); //static
+    IS_READ_ONLY_TYPE =
+        getMethod(BASE_STATE, "isReadOnlyType", (Class<?>[])null); //not static
+    IS_REGION_TYPE =
+        getMethod(BASE_STATE, "isRegionType", (Class<?>[])null); //not static
+    PAGE_COUNT =
+        getMethod(NIO_BITS, "pageCount", long.class); //static
+    PAGE_SIZE =
+        getMethod(NIO_BITS, "pageSize", (Class<?>[])null); //static
+    RESERVE_MEMORY =
+        getMethod(NIO_BITS, "reserveMemory", long.class, long.class); //static
+    UNRESERVE_MEMORY =
+        getMethod(NIO_BITS, "unreserveMemory", long.class, long.class); //static
+    WRAP_DIRECT =
+        getMethod(BASE_WRITABLE_MEMORY_IMPL,
+            "wrapDirect", long.class, ByteOrder.class, MemoryRequestServer.class);  //static method
+  }
+
+  /**
+   * Gets a Class reference to the given class loaded by the SystemClassLoader.
+   * This will work for private, package-private and abstract classes.
+   * @param fullyQualifiedBinaryName the binary name is the name of the class file on disk. This does not instantiate
+   * a concrete class, but allows access to constructors, static fields and static methods.
+   * @return the Class object of the given class.
+   */
+  public static Class<?> getClass(final String fullyQualifiedBinaryName) {
+    try {
+      final ClassLoader scl = ClassLoader.getSystemClassLoader();
+      return scl.loadClass(fullyQualifiedBinaryName);
+    } catch (final ClassNotFoundException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  /**
+   * Gets a declared constructor given the owner class and parameter types
+   * @param ownerClass the Class<?> object of the class loaded by the SystemClassLoader.
+   * @param parameterTypes parameter types for the constructor
+   * @return the constructor
+   */
+  public static Constructor<?> getConstructor(final Class<?> ownerClass, final Class<?>... parameterTypes ) {
+    try {
+      final Constructor<?> ctor = ownerClass.getDeclaredConstructor(parameterTypes);
+      ctor.setAccessible(true);
+      return ctor;
+    } catch (final NoSuchMethodException | SecurityException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  /**
+   * Gets a class instance from its constructor and initializing arguments.
+   * @param constructor the given Constructor
+   * @param initargs the initializing arguments
+   * @return the instantiated class.
+   */
+  public static Object getInstance(final Constructor<?> constructor, final Object... initargs) {
+    try {
+      constructor.setAccessible(true);
+      return constructor.newInstance(initargs);
+    } catch (final InstantiationException | IllegalAccessException | IllegalArgumentException
+          | InvocationTargetException | SecurityException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  /**
+   * Gets a declared field of the given the loaded owner class and field name. The accessible flag will be set true.
+   * @param ownerClass the Class<?> object of the class loaded by the SystemClassLoader.
+   * @param fieldName the desired field name
+   * @return the desired field.
+   */
+  public static Field getField(final Class<?> ownerClass, final String fieldName) {
+    try {
+      final Field field = ownerClass.getDeclaredField(fieldName);
+      field.setAccessible(true);
+      return field;
+    } catch (final NoSuchFieldException | SecurityException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  /**
+   * Gets a field value given the loaded owner class and the Field. The accessible flag will be set true.
+   * @param ownerClass the loaded class owning the field
+   * @param field The Field object
+   * @return the returned value as an object.
+   */
+  public static Object getFieldValue(final Class<?> ownerClass, final Field field) {
+    try {
+      field.setAccessible(true);
+      return field.get(ownerClass);
+    } catch (final IllegalAccessException | SecurityException | IllegalArgumentException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  /**
+   * Gets a declared method of the given the loaded owning class, method name and parameter types.
+   * The accessible flag will be set true.
+   * @param ownerClass the given owner class
+   * @param methodName the given method name
+   * @param parameterTypes the list of parameter types
+   * @return the desired method.
+   */
+  public static Method getMethod(
+      final Class<?> ownerClass, final String methodName, final Class<?>... parameterTypes ) {
+    try {
+      final Method method = (parameterTypes == null)
+          ? ownerClass.getDeclaredMethod(methodName)
+          : ownerClass.getDeclaredMethod(methodName, parameterTypes);
+      method.setAccessible(true);
+      return method;
+    } catch (final NoSuchMethodException | SecurityException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  static void checkValid(final Object target) {
+    try {
+      CHECK_VALID.invoke(target);
+    } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  static long getDirectAllocationsCount() {
+    try {
+      return (long) GET_DIRECT_ALLOCATIONS_COUNT.invoke(null);
+    } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  static long getMaxDirectByteBufferMemory() {
+    try {
+      return (long) GET_MAX_DIRECT_BYTE_BUFFER_MEMORY.invoke(null);
+    } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  static long getNativeBaseOffset(final Object target) {
+    try {
+      return (long) GET_NATIVE_BASE_OFFSET.invoke(target);
+    } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  static long getReservedMemory() {
+    try {
+      return (long) GET_RESERVED_MEMORY.invoke(null);
+    } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  static long getTotalCapacity() {
+    try {
+      return (long) GET_TOTAL_CAPACITY.invoke(null);
+    } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  static Object getUnsafeObject(final Object target) {
+    try {
+      return GET_UNSAFE_OBJECT.invoke(target);
+    } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  static boolean isBBType(final Object target) {
+    try {
+      return (boolean) IS_BB_TYPE.invoke(target);
+    } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  static boolean isBufferType(final Object target) {
+    try {
+      return (boolean) IS_BUFFER_TYPE.invoke(target);
+    } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  static boolean isDirectType(final Object target) {
+    try {
+      return (boolean) IS_DIRECT_TYPE.invoke(target);
+    } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  static boolean isDuplicateType(final Object target) {
+    try {
+      return (boolean) IS_DUPLICATE_TYPE.invoke(target);
+    } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  static boolean isFileReadOnly(final File file) {
+    try {
+      return (boolean) IS_FILE_READ_ONLY.invoke(null, file);
+    } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  static boolean isHeapType(final Object target) {
+    try {
+      return (boolean) IS_HEAP_TYPE.invoke(target);
+    } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  static boolean isMapType(final Object target) {
+    try {
+      return (boolean) IS_MAP_TYPE.invoke(target);
+    } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  static boolean isNonNativeType(final Object target) {
+    try {
+      return (boolean) IS_NON_NATIVE_TYPE.invoke(target);
+    } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  static boolean isPageAligned() {
+    try {
+      return (boolean) IS_PAGE_ALIGHED.invoke(null);
+    } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  static boolean isReadOnlyType(final Object target) {
+    try {
+      return (boolean) IS_READ_ONLY_TYPE.invoke(target);
+    } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  static boolean isRegionType(final Object target) {
+    try {
+      return (boolean) IS_REGION_TYPE.invoke(target);
+    } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  static int pageCount(final long bytes) {
+    try {
+      return (int) PAGE_COUNT.invoke(null, bytes);
+    } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  static int pageSize() {
+    try {
+      return (int) PAGE_SIZE.invoke(null);
+    } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  static void reserveMemory(final long allocationSize, final long capacity) {
+    try {
+     RESERVE_MEMORY.invoke(null, allocationSize, capacity);
+    } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  static void unreserveMemory(final long allocationSize, final long capacity) {
+    try {
+      UNRESERVE_MEMORY.invoke(null, allocationSize, capacity);
+    } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+}
diff --git a/src/test/java/org/apache/datasketches/memory/test/UtilTest.java b/src/test/java/org/apache/datasketches/memory/test/UtilTest.java
new file mode 100644
index 0000000..abe23e4
--- /dev/null
+++ b/src/test/java/org/apache/datasketches/memory/test/UtilTest.java
@@ -0,0 +1,205 @@
+/*
+ * 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.
+ */
+
+/*
+ * Note: Lincoln's Gettysburg Address is in the public domain. See LICENSE.
+ */
+
+package org.apache.datasketches.memory.test;
+
+import static org.apache.datasketches.memory.internal.Util.characterPad;
+import static org.apache.datasketches.memory.internal.Util.getResourceBytes;
+import static org.apache.datasketches.memory.internal.Util.getResourceFile;
+import static org.apache.datasketches.memory.internal.Util.negativeCheck;
+import static org.apache.datasketches.memory.internal.Util.nullCheck;
+import static org.apache.datasketches.memory.internal.Util.zeroCheck;
+import static org.apache.datasketches.memory.internal.Util.zeroPad;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.attribute.PosixFileAttributeView;
+import java.nio.file.attribute.PosixFileAttributes;
+import java.nio.file.attribute.PosixFilePermissions;
+
+import org.apache.datasketches.memory.internal.Util;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+public class UtilTest {
+  private static final String LS = System.getProperty("line.separator");
+
+  //Binary Search
+  @Test
+  public void checkBinarySearch() {
+    int k = 1024; //longs
+    WritableMemory wMem = WritableMemory.allocate(k << 3); //1024 longs
+    for (int i = 0; i < k; i++) { wMem.putLong(i << 3, i); }
+    long idx = Util.binarySearchLongs(wMem, 0, k - 1, k / 2);
+    long val = wMem.getLong(idx << 3);
+    assertEquals(idx, k/2);
+    assertEquals(val, k/2);
+
+    idx = Util.binarySearchLongs(wMem, 0, k - 1, k);
+    assertEquals(idx, -1024);
+  }
+
+//  @Test(expectedExceptions = IllegalArgumentException.class)
+//  public void checkBoundsTest() {
+//    UnsafeUtil.checkBounds(999, 2, 1000);
+//  }
+
+  @Test
+  public void checkPadding() {
+    String s = "123";
+    String t = zeroPad(s, 4);
+    assertTrue(t.startsWith("0"));
+
+    t = characterPad(s, 4, '0', true);
+    assertTrue(t.endsWith("0"));
+
+    t = characterPad(s, 3, '0', false);
+    assertEquals(s, t);
+  }
+
+  @Test
+  public void checkNullZeroNegativeChecks() {
+    Object obj = null;
+    try {
+      nullCheck(obj, "Test Object");
+      fail();
+    } catch (IllegalArgumentException e) {
+      //OK
+    }
+    try {
+      zeroCheck(0, "Test Long");
+      fail();
+    } catch (IllegalArgumentException e) {
+      //OK
+    }
+    try {
+      negativeCheck(-1L, "Test Long");
+      fail();
+    } catch (IllegalArgumentException e) {
+      //OK
+    }
+  }
+
+  @Test
+  public void checkCodePointArr() {
+    final Util.RandomCodePoints rvcp = new Util.RandomCodePoints(true);
+    final int n = 1000;
+    final int[] cpArr = new int[n];
+    rvcp.fillCodePointArray(cpArr);
+    for (int i = 0; i < n; i++) {
+      int cp = cpArr[i];
+      if ((cp >= Character.MIN_SURROGATE) && (cp <= Character.MAX_SURROGATE)) {
+        fail();
+      }
+    }
+  }
+
+  @Test
+  public void checkCodePoint() {
+    final Util.RandomCodePoints rvcp = new Util.RandomCodePoints(true);
+    final int n = 1000;
+    for (int i = 0; i < n; i++) {
+      int cp = rvcp.getCodePoint();
+      if ((cp >= Character.MIN_SURROGATE) && (cp <= Character.MAX_SURROGATE)) {
+        fail();
+      }
+    }
+  }
+
+  static final String getFileAttributes(File file) {
+    try {
+    PosixFileAttributes attrs = Files.getFileAttributeView(
+        file.toPath(), PosixFileAttributeView.class, new LinkOption[0]).readAttributes();
+    String s = String.format("%s: %s %s %s%n",
+        file.getPath(),
+        attrs.owner().getName(),
+        attrs.group().getName(),
+        PosixFilePermissions.toString(attrs.permissions()));
+    return s;
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  static final void setGettysburgAddressFileToReadOnly() {
+    File file = getResourceFile("GettysburgAddress.txt");
+    try {
+    Files.setPosixFilePermissions(file.toPath(), PosixFilePermissions.fromString("r--r--r--"));
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  //Resources
+
+  @Test
+  public void resourceFileExits() {
+    final String shortFileName = "GettysburgAddress.txt";
+    final File file = getResourceFile(shortFileName);
+    assertTrue(file.exists());
+  }
+
+  @Test(expectedExceptions = NullPointerException.class)
+  public void resourceFileNotFound() {
+    final String shortFileName = "GettysburgAddress.txt";
+    getResourceFile(shortFileName + "123");
+  }
+
+  @Test
+  public void resourceBytesCorrect() {
+    final String shortFileName = "GettysburgAddress.txt";
+    final byte[] bytes = getResourceBytes(shortFileName);
+    assertTrue(bytes.length == 1541);
+  }
+
+  @Test(expectedExceptions = NullPointerException.class)
+  public void resourceBytesFileNotFound() {
+    final String shortFileName = "GettysburgAddress.txt";
+    getResourceBytes(shortFileName + "123");
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  static void println(final Object o) {
+    if (o == null) { print(LS); }
+    else { print(o.toString() + LS); }
+  }
+
+  /**
+   * @param o value to print
+   */
+  static void print(final Object o) {
+    if (o != null) {
+      //System.out.print(o.toString()); //disable here
+    }
+  }
+
+}