You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datasketches.apache.org by le...@apache.org on 2022/11/03 21:08:25 UTC

[datasketches-memory] branch refactorInterfaces updated: Made DefaultBufferFactory logic consistent with DefaultMemoryFactory.

This is an automated email from the ASF dual-hosted git repository.

leerho pushed a commit to branch refactorInterfaces
in repository https://gitbox.apache.org/repos/asf/datasketches-memory.git


The following commit(s) were added to refs/heads/refactorInterfaces by this push:
     new 89fada3  Made DefaultBufferFactory logic consistent with DefaultMemoryFactory.
89fada3 is described below

commit 89fada3008c831cf27d71ae52bdae2d9b2cae258
Author: Lee Rhodes <le...@users.noreply.github.com>
AuthorDate: Thu Nov 3 14:08:19 2022 -0700

    Made DefaultBufferFactory logic consistent with DefaultMemoryFactory.
    
    Also reformatted files that used 4 space indent to 2 space indent, which
    is used throughout the library.
---
 .../apache/datasketches/memory/BufferFactory.java  |  96 ++-
 .../datasketches/memory/DefaultBufferFactory.java  |  68 +-
 .../datasketches/memory/DefaultMemoryFactory.java  | 376 ++++-----
 .../apache/datasketches/memory/MemoryFactory.java  | 846 ++++++++++++---------
 .../apache/datasketches/memory/WritableBuffer.java | 740 +++++++++---------
 .../apache/datasketches/memory/internal/Util.java  |  79 +-
 .../memory/internal/IsValidUtf8TestUtil.java       |  15 +-
 .../memory/internal/RandomCodePoints.java          | 136 ++--
 .../datasketches/memory/internal/TestUtils.java    | 397 +++++-----
 .../memory/internal/unsafe/MemoryCleanerTest.java  |  52 +-
 .../memory/internal/unsafe/PrimTest.java           |  25 +-
 .../memory/internal/unsafe/StepBooleanTest.java    |  39 +-
 .../internal/unsafe/VirtualMachineMemoryTest.java  |  20 +-
 tools/scripts/assets/CheckMemoryJar.java           | 212 +++---
 14 files changed, 1634 insertions(+), 1467 deletions(-)

diff --git a/src/main/java/org/apache/datasketches/memory/BufferFactory.java b/src/main/java/org/apache/datasketches/memory/BufferFactory.java
index d41adeb..f2fea4f 100644
--- a/src/main/java/org/apache/datasketches/memory/BufferFactory.java
+++ b/src/main/java/org/apache/datasketches/memory/BufferFactory.java
@@ -25,48 +25,62 @@ import java.nio.ByteOrder;
  * Factory interface for creating various Buffer objects
  */
 public interface BufferFactory {
-    MemoryRequestServer getDefaultMemoryRequestServer();
-    
-    //BYTE BUFFER
-    /**
-     * Accesses the given ByteBuffer for read-only operations. The returned Buffer object has the
-     * same byte order, as the given ByteBuffer.
-     * @param byteBuffer the given ByteBuffer, must not be null.
-     * @return a new Buffer for read-only operations on the given ByteBuffer.
-     */
-    default Buffer wrap(ByteBuffer byteBuffer) {
-      return wrap(byteBuffer, byteBuffer.order());
-    }
 
-    /**
-     * Accesses the given <i>ByteBuffer</i> for write operations. The returned <i>WritableBuffer</i> object has
-     * the same byte order, as the given <i>ByteBuffer</i>.
-     * @param byteBuf the given ByteBuffer. It must be non-null and with capacity &ge; 0.
-     * @return a new <i>WritableBuffer</i> for write operations on the given <i>ByteBuffer</i>.
-     */
-    default WritableBuffer writableWrap(ByteBuffer byteBuf) {
-      return writableWrap(byteBuf, byteBuf.order(), getDefaultMemoryRequestServer());
-    }
+  MemoryRequestServer getMemoryRequestServer();
 
-    /**
-     * Accesses the given ByteBuffer for read-only operations. The returned Buffer object has
-     * the given byte order, ignoring the byte order of the given ByteBuffer.
-     * @param byteBuffer the given ByteBuffer, must not be null
-     * @param byteOrder the byte order to be used, which may be independent of the byte order
-     * state of the given ByteBuffer
-     * @return a new Buffer for read-only operations on the given ByteBuffer.
-     */
-    Buffer wrap(ByteBuffer byteBuffer, ByteOrder byteOrder);
+  // BYTE BUFFER
+  /**
+   * Accesses the given ByteBuffer for read-only operations. The returned Buffer
+   * object has the same byte order, as the given ByteBuffer.
+   *
+   * @param byteBuffer the given ByteBuffer, must not be null.
+   * @return a new Buffer for read-only operations on the given ByteBuffer.
+   */
+  default Buffer wrap(ByteBuffer byteBuffer) {
+    return wrap(byteBuffer, byteBuffer.order());
+  }
 
-    /**
-     * Accesses the given <i>ByteBuffer</i> for write operations. The returned <i>WritableBuffer</i> object has
-     * the given byte order, ignoring the byte order of the given <i>ByteBuffer</i> for future writes and following reads.
-     * However, this does not change the byte order of data already in the <i>ByteBuffer</i>.
-     * @param byteBuf the given ByteBuffer. It must be non-null and with capacity &ge; 0.
-     * @param byteOrder the byte order to be used.
-     * @param memReqSvr A user-specified <i>MemoryRequestServer</i>, which must not be null.
-     * This is a callback mechanism for a user client to request a larger <i>WritableBuffer</i>.
-     * @return a new <i>WritableBuffer</i> for write operations on the given <i>ByteBuffer</i>.
-     */
-    WritableBuffer writableWrap(ByteBuffer byteBuf, ByteOrder byteOrder, MemoryRequestServer memReqSvr);
+  /**
+   * Accesses the given <i>ByteBuffer</i> for write operations. The returned
+   * <i>WritableBuffer</i> object has the same byte order, as the given
+   * <i>ByteBuffer</i>.
+   *
+   * @param byteBuf the given ByteBuffer. It must be non-null and with capacity
+   *                &ge; 0.
+   * @return a new <i>WritableBuffer</i> for write operations on the given
+   *         <i>ByteBuffer</i>.
+   */
+  default WritableBuffer writableWrap(ByteBuffer byteBuf) {
+    return writableWrap(byteBuf, byteBuf.order(), getMemoryRequestServer());
+  }
+
+  /**
+   * Accesses the given ByteBuffer for read-only operations. The returned Buffer
+   * object has the given byte order, ignoring the byte order of the given
+   * ByteBuffer.
+   *
+   * @param byteBuffer the given ByteBuffer, must not be null
+   * @param byteOrder  the byte order to be used, which may be independent of the
+   *                   byte order state of the given ByteBuffer
+   * @return a new Buffer for read-only operations on the given ByteBuffer.
+   */
+  Buffer wrap(ByteBuffer byteBuffer, ByteOrder byteOrder);
+
+  /**
+   * Accesses the given <i>ByteBuffer</i> for write operations. The returned
+   * <i>WritableBuffer</i> object has the given byte order, ignoring the byte
+   * order of the given <i>ByteBuffer</i> for future writes and following reads.
+   * However, this does not change the byte order of data already in the
+   * <i>ByteBuffer</i>.
+   *
+   * @param byteBuf   the given ByteBuffer. It must be non-null and with capacity
+   *                  &ge; 0.
+   * @param byteOrder the byte order to be used.
+   * @param memReqSvr A user-specified <i>MemoryRequestServer</i>, which must not
+   *                  be null. This is a callback mechanism for a user client to
+   *                  request a larger <i>WritableBuffer</i>.
+   * @return a new <i>WritableBuffer</i> for write operations on the given
+   *         <i>ByteBuffer</i>.
+   */
+  WritableBuffer writableWrap(ByteBuffer byteBuf, ByteOrder byteOrder, MemoryRequestServer memReqSvr);
 }
diff --git a/src/main/java/org/apache/datasketches/memory/DefaultBufferFactory.java b/src/main/java/org/apache/datasketches/memory/DefaultBufferFactory.java
index f86335a..4409df9 100644
--- a/src/main/java/org/apache/datasketches/memory/DefaultBufferFactory.java
+++ b/src/main/java/org/apache/datasketches/memory/DefaultBufferFactory.java
@@ -18,49 +18,53 @@
  */
 package org.apache.datasketches.memory;
 
-import org.apache.datasketches.memory.internal.BaseWritableBufferImpl;
+import static org.apache.datasketches.memory.internal.Util.negativeCheck;
 
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.Objects;
 
