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/11 22:50:00 UTC

[datasketches-memory] branch refactorInterfaces17B created (now edbe235)

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

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


      at edbe235  Bring refactorInterfaces17B consistent with refactorInterfaces

This branch includes the following new commits:

     new edbe235  Bring refactorInterfaces17B consistent with refactorInterfaces

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



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


[datasketches-memory] 01/01: Bring refactorInterfaces17B consistent with refactorInterfaces

Posted by le...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit edbe23517d05b24370e0090e542b4f13f988456a
Author: Lee Rhodes <le...@users.noreply.github.com>
AuthorDate: Fri Nov 11 14:49:52 2022 -0800

    Bring refactorInterfaces17B consistent with refactorInterfaces
---
 .github/workflows/.toolchains.xml                  |  20 -
 .github/workflows/auto-jdk-matrix.yml              |  65 ++
 .github/workflows/manual-coverage.yml              |  71 ++
 .github/workflows/manual-os-matrix.yml             |  75 ++
 .github/workflows/maven.yml                        | 119 ---
 pom.xml                                            | 130 ++--
 .../apache/datasketches/memory/BufferFactory.java  |  96 ++-
 .../datasketches/memory/DefaultBufferFactory.java  |  68 +-
 .../datasketches/memory/DefaultMemoryFactory.java  | 372 ++++-----
 .../memory/DefaultMemoryRequestServer.java         |  20 +-
 .../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 +-
 20 files changed, 1828 insertions(+), 1557 deletions(-)

diff --git a/.github/workflows/.toolchains.xml b/.github/workflows/.toolchains.xml
index 70b6e51..5f40493 100644
--- a/.github/workflows/.toolchains.xml
+++ b/.github/workflows/.toolchains.xml
@@ -30,24 +30,4 @@
             <jdkHome>${env.JAVA11_HOME}</jdkHome>
         </configuration>
     </toolchain>
-    <toolchain>
-        <type>jdk</type>
-        <provides>
-            <version>12</version>
-            <vendor>openjdk</vendor>
-        </provides>
-        <configuration>
-            <jdkHome>${env.JAVA12_HOME}</jdkHome>
-        </configuration>
-    </toolchain>
-    <toolchain>
-        <type>jdk</type>
-        <provides>
-            <version>13</version>
-            <vendor>openjdk</vendor>
-        </provides>
-        <configuration>
-            <jdkHome>${env.JAVA13_HOME}</jdkHome>
-        </configuration>
-    </toolchain>
 </toolchains>