-import static org.apache.datasketches.memory.internal.Util.negativeCheck;
+import org.apache.datasketches.memory.internal.BaseWritableBufferImpl;
 
 /**
- * 
+ *
  */
 public class DefaultBufferFactory implements BufferFactory {
-    
-    public static final BufferFactory DEFAULT = new DefaultBufferFactory(new DefaultMemoryRequestServer());
-    
-    private final MemoryRequestServer memoryRequestServer;
-    
-    public DefaultBufferFactory(MemoryRequestServer memoryRequestServer) {
-        this.memoryRequestServer = memoryRequestServer;
-    }
-    
-    @Override
-    public Buffer wrap(ByteBuffer byteBuffer, ByteOrder byteOrder) {
-      Objects.requireNonNull(byteBuffer, "byteBuffer must not be null");
-      Objects.requireNonNull(byteOrder, "byteOrder must not be null");
-      negativeCheck(byteBuffer.capacity(), "byteBuffer");
-      return BaseWritableBufferImpl.wrapByteBuffer(byteBuffer, true, byteOrder, null);
-    }
 
-    @Override
-    public WritableBuffer writableWrap(ByteBuffer byteBuf, ByteOrder byteOrder, MemoryRequestServer memReqSvr) {
-      Objects.requireNonNull(byteBuf, "ByteBuffer 'byteBuf' must not be null");
-      Objects.requireNonNull(byteOrder, "ByteOrder 'byteOrder' must not be null");
-      negativeCheck(byteBuf.capacity(), "byteBuf.capacity");
-      if (byteBuf.isReadOnly()) {
-        throw new IllegalArgumentException("Cannot create a WritableBuffer from a ReadOnly ByteBuffer.");
-      }
-      return BaseWritableBufferImpl.wrapByteBuffer(byteBuf, false, byteOrder, memReqSvr);
-    }
+  public static final BufferFactory DEFAULT = new DefaultBufferFactory(new DefaultMemoryRequestServer());
+
+  private final MemoryRequestServer memoryRequestServer;
+
+  public DefaultBufferFactory() {
+    this(DefaultMemoryRequestServer.DEFAULT);
+  }
 
-    @Override
-    public MemoryRequestServer getDefaultMemoryRequestServer() {
-        return memoryRequestServer;
+  public DefaultBufferFactory(MemoryRequestServer memoryRequestServer) {
+    this.memoryRequestServer = memoryRequestServer;
+  }
+
+  @Override
+  public Buffer wrap(ByteBuffer byteBuffer, ByteOrder byteOrder) {
+    Objects.requireNonNull(byteBuffer, "byteBuffer must not be null");
+    Objects.requireNonNull(byteOrder, "byteOrder must not be null");
+    negativeCheck(byteBuffer.capacity(), "byteBuffer");
+    return BaseWritableBufferImpl.wrapByteBuffer(byteBuffer, true, byteOrder, null);
+  }
+
+  @Override
+  public WritableBuffer writableWrap(ByteBuffer byteBuf, ByteOrder byteOrder, MemoryRequestServer memReqSvr) {
+    Objects.requireNonNull(byteBuf, "ByteBuffer 'byteBuf' must not be null");
+    Objects.requireNonNull(byteOrder, "ByteOrder 'byteOrder' must not be null");
+    negativeCheck(byteBuf.capacity(), "byteBuf.capacity");
+    if (byteBuf.isReadOnly()) {
+      throw new IllegalArgumentException("Cannot create a WritableBuffer from a ReadOnly ByteBuffer.");
     }
+    return BaseWritableBufferImpl.wrapByteBuffer(byteBuf, false, byteOrder, memReqSvr);
+  }
+
+  @Override
+  public MemoryRequestServer getMemoryRequestServer() {
+    return memoryRequestServer;
+  }
 
 }
diff --git a/src/main/java/org/apache/datasketches/memory/DefaultMemoryFactory.java b/src/main/java/org/apache/datasketches/memory/DefaultMemoryFactory.java
index e5998c5..efc6f06 100644
--- a/src/main/java/org/apache/datasketches/memory/DefaultMemoryFactory.java
+++ b/src/main/java/org/apache/datasketches/memory/DefaultMemoryFactory.java
@@ -18,201 +18,207 @@
  */
 package org.apache.datasketches.memory;
 
-import org.apache.datasketches.memory.internal.BaseWritableMemoryImpl;
-import org.apache.datasketches.memory.internal.unsafe.Prim;
-import org.apache.datasketches.memory.internal.unsafe.UnsafeUtil;
+import static org.apache.datasketches.memory.internal.Util.negativeCheck;
 
 import java.io.File;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.Objects;
 
-import static org.apache.datasketches.memory.internal.Util.negativeCheck;
+import org.apache.datasketches.memory.internal.BaseWritableMemoryImpl;
+import org.apache.datasketches.memory.internal.unsafe.Prim;
+import org.apache.datasketches.memory.internal.unsafe.UnsafeUtil;
 
 /**
- * 
+ *
  */
 public class DefaultMemoryFactory implements MemoryFactory {
-    
-    public final static MemoryFactory DEFAULT = new DefaultMemoryFactory();
-    
-    private final MemoryRequestServer memoryRequestServer;
-    
-    public DefaultMemoryFactory() {
-        this(DefaultMemoryRequestServer.DEFAULT);
-    }
-    
-    public DefaultMemoryFactory(MemoryRequestServer memoryRequestServer) {
-        this.memoryRequestServer = memoryRequestServer;
-    }
 
-    @Override
-    public Memory wrap(ByteBuffer byteBuffer, ByteOrder byteOrder) {
-        Objects.requireNonNull(byteBuffer, "byteBuffer must not be null");
-        Objects.requireNonNull(byteOrder, "byteOrder must not be null");
-        negativeCheck(byteBuffer.capacity(), "byteBuffer");
-        return BaseWritableMemoryImpl.wrapByteBuffer(byteBuffer, true, byteOrder, null);
-    }
-
-    @Override
-    public WritableMemory writableWrap(ByteBuffer byteBuffer, ByteOrder byteOrder, MemoryRequestServer memReqSvr) {
-        Objects.requireNonNull(byteBuffer, "byteBuffer must be non-null");
-        Objects.requireNonNull(byteOrder, "byteOrder must be non-null");
-        negativeCheck(byteBuffer.capacity(), "byteBuffer");
-        if (byteBuffer.isReadOnly()) { throw new IllegalArgumentException("byteBuffer must be writable."); }
-        return BaseWritableMemoryImpl.wrapByteBuffer(byteBuffer, false, byteOrder, memReqSvr);
-      }
-    
-    @Override
-    public MmapHandle map(File file, long fileOffsetBytes, long capacityBytes, ByteOrder byteOrder) {
-        Objects.requireNonNull(file, "file must be non-null.");
-        Objects.requireNonNull(byteOrder, "byteOrder must be non-null.");
-        if (!file.canRead()) { throw new IllegalArgumentException("file must be readable."); }
-        negativeCheck(fileOffsetBytes, "fileOffsetBytes");
-        negativeCheck(capacityBytes, "capacityBytes");
-        return BaseWritableMemoryImpl.wrapMap(file, fileOffsetBytes, capacityBytes, true, byteOrder);
-    }
-
-    @Override
-    public WritableMmapHandle writableMap(File file, long fileOffsetBytes, long capacityBytes, ByteOrder byteOrder) {
-        Objects.requireNonNull(file, "file must be non-null.");
-        Objects.requireNonNull(byteOrder, "byteOrder must be non-null.");
-        if (!file.canWrite()) { throw new IllegalArgumentException("file must be writable."); }
-        negativeCheck(file.length(), "file.length()");
-        negativeCheck(fileOffsetBytes, "fileOffsetBytes");
-        negativeCheck(capacityBytes, "capacityBytes");
-        return BaseWritableMemoryImpl.wrapMap(file, fileOffsetBytes, capacityBytes, false, byteOrder);
-    }
-    
-    @Override
-    public WritableHandle allocateDirect(long capacityBytes, ByteOrder byteOrder, MemoryRequestServer memReqSvr) {
-        Objects.requireNonNull(byteOrder, "byteOrder must be non-null");
-        negativeCheck(capacityBytes, "capacityBytes");
-        return BaseWritableMemoryImpl.wrapDirect(capacityBytes, byteOrder, memReqSvr);
-    }
-    
-    @Override
-    public Memory wrap(byte[] array, int offsetBytes, int lengthBytes, ByteOrder byteOrder) {
-        Objects.requireNonNull(array, "array must be non-null");
-        Objects.requireNonNull(byteOrder, "byteOrder must be non-null");
-        negativeCheck(offsetBytes, "offsetBytes");
-        negativeCheck(lengthBytes, "lengthBytes");
-        UnsafeUtil.checkBounds(offsetBytes, lengthBytes, array.length);
-        return BaseWritableMemoryImpl.wrapHeapArray(array, 0, lengthBytes, true, ByteOrder.nativeOrder(), null);
-    }
-
-    @Override
-    public WritableMemory writableWrap(byte[] array, int offsetBytes, int lengthBytes, ByteOrder byteOrder,
-            MemoryRequestServer memReqSvr) {
-        Objects.requireNonNull(array, "array must be non-null");
-        Objects.requireNonNull(byteOrder, "byteOrder must be non-null");
-        negativeCheck(offsetBytes, "offsetBytes");
-        negativeCheck(lengthBytes, "lengthBytes");
-        UnsafeUtil.checkBounds(offsetBytes, lengthBytes, array.length);
-        return BaseWritableMemoryImpl.wrapHeapArray(array, offsetBytes, lengthBytes, false, byteOrder, memReqSvr);
-      }
-
-    @Override
-    public Memory wrap(boolean[] array) {
-        Objects.requireNonNull(array, "array must be non-null");
-        final long lengthBytes = array.length << Prim.BOOLEAN.shift();
-        return BaseWritableMemoryImpl.wrapHeapArray(array, 0, lengthBytes, true, ByteOrder.nativeOrder(), null);
-    }
-    
-    @Override
-    public WritableMemory writableWrap(boolean[] array) {
-        Objects.requireNonNull(array, "array must be non-null");
-        final long lengthBytes = array.length << Prim.BOOLEAN.shift();
-        return BaseWritableMemoryImpl.wrapHeapArray(array, 0, lengthBytes, false, ByteOrder.nativeOrder(), null);
-    }
-
-    @Override
-    public Memory wrap(char[] array) {
-        Objects.requireNonNull(array, "array must be non-null");
-        final long lengthBytes = array.length << Prim.CHAR.shift();
-        return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, true, ByteOrder.nativeOrder(), null);
-    }
-    
-    @Override
-    public WritableMemory writableWrap(char[] array) {
-        Objects.requireNonNull(array, "array must be non-null");
-        final long lengthBytes = array.length << Prim.CHAR.shift();
-        return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(), null);
-    }
-
-    @Override
-    public Memory wrap(short[] array) {
-        Objects.requireNonNull(array, "arr must be non-null");
-        final long lengthBytes = array.length << Prim.SHORT.shift();
-        return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, true, ByteOrder.nativeOrder(), null);
-    }
-    
-    @Override
-    public WritableMemory writableWrap(short[] array) {
-        Objects.requireNonNull(array, "arr must be non-null");
-        final long lengthBytes = array.length << Prim.SHORT.shift();
-        return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(), null);
-    }
-    
-    @Override
-    public Memory wrap(int[] array) {
-        Objects.requireNonNull(array, "arr must be non-null");
-        final long lengthBytes = array.length << Prim.INT.shift();
-        return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, true, ByteOrder.nativeOrder(), null);
-    }
-
-    @Override
-    public WritableMemory writableWrap(int[] array) {
-        Objects.requireNonNull(array, "arr must be non-null");
-        final long lengthBytes = array.length << Prim.INT.shift();
-        return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(), null);
-    }
-
-    @Override
-    public Memory wrap(long[] array) {
-        Objects.requireNonNull(array, "arr must be non-null");
-        final long lengthBytes = array.length << Prim.LONG.shift();
-        return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, true, ByteOrder.nativeOrder(), null);
-    }
-
-    @Override
-    public WritableMemory writableWrap(long[] array) {
-        Objects.requireNonNull(array, "arr must be non-null");
-        final long lengthBytes = array.length << Prim.LONG.shift();
-        return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(), null);
-    }
-    
-    @Override
-    public Memory wrap(float[] array) {
-        Objects.requireNonNull(array, "arr must be non-null");
-        final long lengthBytes = array.length << Prim.FLOAT.shift();
-        return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, true, ByteOrder.nativeOrder(), null);
-    }
-    
-    @Override
-    public WritableMemory writableWrap(float[] array) {
-        Objects.requireNonNull(array, "arr must be non-null");
-        final long lengthBytes = array.length << Prim.FLOAT.shift();
-        return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(), null);
-    }
-
-    @Override
-    public Memory wrap(double[] array) {
-        Objects.requireNonNull(array, "arr must be non-null");
-        final long lengthBytes = array.length << Prim.DOUBLE.shift();
-        return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, true, ByteOrder.nativeOrder(), null);
-    }
-    
-    @Override
-    public WritableMemory writableWrap(double[] array) {
-        Objects.requireNonNull(array, "arr must be non-null");
-        final long lengthBytes = array.length << Prim.DOUBLE.shift();
-        return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(), null);
-    }
-
-    @Override
-    public MemoryRequestServer getDefaultMemoryRequestServer() {
-        return memoryRequestServer;
-    }
+  public final static MemoryFactory DEFAULT = new DefaultMemoryFactory();
+
+  private final MemoryRequestServer memoryRequestServer;
+
+  public DefaultMemoryFactory() {
+    this(DefaultMemoryRequestServer.DEFAULT);
+  }
+
+  public DefaultMemoryFactory(MemoryRequestServer memoryRequestServer) {
+    this.memoryRequestServer = memoryRequestServer;
+  }
+
+  @Override
+  public Memory wrap(ByteBuffer byteBuffer, ByteOrder byteOrder) {
+    Objects.requireNonNull(byteBuffer, "byteBuffer must not be null");
+    Objects.requireNonNull(byteOrder, "byteOrder must not be null");
+    negativeCheck(byteBuffer.capacity(), "byteBuffer");
+    return BaseWritableMemoryImpl.wrapByteBuffer(byteBuffer, true, byteOrder, null);
+  }
+
+  @Override
+  public WritableMemory writableWrap(ByteBuffer byteBuffer, ByteOrder byteOrder, MemoryRequestServer memReqSvr) {
+    Objects.requireNonNull(byteBuffer, "byteBuffer must be non-null");
+    Objects.requireNonNull(byteOrder, "byteOrder must be non-null");
+    negativeCheck(byteBuffer.capacity(), "byteBuffer");
+    if (byteBuffer.isReadOnly()) {
+      throw new IllegalArgumentException("byteBuffer must be writable.");
+    }
+    return BaseWritableMemoryImpl.wrapByteBuffer(byteBuffer, false, byteOrder, memReqSvr);
+  }
+
+  @Override
+  public MmapHandle map(File file, long fileOffsetBytes, long capacityBytes, ByteOrder byteOrder) {
+    Objects.requireNonNull(file, "file must be non-null.");
+    Objects.requireNonNull(byteOrder, "byteOrder must be non-null.");
+    if (!file.canRead()) {
+      throw new IllegalArgumentException("file must be readable.");
+    }
+    negativeCheck(fileOffsetBytes, "fileOffsetBytes");
+    negativeCheck(capacityBytes, "capacityBytes");
+    return BaseWritableMemoryImpl.wrapMap(file, fileOffsetBytes, capacityBytes, true, byteOrder);
+  }
+
+  @Override
+  public WritableMmapHandle writableMap(File file, long fileOffsetBytes, long capacityBytes, ByteOrder byteOrder) {
+    Objects.requireNonNull(file, "file must be non-null.");
+    Objects.requireNonNull(byteOrder, "byteOrder must be non-null.");
+    if (!file.canWrite()) {
+      throw new IllegalArgumentException("file must be writable.");
+    }
+    negativeCheck(file.length(), "file.length()");
+    negativeCheck(fileOffsetBytes, "fileOffsetBytes");
+    negativeCheck(capacityBytes, "capacityBytes");
+    return BaseWritableMemoryImpl.wrapMap(file, fileOffsetBytes, capacityBytes, false, byteOrder);
+  }
+
+  @Override
+  public WritableHandle allocateDirect(long capacityBytes, ByteOrder byteOrder, MemoryRequestServer memReqSvr) {
+    Objects.requireNonNull(byteOrder, "byteOrder must be non-null");
+    negativeCheck(capacityBytes, "capacityBytes");
+    return BaseWritableMemoryImpl.wrapDirect(capacityBytes, byteOrder, memReqSvr);
+  }
+
+  @Override
+  public Memory wrap(byte[] array, int offsetBytes, int lengthBytes, ByteOrder byteOrder) {
+    Objects.requireNonNull(array, "array must be non-null");
+    Objects.requireNonNull(byteOrder, "byteOrder must be non-null");
+    negativeCheck(offsetBytes, "offsetBytes");
+    negativeCheck(lengthBytes, "lengthBytes");
+    UnsafeUtil.checkBounds(offsetBytes, lengthBytes, array.length);
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0, lengthBytes, true, ByteOrder.nativeOrder(), null);
+  }
+
+  @Override
+  public WritableMemory writableWrap(byte[] array, int offsetBytes, int lengthBytes, ByteOrder byteOrder,
+      MemoryRequestServer memReqSvr) {
+    Objects.requireNonNull(array, "array must be non-null");
+    Objects.requireNonNull(byteOrder, "byteOrder must be non-null");
+    negativeCheck(offsetBytes, "offsetBytes");
+    negativeCheck(lengthBytes, "lengthBytes");
+    UnsafeUtil.checkBounds(offsetBytes, lengthBytes, array.length);
+    return BaseWritableMemoryImpl.wrapHeapArray(array, offsetBytes, lengthBytes, false, byteOrder, memReqSvr);
+  }
+
+  @Override
+  public Memory wrap(boolean[] array) {
+    Objects.requireNonNull(array, "array must be non-null");
+    final long lengthBytes = array.length << Prim.BOOLEAN.shift();
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0, lengthBytes, true, ByteOrder.nativeOrder(), null);
+  }
+
+  @Override
+  public WritableMemory writableWrap(boolean[] array) {
+    Objects.requireNonNull(array, "array must be non-null");
+    final long lengthBytes = array.length << Prim.BOOLEAN.shift();
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0, lengthBytes, false, ByteOrder.nativeOrder(), null);
+  }
+
+  @Override
+  public Memory wrap(char[] array) {
+    Objects.requireNonNull(array, "array must be non-null");
+    final long lengthBytes = array.length << Prim.CHAR.shift();
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, true, ByteOrder.nativeOrder(), null);
+  }
+
+  @Override
+  public WritableMemory writableWrap(char[] array) {
+    Objects.requireNonNull(array, "array must be non-null");
+    final long lengthBytes = array.length << Prim.CHAR.shift();
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(), null);
+  }
+
+  @Override
+  public Memory wrap(short[] array) {
+    Objects.requireNonNull(array, "arr must be non-null");
+    final long lengthBytes = array.length << Prim.SHORT.shift();
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, true, ByteOrder.nativeOrder(), null);
+  }
+
+  @Override
+  public WritableMemory writableWrap(short[] array) {
+    Objects.requireNonNull(array, "arr must be non-null");
+    final long lengthBytes = array.length << Prim.SHORT.shift();
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(), null);
+  }
+
+  @Override
+  public Memory wrap(int[] array) {
+    Objects.requireNonNull(array, "arr must be non-null");
+    final long lengthBytes = array.length << Prim.INT.shift();
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, true, ByteOrder.nativeOrder(), null);
+  }
+
+  @Override
+  public WritableMemory writableWrap(int[] array) {
+    Objects.requireNonNull(array, "arr must be non-null");
+    final long lengthBytes = array.length << Prim.INT.shift();
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(), null);
+  }
+
+  @Override
+  public Memory wrap(long[] array) {
+    Objects.requireNonNull(array, "arr must be non-null");
+    final long lengthBytes = array.length << Prim.LONG.shift();
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, true, ByteOrder.nativeOrder(), null);
+  }
+
+  @Override
+  public WritableMemory writableWrap(long[] array) {
+    Objects.requireNonNull(array, "arr must be non-null");
+    final long lengthBytes = array.length << Prim.LONG.shift();
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(), null);
+  }
+
+  @Override
+  public Memory wrap(float[] array) {
+    Objects.requireNonNull(array, "arr must be non-null");
+    final long lengthBytes = array.length << Prim.FLOAT.shift();
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, true, ByteOrder.nativeOrder(), null);
+  }
+
+  @Override
+  public WritableMemory writableWrap(float[] array) {
+    Objects.requireNonNull(array, "arr must be non-null");
+    final long lengthBytes = array.length << Prim.FLOAT.shift();
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(), null);
+  }
+
+  @Override
+  public Memory wrap(double[] array) {
+    Objects.requireNonNull(array, "arr must be non-null");
+    final long lengthBytes = array.length << Prim.DOUBLE.shift();
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, true, ByteOrder.nativeOrder(), null);
+  }
+
+  @Override
+  public WritableMemory writableWrap(double[] array) {
+    Objects.requireNonNull(array, "arr must be non-null");
+    final long lengthBytes = array.length << Prim.DOUBLE.shift();
+    return BaseWritableMemoryImpl.wrapHeapArray(array, 0L, lengthBytes, false, ByteOrder.nativeOrder(), null);
+  }
+
+  @Override
+  public MemoryRequestServer getMemoryRequestServer() {
+    return memoryRequestServer;
+  }
 
 }
diff --git a/src/main/java/org/apache/datasketches/memory/MemoryFactory.java b/src/main/java/org/apache/datasketches/memory/MemoryFactory.java
index f00f1a5..7e144d6 100644
--- a/src/main/java/org/apache/datasketches/memory/MemoryFactory.java
+++ b/src/main/java/org/apache/datasketches/memory/MemoryFactory.java
@@ -18,378 +18,494 @@
  */
 package org.apache.datasketches.memory;
 
-import org.apache.datasketches.memory.internal.Util;
-
 import java.io.File;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.Objects;
 
+import org.apache.datasketches.memory.internal.Util;
+
 /**
  * Factory interface for creating various Memory objects
  */
 public interface MemoryFactory {
-    
-    MemoryRequestServer getDefaultMemoryRequestServer();
-    
-    //BYTE BUFFER
-
-    /**
-     * Accesses the given <i>ByteBuffer</i> for read-only operations. The returned <i>Memory</i> object has
-     * the same byte order, as the given <i>ByteBuffer</i>.
-     * @param byteBuffer the given <i>ByteBuffer</i>. It must be non-null and with capacity &ge; 0.
-     * @return a new <i>Memory</i> for read-only operations on the given <i>ByteBuffer</i>.
-     */
-    default Memory wrap(ByteBuffer byteBuffer) {
-      return wrap(byteBuffer, byteBuffer.order());
-    }
-
-    /**
-     * Accesses the given <i>ByteBuffer</i> for write operations. The returned <i>WritableMemory</i> object has
-     * the same byte order, as the given <i>ByteBuffer</i>.
-     * @param byteBuffer the given <i>ByteBuffer</i>. It must be non-null, with capacity &ge; 0, and writable.
-     * @return a new <i>WritableMemory</i> for write operations on the given <i>ByteBuffer</i>.
-     */
-    default WritableMemory writableWrap(ByteBuffer byteBuffer) {
-      return writableWrap(byteBuffer, byteBuffer.order());
-    }
-
-    /**
-     * Accesses the given <i>ByteBuffer</i> for read-only operations. The returned <i>Memory</i> object has
-     * the given byte order, ignoring the byte order of the given <i>ByteBuffer</i> for future reads and writes.
-     * @param byteBuffer the given <i>ByteBuffer</i>. It must be non-null and with capacity &ge; 0.
-     * @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>.
-     */
-    Memory wrap(ByteBuffer byteBuffer, ByteOrder byteOrder);
-
-    /**
-     * Accesses the given <i>ByteBuffer</i> for write operations. The returned <i>WritableMemory</i> object has
-     * the given byte order, ignoring the byte order of the given <i>ByteBuffer</i> for future writes and following reads.
-     * However, this does not change the byte order of data already in the <i>ByteBuffer</i>.
-     * @param byteBuffer the given <i>ByteBuffer</i>. It must be non-null, with capacity &ge; 0, and writable.
-     * @param byteOrder the byte order to be used. It must be non-null.
-     * @return a new <i>WritableMemory</i> for write operations on the given <i>ByteBuffer</i>.
-     */
-    default WritableMemory writableWrap(ByteBuffer byteBuffer, ByteOrder byteOrder) {
-        return writableWrap(byteBuffer, byteOrder, getDefaultMemoryRequestServer());
-    }
-    
-    /**
-     * Accesses the given <i>ByteBuffer</i> for write operations. The returned <i>WritableMemory</i> object has
-     * the given byte order, ignoring the byte order of the given <i>ByteBuffer</i> for future reads and writes.
-     * However, this does not change the byte order of data already in the <i>ByteBuffer</i>.
-     * @param byteBuffer the given <i>ByteBuffer</i>. It must be non-null, with capacity &ge; 0, and writable.
-     * @param byteOrder the byte order to be used. It must be non-null.
-     * @param memReqSvr A user-specified <i>MemoryRequestServer</i>, which may be null.
-     * This is a callback mechanism for a user client to request a larger <i>WritableMemory</i>.
-     * @return a new <i>WritableMemory</i> for write operations on the given <i>ByteBuffer</i>.
-     */
-    WritableMemory writableWrap(ByteBuffer byteBuffer, ByteOrder byteOrder, MemoryRequestServer memReqSvr);
-
-    //MAP
-    /**
-     * Maps the entire given file into native-ordered <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.
-     * @return <i>MmapHandle</i> for managing the mapped memory.
-     * Please read Javadocs for {@link Handle}.
-     */
-    default MmapHandle map(File file) {
-      return map(file, 0, file.length(), ByteOrder.nativeOrder());
-    }
-
-    /**
-     * Maps the entire given file into native-ordered WritableMemory for write operations
-     * Calling this method is equivalent to calling
-     * {@link #writableMap(File, long, long, ByteOrder) writableMap(file, 0, file.length(), ByteOrder.nativeOrder())}.
-     * @param file the given file to map. It must be non-null, with length &ge; 0, and writable.
-     * @return WritableMmapHandle for managing the mapped Memory.
-     * Please read Javadocs for {@link Handle}.
-     */
-    default WritableMmapHandle writableMap(File file) {
-      return writableMap(file, 0, file.length(), 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 and readable.
-     * @param fileOffsetBytes the position in the given file in bytes. It must not be negative.
-     * @param capacityBytes the size of the mapped memory. It must not be negative.
-     * @param byteOrder the byte order to be used for the mapped memory. It must be non-null.
-     * @return <i>MmapHandle</i> for managing the mapped memory.
-     * Please read Javadocs for {@link Handle}.
-     */
-     MmapHandle map(File file, long fileOffsetBytes, long capacityBytes, ByteOrder byteOrder);
-
-     /**
-      * Maps the specified portion of the given file into Memory for write operations.
-      *
-      * <p><b>Note:</b> Always qualify this method with the class name, e.g.,
-      * <i>WritableMemory.map(...)</i>.
-      * @param file the given file to map. It must be non-null, writable and length &ge; 0.
-      * @param fileOffsetBytes the position in the given file in bytes. It must not be negative.
-      * @param capacityBytes the size of the mapped Memory. It must not be negative.
-      * @param byteOrder the byte order to be used for the given file. It must be non-null.
-      * @return WritableMapHandle for managing the mapped Memory.
-      * Please read Javadocs for {@link Handle}.
-      */
-     WritableMmapHandle writableMap(File file, long fileOffsetBytes, long capacityBytes, ByteOrder byteOrder) ;
-     
-     //ALLOCATE HEAP VIA AUTOMATIC BYTE ARRAY
-     /**
-      * Creates on-heap WritableMemory with the given capacity and the native byte order.
-      * @param capacityBytes the given capacity in bytes. It must be &ge; 0.
-      * @return a new WritableMemory for write operations on a new byte array.
-      */
-     default WritableMemory allocate(int capacityBytes) {
-       return allocate(capacityBytes, ByteOrder.nativeOrder());
-     }
-
-     /**
-      * Creates on-heap WritableMemory with the given capacity and the given byte order.
-      * @param capacityBytes the given capacity in bytes. It must be &ge; 0.
-      * @param byteOrder the given byte order to allocate new Memory object with. It must be non-null.
-      * @return a new WritableMemory for write operations on a new byte array.
-      */
-     default WritableMemory allocate(int capacityBytes, ByteOrder byteOrder) {
-       return allocate(capacityBytes, byteOrder, getDefaultMemoryRequestServer());
-     }
-
-     /**
-      * Creates on-heap WritableMemory with the given capacity and the given byte order.
-      * @param capacityBytes the given capacity in bytes. It must be &ge; 0.
-      * @param byteOrder the given byte order to allocate new Memory object with. It must be non-null.
-      * @param memReqSvr A user-specified <i>MemoryRequestServer</i>, which may be null.
-      * This is a callback mechanism for a user client to request a larger <i>WritableMemory</i>.
-      * @return a new WritableMemory for write operations on a new byte array.
-      */
-     default WritableMemory allocate(int capacityBytes, ByteOrder byteOrder, MemoryRequestServer memReqSvr) {
-         final byte[] arr = new byte[capacityBytes];
-         Util.negativeCheck(capacityBytes, "capacityBytes");
-         return writableWrap(arr, 0, capacityBytes, byteOrder, memReqSvr);
-     }
-
-     //ALLOCATE DIRECT
-     /**
-      * Allocates and provides access to capacityBytes directly in native (off-heap) memory.
-      * Native byte order is assumed.
-      * The allocated memory will be 8-byte aligned, but may not be page aligned.
-      *
-      * <p><b>NOTE:</b> Native/Direct memory acquired may have garbage in it.
-      * It is the responsibility of the using application to clear this memory, if required,
-      * and to call <i>close()</i> when done.</p>
-      *
-      * @param capacityBytes the size of the desired memory in bytes. It must be &ge; 0.
-      * @return WritableHandle for this off-heap resource.
-      * Please read Javadocs for {@link Handle}.
-      */
-     default WritableHandle allocateDirect(long capacityBytes) {
-       return allocateDirect(capacityBytes, ByteOrder.nativeOrder(), getDefaultMemoryRequestServer());
-     }
-
-     /**
-      * Allocates and provides access to capacityBytes directly in native (off-heap) memory.
-      * The allocated memory will be 8-byte aligned, but may not be page aligned.
-      *
-      * <p><b>NOTE:</b> Native/Direct memory acquired may have garbage in it.
-      * It is the responsibility of the using application to clear this memory, if required,
-      * and to call <i>close()</i> when done.</p>
-      *
-      * @param capacityBytes the size of the desired memory in bytes. It must be &ge; 0.
-      * @param byteOrder the given byte order. It must be non-null.
-      * @param memReqSvr A user-specified MemoryRequestServer, which may be null.
-      * This is a callback mechanism for a user client of direct memory to request more memory.
-      * @return WritableHandle for this off-heap resource.
-      * Please read Javadocs for {@link Handle}.
-      */
-     WritableHandle allocateDirect(long capacityBytes, ByteOrder byteOrder, MemoryRequestServer memReqSvr);
-     
-    //ACCESS PRIMITIVE HEAP ARRAYS
-    /**
-     * Wraps the given primitive array for read operations assuming native byte order.
-     * @param array the given primitive array.
-     * @return a new <i>Memory</i> for read operations
-     */
-    default Memory wrap(byte[] array) {
-      Objects.requireNonNull(array, "array must be non-null");
-      return wrap(array, 0, array.length, ByteOrder.nativeOrder());
-    }
-
-    /**
-     * Wraps the given primitive array for write operations assuming native byte order.
-     *
-     * <p><b>Note:</b> Always qualify this method with the class name, e.g.,
-     * <i>WritableMemory.wrap(...)</i>.
-     * @param array the given primitive array. It must be non-null.
-     * @return a new WritableMemory for write operations on the given primitive array.
-     */
-    default WritableMemory writableWrap(byte[] array) {
-      return writableWrap(array, 0, array.length, ByteOrder.nativeOrder());
-    }
-
-    /**
-     * Wraps the given primitive array for read operations with the given byte order.
-     * @param array the given primitive array.
-     * @param byteOrder the byte order to be used
-     * @return a new <i>Memory</i> for read operations
-     */
-    default Memory wrap(byte[] array, ByteOrder byteOrder) {
-      return wrap(array, 0, array.length, byteOrder);
-    }
-
-    /**
-     * Wraps the given primitive array for write operations with the given byte order.
-     *
-     * <p><b>Note:</b> Always qualify this method with the class name, e.g.,
-     * <i>WritableMemory.wrap(...)</i>.
-     * @param array the given primitive array. It must be non-null.
-     * @param byteOrder the byte order to be used. It must be non-null.
-     * @return a new WritableMemory for write operations on the given primitive array.
-     */
-    default WritableMemory writableWrap(byte[] array, ByteOrder byteOrder) {
-      return writableWrap(array, 0, array.length, byteOrder, getDefaultMemoryRequestServer());
-    }
-
-    /**
-     * Wraps the given primitive array for read operations with the given byte order.
-     * @param array the given primitive array.
-     * @param offsetBytes the byte offset into the given array
-     * @param lengthBytes the number of bytes to include from the given array
-     * @param byteOrder the byte order to be used
-     * @return a new <i>Memory</i> for read operations
-     */
-    Memory wrap(byte[] array, int offsetBytes, int lengthBytes, ByteOrder byteOrder);
-
-    /**
-     * Wraps the given primitive array for write operations with the given byte order.
-     *
-     * <p><b>Note:</b> Always qualify this method with the class name, e.g.,
-     * <i>WritableMemory.wrap(...)</i>.
-     * @param array the given primitive array. It must be non-null.
-     * @param offsetBytes the byte offset into the given array. It must be &ge; 0.
-     * @param lengthBytes the number of bytes to include from the given array. It must be &ge; 0.
-     * @param byteOrder the byte order to be used. It must be non-null.
-     * @return a new WritableMemory for write operations on the given primitive array.
-     */
-    default WritableMemory writableWrap(byte[] array, int offsetBytes, int lengthBytes, ByteOrder byteOrder) {
-      return writableWrap(array, offsetBytes, lengthBytes, byteOrder, getDefaultMemoryRequestServer());
-    }
-
-    /**
-     * Wraps the given primitive array for write operations with the given byte order. If the given
-     * lengthBytes is zero, backing storage, byte order and read-only status of the returned
-     * WritableMemory object are unspecified.
-     *
-     * <p><b>Note:</b> Always qualify this method with the class name, e.g.,
-     * <i>WritableMemory.wrap(...)</i>.
-     * @param array the given primitive array. It must be non-null.
-     * @param offsetBytes the byte offset into the given array. It must be &ge; 0.
-     * @param lengthBytes the number of bytes to include from the given array. It must be &ge; 0.
-     * @param byteOrder the byte order to be used. It must be non-null.
-     * @param memReqSvr A user-specified <i>MemoryRequestServer</i>, which may be null.
-     * This is a callback mechanism for a user client to request a larger <i>WritableMemory</i>.
-     * @return a new WritableMemory for write operations on the given primitive array.
-     */
-    WritableMemory writableWrap(byte[] array, int offsetBytes, int lengthBytes, ByteOrder byteOrder, 
-            MemoryRequestServer memReqSvr);
-
-    /**
-     * Wraps the given primitive array for read operations assuming native byte order.
-     * @param array the given primitive array.
-     * @return a new <i>Memory</i> for read operations
-     */
-    Memory wrap(boolean[] array);
-
-    /**
-     * Wraps the given primitive array for write operations assuming native byte order.
-     * @param array the given primitive array. It must be non-null.
-     * @return a new WritableMemory for write operations on the given primitive array.
-     */
-    WritableMemory writableWrap(boolean[] array);
-
-    /**
-     * Wraps the given primitive array for read operations assuming native byte order.
-     * @param array the given primitive array.
-     * @return a new <i>Memory</i> for read operations
-     */
-    Memory wrap(char[] array);
-
-    /**
-     * Wraps the given primitive array for write operations assuming native byte order.
-     * @param array the given primitive array.
-     * @return a new WritableMemory for write operations on the given primitive array.
-     */
-    WritableMemory writableWrap(char[] array);
-
-    /**
-     * Wraps the given primitive array for read operations assuming native byte order.
-     * @param array the given primitive array.
-     * @return a new <i>Memory</i> for read operations
-     */
-    Memory wrap(short[] array);
-
-    /**
-     * Wraps the given primitive array for write operations assuming native byte order.
-     * @param array the given primitive array.
-     * @return a new WritableMemory for write operations on the given primitive array.
-     */
-    WritableMemory writableWrap(short[] array);
-
-    /**
-     * Wraps the given primitive array for read operations assuming native byte order.
-     * @param array the given primitive array.
-     * @return a new <i>Memory</i> for read operations
-     */
-    Memory wrap(int[] array);
-
-    /**
-     * Wraps the given primitive array for write operations assuming native byte order.
-     * @param array the given primitive array.
-     * @return a new WritableMemory for write operations on the given primitive array.
-     */
-    WritableMemory writableWrap(int[] array);
-    
-    /**
-     * Wraps the given primitive array for read operations assuming native byte order.
-     * @param array the given primitive array.
-     * @return a new <i>Memory</i> for read operations
-     */
-    Memory wrap(long[] array);
-
-    /**
-     * Wraps the given primitive array for write operations assuming native byte order.
-     * @param array the given primitive array.
-     * @return a new WritableMemory for write operations on the given primitive array.
-     */
-    WritableMemory writableWrap(long[] array);
-
-    /**
-     * Wraps the given primitive array for read operations assuming native byte order.
-     * @param array the given primitive array.
-     * @return a new <i>Memory</i> for read operations
-     */
-    Memory wrap(float[] array);
-
-    /**
-     * Wraps the given primitive array for write operations assuming native byte order.
-     * @param array the given primitive array.
-     * @return a new WritableMemory for write operations on the given primitive array.
-     */
-    WritableMemory writableWrap(float[] array);
-    
-    /**
-     * Wraps the given primitive array for read operations assuming native byte order.
-     * @param array the given primitive array.
-     * @return a new <i>Memory</i> for read operations
-     */
-    Memory wrap(double[] array);
-
-    /**
-     * Wraps the given primitive array for write operations assuming native byte order.
-     * @param array the given primitive array.
-     * @return a new WritableMemory for write operations on the given primitive array.
-     */
-    WritableMemory writableWrap(double[] array);
+
+  MemoryRequestServer getMemoryRequestServer();
+
+  // BYTE BUFFER
+
+  /**
+   * Accesses the given <i>ByteBuffer</i> for read-only operations. The returned
+   * <i>Memory</i> object has the same byte order, as the given <i>ByteBuffer</i>.
+   *
+   * @param byteBuffer the given <i>ByteBuffer</i>. It must be non-null and with
+   *                   capacity &ge; 0.
+   * @return a new <i>Memory</i> for read-only operations on the given
+   *         <i>ByteBuffer</i>.
+   */
+  default Memory wrap(ByteBuffer byteBuffer) {
+    return wrap(byteBuffer, byteBuffer.order());
+  }
+
+  /**
+   * Accesses the given <i>ByteBuffer</i> for write operations. The returned
+   * <i>WritableMemory</i> object has the same byte order, as the given
+   * <i>ByteBuffer</i>.
+   *
+   * @param byteBuffer the given <i>ByteBuffer</i>. It must be non-null, with
+   *                   capacity &ge; 0, and writable.
+   * @return a new <i>WritableMemory</i> for write operations on the given
+   *         <i>ByteBuffer</i>.
+   */
+  default WritableMemory writableWrap(ByteBuffer byteBuffer) {
+    return writableWrap(byteBuffer, byteBuffer.order());
+  }
+
+  /**
+   * Accesses the given <i>ByteBuffer</i> for read-only operations. The returned
+   * <i>Memory</i> object has the given byte order, ignoring the byte order of the
+   * given <i>ByteBuffer</i> for future reads and writes.
+   *
+   * @param byteBuffer the given <i>ByteBuffer</i>. It must be non-null and with
+   *                   capacity &ge; 0.
+   * @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>.
+   */
+  Memory wrap(ByteBuffer byteBuffer, ByteOrder byteOrder);
+
+  /**
+   * Accesses the given <i>ByteBuffer</i> for write operations. The returned
+   * <i>WritableMemory</i> object has the given byte order, ignoring the byte
+   * order of the given <i>ByteBuffer</i> for future writes and following reads.
+   * However, this does not change the byte order of data already in the
+   * <i>ByteBuffer</i>.
+   *
+   * @param byteBuffer the given <i>ByteBuffer</i>. It must be non-null, with
+   *                   capacity &ge; 0, and writable.
+   * @param byteOrder  the byte order to be used. It must be non-null.
+   * @return a new <i>WritableMemory</i> for write operations on the given
+   *         <i>ByteBuffer</i>.
+   */
+  default WritableMemory writableWrap(ByteBuffer byteBuffer, ByteOrder byteOrder) {
+    return writableWrap(byteBuffer, byteOrder, getMemoryRequestServer());
+  }
+
+  /**
+   * Accesses the given <i>ByteBuffer</i> for write operations. The returned
+   * <i>WritableMemory</i> object has the given byte order, ignoring the byte
+   * order of the given <i>ByteBuffer</i> for future reads and writes. However,
+   * this does not change the byte order of data already in the <i>ByteBuffer</i>.
+   *
+   * @param byteBuffer the given <i>ByteBuffer</i>. It must be non-null, with
+   *                   capacity &ge; 0, and writable.
+   * @param byteOrder  the byte order to be used. It must be non-null.
+   * @param memReqSvr  A user-specified <i>MemoryRequestServer</i>, which may be
+   *                   null. This is a callback mechanism for a user client to
+   *                   request a larger <i>WritableMemory</i>.
+   * @return a new <i>WritableMemory</i> for write operations on the given
+   *         <i>ByteBuffer</i>.
+   */
+  WritableMemory writableWrap(ByteBuffer byteBuffer, ByteOrder byteOrder, MemoryRequestServer memReqSvr);
+
+  // MMAP
+  /**
+   * Maps the entire given file into native-ordered <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.
+   * @return <i>MmapHandle</i> for managing the mapped memory. Please read
+   *         Javadocs for {@link Handle}.
+   */
+  default MmapHandle map(File file) {
+    return map(file, 0, file.length(), ByteOrder.nativeOrder());
+  }
+
+  /**
+   * Maps the entire given file into native-ordered WritableMemory for write
+   * operations Calling this method is equivalent to calling
+   * {@link #writableMap(File, long, long, ByteOrder) writableMap(file, 0,
+   * file.length(), ByteOrder.nativeOrder())}.
+   *
+   * @param file the given file to map. It must be non-null, with length &ge; 0,
+   *             and writable.
+   * @return WritableMmapHandle for managing the mapped Memory. Please read
+   *         Javadocs for {@link Handle}.
+   */
+  default WritableMmapHandle writableMap(File file) {
+    return writableMap(file, 0, file.length(), 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 and
+   *                        readable.
+   * @param fileOffsetBytes the position in the given file in bytes. It must not
+   *                        be negative.
+   * @param capacityBytes   the size of the mapped memory. It must not be
+   *                        negative.
+   * @param byteOrder       the byte order to be used for the mapped memory. It
+   *                        must be non-null.
+   * @return <i>MmapHandle</i> for managing the mapped memory. Please read
+   *         Javadocs for {@link Handle}.
+   */
+  MmapHandle map(File file, long fileOffsetBytes, long capacityBytes, ByteOrder byteOrder);
+
+  /**
+   * Maps the specified portion of the given file into Memory for write
+   * operations.
+   *
+   * <p>
+   * <b>Note:</b> Always qualify this method with the class name, e.g.,
+   * <i>WritableMemory.map(...)</i>.
+   *
+   * @param file            the given file to map. It must be non-null, writable
+   *                        and length &ge; 0.
+   * @param fileOffsetBytes the position in the given file in bytes. It must not
+   *                        be negative.
+   * @param capacityBytes   the size of the mapped Memory. It must not be
+   *                        negative.
+   * @param byteOrder       the byte order to be used for the given file. It must
+   *                        be non-null.
+   * @return WritableMapHandle for managing the mapped Memory. Please read
+   *         Javadocs for {@link Handle}.
+   */
+  WritableMmapHandle writableMap(File file, long fileOffsetBytes, long capacityBytes, ByteOrder byteOrder);
+
+  // ALLOCATE HEAP VIA AUTOMATIC BYTE ARRAY
+  /**
+   * Creates on-heap WritableMemory with the given capacity and the native byte
+   * order.
+   *
+   * @param capacityBytes the given capacity in bytes. It must be &ge; 0.
+   * @return a new WritableMemory for write operations on a new byte array.
+   */
+  default WritableMemory allocate(int capacityBytes) {
+    return allocate(capacityBytes, ByteOrder.nativeOrder());
+  }
+
+  /**
+   * Creates on-heap WritableMemory with the given capacity and the given byte
+   * order.
+   *
+   * @param capacityBytes the given capacity in bytes. It must be &ge; 0.
+   * @param byteOrder     the given byte order to allocate new Memory object with.
+   *                      It must be non-null.
+   * @return a new WritableMemory for write operations on a new byte array.
+   */
+  default WritableMemory allocate(int capacityBytes, ByteOrder byteOrder) {
+    return allocate(capacityBytes, byteOrder, getMemoryRequestServer());
+  }
+
+  /**
+   * Creates on-heap WritableMemory with the given capacity and the given byte
+   * order.
+   *
+   * @param capacityBytes the given capacity in bytes. It must be &ge; 0.
+   * @param byteOrder     the given byte order to allocate new Memory object with.
+   *                      It must be non-null.
+   * @param memReqSvr     A user-specified <i>MemoryRequestServer</i>, which may
+   *                      be null. This is a callback mechanism for a user client
+   *                      to request a larger <i>WritableMemory</i>.
+   * @return a new WritableMemory for write operations on a new byte array.
+   */
+  default WritableMemory allocate(int capacityBytes, ByteOrder byteOrder, MemoryRequestServer memReqSvr) {
+    final byte[] arr = new byte[capacityBytes];
+    Util.negativeCheck(capacityBytes, "capacityBytes");
+    return writableWrap(arr, 0, capacityBytes, byteOrder, memReqSvr);
+  }
+
+  // ALLOCATE DIRECT
+  /**
+   * Allocates and provides access to capacityBytes directly in native (off-heap)
+   * memory. Native byte order is assumed. The allocated memory will be 8-byte
+   * aligned, but may not be page aligned.
+   *
+   * <p>
+   * <b>NOTE:</b> Native/Direct memory acquired may have garbage in it. It is the
+   * responsibility of the using application to clear this memory, if required,
+   * and to call <i>close()</i> when done.
+   * </p>
+   *
+   * @param capacityBytes the size of the desired memory in bytes. It must be &ge;
+   *                      0.
+   * @return WritableHandle for this off-heap resource. Please read Javadocs for
+   *         {@link Handle}.
+   */
+  default WritableHandle allocateDirect(long capacityBytes) {
+    return allocateDirect(capacityBytes, ByteOrder.nativeOrder(), getMemoryRequestServer());
+  }
+
+  /**
+   * Allocates and provides access to capacityBytes directly in native (off-heap)
+   * memory. The allocated memory will be 8-byte aligned, but may not be page
+   * aligned.
+   *
+   * <p>
+   * <b>NOTE:</b> Native/Direct memory acquired may have garbage in it. It is the
+   * responsibility of the using application to clear this memory, if required,
+   * and to call <i>close()</i> when done.
+   * </p>
+   *
+   * @param capacityBytes the size of the desired memory in bytes. It must be &ge;
+   *                      0.
+   * @param byteOrder     the given byte order. It must be non-null.
+   * @param memReqSvr     A user-specified MemoryRequestServer, which may be null.
+   *                      This is a callback mechanism for a user client of direct
+   *                      memory to request more memory.
+   * @return WritableHandle for this off-heap resource. Please read Javadocs for
+   *         {@link Handle}.
+   */
+  WritableHandle allocateDirect(long capacityBytes, ByteOrder byteOrder, MemoryRequestServer memReqSvr);
+
+  // ACCESS PRIMITIVE HEAP ARRAYS
+  /**
+   * Wraps the given primitive array for read operations assuming native byte
+   * order.
+   *
+   * @param array the given primitive array.
+   * @return a new <i>Memory</i> for read operations
+   */
+  default Memory wrap(byte[] array) {
+    Objects.requireNonNull(array, "array must be non-null");
+    return wrap(array, 0, array.length, ByteOrder.nativeOrder());
+  }
+
+  /**
+   * Wraps the given primitive array for write operations assuming native byte
+   * order.
+   *
+   * <p>
+   * <b>Note:</b> Always qualify this method with the class name, e.g.,
+   * <i>WritableMemory.wrap(...)</i>.
+   *
+   * @param array the given primitive array. It must be non-null.
+   * @return a new WritableMemory for write operations on the given primitive
+   *         array.
+   */
+  default WritableMemory writableWrap(byte[] array) {
+    return writableWrap(array, 0, array.length, ByteOrder.nativeOrder());
+  }
+
+  /**
+   * Wraps the given primitive array for read operations with the given byte
+   * order.
+   *
+   * @param array     the given primitive array.
+   * @param byteOrder the byte order to be used
+   * @return a new <i>Memory</i> for read operations
+   */
+  default Memory wrap(byte[] array, ByteOrder byteOrder) {
+    return wrap(array, 0, array.length, byteOrder);
+  }
+
+  /**
+   * Wraps the given primitive array for write operations with the given byte
+   * order.
+   *
+   * <p>
+   * <b>Note:</b> Always qualify this method with the class name, e.g.,
+   * <i>WritableMemory.wrap(...)</i>.
+   *
+   * @param array     the given primitive array. It must be non-null.
+   * @param byteOrder the byte order to be used. It must be non-null.
+   * @return a new WritableMemory for write operations on the given primitive
+   *         array.
+   */
+  default WritableMemory writableWrap(byte[] array, ByteOrder byteOrder) {
+    return writableWrap(array, 0, array.length, byteOrder, getMemoryRequestServer());
+  }
+
+  /**
+   * Wraps the given primitive array for read operations with the given byte
+   * order.
+   *
+   * @param array       the given primitive array.
+   * @param offsetBytes the byte offset into the given array
+   * @param lengthBytes the number of bytes to include from the given array
+   * @param byteOrder   the byte order to be used
+   * @return a new <i>Memory</i> for read operations
+   */
+  Memory wrap(byte[] array, int offsetBytes, int lengthBytes, ByteOrder byteOrder);
+
+  /**
+   * Wraps the given primitive array for write operations with the given byte
+   * order.
+   *
+   * <p>
+   * <b>Note:</b> Always qualify this method with the class name, e.g.,
+   * <i>WritableMemory.wrap(...)</i>.
+   *
+   * @param array       the given primitive array. It must be non-null.
+   * @param offsetBytes the byte offset into the given array. It must be &ge; 0.
+   * @param lengthBytes the number of bytes to include from the given array. It
+   *                    must be &ge; 0.
+   * @param byteOrder   the byte order to be used. It must be non-null.
+   * @return a new WritableMemory for write operations on the given primitive
+   *         array.
+   */
+  default WritableMemory writableWrap(byte[] array, int offsetBytes, int lengthBytes, ByteOrder byteOrder) {
+    return writableWrap(array, offsetBytes, lengthBytes, byteOrder, getMemoryRequestServer());
+  }
+
+  /**
+   * Wraps the given primitive array for write operations with the given byte
+   * order. If the given lengthBytes is zero, backing storage, byte order and
+   * read-only status of the returned WritableMemory object are unspecified.
+   *
+   * <p>
+   * <b>Note:</b> Always qualify this method with the class name, e.g.,
+   * <i>WritableMemory.wrap(...)</i>.
+   *
+   * @param array       the given primitive array. It must be non-null.
+   * @param offsetBytes the byte offset into the given array. It must be &ge; 0.
+   * @param lengthBytes the number of bytes to include from the given array. It
+   *                    must be &ge; 0.
+   * @param byteOrder   the byte order to be used. It must be non-null.
+   * @param memReqSvr   A user-specified <i>MemoryRequestServer</i>, which may be
+   *                    null. This is a callback mechanism for a user client to
+   *                    request a larger <i>WritableMemory</i>.
+   * @return a new WritableMemory for write operations on the given primitive
+   *         array.
+   */
+  WritableMemory writableWrap(byte[] array, int offsetBytes, int lengthBytes, ByteOrder byteOrder,
+      MemoryRequestServer memReqSvr);
+
+  /**
+   * Wraps the given primitive array for read operations assuming native byte
+   * order.
+   *
+   * @param array the given primitive array.
+   * @return a new <i>Memory</i> for read operations
+   */
+  Memory wrap(boolean[] array);
+
+  /**
+   * Wraps the given primitive array for write operations assuming native byte
+   * order.
+   *
+   * @param array the given primitive array. It must be non-null.
+   * @return a new WritableMemory for write operations on the given primitive
+   *         array.
+   */
+  WritableMemory writableWrap(boolean[] array);
+
+  /**
+   * Wraps the given primitive array for read operations assuming native byte
+   * order.
+   *
+   * @param array the given primitive array.
+   * @return a new <i>Memory</i> for read operations
+   */
+  Memory wrap(char[] array);
+
+  /**
+   * Wraps the given primitive array for write operations assuming native byte
+   * order.
+   *
+   * @param array the given primitive array.
+   * @return a new WritableMemory for write operations on the given primitive
+   *         array.
+   */
+  WritableMemory writableWrap(char[] array);
+
+  /**
+   * Wraps the given primitive array for read operations assuming native byte
+   * order.
+   *
+   * @param array the given primitive array.
+   * @return a new <i>Memory</i> for read operations
+   */
+  Memory wrap(short[] array);
+
+  /**
+   * Wraps the given primitive array for write operations assuming native byte
+   * order.
+   *
+   * @param array the given primitive array.
+   * @return a new WritableMemory for write operations on the given primitive
+   *         array.
+   */
+  WritableMemory writableWrap(short[] array);
+
+  /**
+   * Wraps the given primitive array for read operations assuming native byte
+   * order.
+   *
+   * @param array the given primitive array.
+   * @return a new <i>Memory</i> for read operations
+   */
+  Memory wrap(int[] array);
+
+  /**
+   * Wraps the given primitive array for write operations assuming native byte
+   * order.
+   *
+   * @param array the given primitive array.
+   * @return a new WritableMemory for write operations on the given primitive
+   *         array.
+   */
+  WritableMemory writableWrap(int[] array);
+
+  /**
+   * Wraps the given primitive array for read operations assuming native byte
+   * order.
+   *
+   * @param array the given primitive array.
+   * @return a new <i>Memory</i> for read operations
+   */
+  Memory wrap(long[] array);
+
+  /**
+   * Wraps the given primitive array for write operations assuming native byte
+   * order.
+   *
+   * @param array the given primitive array.
+   * @return a new WritableMemory for write operations on the given primitive
+   *         array.
+   */
+  WritableMemory writableWrap(long[] array);
+
+  /**
+   * Wraps the given primitive array for read operations assuming native byte
+   * order.
+   *
+   * @param array the given primitive array.
+   * @return a new <i>Memory</i> for read operations
+   */
+  Memory wrap(float[] array);
+
+  /**
+   * Wraps the given primitive array for write operations assuming native byte
+   * order.
+   *
+   * @param array the given primitive array.
+   * @return a new WritableMemory for write operations on the given primitive
+   *         array.
+   */
+  WritableMemory writableWrap(float[] array);
+
+  /**
+   * Wraps the given primitive array for read operations assuming native byte
+   * order.
+   *
+   * @param array the given primitive array.
+   * @return a new <i>Memory</i> for read operations
+   */
+  Memory wrap(double[] array);
+
+  /**
+   * Wraps the given primitive array for write operations assuming native byte
+   * order.
+   *
+   * @param array the given primitive array.
+   * @return a new WritableMemory for write operations on the given primitive
+   *         array.
+   */
+  WritableMemory writableWrap(double[] array);
 }
diff --git a/src/main/java/org/apache/datasketches/memory/WritableBuffer.java b/src/main/java/org/apache/datasketches/memory/WritableBuffer.java
index d79570c..a749f53 100644
--- a/src/main/java/org/apache/datasketches/memory/WritableBuffer.java
+++ b/src/main/java/org/apache/datasketches/memory/WritableBuffer.java
@@ -25,371 +25,377 @@ import java.nio.ByteOrder;
  * Defines the writable API for relative positional access to a resource
  */
 public interface WritableBuffer extends Buffer {
-    // DUPLICATES
-    /**
-     * Returns a duplicate writable view of this Buffer with the same but independent values of
-     * <i>start</i>, <i>position</i> and <i>end</i>.
-     * <ul>
-     * <li>Returned object's origin = this object's origin</li>
-     * <li>Returned object's <i>start</i> = this object's <i>start</i></li>
-     * <li>Returned object's <i>position</i> = this object's <i>position</i></li>
-     * <li>Returned object's <i>end</i> = this object's <i>end</i></li>
-     * <li>Returned object's <i>capacity</i> = this object' <i>capacityBytes</i></li>
-     * <li>Returned object's <i>start</i>, <i>position</i> and <i>end</i> are mutable and
-     * independent of this object's <i>start</i>, <i>position</i> and <i>end</i></li>
-     * </ul>
-     * 
-     * @return a duplicate writable view of this Buffer with the same but independent values of
-     *         <i>start</i>, <i>position</i> and <i>end</i>.
-     */
-    WritableBuffer writableDuplicate();
-
-    /**
-     * Returns a duplicate writable view of this Buffer with the same but independent values of
-     * <i>start</i>, <i>position</i> and <i>end</i>, but with the specified byteOrder.
-     * <ul>
-     * <li>Returned object's origin = this object's origin</li>
-     * <li>Returned object's <i>start</i> = this object's <i>start</i></li>
-     * <li>Returned object's <i>position</i> = this object's <i>position</i></li>
-     * <li>Returned object's <i>end</i> = this object's <i>end</i></li>
-     * <li>Returned object's <i>capacity</i> = this object' <i>capacityBytes</i></li>
-     * <li>Returned object's <i>start</i>, <i>position</i> and <i>end</i> are mutable and
-     * independent of this object's <i>start</i>, <i>position</i> and <i>end</i></li>
-     * </ul>
-     * 
-     * @param byteOrder the given <i>ByteOrder</i>.
-     * @return a duplicate writable view of this Buffer with the same but independent values of
-     *         <i>start</i>, <i>position</i> and <i>end</i>.
-     */
-    WritableBuffer writableDuplicate(ByteOrder byteOrder);
-
-    // REGIONS
-    /**
-     * A writable region is a writable view of this object.
-     * <ul>
-     * <li>Returned object's origin = this object's <i>position</i></li>
-     * <li>Returned object's <i>start</i> = 0</li>
-     * <li>Returned object's <i>position</i> = 0</li>
-     * <li>Returned object's <i>end</i> = this object's (<i>end</i> - <i>position</i>)</li>
-     * <li>Returned object's <i>capacity</i> = this object's (<i>end</i> - <i>position</i>)</li>
-     * <li>Returned object's <i>start</i>, <i>position</i> and <i>end</i> are mutable and
-     * independent of this object's <i>start</i>, <i>position</i> and <i>end</i></li>
-     * </ul>
-     * 
-     * @return a new <i>WritableBuffer</i> representing the defined writable region.
-     */
-    WritableBuffer writableRegion();
-
-    /**
-     * A writable region is a writable view of this object.
-     * <ul>
-     * <li>Returned object's origin = this objects' origin + <i>offsetBytes</i></li>
-     * <li>Returned object's <i>start</i> = 0</li>
-     * <li>Returned object's <i>position</i> = 0</li>
-     * <li>Returned object's <i>end</i> = <i>capacityBytes</i></li>
-     * <li>Returned object's <i>capacity</i> = <i>capacityBytes</i></li>
-     * <li>Returned object's <i>start</i>, <i>position</i> and <i>end</i> are mutable and
-     * independent of this object's <i>start</i>, <i>position</i> and <i>end</i></li>
-     * <li>Returned object's byte order = <i>byteOrder</i></li>
-     * </ul>
-     *
-     * <p>
-     * <b>Note: </b><i>asWritableMemory()</i> and <i>asMemory()</i>
-     * will return the originating <i>Memory</i> byte order.
-     * </p>
-     * 
-     * @param offsetBytes the starting offset with respect to the origin of this <i>WritableBuffer</i>
-     * @param capacityBytes the <i>capacity</i> of the returned region in bytes
-     * @param byteOrder the given byte order
-     * @return a new <i>WritableBuffer</i> representing the defined writable region
-     *         with the given offsetBytes, capacityBytes and byte order.
-     */
-    WritableBuffer writableRegion(long offsetBytes, long capacityBytes, ByteOrder byteOrder);
-
-    // AS WRITABLE MEMORY
-    /**
-     * Convert this WritableBuffer to a WritableMemory.
-     * If this object's capacity is zero, the returned object is effectively immutable and
-     * the backing storage and byte order are unspecified.
-     * 
-     * @return WritableMemory
-     */
-    default WritableMemory asWritableMemory() {
-        return asWritableMemory(ByteOrder.nativeOrder());
-    }
-
-    /**
-     * Convert this WritableBuffer to a WritableMemory with the given byte order.
-     * If this object's capacity is zero, the returned object is effectively immutable and
-     * the backing storage and byte order are unspecified.
-     * 
-     * @param byteOrder the byte order to be used.
-     * @return WritableMemory
-     */
-    WritableMemory asWritableMemory(ByteOrder byteOrder);
-
-    // NO ALLOCATE HEAP VIA AUTOMATIC BYTE ARRAY
-
-    // NO ACCESS PRIMITIVE HEAP ARRAYS for WRITE
-
-    // PRIMITIVE putX() and putXArray()
-    /**
-     * Puts the boolean value at the current position.
-     * Increments the position by 1.
-     * 
-     * @param value the value to put
-     */
-    void putBoolean(boolean value);
-
-    /**
-     * Puts the boolean value at the given offset.
-     * This does not change the position.
-     * 
-     * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start.
-     * @param value the value to put
-     */
-    void putBoolean(long offsetBytes, boolean value);
-
-    /**
-     * Puts the boolean array at the current position.
-     * Increments the position by <i>lengthBooleans - srcOffsetBooleans</i>.
-     * 
-     * @param srcArray The source array.
-     * @param srcOffsetBooleans offset in array units
-     * @param lengthBooleans number of array units to transfer
-     */
-    void putBooleanArray(boolean[] srcArray, int srcOffsetBooleans, int lengthBooleans);
-
-    /**
-     * Puts the byte value at the current position.
-     * Increments the position by <i>Byte.BYTES</i>.
-     * 
-     * @param value the value to put
-     */
-    void putByte(byte value);
-
-    /**
-     * Puts the byte value at the given offset.
-     * This does not change the position.
-     * 
-     * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
-     * @param value the value to put
-     */
-    void putByte(long offsetBytes, byte value);
-
-    /**
-     * Puts the byte array at the current position.
-     * Increments the position by <i>Byte.BYTES * (lengthBytes - srcOffsetBytes)</i>.
-     * 
-     * @param srcArray The source array.
-     * @param srcOffsetBytes offset in array units
-     * @param lengthBytes number of array units to transfer
-     */
-    void putByteArray(byte[] srcArray, int srcOffsetBytes, int lengthBytes);
-
-    /**
-     * Puts the char value at the current position.
-     * Increments the position by <i>Character.BYTES</i>.
-     * 
-     * @param value the value to put
-     */
-    void putChar(char value);
-
-    /**
-     * Puts the char value at the given offset.
-     * This does not change the position.
-     * 
-     * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
-     * @param value the value to put
-     */
-    void putChar(long offsetBytes, char value);
-
-    /**
-     * Puts the char array at the current position.
-     * Increments the position by <i>Character.BYTES * (lengthChars - srcOffsetChars)</i>.
-     * 
-     * @param srcArray The source array.
-     * @param srcOffsetChars offset in array units
-     * @param lengthChars number of array units to transfer
-     */
-    void putCharArray(char[] srcArray, int srcOffsetChars, int lengthChars);
-
-    /**
-     * Puts the double value at the current position.
-     * Increments the position by <i>Double.BYTES</i>.
-     * 
-     * @param value the value to put
-     */
-    void putDouble(double value);
-
-    /**
-     * Puts the double value at the given offset.
-     * This does not change the position.
-     * 
-     * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
-     * @param value the value to put
-     */
-    void putDouble(long offsetBytes, double value);
-
-    /**
-     * Puts the double array at the current position.
-     * Increments the position by <i>Double.BYTES * (lengthDoubles - srcOffsetDoubles)</i>.
-     * 
-     * @param srcArray The source array.
-     * @param srcOffsetDoubles offset in array units
-     * @param lengthDoubles number of array units to transfer
-     */
-    void putDoubleArray(double[] srcArray, int srcOffsetDoubles, int lengthDoubles);
-
-    /**
-     * Puts the float value at the current position.
-     * Increments the position by <i>Float.BYTES</i>.
-     * 
-     * @param value the value to put
-     */
-    void putFloat(float value);
-
-    /**
-     * Puts the float value at the given offset.
-     * This does not change the position.
-     * 
-     * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
-     * @param value the value to put
-     */
-    void putFloat(long offsetBytes, float value);
-
-    /**
-     * Puts the float array at the current position.
-     * Increments the position by <i>Float.BYTES * (lengthFloats - srcOffsetFloats)</i>.
-     * 
-     * @param srcArray The source array.
-     * @param srcOffsetFloats offset in array units
-     * @param lengthFloats number of array units to transfer
-     */
-    void putFloatArray(float[] srcArray, int srcOffsetFloats, int lengthFloats);
-
-    /**
-     * Puts the int value at the current position.
-     * Increments the position by <i>Integer.BYTES</i>.
-     * 
-     * @param value the value to put
-     */
-    void putInt(int value);
-
-    /**
-     * Puts the int value at the given offset.
-     * This does not change the position.
-     * 
-     * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
-     * @param value the value to put
-     */
-    void putInt(long offsetBytes, int value);
-
-    /**
-     * Puts the int array at the current position.
-     * Increments the position by <i>Integer.BYTES * (lengthInts - srcOffsetInts)</i>.
-     * 
-     * @param srcArray The source array.
-     * @param srcOffsetInts offset in array units
-     * @param lengthInts number of array units to transfer
-     */
-    void putIntArray(int[] srcArray, int srcOffsetInts, int lengthInts);
-
-    /**
-     * Puts the long value at the current position.
-     * Increments the position by <i>Long.BYTES</i>.
-     * 
-     * @param value the value to put
-     */
-    void putLong(long value);
-
-    /**
-     * Puts the long value at the given offset.
-     * This does not change the position.
-     * 
-     * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
-     * @param value the value to put
-     */
-    void putLong(long offsetBytes, long value);
-
-    /**
-     * Puts the long array at the current position.
-     * Increments the position by <i>Long.BYTES * (lengthLongs - srcOffsetLongs)</i>.
-     * 
-     * @param srcArray The source array.
-     * @param srcOffsetLongs offset in array units
-     * @param lengthLongs number of array units to transfer
-     */
-    void putLongArray(long[] srcArray, int srcOffsetLongs, int lengthLongs);
-
-    /**
-     * Puts the short value at the current position.
-     * Increments the position by <i>Short.BYTES</i>.
-     * 
-     * @param value the value to put
-     */
-    void putShort(short value);
-
-    /**
-     * Puts the short value at the given offset.
-     * This does not change the position.
-     * 
-     * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
-     * @param value the value to put
-     */
-    void putShort(long offsetBytes, short value);
-
-    /**
-     * Puts the short array at the current position.
-     * Increments the position by <i>Short.BYTES * (lengthShorts - srcOffsetShorts)</i>.
-     * 
-     * @param srcArray The source array.
-     * @param srcOffsetShorts offset in array units
-     * @param lengthShorts number of array units to transfer
-     */
-    void putShortArray(short[] srcArray, int srcOffsetShorts, int lengthShorts);
-
-    // NO ATOMIC METHODS
-
-    // OTHER WRITE METHODS
-    /**
-     * Returns the primitive backing array, otherwise null.
-     * 
-     * @return the primitive backing array, otherwise null.
-     */
-    Object getArray();
-
-    /**
-     * Clears all bytes of this Buffer from position to end to zero. The position will be set to end.
-     */
-    void clear();
-
-    // NO clearBits(...)
-
-    /**
-     * Fills this Buffer from position to end with the given byte value.
-     * The position will be set to <i>end</i>.
-     * 
-     * @param value the given byte value
-     */
-    void fill(byte value);
-
-    //OTHER WRITABLE API METHODS
-    /**
-     * WritableBuffer enables this for ByteBuffer backed resources. However, the object returned is in the form of
-     * a WritableMemory. To convert to WritableBuffer use asWritableBuffer(). To enable for Heap and Direct Memory
-     * resources, use the WritableMemory to configure and then call asWritableBuffer().
-     * Map backed resources will always return null.
-     * Gets the MemoryRequestServer object, if set, for the above resources to request additional memory.
-     * The user must customize the actions of the MemoryRequestServer by
-     * implementing the MemoryRequestServer interface and set using the following method:
-     * <ul>
-     * <li>{@link BufferFactory#writableWrap(ByteBuffer, ByteOrder, MemoryRequestServer)}</li>
-     * </ul>
-     * Simple implementation examples include the DefaultMemoryRequestServer in the main tree, as well as
-     * the ExampleMemoryRequestServerIT and the use with ByteBuffer documented in the DruidIssue11544IT
-     * in the test tree.
-     * @return the MemoryRequestServer object or null.
-     */
-    public MemoryRequestServer getMemoryRequestServer();
+  // DUPLICATES
+  /**
+   * Returns a duplicate writable view of this Buffer with the same but
+   * independent values of <i>start</i>, <i>position</i> and <i>end</i>.
+   * <ul>
+   * <li>Returned object's origin = this object's origin</li>
+   * <li>Returned object's <i>start</i> = this object's <i>start</i></li>
+   * <li>Returned object's <i>position</i> = this object's <i>position</i></li>
+   * <li>Returned object's <i>end</i> = this object's <i>end</i></li>
+   * <li>Returned object's <i>capacity</i> = this object'
+   * <i>capacityBytes</i></li>
+   * <li>Returned object's <i>start</i>, <i>position</i> and <i>end</i> are
+   * mutable and independent of this object's <i>start</i>, <i>position</i> and
+   * <i>end</i></li>
+   * </ul>
+   *
+   * @return a duplicate writable view of this Buffer with the same but
+   *         independent values of <i>start</i>, <i>position</i> and <i>end</i>.
+   */
+  WritableBuffer writableDuplicate();
+
+  /**
+   * Returns a duplicate writable view of this Buffer with the same but
+   * independent values of <i>start</i>, <i>position</i> and <i>end</i>, but with
+   * the specified byteOrder.
+   * <ul>
+   * <li>Returned object's origin = this object's origin</li>
+   * <li>Returned object's <i>start</i> = this object's <i>start</i></li>
+   * <li>Returned object's <i>position</i> = this object's <i>position</i></li>
+   * <li>Returned object's <i>end</i> = this object's <i>end</i></li>
+   * <li>Returned object's <i>capacity</i> = this object'
+   * <i>capacityBytes</i></li>
+   * <li>Returned object's <i>start</i>, <i>position</i> and <i>end</i> are
+   * mutable and independent of this object's <i>start</i>, <i>position</i> and
+   * <i>end</i></li>
+   * </ul>
+   *
+   * @param byteOrder the given <i>ByteOrder</i>.
+   * @return a duplicate writable view of this Buffer with the same but
+   *         independent values of <i>start</i>, <i>position</i> and <i>end</i>.
+   */
+  WritableBuffer writableDuplicate(ByteOrder byteOrder);
+
+  // REGIONS
+  /**
+   * A writable region is a writable view of this object.
+   * <ul>
+   * <li>Returned object's origin = this object's <i>position</i></li>
+   * <li>Returned object's <i>start</i> = 0</li>
+   * <li>Returned object's <i>position</i> = 0</li>
+   * <li>Returned object's <i>end</i> = this object's (<i>end</i> -
+   * <i>position</i>)</li>
+   * <li>Returned object's <i>capacity</i> = this object's (<i>end</i> -
+   * <i>position</i>)</li>
+   * <li>Returned object's <i>start</i>, <i>position</i> and <i>end</i> are
+   * mutable and independent of this object's <i>start</i>, <i>position</i> and
+   * <i>end</i></li>
+   * </ul>
+   *
+   * @return a new <i>WritableBuffer</i> representing the defined writable region.
+   */
+  WritableBuffer writableRegion();
+
+  /**
+   * A writable region is a writable view of this object.
+   * <ul>
+   * <li>Returned object's origin = this objects' origin + <i>offsetBytes</i></li>
+   * <li>Returned object's <i>start</i> = 0</li>
+   * <li>Returned object's <i>position</i> = 0</li>
+   * <li>Returned object's <i>end</i> = <i>capacityBytes</i></li>
+   * <li>Returned object's <i>capacity</i> = <i>capacityBytes</i></li>
+   * <li>Returned object's <i>start</i>, <i>position</i> and <i>end</i> are
+   * mutable and independent of this object's <i>start</i>, <i>position</i> and
+   * <i>end</i></li>
+   * <li>Returned object's byte order = <i>byteOrder</i></li>
+   * </ul>
+   *
+   * <p>
+   * <b>Note: </b><i>asWritableMemory()</i> and <i>asMemory()</i> will return the
+   * originating <i>Memory</i> byte order.
+   * </p>
+   *
+   * @param offsetBytes   the starting offset with respect to the origin of this
+   *                      <i>WritableBuffer</i>
+   * @param capacityBytes the <i>capacity</i> of the returned region in bytes
+   * @param byteOrder     the given byte order
+   * @return a new <i>WritableBuffer</i> representing the defined writable region
+   *         with the given offsetBytes, capacityBytes and byte order.
+   */
+  WritableBuffer writableRegion(long offsetBytes, long capacityBytes, ByteOrder byteOrder);
+
+  // AS WRITABLE MEMORY
+  /**
+   * Convert this WritableBuffer to a WritableMemory. If this object's capacity is
+   * zero, the returned object is effectively immutable and the backing storage
+   * and byte order are unspecified.
+   *
+   * @return WritableMemory
+   */
+  default WritableMemory asWritableMemory() {
+    return asWritableMemory(ByteOrder.nativeOrder());
+  }
+
+  /**
+   * Convert this WritableBuffer to a WritableMemory with the given byte order. If
+   * this object's capacity is zero, the returned object is effectively immutable
+   * and the backing storage and byte order are unspecified.
+   *
+   * @param byteOrder the byte order to be used.
+   * @return WritableMemory
+   */
+  WritableMemory asWritableMemory(ByteOrder byteOrder);
+
+  // NO ALLOCATE HEAP VIA AUTOMATIC BYTE ARRAY
+
+  // NO ACCESS PRIMITIVE HEAP ARRAYS for WRITE
+
+  // PRIMITIVE putX() and putXArray()
+  /**
+   * Puts the boolean value at the current position. Increments the position by 1.
+   *
+   * @param value the value to put
+   */
+  void putBoolean(boolean value);
+
+  /**
+   * Puts the boolean value at the given offset. This does not change the
+   * position.
+   *
+   * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start.
+   * @param value       the value to put
+   */
+  void putBoolean(long offsetBytes, boolean value);
+
+  /**
+   * Puts the boolean array at the current position. Increments the position by
+   * <i>lengthBooleans - srcOffsetBooleans</i>.
+   *
+   * @param srcArray          The source array.
+   * @param srcOffsetBooleans offset in array units
+   * @param lengthBooleans    number of array units to transfer
+   */
+  void putBooleanArray(boolean[] srcArray, int srcOffsetBooleans, int lengthBooleans);
+
+  /**
+   * Puts the byte value at the current position. Increments the position by
+   * <i>Byte.BYTES</i>.
+   *
+   * @param value the value to put
+   */
+  void putByte(byte value);
+
+  /**
+   * Puts the byte value at the given offset. This does not change the position.
+   *
+   * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
+   * @param value       the value to put
+   */
+  void putByte(long offsetBytes, byte value);
+
+  /**
+   * Puts the byte array at the current position. Increments the position by
+   * <i>Byte.BYTES * (lengthBytes - srcOffsetBytes)</i>.
+   *
+   * @param srcArray       The source array.
+   * @param srcOffsetBytes offset in array units
+   * @param lengthBytes    number of array units to transfer
+   */
+  void putByteArray(byte[] srcArray, int srcOffsetBytes, int lengthBytes);
+
+  /**
+   * Puts the char value at the current position. Increments the position by
+   * <i>Character.BYTES</i>.
+   *
+   * @param value the value to put
+   */
+  void putChar(char value);
+
+  /**
+   * Puts the char value at the given offset. This does not change the position.
+   *
+   * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
+   * @param value       the value to put
+   */
+  void putChar(long offsetBytes, char value);
+
+  /**
+   * Puts the char array at the current position. Increments the position by
+   * <i>Character.BYTES * (lengthChars - srcOffsetChars)</i>.
+   *
+   * @param srcArray       The source array.
+   * @param srcOffsetChars offset in array units
+   * @param lengthChars    number of array units to transfer
+   */
+  void putCharArray(char[] srcArray, int srcOffsetChars, int lengthChars);
+
+  /**
+   * Puts the double value at the current position. Increments the position by
+   * <i>Double.BYTES</i>.
+   *
+   * @param value the value to put
+   */
+  void putDouble(double value);
+
+  /**
+   * Puts the double value at the given offset. This does not change the position.
+   *
+   * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
+   * @param value       the value to put
+   */
+  void putDouble(long offsetBytes, double value);
+
+  /**
+   * Puts the double array at the current position. Increments the position by
+   * <i>Double.BYTES * (lengthDoubles - srcOffsetDoubles)</i>.
+   *
+   * @param srcArray         The source array.
+   * @param srcOffsetDoubles offset in array units
+   * @param lengthDoubles    number of array units to transfer
+   */
+  void putDoubleArray(double[] srcArray, int srcOffsetDoubles, int lengthDoubles);
+
+  /**
+   * Puts the float value at the current position. Increments the position by
+   * <i>Float.BYTES</i>.
+   *
+   * @param value the value to put
+   */
+  void putFloat(float value);
+
+  /**
+   * Puts the float value at the given offset. This does not change the position.
+   *
+   * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
+   * @param value       the value to put
+   */
+  void putFloat(long offsetBytes, float value);
+
+  /**
+   * Puts the float array at the current position. Increments the position by
+   * <i>Float.BYTES * (lengthFloats - srcOffsetFloats)</i>.
+   *
+   * @param srcArray        The source array.
+   * @param srcOffsetFloats offset in array units
+   * @param lengthFloats    number of array units to transfer
+   */
+  void putFloatArray(float[] srcArray, int srcOffsetFloats, int lengthFloats);
+
+  /**
+   * Puts the int value at the current position. Increments the position by
+   * <i>Integer.BYTES</i>.
+   *
+   * @param value the value to put
+   */
+  void putInt(int value);
+
+  /**
+   * Puts the int value at the given offset. This does not change the position.
+   *
+   * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
+   * @param value       the value to put
+   */
+  void putInt(long offsetBytes, int value);
+
+  /**
+   * Puts the int array at the current position. Increments the position by
+   * <i>Integer.BYTES * (lengthInts - srcOffsetInts)</i>.
+   *
+   * @param srcArray      The source array.
+   * @param srcOffsetInts offset in array units
+   * @param lengthInts    number of array units to transfer
+   */
+  void putIntArray(int[] srcArray, int srcOffsetInts, int lengthInts);
+
+  /**
+   * Puts the long value at the current position. Increments the position by
+   * <i>Long.BYTES</i>.
+   *
+   * @param value the value to put
+   */
+  void putLong(long value);
+
+  /**
+   * Puts the long value at the given offset. This does not change the position.
+   *
+   * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
+   * @param value       the value to put
+   */
+  void putLong(long offsetBytes, long value);
+
+  /**
+   * Puts the long array at the current position. Increments the position by
+   * <i>Long.BYTES * (lengthLongs - srcOffsetLongs)</i>.
+   *
+   * @param srcArray       The source array.
+   * @param srcOffsetLongs offset in array units
+   * @param lengthLongs    number of array units to transfer
+   */
+  void putLongArray(long[] srcArray, int srcOffsetLongs, int lengthLongs);
+
+  /**
+   * Puts the short value at the current position. Increments the position by
+   * <i>Short.BYTES</i>.
+   *
+   * @param value the value to put
+   */
+  void putShort(short value);
+
+  /**
+   * Puts the short value at the given offset. This does not change the position.
+   *
+   * @param offsetBytes offset bytes relative to this <i>WritableMemory</i> start
+   * @param value       the value to put
+   */
+  void putShort(long offsetBytes, short value);
+
+  /**
+   * Puts the short array at the current position. Increments the position by
+   * <i>Short.BYTES * (lengthShorts - srcOffsetShorts)</i>.
+   *
+   * @param srcArray        The source array.
+   * @param srcOffsetShorts offset in array units
+   * @param lengthShorts    number of array units to transfer
+   */
+  void putShortArray(short[] srcArray, int srcOffsetShorts, int lengthShorts);
+
+  // NO ATOMIC METHODS
+
+  // OTHER WRITE METHODS
+  /**
+   * Returns the primitive backing array, otherwise null.
+   *
+   * @return the primitive backing array, otherwise null.
+   */
+  Object getArray();
+
+  /**
+   * Clears all bytes of this Buffer from position to end to zero. The position
+   * will be set to end.
+   */
+  void clear();
+
+  // NO clearBits(...)
+
+  /**
+   * Fills this Buffer from position to end with the given byte value. The
+   * position will be set to <i>end</i>.
+   *
+   * @param value the given byte value
+   */
+  void fill(byte value);
+
+  // OTHER WRITABLE API METHODS
+  /**
+   * WritableBuffer enables this for ByteBuffer backed resources. However, the
+   * object returned is in the form of a WritableMemory. To convert to
+   * WritableBuffer use asWritableBuffer(). To enable for Heap and Direct Memory
+   * resources, use the WritableMemory to configure and then call
+   * asWritableBuffer(). Map backed resources will always return null. Gets the
+   * MemoryRequestServer object, if set, for the above resources to request
+   * additional memory. The user must customize the actions of the
+   * MemoryRequestServer by implementing the MemoryRequestServer interface and set
+   * using the following method:
+   * <ul>
+   * <li>{@link BufferFactory#writableWrap(ByteBuffer, ByteOrder, MemoryRequestServer)}</li>
+   * </ul>
+   * Simple implementation examples include the DefaultMemoryRequestServer in the
+   * main tree, as well as the ExampleMemoryRequestServerIT and the use with
+   * ByteBuffer documented in the DruidIssue11544IT in the test tree.
+   *
+   * @return the MemoryRequestServer object or null.
+   */
+  public MemoryRequestServer getMemoryRequestServer();
 }
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 d255843..4029394 100644
--- a/src/main/java/org/apache/datasketches/memory/internal/Util.java
+++ b/src/main/java/org/apache/datasketches/memory/internal/Util.java
@@ -24,48 +24,53 @@ import java.nio.ByteOrder;
  * Various utility methods and helpers used by the rest of the code
  */
 public final class Util {
-    
-    //Byte Order related
-    public static final ByteOrder NON_NATIVE_BYTE_ORDER = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN
-        ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
 
-    public static ByteOrder otherByteOrder(final ByteOrder order) {
-      return (order == ByteOrder.nativeOrder()) ? NON_NATIVE_BYTE_ORDER : ByteOrder.nativeOrder();
-    }
+  // Byte Order related
+  public static final ByteOrder NON_NATIVE_BYTE_ORDER = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN
+      ? ByteOrder.BIG_ENDIAN
+      : ByteOrder.LITTLE_ENDIAN;
+
+  public static ByteOrder otherByteOrder(final ByteOrder order) {
+    return (order == ByteOrder.nativeOrder()) ? NON_NATIVE_BYTE_ORDER : ByteOrder.nativeOrder();
+  }
 
-    /**
-     * Returns true if the given byteOrder is the same as the native byte order.
-     * @param byteOrder the given byte order
-     * @return true if the given byteOrder is the same as the native byte order.
-     */
-    public static boolean isNativeByteOrder(final ByteOrder byteOrder) {
-      if (byteOrder == null) {
-        throw new IllegalArgumentException("ByteOrder parameter cannot be null.");
-      }
-      return ByteOrder.nativeOrder() == byteOrder;
+  /**
+   * Returns true if the given byteOrder is the same as the native byte order.
+   *
+   * @param byteOrder the given byte order
+   * @return true if the given byteOrder is the same as the native byte order.
+   */
+  public static boolean isNativeByteOrder(final ByteOrder byteOrder) {
+    if (byteOrder == null) {
+      throw new IllegalArgumentException("ByteOrder parameter cannot be null.");
     }
+    return ByteOrder.nativeOrder() == byteOrder;
+  }
+
+  /**
+   * Don't use sun.misc.Unsafe#copyMemory to copy blocks of memory larger than
+   * this threshold, because internally it doesn't have safepoint polls, that may
+   * cause long "Time To Safe Point" pauses in the application. This has been
+   * fixed in JDK 9 (see https://bugs.openjdk.java.net/browse/JDK-8149596 and
+   * https://bugs.openjdk.java.net/browse/JDK-8141491), but not in JDK 8, so the
+   * Memory library should keep having this boilerplate as long as it supports
+   * Java 8.
+   *
+   * <p>
+   * A reference to this can be found in java.nio.Bits.
+   * </p>
+   */
+  public static final int UNSAFE_COPY_THRESHOLD_BYTES = 1024 * 1024;
 
-    /**
-     * Don't use sun.misc.Unsafe#copyMemory to copy blocks of memory larger than this
-     * threshold, because internally it doesn't have safepoint polls, that may cause long
-     * "Time To Safe Point" pauses in the application. This has been fixed in JDK 9 (see
-     * https://bugs.openjdk.java.net/browse/JDK-8149596 and
-     * https://bugs.openjdk.java.net/browse/JDK-8141491), but not in JDK 8, so the Memory library
-     * should keep having this boilerplate as long as it supports Java 8.
-     *
-     * <p>A reference to this can be found in java.nio.Bits.</p>
-     */
-    public static final int UNSAFE_COPY_THRESHOLD_BYTES = 1024 * 1024;
-    
-    public static final void zeroCheck(final long value, final String arg) {
-        if (value <= 0) {
-          throw new IllegalArgumentException("The argument '" + arg + "' may not be negative or zero.");
-        }
+  public static final void zeroCheck(final long value, final String arg) {
+    if (value <= 0) {
+      throw new IllegalArgumentException("The argument '" + arg + "' may not be negative or zero.");
     }
+  }
 
-    public static final void negativeCheck(final long value, final String arg) {
-        if (value < 0) {
-            throw new IllegalArgumentException("The argument '" + arg + "' may not be negative.");
-        }
+  public static final void negativeCheck(final long value, final String arg) {
+    if (value < 0) {
+      throw new IllegalArgumentException("The argument '" + arg + "' may not be negative.");
     }
+  }
 }
diff --git a/src/test/java/org/apache/datasketches/memory/internal/IsValidUtf8TestUtil.java b/src/test/java/org/apache/datasketches/memory/internal/IsValidUtf8TestUtil.java
index cf01920..f504c64 100644
--- a/src/test/java/org/apache/datasketches/memory/internal/IsValidUtf8TestUtil.java
+++ b/src/test/java/org/apache/datasketches/memory/internal/IsValidUtf8TestUtil.java
@@ -42,23 +42,22 @@ public class IsValidUtf8TestUtil {
   static final long EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT =
       // Both bytes are one byte characters
       (long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 2)
-      // The possible number of two byte characters
-      + TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS;
+          // The possible number of two byte characters
+          + TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS;
 
   // 2048
   static final long THREE_BYTE_SURROGATES = 2 * 1024;
 
   // 61,440 [chars 0x0800 to 0xFFFF, minus surrogates]
-  static final long THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS =
-      ((0xFFFF - 0x0800) + 1) - THREE_BYTE_SURROGATES;
+  static final long THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS = ((0xFFFF - 0x0800) + 1) - THREE_BYTE_SURROGATES;
 
   // 2,650,112
   static final long EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT =
       // All one byte characters
       (long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 3)
-      // One two byte character and a one byte character
-      + (2 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS * ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS)
-      // Three byte characters
-      + THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS;
+          // One two byte character and a one byte character
+          + (2 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS * ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS)
+          // Three byte characters
+          + THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS;
 
 }
diff --git a/src/test/java/org/apache/datasketches/memory/internal/RandomCodePoints.java b/src/test/java/org/apache/datasketches/memory/internal/RandomCodePoints.java
index 9c782f9..b5b1a47 100644
--- a/src/test/java/org/apache/datasketches/memory/internal/RandomCodePoints.java
+++ b/src/test/java/org/apache/datasketches/memory/internal/RandomCodePoints.java
@@ -21,78 +21,84 @@ package org.apache.datasketches.memory.internal;
 import java.util.Random;
 
 public class RandomCodePoints {
-    private Random rand; //
-    private static final int ALL_CP = Character.MAX_CODE_POINT + 1;
-    private static final int MIN_SUR = Character.MIN_SURROGATE;
-    private static final int MAX_SUR = Character.MAX_SURROGATE;
+  private Random rand; //
+  private static final int ALL_CP = Character.MAX_CODE_POINT + 1;
+  private static final int MIN_SUR = Character.MIN_SURROGATE;
+  private static final int MAX_SUR = Character.MAX_SURROGATE;
 
-    /**
-     * @param deterministic if true, configure java.util.Random with a fixed seed.
-     */
-    public RandomCodePoints(final boolean deterministic) {
-      rand = deterministic ? new Random(0) : new Random();
-    }
+  /**
+   * @param deterministic if true, configure java.util.Random with a fixed seed.
+   */
+  public RandomCodePoints(final boolean deterministic) {
+    rand = deterministic ? new Random(0) : new Random();
+  }
 
-    /**
-     * Fills the given array with random valid Code Points from 0, inclusive, to
-     * <i>Character.MAX_CODE_POINT</i>, inclusive.
-     * The surrogate range, which is from <i>Character.MIN_SURROGATE</i>, inclusive, to
-     * <i>Character.MAX_SURROGATE</i>, inclusive, is always <u>excluded</u>.
-     * @param cpArr the array to fill
-     */
-    public final void fillCodePointArray(final int[] cpArr) {
-      fillCodePointArray(cpArr, 0, ALL_CP);
-    }
+  /**
+   * Fills the given array with random valid Code Points from 0, inclusive, to
+   * <i>Character.MAX_CODE_POINT</i>, inclusive. The surrogate range, which is
+   * from <i>Character.MIN_SURROGATE</i>, inclusive, to
+   * <i>Character.MAX_SURROGATE</i>, inclusive, is always <u>excluded</u>.
+   *
+   * @param cpArr the array to fill
+   */
+  public final void fillCodePointArray(final int[] cpArr) {
+    fillCodePointArray(cpArr, 0, ALL_CP);
+  }
 
-    /**
-     * Fills the given array with random valid Code Points from <i>startCP</i>, inclusive, to
-     * <i>endCP</i>, exclusive.
-     * The surrogate range, which is from <i>Character.MIN_SURROGATE</i>, inclusive, to
-     * <i>Character.MAX_SURROGATE</i>, inclusive, is always <u>excluded</u>.
-     * @param cpArr the array to fill
-     * @param startCP the starting Code Point, included.
-     * @param endCP the ending Code Point, excluded. This value cannot exceed 0x110000.
-     */
-    public final void fillCodePointArray(final int[] cpArr, final int startCP, final int endCP) {
-      final int arrLen = cpArr.length;
-      final int numCP = Math.min(endCP, 0X110000) - Math.min(0, startCP);
-      int idx = 0;
-      while (idx < arrLen) {
-        final int cp = startCP + rand.nextInt(numCP);
-        if ((cp >= MIN_SUR) && (cp <= MAX_SUR)) {
-          continue;
-        }
-        cpArr[idx++] = cp;
+  /**
+   * Fills the given array with random valid Code Points from <i>startCP</i>,
+   * inclusive, to <i>endCP</i>, exclusive. The surrogate range, which is from
+   * <i>Character.MIN_SURROGATE</i>, inclusive, to <i>Character.MAX_SURROGATE</i>,
+   * inclusive, is always <u>excluded</u>.
+   *
+   * @param cpArr   the array to fill
+   * @param startCP the starting Code Point, included.
+   * @param endCP   the ending Code Point, excluded. This value cannot exceed
+   *                0x110000.
+   */
+  public final void fillCodePointArray(final int[] cpArr, final int startCP, final int endCP) {
+    final int arrLen = cpArr.length;
+    final int numCP = Math.min(endCP, 0X110000) - Math.min(0, startCP);
+    int idx = 0;
+    while (idx < arrLen) {
+      final int cp = startCP + rand.nextInt(numCP);
+      if ((cp >= MIN_SUR) && (cp <= MAX_SUR)) {
+        continue;
       }
+      cpArr[idx++] = cp;
     }
+  }
 
-    /**
-     * Return a single valid random Code Point from 0, inclusive, to
-     * <i>Character.MAX_CODE_POINT</i>, inclusive.
-     * The surrogate range, which is from <i>Character.MIN_SURROGATE</i>, inclusive, to
-     * <i>Character.MAX_SURROGATE</i>, inclusive, is always <u>excluded</u>.
-     * @return a single valid random CodePoint.
-     */
-    public final int getCodePoint() {
-      return getCodePoint(0, ALL_CP);
-    }
+  /**
+   * Return a single valid random Code Point from 0, inclusive, to
+   * <i>Character.MAX_CODE_POINT</i>, inclusive. The surrogate range, which is
+   * from <i>Character.MIN_SURROGATE</i>, inclusive, to
+   * <i>Character.MAX_SURROGATE</i>, inclusive, is always <u>excluded</u>.
+   *
+   * @return a single valid random CodePoint.
+   */
+  public final int getCodePoint() {
+    return getCodePoint(0, ALL_CP);
+  }
 
-    /**
-     * Return a single valid random Code Point from <i>startCP</i>, inclusive, to
-     * <i>endCP</i>, exclusive.
-     * The surrogate range, which is from <i>Character.MIN_SURROGATE</i>, inclusive, to
-     * <i>Character.MAX_SURROGATE</i>, inclusive, is always <u>excluded</u>.
-     * @param startCP the starting Code Point, included.
-     * @param endCP the ending Code Point, excluded. This value cannot exceed 0x110000.
-     * @return a single valid random CodePoint.
-     */
-    public final int getCodePoint(final int startCP, final int endCP) {
-      final int numCP = Math.min(endCP, 0X110000) - Math.min(0, startCP);
-      while (true) {
-        final int cp = startCP + rand.nextInt(numCP);
-        if ((cp < MIN_SUR) || (cp > MAX_SUR)) {
-          return cp;
-        }
+  /**
+   * Return a single valid random Code Point from <i>startCP</i>, inclusive, to
+   * <i>endCP</i>, exclusive. The surrogate range, which is from
+   * <i>Character.MIN_SURROGATE</i>, inclusive, to <i>Character.MAX_SURROGATE</i>,
+   * inclusive, is always <u>excluded</u>.
+   *
+   * @param startCP the starting Code Point, included.
+   * @param endCP   the ending Code Point, excluded. This value cannot exceed
+   *                0x110000.
+   * @return a single valid random CodePoint.
+   */
+  public final int getCodePoint(final int startCP, final int endCP) {
+    final int numCP = Math.min(endCP, 0X110000) - Math.min(0, startCP);
+    while (true) {
+      final int cp = startCP + rand.nextInt(numCP);
+      if ((cp < MIN_SUR) || (cp > MAX_SUR)) {
+        return cp;
       }
     }
+  }
   } //End class RandomCodePoints
\ No newline at end of file
diff --git a/src/test/java/org/apache/datasketches/memory/internal/TestUtils.java b/src/test/java/org/apache/datasketches/memory/internal/TestUtils.java
index 404fd23..f242270 100644
--- a/src/test/java/org/apache/datasketches/memory/internal/TestUtils.java
+++ b/src/test/java/org/apache/datasketches/memory/internal/TestUtils.java
@@ -18,9 +18,6 @@
  */
 package org.apache.datasketches.memory.internal;
 
-import org.apache.datasketches.memory.Memory;
-import org.apache.datasketches.memory.internal.unsafe.UnsafeUtil;
-
 import java.io.File;
 import java.io.IOException;
 import java.net.URI;
@@ -34,220 +31,230 @@ import java.nio.file.attribute.PosixFileAttributes;
 import java.nio.file.attribute.PosixFilePermissions;
 import java.util.Objects;
 
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.internal.unsafe.UnsafeUtil;
+
 /**
  * Utility functions used in unit tests
  */
 public class TestUtils {
-    public static final String LS = System.lineSeparator();
-
-    /**
-     * 
-     * Return true if all the masked bits of value are zero
-     * 
-     * @param value the value to be tested
-     * @param bitMask defines the bits of interest
-     * @return true if all the masked bits of value are zero
-     */
-    public static final boolean isAllBitsClear(final long value, final long bitMask) {
-        return (~value & bitMask) == bitMask;
-    }
+  public static final String LS = System.lineSeparator();
 
-    /**
-     * Return true if all the masked bits of value are one
-     * 
-     * @param value the value to be tested
-     * @param bitMask defines the bits of interest
-     * @return true if all the masked bits of value are one
-     */
-    public static final boolean isAllBitsSet(final long value, final long bitMask) {
-        return (value & bitMask) == bitMask;
-    }
+  /**
+   *
+   * Return true if all the masked bits of value are zero
+   *
+   * @param value   the value to be tested
+   * @param bitMask defines the bits of interest
+   * @return true if all the masked bits of value are zero
+   */
+  public static final boolean isAllBitsClear(final long value, final long bitMask) {
+    return (~value & bitMask) == bitMask;
+  }
 
-    /**
-     * Return true if any the masked bits of value are zero
-     * 
-     * @param value the value to be tested
-     * @param bitMask defines the bits of interest
-     * @return true if any the masked bits of value are zero
-     */
-    public static final boolean isAnyBitsClear(final long value, final long bitMask) {
-        return (~value & bitMask) != 0;
-    }
+  /**
+   * Return true if all the masked bits of value are one
+   *
+   * @param value   the value to be tested
+   * @param bitMask defines the bits of interest
+   * @return true if all the masked bits of value are one
+   */
+  public static final boolean isAllBitsSet(final long value, final long bitMask) {
+    return (value & bitMask) == bitMask;
+  }
 
-    /**
-     * Return true if any the masked bits of value are one
-     * 
-     * @param value the value to be tested
-     * @param bitMask defines the bits of interest
-     * @return true if any the masked bits of value are one
-     */
-    public static final boolean isAnyBitsSet(final long value, final long bitMask) {
-        return (value & bitMask) != 0;
-    }
+  /**
+   * Return true if any the masked bits of value are zero
+   *
+   * @param value   the value to be tested
+   * @param bitMask defines the bits of interest
+   * @return true if any the masked bits of value are zero
+   */
+  public static final boolean isAnyBitsClear(final long value, final long bitMask) {
+    return (~value & bitMask) != 0;
+  }
 
-    // Resources NOTE: these 3 methods are duplicated in Java/ datasketches/Util
-
-    /**
-     * Gets the absolute path of the given resource file's shortName.
-     *
-     * <p>
-     * Note that the ClassLoader.getResource(shortName) returns a URL,
-     * which can have special characters, e.g., "%20" for spaces. This method
-     * obtains the URL, converts it to a URI, then does a uri.getPath(), which
-     * decodes any special characters in the URI path. This is required to make
-     * obtaining resources operating-system independent.
-     * </p>
-     *
-     * @param shortFileName the last name in the pathname's name sequence.
-     * @return the absolute path of the given resource file's shortName.
-     */
-    public static String getResourcePath(final String shortFileName) {
-        Objects.requireNonNull(shortFileName, "input parameter " + shortFileName + " cannot be null.");
-        try {
-            final URL url = Util.class.getClassLoader().getResource(shortFileName);
-            Objects.requireNonNull(url, "resource " + shortFileName + " could not be acquired.");
-            final URI uri = url.toURI();
-            // decodes any special characters
-            final String path = uri.isAbsolute() ? Paths.get(uri).toAbsolutePath().toString() : uri.getPath();
-            return path;
-        } catch (final URISyntaxException e) {
-            throw new IllegalArgumentException("Cannot find resource: " + shortFileName + LS + e);
-        }
-    }
+  /**
+   * Return true if any the masked bits of value are one
+   *
+   * @param value   the value to be tested
+   * @param bitMask defines the bits of interest
+   * @return true if any the masked bits of value are one
+   */
+  public static final boolean isAnyBitsSet(final long value, final long bitMask) {
+    return (value & bitMask) != 0;
+  }
 
-    /**
-     * Gets the file defined by the given resource file's shortFileName.
-     * 
-     * @param shortFileName the last name in the pathname's name sequence.
-     * @return the file defined by the given resource file's shortFileName.
-     */
-    public static File getResourceFile(final String shortFileName) {
-        return new File(getResourcePath(shortFileName));
-    }
+  // Resources NOTE: these 3 methods are duplicated in Java/ datasketches/Util
 
-    /**
-     * Returns a byte array of the contents of the file defined by the given resource file's
-     * shortFileName.
-     * 
-     * @param shortFileName the last name in the pathname's name sequence.
-     * @return a byte array of the contents of the file defined by the given resource file's
-     *         shortFileName.
-     */
-    public static byte[] getResourceBytes(final String shortFileName) {
-        try {
-            return Files.readAllBytes(Paths.get(getResourcePath(shortFileName)));
-        } catch (final IOException e) {
-            throw new IllegalArgumentException("Cannot read resource: " + shortFileName + LS + e);
-        }
+  /**
+   * Gets the absolute path of the given resource file's shortName.
+   *
+   * <p>
+   * Note that the ClassLoader.getResource(shortName) returns a URL, which can
+   * have special characters, e.g., "%20" for spaces. This method obtains the URL,
+   * converts it to a URI, then does a uri.getPath(), which decodes any special
+   * characters in the URI path. This is required to make obtaining resources
+   * operating-system independent.
+   * </p>
+   *
+   * @param shortFileName the last name in the pathname's name sequence.
+   * @return the absolute path of the given resource file's shortName.
+   */
+  public static String getResourcePath(final String shortFileName) {
+    Objects.requireNonNull(shortFileName, "input parameter " + shortFileName + " cannot be null.");
+    try {
+      final URL url = Util.class.getClassLoader().getResource(shortFileName);
+      Objects.requireNonNull(url, "resource " + shortFileName + " could not be acquired.");
+      final URI uri = url.toURI();
+      // decodes any special characters
+      final String path = uri.isAbsolute() ? Paths.get(uri).toAbsolutePath().toString() : uri.getPath();
+      return path;
+    } catch (final URISyntaxException e) {
+      throw new IllegalArgumentException("Cannot find resource: " + shortFileName + LS + e);
     }
+  }
 
-    public 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);
-        }
+  /**
+   * Gets the file defined by the given resource file's shortFileName.
+   *
+   * @param shortFileName the last name in the pathname's name sequence.
+   * @return the file defined by the given resource file's shortFileName.
+   */
+  public static File getResourceFile(final String shortFileName) {
+    return new File(getResourcePath(shortFileName));
+  }
+
+  /**
+   * Returns a byte array of the contents of the file defined by the given
+   * resource file's shortFileName.
+   *
+   * @param shortFileName the last name in the pathname's name sequence.
+   * @return a byte array of the contents of the file defined by the given
+   *         resource file's shortFileName.
+   */
+  public static byte[] getResourceBytes(final String shortFileName) {
+    try {
+      return Files.readAllBytes(Paths.get(getResourcePath(shortFileName)));
+    } catch (final IOException e) {
+      throw new IllegalArgumentException("Cannot read resource: " + shortFileName + LS + e);
     }
+  }
 
-    /**
-     * Searches a range of the specified array of longs for the specified value using the binary
-     * search algorithm. The range must be sorted method) prior to making this call.
-     * If it is not sorted, the results are undefined. If the range contains
-     * multiple elements with the specified value, there is no guarantee which one will be found.
-     * @param mem the Memory to be searched
-     * @param fromLongIndex the index of the first element (inclusive) to be searched
-     * @param toLongIndex the index of the last element (exclusive) to be searched
-     * @param key the value to be searched for
-     * @return index of the search key, if it is contained in the array within the specified range;
-     * otherwise, (-(insertion point) - 1). The insertion point is defined as the point at which
-     * the key would be inserted into the array: the index of the first element in the range greater
-     * than the key, or toIndex if all elements in the range are less than the specified key.
-     * Note that this guarantees that the return value will be &ge; 0 if and only if the key is found.
-     */
-    public static long binarySearchLongs(final Memory mem, final long fromLongIndex,
-        final long toLongIndex, final long key) {
-      UnsafeUtil.checkBounds(fromLongIndex << 3, (toLongIndex - fromLongIndex) << 3, mem.getCapacity());
-      long low = fromLongIndex;
-      long high = toLongIndex - 1L;
-
-      while (low <= high) {
-        final long mid = (low + high) >>> 1;
-        final long midVal = mem.getLong(mid << 3);
-
-        if (midVal < key)      { low = mid + 1;  }
-        else if (midVal > key) { high = mid - 1; }
-        else                   { return mid;     } // key found
-      }
-      return -(low + 1); // key not found.
+  public 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);
     }
+  }
 
-    public static final void nullCheck(final Object obj, final String arg) {
-        if (obj == null) {
-            throw new IllegalArgumentException("The argument '" + arg + "' may not be null.");
-        }
+  /**
+   * Searches a range of the specified array of longs for the specified value
+   * using the binary search algorithm. The range must be sorted method) prior to
+   * making this call. If it is not sorted, the results are undefined. If the
+   * range contains multiple elements with the specified value, there is no
+   * guarantee which one will be found.
+   *
+   * @param mem           the Memory to be searched
+   * @param fromLongIndex the index of the first element (inclusive) to be
+   *                      searched
+   * @param toLongIndex   the index of the last element (exclusive) to be searched
+   * @param key           the value to be searched for
+   * @return index of the search key, if it is contained in the array within the
+   *         specified range; otherwise, (-(insertion point) - 1). The insertion
+   *         point is defined as the point at which the key would be inserted into
+   *         the array: the index of the first element in the range greater than
+   *         the key, or toIndex if all elements in the range are less than the
+   *         specified key. Note that this guarantees that the return value will
+   *         be &ge; 0 if and only if the key is found.
+   */
+  public static long binarySearchLongs(final Memory mem, final long fromLongIndex, final long toLongIndex,
+      final long key) {
+    UnsafeUtil.checkBounds(fromLongIndex << 3, (toLongIndex - fromLongIndex) << 3, mem.getCapacity());
+    long low = fromLongIndex;
+    long high = toLongIndex - 1L;
+
+    while (low <= high) {
+      final long mid = (low + high) >>> 1;
+      final long midVal = mem.getLong(mid << 3);
+
+      if (midVal < key) {
+        low = mid + 1;
+      } else if (midVal > key) {
+        high = mid - 1;
+      } else {
+        return mid;
+      } // key found
     }
+    return -(low + 1); // key not found.
+  }
 
-    public static final void setGettysburgAddressFileToReadOnly() {
-        File file = getResourceFile("GettysburgAddress.txt");
-        file.setWritable(false);
+  public static final void nullCheck(final Object obj, final String arg) {
+    if (obj == null) {
+      throw new IllegalArgumentException("The argument '" + arg + "' may not be null.");
     }
+  }
 
+  public static final void setGettysburgAddressFileToReadOnly() {
+    File file = getResourceFile("GettysburgAddress.txt");
+    file.setWritable(false);
+  }
 
-    /**
-     * Prepend the given string with zeros. If the given string is equal or greater than the given
-     * field length, it will be returned without modification.
-     * 
-     * @param s the given string
-     * @param fieldLength desired total field length including the given string
-     * @return the given string prepended with zeros.
-     */
-    public static final String zeroPad(final String s, final int fieldLength) {
-        return characterPad(s, fieldLength, '0', false);
-    }
+  /**
+   * Prepend the given string with zeros. If the given string is equal or greater
+   * than the given field length, it will be returned without modification.
+   *
+   * @param s           the given string
+   * @param fieldLength desired total field length including the given string
+   * @return the given string prepended with zeros.
+   */
+  public static final String zeroPad(final String s, final int fieldLength) {
+    return characterPad(s, fieldLength, '0', false);
+  }
 
-    /**
-     * Prepend or postpend the given string with the given character to fill the given field length.
-     * If the given string is equal or greater than the given field length, it will be returned
-     * without modification.
-     * 
-     * @param s the given string
-     * @param fieldLength the desired field length
-     * @param padChar the desired pad character
-     * @param postpend if true append the pacCharacters to the end of the string.
-     * @return prepended or postpended given string with the given character to fill the given field
-     *         length.
-     */
-    public static final String characterPad(final String s, final int fieldLength, final char padChar,
-            final boolean postpend) {
-        final char[] chArr = s.toCharArray();
-        final int sLen = chArr.length;
-        if (sLen < fieldLength) {
-            final char[] out = new char[fieldLength];
-            final int blanks = fieldLength - sLen;
-
-            if (postpend) {
-                for (int i = 0; i < sLen; i++) {
-                    out[i] = chArr[i];
-                }
-                for (int i = sLen; i < fieldLength; i++) {
-                    out[i] = padChar;
-                }
-            } else { // prepend
-                for (int i = 0; i < blanks; i++) {
-                    out[i] = padChar;
-                }
-                for (int i = blanks; i < fieldLength; i++) {
-                    out[i] = chArr[i - blanks];
-                }
-            }
-
-            return String.valueOf(out);
+  /**
+   * Prepend or postpend the given string with the given character to fill the
+   * given field length. If the given string is equal or greater than the given
+   * field length, it will be returned without modification.
+   *
+   * @param s           the given string
+   * @param fieldLength the desired field length
+   * @param padChar     the desired pad character
+   * @param postpend    if true append the pacCharacters to the end of the string.
+   * @return prepended or postpended given string with the given character to fill
+   *         the given field length.
+   */
+  public static final String characterPad(final String s, final int fieldLength, final char padChar,
+      final boolean postpend) {
+    final char[] chArr = s.toCharArray();
+    final int sLen = chArr.length;
+    if (sLen < fieldLength) {
+      final char[] out = new char[fieldLength];
+      final int blanks = fieldLength - sLen;
+
+      if (postpend) {
+        for (int i = 0; i < sLen; i++) {
+          out[i] = chArr[i];
+        }
+        for (int i = sLen; i < fieldLength; i++) {
+          out[i] = padChar;
+        }
+      } else { // prepend
+        for (int i = 0; i < blanks; i++) {
+          out[i] = padChar;
         }
-        return s;
+        for (int i = blanks; i < fieldLength; i++) {
+          out[i] = chArr[i - blanks];
+        }
+      }
+
+      return String.valueOf(out);
     }
+    return s;
+  }
 }
diff --git a/src/test/java/org/apache/datasketches/memory/internal/unsafe/MemoryCleanerTest.java b/src/test/java/org/apache/datasketches/memory/internal/unsafe/MemoryCleanerTest.java
index ee8c5e8..9626ffa 100644
--- a/src/test/java/org/apache/datasketches/memory/internal/unsafe/MemoryCleanerTest.java
+++ b/src/test/java/org/apache/datasketches/memory/internal/unsafe/MemoryCleanerTest.java
@@ -28,35 +28,35 @@ import org.testng.annotations.Test;
 
 public class MemoryCleanerTest {
 
-    @Test
-    public void cleanerDeallocates() {
-       SimpleDeallocator deallocator = new SimpleDeallocator();
-       MemoryCleaner cleaner = new MemoryCleaner(this, deallocator);
-       cleaner.clean();
-       assertTrue(SimpleDeallocator.getHasRun());
+  @Test
+  public void cleanerDeallocates() {
+    SimpleDeallocator deallocator = new SimpleDeallocator();
+    MemoryCleaner cleaner = new MemoryCleaner(this, deallocator);
+    cleaner.clean();
+    assertTrue(SimpleDeallocator.getHasRun());
+  }
+
+  @Test
+  public void noDeallocation() {
+    SimpleDeallocator deallocator = new SimpleDeallocator();
+    new MemoryCleaner(this, deallocator);
+    assertFalse(SimpleDeallocator.getHasRun());
+  }
+
+  static final class SimpleDeallocator implements Runnable {
+    static final AtomicBoolean hasRun = new AtomicBoolean();
+
+    SimpleDeallocator() {
+      hasRun.set(false);
     }
 
-    @Test
-    public void noDeallocation() {
-        SimpleDeallocator deallocator = new SimpleDeallocator();
-        new MemoryCleaner(this, deallocator);
-        assertFalse(SimpleDeallocator.getHasRun());
+    @Override
+    public void run() {
+      hasRun.compareAndSet(false, true);
     }
 
-    static final class SimpleDeallocator implements Runnable {
-        static final AtomicBoolean hasRun = new AtomicBoolean();
-
-        SimpleDeallocator() {
-            hasRun.set(false);
-        }
-
-        @Override
-        public void run() {
-            hasRun.compareAndSet(false, true);
-        }
-
-        public static Boolean getHasRun() {
-            return hasRun.get();
-        }
+    public static Boolean getHasRun() {
+      return hasRun.get();
     }
+  }
 }
diff --git a/src/test/java/org/apache/datasketches/memory/internal/unsafe/PrimTest.java b/src/test/java/org/apache/datasketches/memory/internal/unsafe/PrimTest.java
index 96ca4f9..6c87036 100644
--- a/src/test/java/org/apache/datasketches/memory/internal/unsafe/PrimTest.java
+++ b/src/test/java/org/apache/datasketches/memory/internal/unsafe/PrimTest.java
@@ -19,24 +19,25 @@
 
 package org.apache.datasketches.memory.internal.unsafe;
 
-import org.testng.annotations.Test;
-
 import static org.apache.datasketches.memory.internal.unsafe.UnsafeUtil.ARRAY_DOUBLE_INDEX_SCALE;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertTrue;
 
+import org.testng.annotations.Test;
+
 /**
- * 
+ *
  */
 public class PrimTest {
-    @Test
-    public void checkPrimOffset() {
-      int off = (int)Prim.BYTE.off();
-      assertTrue(off > 0);
-    }
 
-    @Test
-    public void checkPrim() {
-      assertEquals(Prim.DOUBLE.scale(), ARRAY_DOUBLE_INDEX_SCALE);
-    }
+  @Test
+  public void checkPrimOffset() {
+    int off = (int) Prim.BYTE.off();
+    assertTrue(off > 0);
+  }
+
+  @Test
+  public void checkPrim() {
+    assertEquals(Prim.DOUBLE.scale(), ARRAY_DOUBLE_INDEX_SCALE);
+  }
 }
diff --git a/src/test/java/org/apache/datasketches/memory/internal/unsafe/StepBooleanTest.java b/src/test/java/org/apache/datasketches/memory/internal/unsafe/StepBooleanTest.java
index 62580b0..8cb5cda 100644
--- a/src/test/java/org/apache/datasketches/memory/internal/unsafe/StepBooleanTest.java
+++ b/src/test/java/org/apache/datasketches/memory/internal/unsafe/StepBooleanTest.java
@@ -19,31 +19,30 @@
 
 package org.apache.datasketches.memory.internal.unsafe;
 
-import org.testng.annotations.Test;
-
 import static org.testng.Assert.assertTrue;
 
+import org.testng.annotations.Test;
+
 /**
- * 
+ *
  */
 public class StepBooleanTest {
-    //StepBoolean checks
-    @Test
-    public void checkStepBoolean() {
-      checkStepBoolean(true);
-      checkStepBoolean(false);
-    }
-
-    private static void checkStepBoolean(boolean initialState) {
-      StepBoolean step = new StepBoolean(initialState);
-      assertTrue(step.get() == initialState); //confirm initialState
-      step.change();
-      assertTrue(step.hasChanged());      //1st change was successful
-      assertTrue(step.get() != initialState); //confirm it is different from initialState
-      step.change();
-      assertTrue(step.get() != initialState); //Still different from initialState
-      assertTrue(step.hasChanged());  //confirm it was changed from initialState value
-    }
+  // StepBoolean checks
+  @Test
+  public void checkStepBoolean() {
+    checkStepBoolean(true);
+    checkStepBoolean(false);
+  }
 
+  private static void checkStepBoolean(boolean initialState) {
+    StepBoolean step = new StepBoolean(initialState);
+    assertTrue(step.get() == initialState); // confirm initialState
+    step.change();
+    assertTrue(step.hasChanged()); // 1st change was successful
+    assertTrue(step.get() != initialState); // confirm it is different from initialState
+    step.change();
+    assertTrue(step.get() != initialState); // Still different from initialState
+    assertTrue(step.hasChanged()); // confirm it was changed from initialState value
+  }
 
 }
diff --git a/src/test/java/org/apache/datasketches/memory/internal/unsafe/VirtualMachineMemoryTest.java b/src/test/java/org/apache/datasketches/memory/internal/unsafe/VirtualMachineMemoryTest.java
index 5faf111..0358263 100644
--- a/src/test/java/org/apache/datasketches/memory/internal/unsafe/VirtualMachineMemoryTest.java
+++ b/src/test/java/org/apache/datasketches/memory/internal/unsafe/VirtualMachineMemoryTest.java
@@ -24,15 +24,15 @@ import org.testng.annotations.Test;
 @SuppressWarnings({"unused"})
 public class VirtualMachineMemoryTest {
 
-    @Test
-    public void maxDirectBufferMemory() {
-       assert(VirtualMachineMemory.getMaxDBBMemory() >= 0);
-    }
+  @Test
+  public void maxDirectBufferMemory() {
+    assert (VirtualMachineMemory.getMaxDBBMemory() >= 0);
+  }
 
-    @Test
-    public void inertPageAlignment() {
-      boolean result = VirtualMachineMemory.getIsPageAligned();
-      //System.out.println("VM page alignment:" + result);
-      assert(true); //no exception was thrown
-    }
+  @Test
+  public void inertPageAlignment() {
+    boolean result = VirtualMachineMemory.getIsPageAligned();
+    // System.out.println("VM page alignment:" + result);
+    assert (true); // no exception was thrown
+  }
 }
diff --git a/tools/scripts/assets/CheckMemoryJar.java b/tools/scripts/assets/CheckMemoryJar.java
index d369c85..6c5d7a7 100644
--- a/tools/scripts/assets/CheckMemoryJar.java
+++ b/tools/scripts/assets/CheckMemoryJar.java
@@ -30,117 +30,121 @@ import org.apache.datasketches.memory.WritableMemory;
 
 public class CheckMemoryJar {
 
-    public void printJDK() {
-        String JdkVersionString = System.getProperty("java.version");
-        int JdkMajorVersion = getJavaMajorVersion(JdkVersionString);
-        println("JDK Full Version : " + JdkVersionString);
-        println("JDK Major Version: " + JdkMajorVersion);
-        println("");
+  public void printJDK() {
+    String JdkVersionString = System.getProperty("java.version");
+    int JdkMajorVersion = getJavaMajorVersion(JdkVersionString);
+    println("JDK Full Version : " + JdkVersionString);
+    println("JDK Major Version: " + JdkMajorVersion);
+    println("");
+  }
+
+  public void checkHeapWritableMemory() {
+    try {
+      String str = "1 - Heap WritableMemory Successful";
+      WritableMemory mem = WritableMemory.allocate(2 * str.length());
+      writeReadAndPrintString(mem, str);
+    } catch (Exception ex) {
+      exitOnError("Heap Writable Memory", ex);
     }
-
-    public void checkHeapWritableMemory() {
-        try {
-            String str = "1 - Heap WritableMemory Successful";
-            WritableMemory mem = WritableMemory.allocate(2 * str.length());
-            writeReadAndPrintString(mem, str);
-        } catch (Exception ex) {
-            exitOnError("Heap Writable Memory", ex);
-        }
-    }
-
-    public void checkAllocateDirect() throws Exception {
-        try {
-            String str = "2 - Allocate Direct Successful";
-            WritableHandle wh = WritableMemory.allocateDirect(2 * str.length());
-            WritableMemory wmem = wh.getWritable();
-            writeReadAndPrintString(wmem, str);
-            wh.close();
-        } catch (Exception ex) {
-            exitOnError("Allocate Direct", ex);
-        }
-    }
-
-    public void checkByteBuffer() throws Exception {
-        try {
-            String str = "3 - Map ByteBuffer Successful";
-            ByteBuffer bb = ByteBuffer.allocateDirect(2 * str.length());
-            bb.order(ByteOrder.nativeOrder());
-            WritableMemory wmem = WritableMemory.writableWrap(bb);
-            writeReadAndPrintString(wmem, str);
-        } catch (Exception ex) {
-            exitOnError("Map ByteBuffer", ex);
-        }
-    }
-
-    public void checkMap(String mappedFilePath) throws Exception {
-        try {
-            String str = "4 - Memory Map Successful";
-            File file = new File(mappedFilePath);
-            MapHandle mh = Memory.map(file);
-            Memory mem = mh.get();
-            mh.close();
-            println(str);
-        } catch (Exception ex) {
-            exitOnError("Memory Map", ex);
-        }
-    }
-
-    public static void main(final String[] args) throws Exception {
-        if (args.length < 1) {
-            System.out.println("Please provide the full path to the memory mapped file!");
-            System.exit(1);
-        }
-
-        String mappedFilePath = args[0];
-        CheckMemoryJar check = new CheckMemoryJar();
-        check.printJDK();
-        check.checkHeapWritableMemory();
-        check.checkAllocateDirect();
-        check.checkByteBuffer();
-        check.checkMap(mappedFilePath);
-        println("");
-        println("All checks passed.");
+  }
+
+  public void checkAllocateDirect() throws Exception {
+    try {
+      String str = "2 - Allocate Direct Successful";
+      WritableHandle wh = WritableMemory.allocateDirect(2 * str.length());
+      WritableMemory wmem = wh.getWritable();
+      writeReadAndPrintString(wmem, str);
+      wh.close();
+    } catch (Exception ex) {
+      exitOnError("Allocate Direct", ex);
     }
-
-    /**********************/
-
-    private static void writeReadAndPrintString(WritableMemory wmem, String str) {
-        int len = str.length();
-        char[] cArr1 = str.toCharArray();
-        wmem.putCharArray(0, cArr1, 0, len);
-        char[] cArr2 = new char[len];
-        wmem.getCharArray(0, cArr2, 0, len);
-        String s2 = String.valueOf(cArr2);
-        println(s2);
+  }
+
+  public void checkByteBuffer() throws Exception {
+    try {
+      String str = "3 - Map ByteBuffer Successful";
+      ByteBuffer bb = ByteBuffer.allocateDirect(2 * str.length());
+      bb.order(ByteOrder.nativeOrder());
+      WritableMemory wmem = WritableMemory.writableWrap(bb);
+      writeReadAndPrintString(wmem, str);
+    } catch (Exception ex) {
+      exitOnError("Map ByteBuffer", ex);
     }
-
-    private static void exitOnError(String checkName, Exception ex){
-        println(checkName + " check failed. Error: " + ex.toString());
-        System.exit(1);
+  }
+
+  public void checkMap(String mappedFilePath) throws Exception {
+    try {
+      String str = "4 - Memory Map Successful";
+      File file = new File(mappedFilePath);
+      MapHandle mh = Memory.map(file);
+      Memory mem = mh.get();
+      mh.close();
+      println(str);
+    } catch (Exception ex) {
+      exitOnError("Memory Map", ex);
     }
+  }
 
-    private static int getJavaMajorVersion(final String jdkVersion) {
-        int[] verArr = parseJavaVersion(jdkVersion);
-        return (verArr[0] == 1) ? verArr[1] : verArr[0];
+  public static void main(final String[] args) throws Exception {
+    if (args.length < 1) {
+      System.out.println("Please provide the full path to the memory mapped file!");
+      System.exit(1);
     }
 
-    /**
-     * Returns first two number groups of the java version string.
-     * @param jdkVersion the java version string from System.getProperty("java.version").
-     * @return first two number groups of the java version string.
-     */
-    private static int[] parseJavaVersion(final String jdkVersion) {
-        final int p0, p1;
-        try {
-            String[] parts = jdkVersion.trim().split("[^0-9\\.]");//grab only number groups and "."
-            parts = parts[0].split("\\."); //split out the number groups
-            p0 = Integer.parseInt(parts[0]); //the first number group
-            p1 = (parts.length > 1) ? Integer.parseInt(parts[1]) : 0; //2nd number group, or 0
-        } catch (final NumberFormatException | ArrayIndexOutOfBoundsException  e) {
-            throw new IllegalArgumentException("Improper Java -version string: " + jdkVersion + "\n" + e);
-        }
-        return new int[] {p0, p1};
+    String mappedFilePath = args[0];
+    CheckMemoryJar check = new CheckMemoryJar();
+    check.printJDK();
+    check.checkHeapWritableMemory();
+    check.checkAllocateDirect();
+    check.checkByteBuffer();
+    check.checkMap(mappedFilePath);
+    println("");
+    println("All checks passed.");
+  }
+
+  /**********************/
+
+  private static void writeReadAndPrintString(WritableMemory wmem, String str) {
+    int len = str.length();
+    char[] cArr1 = str.toCharArray();
+    wmem.putCharArray(0, cArr1, 0, len);
+    char[] cArr2 = new char[len];
+    wmem.getCharArray(0, cArr2, 0, len);
+    String s2 = String.valueOf(cArr2);
+    println(s2);
+  }
+
+  private static void exitOnError(String checkName, Exception ex) {
+    println(checkName + " check failed. Error: " + ex.toString());
+    System.exit(1);
+  }
+
+  private static int getJavaMajorVersion(final String jdkVersion) {
+    int[] verArr = parseJavaVersion(jdkVersion);
+    return (verArr[0] == 1) ? verArr[1] : verArr[0];
+  }
+
+  /**
+   * Returns first two number groups of the java version string.
+   * 
+   * @param jdkVersion the java version string from
+   *                   System.getProperty("java.version").
+   * @return first two number groups of the java version string.
+   */
+  private static int[] parseJavaVersion(final String jdkVersion) {
+    final int p0, p1;
+    try {
+      String[] parts = jdkVersion.trim().split("[^0-9\\.]");// grab only number groups and "."
+      parts = parts[0].split("\\."); // split out the number groups
+      p0 = Integer.parseInt(parts[0]); // the first number group
+      p1 = (parts.length > 1) ? Integer.parseInt(parts[1]) : 0; // 2nd number group, or 0
+    } catch (final NumberFormatException | ArrayIndexOutOfBoundsException e) {
+      throw new IllegalArgumentException("Improper Java -version string: " + jdkVersion + "\n" + e);
     }
+    return new int[] { p0, p1 };
+  }
 
-    private static void println(Object obj) { System.out.println(obj.toString()); }
+  private static void println(Object obj) {
+    System.out.println(obj.toString());
+  }
 }


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