\ No newline at end of file
diff --git a/.github/workflows/auto-jdk-matrix.yml b/.github/workflows/auto-jdk-matrix.yml
new file mode 100644
index 0000000..32e12af
--- /dev/null
+++ b/.github/workflows/auto-jdk-matrix.yml
@@ -0,0 +1,65 @@
+name: DataSketches-Memory Auto JDK Matrix Test & Install
+
+on:
+    pull_request:
+    push:
+        branches: [ master ]
+    workflow_dispatch:
+
+env:
+    MAVEN_OPTS: -Xmx4g -Xms1g
+
+jobs:
+    build:
+        name: Build, Test, Install
+        runs-on: ubuntu-latest
+        strategy:
+          fail-fast: false
+          matrix:
+              jdk: [ 8,11 ]
+        env:
+          JDK_VERSION: ${{ matrix.jdk }}
+
+        steps:
+        - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
+          uses: actions/checkout@v3
+          with:
+              persist-credentials: false
+
+        - name: Cache local Maven repository
+          uses: actions/cache@v3
+          with:
+              path: ~/.m2/repository
+              key: build-${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+              restore-keys: build-${{ runner.os }}-maven-
+
+        - name: Install Matrix JDK
+          uses: actions/setup-java@v3
+          with:
+              java-version: ${{ matrix.jdk }}
+              distribution: 'temurin'
+              java-package: jdk
+              architecture: x64 
+# Architecture options: x86, x64, armv7, aarch64, ppc64le
+# setup-java@v3 has a "with cache" option
+
+        - name: Echo Java Version
+          run: >
+              java -version
+
+        - name: Test
+          run: >
+              mvn clean test
+              -Dmaven.javadoc.skip=true
+              -Dgpg.skip=true
+
+        - name: Install
+          run: >
+              mvn clean install -B
+              -DskipTests=true
+              -Dgpg.skip=true
+
+# Lifecycle: validate, compile, test, package, verify, install, deploy
+# -B batch mode
+# -V show Version without stopping
+# -q quiet, only show errors
diff --git a/.github/workflows/manual-coverage.yml b/.github/workflows/manual-coverage.yml
new file mode 100644
index 0000000..03320e5
--- /dev/null
+++ b/.github/workflows/manual-coverage.yml
@@ -0,0 +1,71 @@
+name: Datasketches-Memory Manual Coverage Report
+
+on:
+    workflow_dispatch:
+
+env:
+    MAVEN_OPTS: -Xmx4g -Xms1g
+
+jobs:
+    build:
+        name: Build, Test, Coverage
+        runs-on: ${{matrix.os}}
+        strategy:
+          fail-fast: false
+          matrix:
+            jdk: [ 8 ]
+            os: [ ubuntu-latest ]
+            include:
+#              - os: windows-latest
+#                skip_javadoc: "`-Dmaven`.javadoc`.skip=true"
+#                skip_gpg: "`-Dgpg`.skip=true"
+              - os: ubuntu-latest
+                skip_javadoc: -Dmaven.javadoc.skip=true
+                skip_gpg: -Dgpg.skip=true
+#              - os: macos-latest
+#                skip_javadoc: -Dmaven.javadoc.skip=true
+#                skip_gpg: -Dgpg.skip=true
+
+        env:
+          JDK_VERSION: ${{ matrix.jdk }}
+
+        steps:
+        - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
+          uses: actions/checkout@v3
+          with:
+              persist-credentials: false
+
+        - name: Cache local Maven repository
+          uses: actions/cache@v3
+          with:
+              path: ~/.m2/repository
+              key: build-${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+              restore-keys: build-${{ runner.os }}-maven-
+
+        - name: Install Matrix JDK
+          uses: actions/setup-java@v3
+          with:
+              java-version: ${{ matrix.jdk }}
+              distribution: 'temurin'
+              java-package: jdk
+              architecture: x64 
+# Architecture options: x86, x64, armv7, aarch64, ppc64le
+# setup-java@v3 has a "with cache" option
+
+        - name: Echo Java Version
+          run: >
+              java -version
+
+        - name: Test, Package, Verify, Coverage Report
+          if: ${{ matrix.jdk == 8 && success() }}
+          run: 
+              mvn verify coveralls:report -B
+              -DrepoToken=${{secrets.coveralls_token}}
+              ${{matrix.os.skip_javadoc}}
+              ${{matrix.os.skip_gpg}}
+              
+# Lifecycle: validate, compile, test, package, verify, install, deploy
+# Coverage reports are available after the verify phase
+# -B batch mode
+# -V show Version without stopping
+# -q quiet, only show errors
diff --git a/.github/workflows/manual-os-matrix.yml b/.github/workflows/manual-os-matrix.yml
new file mode 100644
index 0000000..860b315
--- /dev/null
+++ b/.github/workflows/manual-os-matrix.yml
@@ -0,0 +1,75 @@
+name: DataSketches-Memory Manual OS Matrix Test & Install
+
+on:
+    workflow_dispatch:
+
+env:
+    MAVEN_OPTS: -Xmx4g -Xms1g
+
+jobs:
+    build:
+        name: Build, Test, Install
+        runs-on: ${{matrix.os}}
+        strategy:
+          fail-fast: false
+          matrix:
+            jdk: [ 8, 11 ]
+            os: [ windows-latest, ubuntu-latest, macos-latest ]
+            include:
+              - os: windows-latest
+                skip_javadoc: "`-Dmaven`.javadoc`.skip=true"
+                skip_gpg: "`-Dgpg`.skip=true"
+              - os: ubuntu-latest
+                skip_javadoc: -Dmaven.javadoc.skip=true
+                skip_gpg: -Dgpg.skip=true
+              - os: macos-latest
+                skip_javadoc: -Dmaven.javadoc.skip=true
+                skip_gpg: -Dgpg.skip=true
+
+        env:
+          JDK_VERSION: ${{ matrix.jdk }}
+
+        steps:
+        - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
+          uses: actions/checkout@v3
+          with:
+              persist-credentials: false
+
+        - name: Cache local Maven repository
+          uses: actions/cache@v3
+          with:
+              path: ~/.m2/repository
+              key: build-${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+              restore-keys: build-${{ runner.os }}-maven-
+
+        - name: Install Matrix JDK
+          uses: actions/setup-java@v3
+          with:
+              java-version: ${{ matrix.jdk }}
+              distribution: 'temurin'
+              java-package: jdk
+              architecture: x64 
+# Architecture options: x86, x64, armv7, aarch64, ppc64le
+# setup-java@v3 has a "with cache" option
+
+        - name: Echo Java Version
+          run: >
+              java -version
+
+        - name: Test
+          run: >
+              mvn clean test
+              ${{matrix.os.skip_javadoc}}
+              ${{matrix.os.skip_gpg}}
+
+        - name: Install
+          run: >
+              mvn clean install -B
+              ${{matrix.os.skip_javadoc}}
+              -D skipTests=true
+              ${{matrix.os.skip_gpg}}
+
+# Lifecycle: validate, compile, test, package, verify, install, deploy
+# -B batch mode
+# -V show Version without stopping
+# -q quiet, only show errors
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
deleted file mode 100644
index 22fc03f..0000000
--- a/.github/workflows/maven.yml
+++ /dev/null
@@ -1,119 +0,0 @@
-name: Java Test Coverage with Maven, Coveralls
-
-on:
-  pull_request:
-  push:
-    branches: [ master ]
-  workflow_dispatch:
-
-env:
-  MAVEN_OPTS: -Xmx4g -Xms1g
-  repo_token: ${{secrets.coveralls_token}}
-  RUNNER_TEMP: /tmp
-
-jobs:
-  build:
-    name: Build, Test, Coverage
-    runs-on: ubuntu-latest
-    strategy:
-      fail-fast: false
-      matrix:
-        jdk: [8,11,12,13]
-
-    # All JDKs are installed per build machine which is inefficient
-
-    env:
-      JDK_VERSION: ${{ matrix.jdk }}
-
-    steps:
-      - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
-        uses: actions/checkout@v2
-        with:
-          persist-credentials: false
-
-      - name: Cache local Maven repository
-        uses: actions/cache@v2
-        with:
-          path: ~/.m2/repository
-          key: build-${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
-          restore-keys: build-${{ runner.os }}-maven-
-
-      - name: Install JDK 8
-        uses: AdoptOpenJDK/install-jdk@v1
-        with:
-          version: '8'
-          architecture: x64
-          impl: hotspot
-          targets: 'JAVA8_HOME'
-
-      - name: Install JDK 11
-        uses: AdoptOpenJDK/install-jdk@v1
-        with:
-          version: '11'
-          architecture: x64
-          impl: hotspot
-          targets: 'JAVA11_HOME'
-
-      - name: Install JDK 12
-        uses: AdoptOpenJDK/install-jdk@v1
-        with:
-          version: '12'
-          architecture: x64
-          impl: hotspot
-          targets: 'JAVA12_HOME'
-
-      - name: Install JDK 13
-        uses: AdoptOpenJDK/install-jdk@v1
-        with:
-          version: '13'
-          architecture: x64
-          impl: hotspot
-          targets: 'JAVA13_HOME'
-
-      - name: Install Matrix JDK
-        uses: AdoptOpenJDK/install-jdk@v1
-        with:
-          version: ${{ matrix.jdk }}
-          architecture: x64
-          impl: hotspot
-          targets: 'JAVA_HOME'
-
-      - name: Echo Java Version
-        run: >
-          java -version
-
-      - name: Compile
-        run: >
-          mvn clean compile
-          -Dmaven.javadoc.skip=true
-          -Dgpg.skip=true
-          --toolchains .github/workflows/.toolchains.xml
-
-      - name: Install Dependencies
-        run: >
-          mvn clean install
-          -DskipTests=true
-          -Dgpg.skip=true
-          --toolchains .github/workflows/.toolchains.xml
-
-      - name: Package
-        run: >
-          mvn package
-          -Dmaven.javadoc.skip=false
-          -Dgpg.skip=true
-          --toolchains .github/workflows/.toolchains.xml
-
-      # The GitTag for CI purposes is irrelevant
-      - name: Custom build script
-        run: |
-          ./tools/scripts/package-single-release-jar.sh $JAVA_HOME x.y.z .
-        shell: bash
-
-      - name: Test & Report
-        if: ${{ matrix.jdk == 8 && success() }}
-        run: >
-          mvn verify coveralls:report -B -V
-          -Dcoveralls-repo-token=${repo_token}
-          -Dmaven.javadoc.skip=true
-          -Dgpg.skip=true
-          --toolchains .github/workflows/.toolchains.xml
diff --git a/pom.xml b/pom.xml
index 7baaaab..40f4dfc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,7 +28,7 @@
   <parent>
     <groupId>org.apache</groupId>
     <artifactId>apache</artifactId>
-    <version>23</version>
+    <version>27</version>
   </parent>
 
   <groupId>org.apache.datasketches</groupId>
@@ -85,9 +85,11 @@
   <properties>
     <maven.compiler.source>1.8</maven.compiler.source>
     <maven.compiler.target>1.8</maven.compiler.target>
-    <maven.build.timestamp.format>yyyy-MM-dd'T'HH mm ss'Z'</maven.build.timestamp.format>
-
     <jdk-toolchain.version>8</jdk-toolchain.version>
+    <maven.build.timestamp.format>yyyy-MM-dd'T'HH mm ss'Z'</maven.build.timestamp.format>
+    <!-- org.eluder Maven Plugins -->
+    <coveralls-repo-token></coveralls-repo-token>
+    <coveralls-maven-plugin.version>4.3.0</coveralls-maven-plugin.version>
   </properties>
 
   <repositories>
@@ -141,7 +143,8 @@
   <build>
     <pluginManagement>
       <plugins>
-        <plugin>
+
+        <plugin><!-- Extends maven-apache-parent pom.xml -->
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-compiler-plugin</artifactId>
           <version>3.10.1</version>
@@ -151,14 +154,35 @@
             </jdkToolchain>
           </configuration>
         </plugin>
-        <plugin>
-          <!-- Extends Apache Parent pom, pluginManagement -->
+
+        <plugin><!-- Extends maven-apache-parent pom.xml -->
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-enforcer-plugin</artifactId>
+          <version>3.1.0</version>
+        </plugin>
+
+        <plugin><!-- Extends maven-apache-parent pom.xml -->
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-failsafe-plugin</artifactId>
+          <version>3.0.0-M7</version><!-- same as surefire -->
+          <configuration>
+            <trimStackTrace>false</trimStackTrace>
+            <useManifestOnlyJar>false</useManifestOnlyJar>
+            <redirectTestOutputToFile>true</redirectTestOutputToFile>
+            <jdkToolchain>
+              <version>${jdk-toolchain.version}</version>
+            </jdkToolchain>
+            <reportsDirectory>${project.build.directory}/validation-output/${maven.build.timestamp}</reportsDirectory>
+          </configuration>
+        </plugin>
+
+        <plugin><!-- Extends maven-apache-parent pom.xml -->
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-jar-plugin</artifactId>
           <version>3.3.0</version>
         </plugin>
-        <plugin>
-          <!-- Extends Apache Parent pom, apache-release profile -->
+
+        <plugin><!-- Extends maven-apache-parent pom.xml -->
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-javadoc-plugin</artifactId>
           <version>3.4.1</version>
@@ -172,17 +196,10 @@
           </configuration>
         </plugin>
 
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-enforcer-plugin</artifactId>
-          <version>3.1.0</version>
-        </plugin>
-
-        <plugin>
-          <!-- Apache Parent pom, pluginManagement -->
+        <plugin><!-- Extends maven-apache-parent pom.xml -->
           <groupId>org.apache.rat</groupId>
           <artifactId>apache-rat-plugin</artifactId>
-          <version>0.13</version>
+          <version>0.15</version>
           <configuration>
             <outputDirectory>${project.basedir}/rat</outputDirectory>
             <consoleOutput>true</consoleOutput>
@@ -197,6 +214,9 @@
               <exclude>**/validation-output/**/*</exclude>
               <exclude>**/img/**/*.png</exclude>
               <exclude>**/git.properties</exclude>
+              <exclude>.gitattributes</exclude>
+              <exclude>.gitignore</exclude>
+              <exclude>.git/**</exclude>
               <exclude>**/scripts/assets/LoremIpsum.txt</exclude>
               <exclude>LICENSE</exclude>
               <exclude>NOTICE</exclude>
@@ -204,15 +224,13 @@
           </configuration>
         </plugin>
 
-        <plugin>
-          <!-- Extends Apache Parent pom, apache-release profile -->
+        <plugin><!-- Extends maven-apache-parent pom.xml -->
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-source-plugin</artifactId>
           <version>3.2.1</version>
         </plugin>
 
-        <plugin>
-          <!-- Apache Parent pom, pluginManagement -->
+        <plugin><!-- Extends maven-apache-parent pom.xml -->
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-surefire-plugin</artifactId>
           <version>3.0.0-M7</version>
@@ -227,22 +245,6 @@
           </configuration>
         </plugin>
 
-        <plugin>
-          <!-- Apache Parent pom, pluginManagement -->
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-failsafe-plugin</artifactId>
-          <version>3.0.0-M7</version>
-          <configuration>
-            <trimStackTrace>false</trimStackTrace>
-            <useManifestOnlyJar>false</useManifestOnlyJar>
-            <redirectTestOutputToFile>true</redirectTestOutputToFile>
-            <jdkToolchain>
-              <version>${jdk-toolchain.version}</version>
-            </jdkToolchain>
-            <reportsDirectory>${project.build.directory}/validation-output/${maven.build.timestamp}</reportsDirectory>
-          </configuration>
-        </plugin>
-
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-toolchains-plugin</artifactId>
@@ -260,7 +262,7 @@
           <!-- Generates code coverage report from website. -->
           <groupId>org.jacoco</groupId>
           <artifactId>jacoco-maven-plugin</artifactId>
-          <version>0.8.6</version>
+          <version>0.8.8</version>
         </plugin>
 
         <plugin>
@@ -285,6 +287,8 @@
         <artifactId>maven-compiler-plugin</artifactId>
         <executions>
           <execution>
+            <!-- Compiling main code with Java 8.
+                 All Java 9+ code must be excluded elsewhere, incuding add-excludes & opens -->
             <id>default-compile</id>
             <goals>
               <goal>compile</goal>
@@ -298,6 +302,8 @@
             </configuration>
           </execution>
           <execution>
+            <!-- Compiling test code with Java 8. All test code is run only from Java 8.
+                 Any Java 9+ tests must be excluded elsewhere, incuding add-excludes and opens -->
             <id>default-testCompile</id>
             <goals>
               <goal>testCompile</goal>
@@ -309,11 +315,14 @@
               <source>1.8</source>
               <target>1.8</target>
               <testExcludes>
+                <!-- In Java 8 this is not allowed, if not excluded elsewhere -->
                 <testExclude>module-info.java</testExclude>
               </testExcludes>
             </configuration>
           </execution>
           <execution>
+            <!-- Compiling main code with Java 11. 
+                 All code specific to other Java versions must be excluded elsewhere -->
             <id>compile-java-11</id>
             <phase>compile</phase>
             <goals>
@@ -321,6 +330,7 @@
             </goals>
             <configuration>
               <compilerArgs>
+                <!-- The following export provides access to the JVM Cleaner and is required at compile time: -->
                 <arg>--add-exports</arg>
                 <arg>java.base/jdk.internal.ref=org.apache.datasketches.memory</arg>
               </compilerArgs>
@@ -336,10 +346,17 @@
               <outputDirectory>${project.build.outputDirectory}/META-INF/versions/11</outputDirectory>
             </configuration>
           </execution>
+          <!-- The following exports would be required to compile tests IF the tests were run from Java 11.
+               They are provided here for reference if this fact changes.
+               Note that the target is ALL-UNNAMED, because test code is part of the classpath, not modulepath.
+                <arg>==add-exports</arg>
+                <arg>java.base/jdk.internal.misc=ALL-UNNAMED</arg>
+                <arg>==add-exports</arg>
+                <arg>java.base/sun.nio.ch=ALL-UNNAMED</arg> -->
         </executions>
       </plugin>
-      <plugin>
-        <!-- Extends Apache Parent pom, pluginManagement -->
+
+      <plugin><!-- Extends maven-apache-parent pom.xml -->
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-jar-plugin</artifactId>
         <executions>
@@ -367,7 +384,8 @@
           </execution>
         </executions>
       </plugin>
-      <plugin>
+
+      <plugin><!-- Extends maven-apache-parent pom.xml -->
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-javadoc-plugin</artifactId>
         <executions>
@@ -380,7 +398,8 @@
           </execution>
         </executions>
       </plugin>
-      <plugin>
+
+      <plugin><!-- Extends maven-apache-parent pom.xml -->
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-enforcer-plugin</artifactId>
         <executions>
@@ -409,7 +428,8 @@
           </execution>
         </executions>
       </plugin>
-      <plugin>
+
+      <plugin><!-- Extends maven-apache-parent pom.xml -->
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-source-plugin</artifactId>
         <executions>
@@ -429,7 +449,8 @@
           </execution>
         </executions>
       </plugin>
-      <plugin>
+
+      <plugin><!-- Extends maven-apache-parent pom.xml -->
         <groupId>org.apache.rat</groupId>
         <artifactId>apache-rat-plugin</artifactId>
         <executions>
@@ -441,8 +462,8 @@
           </execution>
         </executions>
       </plugin>
-      <plugin>
-        <!-- Apache Parent pom, pluginManagement -->
+
+      <plugin><!-- Extends maven-apache-parent pom.xml -->
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-failsafe-plugin</artifactId>
         <executions>
@@ -467,12 +488,23 @@
             <configuration>
               <jdkToolchain>
                 <version>11</version>
-              </jdkToolchain>
-              <argLine>--add-exports java.base/jdk.internal.ref=ALL-UNNAMED --add-exports java.base/jdk.internal.misc=ALL-UNNAMED --add-opens java.base/java.nio=ALL-UNNAMED --add-opens java.base/sun.nio.ch=ALL-UNNAMED</argLine>
+              </jdkToolchain>  
+              <!-- 'exports' are required for compile by verify, which runs against the produced jars.
+                   'opens'' is required to run the tests.  Note that the target is ALL-UNNAMED,
+                   because the test code is part of the classpath not the modulepath.
+                   The following export may be required in a different environment:
+                ==add-exports java.base/sun.nio.ch=ALL-UNNAMED  -->
+              <argLine>
+                --add-exports java.base/jdk.internal.ref=ALL-UNNAMED
+                --add-exports java.base/jdk.internal.misc=ALL-UNNAMED
+                --add-opens java.base/sun.nio.ch=ALL-UNNAMED
+                --add-opens java.base/java.nio=ALL-UNNAMED
+              </argLine>
             </configuration>
           </execution>
         </executions>
       </plugin>
+
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-toolchains-plugin</artifactId>
@@ -511,7 +543,7 @@
       <build>
         <pluginManagement>
           <plugins>
-            <plugin>
+            <plugin><!-- Extends maven-apache-parent pom.xml -->
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-remote-resources-plugin</artifactId>
               <version>${maven-remote-resources-plugin.version}</version>
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 11619d3..efc6f06 100644
--- a/src/main/java/org/apache/datasketches/memory/DefaultMemoryFactory.java
+++ b/src/main/java/org/apache/datasketches/memory/DefaultMemoryFactory.java
@@ -18,197 +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 = DefaultMemoryRequestServer.DEFAULT.getFactory();
-    
-    private final MemoryRequestServer memoryRequestServer;
-    
-    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/DefaultMemoryRequestServer.java b/src/main/java/org/apache/datasketches/memory/DefaultMemoryRequestServer.java
index 1393d7c..3759dce 100644
--- a/src/main/java/org/apache/datasketches/memory/DefaultMemoryRequestServer.java
+++ b/src/main/java/org/apache/datasketches/memory/DefaultMemoryRequestServer.java
@@ -68,8 +68,8 @@ public final class DefaultMemoryRequestServer implements MemoryRequestServer {
     
   public static final DefaultMemoryRequestServer DEFAULT = new DefaultMemoryRequestServer();
     
-  private MemoryFactory factory = new DefaultMemoryFactory(this);
-
+  private MemoryFactory factory;
+  
   /**
    * {@inheritDoc}
    *
@@ -77,6 +77,9 @@ public final class DefaultMemoryRequestServer implements MemoryRequestServer {
    */
   @Override
   public WritableMemory request(final WritableMemory currentWritableMemory, final long capacityBytes) {
+    if (factory == null) {
+        factory = DefaultMemoryFactory.DEFAULT;
+    }
     final WritableMemory wmem = factory.allocate((int)capacityBytes, currentWritableMemory.getByteOrder());
     return wmem;
   }
@@ -92,15 +95,12 @@ public final class DefaultMemoryRequestServer implements MemoryRequestServer {
   public void requestClose(final WritableMemory memToRelease, final WritableMemory newMemory) {
     //do nothing
   }
-  
-  /**
-   * Get the associated {@link MemoryFactory}. This has package level access so that the default
-   * {@link DefaultMemoryFactory} can correctly initialize itself with a cross reference to this.
-   * 
-   * @return The current {@link MemoryFactory}
-   */
-  MemoryFactory getFactory() {
+
+  public MemoryFactory getFactory() {
     return factory;
   }
 
+  public void setFactory(MemoryFactory factory) {
+    this.factory = factory;
+  }
 }
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
+  }
 }


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