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/18 06:49:17 UTC

[datasketches-memory] 01/03: Add java17 tests.

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

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

commit fc8ffb59f57d40a35606a16861e4906c7bd38871
Author: Lee Rhodes <le...@users.noreply.github.com>
AuthorDate: Thu Nov 17 20:23:19 2022 -0800

    Add java17 tests.
---
 .../internal/AllocateDirectMapMemoryTest.java      |  138 +++
 .../memory/internal/AllocateDirectMemoryTest.java  |  113 ++
 .../AllocateDirectWritableMapMemoryTest.java       |  240 +++++
 .../memory/internal/BaseBufferTest.java            |   92 ++
 .../memory/internal/BaseStateTest.java             |  138 +++
 .../datasketches/memory/internal/Buffer2Test.java  |  434 ++++++++
 .../memory/internal/BufferBoundaryCheckTest.java   |  185 ++++
 .../memory/internal/BufferInvariantsTest.java      |  345 +++++++
 .../memory/internal/BufferReadWriteSafetyTest.java |  180 ++++
 .../datasketches/memory/internal/BufferTest.java   |  327 ++++++
 .../memory/internal/CommonBufferTest.java          |  430 ++++++++
 .../memory/internal/CommonMemoryTest.java          |  375 +++++++
 .../memory/internal/CopyMemoryOverlapTest.java     |  187 ++++
 .../memory/internal/CopyMemoryTest.java            |  182 ++++
 .../memory/internal/DruidIssue11544Test.java       |  101 ++
 .../internal/ExampleMemoryRequestServerTest.java   |  138 +++
 .../memory/internal/IgnoredArrayOverflowTest.java  |  110 ++
 .../datasketches/memory/internal/LeafImplTest.java |  259 +++++
 .../memory/internal/MemoryBoundaryCheckTest.java   |  185 ++++
 .../memory/internal/MemoryReadWriteSafetyTest.java |  216 ++++
 .../datasketches/memory/internal/MemoryTest.java   |  461 +++++++++
 .../memory/internal/MemoryWriteToTest.java         |  101 ++
 .../memory/internal/MurmurHash3v3Test.java         |  421 ++++++++
 .../internal/NativeWritableBufferImplTest.java     |  559 ++++++++++
 .../internal/NativeWritableMemoryImplTest.java     |  679 ++++++++++++
 .../internal/NonNativeWritableBufferImplTest.java  |  279 +++++
 .../internal/NonNativeWritableMemoryImplTest.java  |  176 ++++
 .../memory/internal/SpecificLeafTest.java          |  202 ++++
 .../datasketches/memory/internal/UtilTest.java     |  107 ++
 .../memory/internal/WritableDirectCopyTest.java    |  253 +++++
 .../memory/internal/WritableMemoryTest.java        |  184 ++++
 .../memory/internal/XxHash64LoopingTest.java       | 1082 ++++++++++++++++++++
 .../datasketches/memory/internal/XxHash64Test.java |  179 ++++
 .../memory/internal/ZeroCapacityTest.java          |   76 ++
 .../src/test/resources/GettysburgAddress.txt       |    7 +
 pom.xml                                            |    4 +-
 36 files changed, 9143 insertions(+), 2 deletions(-)

diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/AllocateDirectMapMemoryTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/AllocateDirectMapMemoryTest.java
new file mode 100644
index 0000000..161eb1b
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/AllocateDirectMapMemoryTest.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * Note: Lincoln's Gettysburg Address is in the public domain. See LICENSE.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.apache.datasketches.memory.internal.Util.getResourceFile;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.io.File;
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.Memory;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+public class AllocateDirectMapMemoryTest {
+  private static final String LS = System.getProperty("line.separator");
+
+  @Test
+  public void simpleMap() throws Exception {
+    File file = getResourceFile("GettysburgAddress.txt");
+    file.setReadOnly();
+    Memory mem = null;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      mem = Memory.map(file, scope);
+    }
+    assertFalse(mem.isAlive());
+  }
+
+  @Test
+  public void testIllegalArguments() throws Exception {
+    File file = getResourceFile("GettysburgAddress.txt");
+    Memory mem = null;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      mem = Memory.map(file, -1, Integer.MAX_VALUE, scope, ByteOrder.nativeOrder());
+      fail("Failed: test IllegalArgumentException: Position was negative.");
+      mem.getCapacity();
+    }
+    catch (IllegalArgumentException e) {
+      //ok
+    }
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      mem = Memory.map(file, 0, -1, scope, ByteOrder.nativeOrder());
+      fail("Failed: testIllegalArgumentException: Size was negative.");
+    } catch (IllegalArgumentException e) {
+      //ok
+    }
+  }
+
+  @Test
+  public void testMapAndMultipleClose() throws Exception {
+    File file = getResourceFile("GettysburgAddress.txt");
+    long memCapacity = file.length();
+    Memory mem = null;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      mem = Memory.map(file, 0, memCapacity, scope, ByteOrder.nativeOrder());
+      assertEquals(memCapacity, mem.getCapacity());
+      //mem.close(); //a close inside the TWR block will throw excption when the TWR block ends
+    }
+    mem.close(); //multiple closes outside the TWR block are OK, but unnecessary
+    mem.close();
+  }
+
+  @Test
+  public void testLoad() throws Exception {
+    File file = getResourceFile("GettysburgAddress.txt");
+    long memCapacity = file.length();
+    Memory mem = null;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      mem = Memory.map(file, 0, memCapacity, scope, ByteOrder.nativeOrder());
+      mem.load();
+      assertTrue(mem.isLoaded());
+    }
+  }
+
+  @SuppressWarnings("resource")
+  @Test
+  public void testHandleHandoff() throws Exception {
+    File file = getResourceFile("GettysburgAddress.txt");
+    long memCapacity = file.length();
+    ResourceScope scope = ResourceScope.newConfinedScope();
+    Memory mem = Memory.map(file, 0, memCapacity, scope, ByteOrder.nativeOrder());
+    ResourceScope.Handle handle = scope.acquire();
+    try {
+      mem.load();
+      assertTrue(mem.isLoaded());
+    } finally {
+      mem.scope().release(handle);
+    }
+    assertTrue(mem.isAlive());
+    mem.close(); //handle must be released before close
+    assertFalse(mem.isAlive());
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  static void println(final Object o) {
+    if (o == null) { print(LS); }
+    else { print(o.toString() + LS); }
+  }
+
+  /**
+   * @param o value to print
+   */
+  static void print(final Object o) {
+    if (o != null) {
+      //System.out.print(o.toString()); //disable here
+    }
+  }
+
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/AllocateDirectMemoryTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/AllocateDirectMemoryTest.java
new file mode 100644
index 0000000..0497a66
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/AllocateDirectMemoryTest.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+public class AllocateDirectMemoryTest {
+  private static final MemoryRequestServer memReqSvr = BaseState.defaultMemReqSvr;
+
+  @SuppressWarnings("resource")
+  @Test
+  public void simpleAllocateDirect() {
+    int longs = 32;
+    WritableMemory wMem = null;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      wMem = WritableMemory.allocateDirect(longs << 3, scope, memReqSvr);
+      for (int i = 0; i<longs; i++) {
+        wMem.putLong(i << 3, i);
+        assertEquals(wMem.getLong(i << 3), i);
+      }
+      //inside the TWR block the memory scope will be alive
+      assertTrue(wMem.isAlive());
+    }
+    //The TWR block has exited, so the memory should be invalid
+    assertFalse(wMem.isAlive());
+  }
+
+  @Test
+  public void checkDefaultMemoryRequestServer() {
+    int longs1 = 32;
+    int bytes1 = longs1 << 3;
+    WritableMemory wmem = null;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      wmem = WritableMemory.allocateDirect(bytes1, scope, memReqSvr);
+
+      for (int i = 0; i < longs1; i++) { //puts data in origWmem
+        wmem.putLong(i << 3, i);
+        assertEquals(wmem.getLong(i << 3), i);
+      }
+      println(wmem.toHexString("Test", 0, 32 * 8, true));
+
+      int longs2 = 64;
+      int bytes2 = longs2 << 3;
+      WritableMemory newWmem = memReqSvr.request(wmem, bytes2); //on the heap
+      assertFalse(newWmem.isDirect()); //on heap by default
+      for (int i = 0; i < longs2; i++) {
+          newWmem.putLong(i << 3, i);
+          assertEquals(newWmem.getLong(i << 3), i);
+      }
+      memReqSvr.requestClose(wmem, newWmem); //The default MRS doesn't close.
+    } // So we let the TWR close it here
+  }
+
+  @SuppressWarnings("resource")
+  @Test
+  public void checkNonNativeDirect() {
+    WritableMemory wmem = null;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      wmem = WritableMemory.allocateDirect( 128, 8, scope,
+          BaseState.NON_NATIVE_BYTE_ORDER, memReqSvr);
+      wmem.putChar(0, (char) 1);
+      assertEquals(wmem.getByte(1), (byte) 1);
+    }
+  }
+
+  @SuppressWarnings("resource")
+  @Test
+  public void checkExplicitCloseNoTWR() {
+    final long cap = 128;
+    WritableMemory wmem = null;
+    ResourceScope scope = ResourceScope.newConfinedScope();
+    wmem = WritableMemory.allocateDirect(cap, scope, memReqSvr);
+    wmem.close(); //explicit close
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void println(String s) {
+    //System.out.println(s); //disable here
+  }
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/AllocateDirectWritableMapMemoryTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/AllocateDirectWritableMapMemoryTest.java
new file mode 100644
index 0000000..1f33854
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/AllocateDirectWritableMapMemoryTest.java
@@ -0,0 +1,240 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * Note: Lincoln's Gettysburg Address is in the public domain. See LICENSE.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.apache.datasketches.memory.internal.Util.getResourceFile;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteOrder;
+import java.nio.file.InvalidPathException;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+public class AllocateDirectWritableMapMemoryTest {
+  private static final String LS = System.getProperty("line.separator");
+  private final MemoryRequestServer memReqSvr = BaseState.defaultMemReqSvr;
+
+  @BeforeClass
+  public void setReadOnly() throws IOException {
+    UtilTest.setGettysburgAddressFileToReadOnly();
+  }
+
+  @Test
+  public void simpleMap()
+      throws IllegalArgumentException, InvalidPathException, IllegalStateException, UnsupportedOperationException,
+      IOException, SecurityException {
+    File file = getResourceFile("GettysburgAddress.txt");
+    Memory mem = null;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      mem = Memory.map(file,scope);
+      byte[] byteArr = new byte[(int)mem.getCapacity()];
+      mem.getByteArray(0, byteArr, 0, byteArr.length);
+      String text = new String(byteArr, UTF_8);
+      println(text);
+      assertTrue(mem.isReadOnly());
+    }
+  }
+
+  @Test
+  public void copyOffHeapToMemoryMappedFile()
+      throws IllegalArgumentException, InvalidPathException, IllegalStateException, UnsupportedOperationException,
+      IOException, SecurityException {
+    long numBytes = 1L << 10; //small for unit tests.  Make it larger than 2GB if you like.
+    long numLongs = numBytes >>> 3;
+
+    File file = new File("TestFile.bin"); //create a dummy file
+    if (file.exists()) {
+      java.nio.file.Files.delete(file.toPath());
+    }
+    assertTrue(file.createNewFile());
+    assertTrue (file.setWritable(true, false)); //writable=true, ownerOnly=false
+    assertTrue (file.isFile());
+    file.deleteOnExit();  //comment out if you want to examine the file.
+
+    WritableMemory dstMem = null;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) { //this scope manages two Memory objects
+      dstMem = WritableMemory.writableMap(file, 0, numBytes, scope, ByteOrder.nativeOrder());
+
+      WritableMemory srcMem
+        = WritableMemory.allocateDirect(numBytes, 8, scope, ByteOrder.nativeOrder(), memReqSvr);
+
+      //load source with consecutive longs
+      for (long i = 0; i < numLongs; i++) {
+        srcMem.putLong(i << 3, i);
+      }
+      //off-heap to off-heap copy
+      srcMem.copyTo(0, dstMem, 0, srcMem.getCapacity());
+      dstMem.force(); //push any remaining to the file
+      //check end value
+      assertEquals(dstMem.getLong(numLongs - 1L << 3), numLongs - 1L);
+    } //both map and direct closed here
+  }
+
+  @Test
+  public void checkNonNativeFile()
+      throws IllegalArgumentException, InvalidPathException, IllegalStateException, UnsupportedOperationException,
+      IOException, SecurityException {
+    File file = new File("TestFile2.bin");
+    if (file.exists()) {
+      java.nio.file.Files.delete(file.toPath());
+    }
+    assertTrue(file.createNewFile());
+    assertTrue(file.setWritable(true, false)); //writable=true, ownerOnly=false
+    assertTrue(file.isFile());
+    file.deleteOnExit();  //comment out if you want to examine the file.
+
+    final long bytes = 8;
+    WritableMemory wmem = null;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      wmem = WritableMemory.writableMap(file, 0L, bytes, scope, BaseState.NON_NATIVE_BYTE_ORDER);
+      wmem.putChar(0, (char) 1);
+      assertEquals(wmem.getByte(1), (byte) 1);
+    }
+  }
+
+  @SuppressWarnings("resource")
+  @Test
+  public void testMapExceptionNoTWR()
+      throws IllegalArgumentException, InvalidPathException, IllegalStateException, UnsupportedOperationException,
+      IOException, SecurityException {
+    File dummy = createFile("dummy.txt", ""); //zero length
+    ResourceScope scope = ResourceScope.newConfinedScope();
+    Memory.map(dummy, 0, dummy.length(), scope, ByteOrder.nativeOrder());
+    scope.close();
+  }
+
+  @Test(expectedExceptions = IllegalArgumentException.class)
+  public void simpleMap2()
+      throws IllegalArgumentException, InvalidPathException, IllegalStateException, UnsupportedOperationException,
+      IOException, SecurityException {
+    File file = getResourceFile("GettysburgAddress.txt");
+    assertTrue(file.canRead());
+    assertFalse(file.canWrite());
+    WritableMemory wmem = null;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      wmem = WritableMemory.writableMap(file, scope); //throws ReadOnlyException
+      wmem.getCapacity();
+    }
+  }
+
+  @Test(expectedExceptions = IllegalArgumentException.class)
+  public void checkReadException()
+      throws IllegalArgumentException, InvalidPathException, IllegalStateException, UnsupportedOperationException,
+      IOException, SecurityException {
+    File file = getResourceFile("GettysburgAddress.txt");
+    WritableMemory wmem = null;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      wmem = WritableMemory.writableMap(file, 0, 1 << 20, scope, ByteOrder.nativeOrder());
+      //throws ReadOnlyException
+      wmem.getCapacity();
+    }
+  }
+
+  @Test
+  public void testForce()
+      throws IllegalArgumentException, InvalidPathException, IllegalStateException, UnsupportedOperationException,
+      IOException, SecurityException {
+    String origStr = "Corectng spellng mistks";
+    File origFile = createFile("force_original.txt", origStr); //23
+    assertTrue(origFile.setWritable(true, false));
+    long origBytes = origFile.length();
+    String correctStr = "Correcting spelling mistakes"; //28
+    byte[] correctByteArr = correctStr.getBytes(UTF_8);
+    long correctBytesLen = correctByteArr.length;
+
+    Memory mem = null;
+    WritableMemory wmem = null;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      mem = Memory.map(origFile, 0, origBytes, scope, ByteOrder.nativeOrder());
+      mem.load();
+      assertTrue(mem.isLoaded());
+      //confirm orig string
+      byte[] buf = new byte[(int)origBytes];
+      mem.getByteArray(0, buf, 0, (int)origBytes);
+      String bufStr = new String(buf, UTF_8);
+      assertEquals(bufStr, origStr);
+
+      wmem = WritableMemory.writableMap(origFile, 0, correctBytesLen, scope, ByteOrder.nativeOrder());
+      wmem.load();
+      assertTrue(wmem.isLoaded());
+      // over write content
+      wmem.putByteArray(0, correctByteArr, 0, (int)correctBytesLen);
+      wmem.force();
+      //confirm correct string
+      byte[] buf2 = new byte[(int)correctBytesLen];
+      wmem.getByteArray(0, buf2, 0, (int)correctBytesLen);
+      String bufStr2 = new String(buf2, UTF_8);
+      assertEquals(bufStr2, correctStr);
+    }
+  }
+
+  private static File createFile(String fileName, String text) throws FileNotFoundException {
+    File file = new File(fileName);
+    file.deleteOnExit();
+    PrintWriter writer;
+    try {
+      writer = new PrintWriter(file, UTF_8.name());
+      writer.print(text);
+      writer.close();
+    } catch (UnsupportedEncodingException e) {
+      e.printStackTrace();
+    }
+    return file;
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  static void println(final Object o) {
+    if (o == null) { print(LS); }
+    else { print(o.toString() + LS); }
+  }
+
+  /**
+   * @param o value to print
+   */
+  static void print(final Object o) {
+    if (o != null) {
+      //System.out.print(o.toString()); //disable here
+    }
+  }
+
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/BaseBufferTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/BaseBufferTest.java
new file mode 100644
index 0000000..73cd01f
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/BaseBufferTest.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.testng.Assert.fail;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.Buffer;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+/**
+ * @author Lee Rhodes
+ */
+public class BaseBufferTest {
+  private static final MemoryRequestServer memReqSvr = BaseState.defaultMemReqSvr;
+
+  @Test
+  public void checkLimits() {
+    Buffer buf = Memory.wrap(new byte[100]).asBuffer();
+    buf.setStartPositionEnd(40, 45, 50);
+    buf.setStartPositionEnd(0, 0, 100);
+    try {
+      buf.setStartPositionEnd(0, 0, 101);
+      fail();
+    } catch (AssertionError e) {
+      //ok
+    }
+  }
+
+  @Test
+  public void checkLimitsAndCheck() {
+    Buffer buf = Memory.wrap(new byte[100]).asBuffer();
+    buf.setAndCheckStartPositionEnd(40, 45, 50);
+    buf.setAndCheckStartPositionEnd(0, 0, 100);
+    try {
+      buf.setAndCheckStartPositionEnd(0, 0, 101);
+      fail();
+    } catch (IllegalArgumentException e) {
+      //ok
+    }
+    buf.setAndCheckPosition(100);
+    try {
+      buf.setAndCheckPosition(101);
+      fail();
+    } catch (IllegalArgumentException e) {
+      //ok
+    }
+    buf.setPosition(99);
+    buf.incrementAndCheckPosition(1L);
+    try {
+      buf.incrementAndCheckPosition(1L);
+      fail();
+    } catch (IllegalArgumentException e) {
+      //ok
+    }
+  }
+
+  @Test
+  public void checkCheckNotAliveAfterTWR() {
+    WritableMemory wmem;
+    Buffer buf;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      wmem = WritableMemory.allocateDirect(100, scope, memReqSvr);
+      buf = wmem.asBuffer();
+    }
+    try {
+      buf.asMemory(); //not alive
+    } catch (IllegalStateException e) { }
+  }
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/BaseStateTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/BaseStateTest.java
new file mode 100644
index 0000000..d4c0bbf
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/BaseStateTest.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.Buffer;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.MemorySegment;
+import jdk.incubator.foreign.ResourceScope;
+
+public class BaseStateTest {
+
+  @Test
+  public void checkNativeOverlap() {
+    MemorySegment par = MemorySegment.allocateNative(100, ResourceScope.newImplicitScope());
+    //Equal sizes
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par,  0, 20), getSeg(par, 40, 60)),   0);
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par,  0, 20), getSeg(par, 20, 40)),   0);
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par,  0, 20), getSeg(par,  0, 20)),  20);
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par,  0, 20), getSeg(par, 10, 30)),  10);
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par, 10, 30), getSeg(par,  0, 20)), -10);
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par, 20, 40), getSeg(par,  0, 20)),   0);
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par,  0,  0), getSeg(par,  0,  0)),   0);
+    //Unequal Sizes A > B
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par,  0, 40), getSeg(par, 60, 80)),   0);
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par,  0, 40), getSeg(par, 40, 60)),   0);
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par,  0, 40), getSeg(par, 30, 50)),  10);
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par,  0, 40), getSeg(par, 20, 40)),  20);
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par,  0, 40), getSeg(par, 10, 30)),  20);
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par,  0, 40), getSeg(par,  0, 20)),  20);
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par, 10, 50), getSeg(par,  0, 20)), -10);
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par, 20, 60), getSeg(par,  0, 20)),   0);
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par, 40, 80), getSeg(par,  0, 20)),   0);
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par, 40, 80), getSeg(par,  0,  0)),   0);
+
+    //Unequal Sizes B > A
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par, 60, 80), getSeg(par,  0, 40)),   0);
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par, 40, 60), getSeg(par,  0, 40)),   0);
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par, 30, 50), getSeg(par,  0, 40)), -10);
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par, 20, 40), getSeg(par,  0, 40)), -20);
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par, 10, 30), getSeg(par,  0, 40)), -20);
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par,  0, 20), getSeg(par,  0, 40)),  20);
+    assertEquals(BaseStateImpl.nativeOverlap( getSeg(par, 0, 20), getSeg(par, 10, 50)),  10);
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par,  0, 20), getSeg(par, 20, 60)),   0);
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par,  0, 20), getSeg(par, 40, 80)),   0);
+    assertEquals(BaseStateImpl.nativeOverlap(getSeg(par,  0,  0), getSeg(par, 40, 80)),   0);
+  }
+
+  private static MemorySegment getSeg(MemorySegment parent, long left, long right) {
+    return parent.asSlice(left, right - left);
+  }
+
+  @Test
+  public void checkNotEqualTo() {
+    byte[] arr1 = new byte[8];
+    Memory mem = Memory.wrap(arr1);
+    byte[] arr2 = new byte[8];
+    arr2[7] = 1;
+    Memory mem2 = Memory.wrap(arr2);
+    assertFalse(mem.equalTo(0, mem2, 0, 8));
+  }
+
+  @Test
+  public void checkIsByteOrderCompatible() {
+    WritableMemory wmem = WritableMemory.allocate(8);
+    assertTrue(wmem.isByteOrderCompatible(ByteOrder.nativeOrder()));
+  }
+
+  @Test
+  public void checkXxHash64() {
+    WritableMemory mem = WritableMemory.allocate(8);
+    long out = mem.xxHash64(mem.getLong(0), 1L);
+    assertTrue(out != 0);
+  }
+
+  @Test
+  public void checkTypeDecode() {
+    for (int i = 0; i < 256; i++) {
+      String str = BaseStateImpl.typeDecode(i);
+      println(i + "\t" + str);
+    }
+  }
+
+  @Test
+  public void checkToHexString() {
+    WritableMemory mem = WritableMemory.writableWrap(new byte[16]);
+    println(mem.toHexString("baseMem", 0, 16, true));
+    for (int i = 0; i < 16; i++) { mem.putByte(i, (byte)i); }
+    Buffer buf = mem.asBuffer();
+    println(buf.toHexString("buffer", 0, 16, true));
+  }
+
+  @Test
+  public void checkToMemorySegment() {
+    WritableMemory mem = WritableMemory.allocate(8);
+    mem.toMemorySegment();
+    mem.asByteBufferView(ByteOrder.nativeOrder());
+  }
+
+  /********************/
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void println(String s) {
+    //System.out.println(s); //disable here
+  }
+
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/Buffer2Test.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/Buffer2Test.java
new file mode 100644
index 0000000..d1eb6cb
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/Buffer2Test.java
@@ -0,0 +1,434 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.Buffer;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.WritableBuffer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+public class Buffer2Test {
+
+  @Test
+  public void testWrapByteBuf() {
+    ByteBuffer bb = ByteBuffer.allocate(64).order(ByteOrder.nativeOrder());
+
+    Byte b = 0;
+    while (bb.hasRemaining()) {
+      bb.put(b);
+      b++;
+    }
+    bb.position(0);
+
+    Buffer buffer = Buffer.wrap(bb.asReadOnlyBuffer().order(ByteOrder.nativeOrder()));
+    while (buffer.hasRemaining()) {
+      assertEquals(bb.get(), buffer.getByte());
+    }
+    assertEquals(true, buffer.hasByteBuffer());
+  }
+
+  @Test
+  public void testWrapDirectBB() {
+    ByteBuffer bb = ByteBuffer.allocateDirect(64).order(ByteOrder.nativeOrder());
+
+    Byte b = 0;
+    while (bb.hasRemaining()) {
+      bb.put(b);
+      b++;
+    }
+    bb.position(0);
+
+    Buffer buffer = Buffer.wrap(bb);
+    while (buffer.hasRemaining()) {
+      assertEquals(bb.get(), buffer.getByte());
+    }
+
+    assertEquals(true, buffer.hasByteBuffer());
+  }
+
+  @Test
+  public void testWrapByteArray() {
+    byte[] byteArray = new byte[64];
+
+    for (byte i = 0; i < 64; i++) {
+      byteArray[i] = i;
+    }
+
+    Buffer buffer = Memory.wrap(byteArray).asBuffer();
+    int i = 0;
+    while (buffer.hasRemaining()) {
+      assertEquals(byteArray[i++], buffer.getByte());
+    }
+
+    buffer.setPosition(0);
+    byte[] copyByteArray = new byte[64];
+    buffer.getByteArray(copyByteArray, 0, 64);
+    assertEquals(byteArray, copyByteArray);
+
+    assertEquals(false, buffer.hasByteBuffer());
+  }
+
+  @Test
+  public void testWrapCharArray() {
+    char[] charArray = new char[64];
+
+    for (char i = 0; i < 64; i++) {
+      charArray[i] = i;
+    }
+
+    Buffer buffer = Memory.wrap(charArray).asBuffer();
+    int i = 0;
+    while (buffer.hasRemaining()) {
+      assertEquals(charArray[i++], buffer.getChar());
+    }
+
+    buffer.setPosition(0);
+    char[] copyCharArray = new char[64];
+    buffer.getCharArray(copyCharArray, 0, 64);
+    assertEquals(charArray, copyCharArray);
+  }
+
+  @Test
+  public void testWrapShortArray() {
+    short[] shortArray = new short[64];
+
+    for (short i = 0; i < 64; i++) {
+      shortArray[i] = i;
+    }
+
+    Buffer buffer = Memory.wrap(shortArray).asBuffer();
+    int i = 0;
+    while (buffer.hasRemaining()) {
+      assertEquals(shortArray[i++], buffer.getShort());
+    }
+
+    buffer.setPosition(0);
+    short[] copyShortArray = new short[64];
+    buffer.getShortArray(copyShortArray, 0, 64);
+    assertEquals(shortArray, copyShortArray);
+  }
+
+  @Test
+  public void testWrapIntArray() {
+    int[] intArray = new int[64];
+
+    for (int i = 0; i < 64; i++) {
+      intArray[i] = i;
+    }
+
+    Buffer buffer = Memory.wrap(intArray).asBuffer();
+    int i = 0;
+    while (buffer.hasRemaining()) {
+      assertEquals(intArray[i++], buffer.getInt());
+    }
+
+    buffer.setPosition(0);
+    int[] copyIntArray = new int[64];
+    buffer.getIntArray(copyIntArray, 0, 64);
+    assertEquals(intArray, copyIntArray);
+  }
+
+  @Test
+  public void testWrapLongArray() {
+    long[] longArray = new long[64];
+
+    for (int i = 0; i < 64; i++) {
+      longArray[i] = i;
+    }
+
+    Buffer buffer = Memory.wrap(longArray).asBuffer();
+    int i = 0;
+    while (buffer.hasRemaining()) {
+      assertEquals(longArray[i++], buffer.getLong());
+    }
+
+    buffer.setPosition(0);
+    long[] copyLongArray = new long[64];
+    buffer.getLongArray(copyLongArray, 0, 64);
+    assertEquals(longArray, copyLongArray);
+  }
+
+  @Test
+  public void testWrapFloatArray() {
+    float[] floatArray = new float[64];
+
+    for (int i = 0; i < 64; i++) {
+      floatArray[i] = i;
+    }
+
+    Buffer buffer = Memory.wrap(floatArray).asBuffer();
+    int i = 0;
+    while (buffer.hasRemaining()) {
+      assertEquals(floatArray[i++], buffer.getFloat());
+    }
+
+    buffer.setPosition(0);
+    float[] copyFloatArray = new float[64];
+    buffer.getFloatArray(copyFloatArray, 0, 64);
+    assertEquals(floatArray, copyFloatArray);
+  }
+
+  @Test
+  public void testWrapDoubleArray() {
+    double[] doubleArray = new double[64];
+
+    for (int i = 0; i < 64; i++) {
+      doubleArray[i] = i;
+    }
+
+    Buffer buffer = Memory.wrap(doubleArray).asBuffer();
+    int i = 0;
+    while (buffer.hasRemaining()) {
+      assertEquals(doubleArray[i++], buffer.getDouble());
+    }
+
+    buffer.setPosition(0);
+    double[] copyDoubleArray = new double[64];
+    buffer.getDoubleArray(copyDoubleArray, 0, 64);
+    assertEquals(doubleArray, copyDoubleArray);
+  }
+
+  @Test
+  public void testByteBufferPositionPreservation() {
+    ByteBuffer bb = ByteBuffer.allocate(64).order(ByteOrder.nativeOrder());
+
+    Byte b = 0;
+    while (bb.hasRemaining()) {
+      bb.put(b);
+      b++;
+    }
+    bb.position(10);
+
+    Buffer buffer = Buffer.wrap(bb);
+    while (buffer.hasRemaining()) {
+      assertEquals(bb.get(), buffer.getByte());
+    }
+  }
+
+  @Test
+  public void testGetAndHasRemaining() {
+    ByteBuffer bb = ByteBuffer.allocate(64).order(ByteOrder.nativeOrder());
+
+    Byte b = 0;
+    while (bb.hasRemaining()) {
+      bb.put(b);
+      b++;
+    }
+    bb.position(10);
+
+    Buffer buffer = Buffer.wrap(bb);
+    assertEquals(bb.hasRemaining(), buffer.hasRemaining());
+    assertEquals(bb.remaining(), buffer.getRemaining());
+  }
+
+  @Test
+  public void testGetSetIncResetPosition() {
+    ByteBuffer bb = ByteBuffer.allocate(64).order(ByteOrder.nativeOrder());
+
+    byte b = 0;
+    while (bb.hasRemaining()) {
+      bb.put(b);
+      b++;
+    }
+    bb.position(10);
+
+    Buffer buffer = Buffer.wrap(bb);
+    assertEquals(bb.position(), buffer.getPosition());
+    assertEquals(30, buffer.setPosition(30).getPosition());
+    assertEquals(40, buffer.incrementPosition(10).getPosition());
+    assertEquals(0, buffer.resetPosition().getPosition());
+  }
+
+  @Test
+  public void testByteBufferSlice() {
+    ByteBuffer bb = ByteBuffer.allocate(64).order(ByteOrder.nativeOrder());
+
+    Byte b = 0;
+    while (bb.hasRemaining()) {
+      bb.put(b);
+      b++;
+    }
+    bb.position(10);
+
+    Buffer buffer = Buffer.wrap(bb.slice().order(ByteOrder.nativeOrder()));
+    while (buffer.hasRemaining()) {
+      assertEquals(bb.get(), buffer.getByte());
+    }
+
+    assertEquals(bb.position(), buffer.getPosition() + 10);
+    assertEquals(30, buffer.setPosition(30).getPosition());
+    assertEquals(40, buffer.incrementPosition(10).getPosition());
+    assertEquals(0, buffer.resetPosition().getPosition());
+  }
+
+  @Test
+  public void testDuplicateAndRegion() {
+    ByteBuffer bb = ByteBuffer.allocate(64).order(ByteOrder.nativeOrder());
+
+    Byte b = 0;
+    while (bb.hasRemaining()) {
+      bb.put(b);
+      b++;
+    }
+    bb.position(10);
+
+    Buffer buffer = Buffer.wrap(bb.slice().order(ByteOrder.nativeOrder())); //slice = 54
+    buffer.setPosition(30);//remaining = 24
+    Buffer dupBuffer = buffer.duplicate(); //all 54
+    Buffer regionBuffer = buffer.region(); //24
+
+    assertEquals(dupBuffer.getStart(), buffer.getStart());
+    assertEquals(regionBuffer.getStart(), buffer.getStart());
+    assertEquals(dupBuffer.getEnd(), buffer.getEnd());
+    assertEquals(regionBuffer.getEnd(), buffer.getRemaining());
+    assertEquals(dupBuffer.getPosition(), buffer.getPosition());
+    assertEquals(regionBuffer.getPosition(), 0);
+    assertEquals(dupBuffer.getCapacity(), buffer.getCapacity());
+    assertEquals(regionBuffer.getCapacity(), buffer.getCapacity() - 30);
+  }
+
+  @Test
+  public void checkRORegions() {
+    int n = 16;
+    int n2 = n / 2;
+    long[] arr = new long[n];
+    for (int i = 0; i < n; i++) { arr[i] = i; }
+    Memory mem = Memory.wrap(arr);
+    Buffer buf = mem.asBuffer();
+    Buffer reg = buf.region(n2 * 8, n2 * 8, buf.getByteOrder()); //top half
+    for (int i = 0; i < n2; i++) {
+      long v = reg.getLong(i * 8);
+      long e = i + n2;
+      assertEquals(v, e);
+    }
+  }
+
+  @Test
+  public void testAsMemory() {
+    ByteBuffer bb = ByteBuffer.allocate(64).order(ByteOrder.nativeOrder());
+
+    Byte b = 0;
+    while (bb.hasRemaining()) {
+      bb.put(b);
+      b++;
+    }
+    bb.position(10);
+
+    Buffer buffer = Buffer.wrap(bb);
+    Memory memory = buffer.asMemory();
+
+    assertEquals(buffer.getCapacity(), memory.getCapacity());
+
+    while(buffer.hasRemaining()){
+      assertEquals(memory.getByte(buffer.getPosition()), buffer.getByte());
+    }
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testROByteBuffer() {
+    byte[] arr = new byte[64];
+    ByteBuffer roBB = ByteBuffer.wrap(arr).asReadOnlyBuffer();
+    Buffer buf = Buffer.wrap(roBB);
+    WritableBuffer wbuf = (WritableBuffer) buf;
+    wbuf.putByte(0, (byte) 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testROByteBuffer2() {
+    byte[] arr = new byte[64];
+    ByteBuffer roBB = ByteBuffer.wrap(arr).asReadOnlyBuffer();
+    Buffer buf = Buffer.wrap(roBB);
+    WritableBuffer wbuf = (WritableBuffer) buf;
+    wbuf.putByteArray(arr, 0, 64);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testIllegalFill() {
+    byte[] arr = new byte[64];
+    ByteBuffer roBB = ByteBuffer.wrap(arr).asReadOnlyBuffer();
+    Buffer buf = Buffer.wrap(roBB);
+    WritableBuffer wbuf = (WritableBuffer) buf;
+    wbuf.fill((byte)0);
+  }
+
+  @Test
+  public void checkWritableWrap() {
+    ByteBuffer bb = ByteBuffer.allocate(16);
+    WritableBuffer buf = WritableBuffer.writableWrap(bb, ByteOrder.nativeOrder(), BaseState.defaultMemReqSvr);
+    assertNotNull(buf);
+  }
+
+  @Test
+  public void testWritableDuplicate() {
+    WritableMemory wmem = WritableMemory.writableWrap(new byte[1]);
+    WritableBuffer wbuf = wmem.asWritableBuffer();
+    WritableBuffer wbuf2 = wbuf.writableDuplicate();
+    assertEquals(wbuf2.getCapacity(), 1);
+    Buffer buf = wmem.asBuffer();
+    assertEquals(buf.getCapacity(), 1);
+  }
+
+  @Test
+  public void checkIndependence() {
+    int cap = 64;
+    ResourceScope scope = ResourceScope.newImplicitScope();
+    WritableMemory wmem = WritableMemory.allocateDirect(cap, scope, null);
+    WritableBuffer wbuf1 = wmem.asWritableBuffer();
+    WritableBuffer wbuf2 = wmem.asWritableBuffer();
+    assertFalse(wbuf1 == wbuf2);
+    assertTrue(wbuf1.nativeOverlap(wbuf2) == cap);
+
+    WritableMemory reg1 = wmem.writableRegion(0, cap);
+    WritableMemory reg2 = wmem.writableRegion(0, cap);
+    assertFalse(reg1 == reg2);
+    assertTrue(reg1.nativeOverlap(reg2) == cap);
+
+
+    WritableBuffer wbuf3 = wbuf1.writableRegion();
+    WritableBuffer wbuf4 = wbuf1.writableRegion();
+    assertFalse(wbuf3 == wbuf4);
+    assertTrue(wbuf3.nativeOverlap(wbuf4) == cap);
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void println(String s) {
+    //System.out.println(s); //disable here
+  }
+
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/BufferBoundaryCheckTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/BufferBoundaryCheckTest.java
new file mode 100644
index 0000000..d45f5f8
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/BufferBoundaryCheckTest.java
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.testng.Assert.fail;
+
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+public class BufferBoundaryCheckTest {
+
+  private final WritableMemory writableMemory = WritableMemory.allocate(8);
+
+  @Test
+  public void testGetByte() {
+    writableMemory.getByte(7);
+    try {
+      writableMemory.getByte(8);
+      fail("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutByte() {
+    writableMemory.putByte(7, (byte) 1);
+    try {
+      writableMemory.putByte(8, (byte) 1);
+      fail("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetChar() {
+    writableMemory.getChar(6);
+    try {
+      writableMemory.getChar(7);
+      fail("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutChar() {
+    writableMemory.putChar(6, 'a');
+    try {
+      writableMemory.putChar(7, 'a');
+      fail("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetShort() {
+    writableMemory.getShort(6);
+    try {
+      writableMemory.getShort(7);
+      fail("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutShort() {
+    writableMemory.putShort(6, (short) 1);
+    try {
+      writableMemory.putShort(7, (short) 1);
+      fail("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetInt() {
+    writableMemory.getInt(4);
+    try {
+      writableMemory.getInt(5);
+      fail("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutInt() {
+    writableMemory.putInt(4, 1);
+    try {
+      writableMemory.putInt(5, 1);
+      fail("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetFloat() {
+    writableMemory.getFloat(4);
+    try {
+      writableMemory.getFloat(5);
+      fail("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutFloat() {
+    writableMemory.putFloat(4, 1f);
+    try {
+      writableMemory.putFloat(5, 1f);
+      fail("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetLong() {
+    writableMemory.getLong(0);
+    try {
+      writableMemory.getLong(1);
+      fail("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutLong() {
+    writableMemory.putLong(0, 1L);
+    try {
+      writableMemory.putLong(1, 1L);
+      fail("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetDouble() {
+    writableMemory.getDouble(0);
+    try {
+      writableMemory.getDouble(1);
+      fail("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutDouble() {
+    writableMemory.putDouble(0, 1d);
+    try {
+      writableMemory.putDouble(1, 1d);
+      fail("Expected IndexOutOfBoundsException");
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/BufferInvariantsTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/BufferInvariantsTest.java
new file mode 100644
index 0000000..4b233be
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/BufferInvariantsTest.java
@@ -0,0 +1,345 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+import java.nio.ByteBuffer;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.Buffer;
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableBuffer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+/**
+ * @author Lee Rhodes
+ */
+public class BufferInvariantsTest {
+  private static final MemoryRequestServer memReqSvr = BaseState.defaultMemReqSvr;
+
+  @Test
+  public void testRegion() {
+    ByteBuffer byteBuffer = ByteBuffer.allocate(10);
+    byteBuffer.limit(7);
+    Buffer buff = Buffer.wrap(byteBuffer); //assuming buff has cap of 8
+    assertEquals(buff.getCapacity(), 10); //wrong should be 8
+    buff.getByte(); //pos moves to 1
+    Buffer copyBuff = buff.region(); //pos: 0, start: 0, end: 6: cap: 7
+    assertEquals(copyBuff.getEnd(), 6);
+    assertEquals(copyBuff.getCapacity(), 6);
+    assertEquals(copyBuff.getStart(), 0);
+    assertEquals(copyBuff.getPosition(), 0);
+
+    buff.setStartPositionEnd(1, 1, 5);
+    buff.getByte();
+    Buffer copyBuff2 = buff.region();
+    assertEquals(copyBuff2.getEnd(), 3);
+    assertEquals(copyBuff2.getCapacity(), 3);
+    assertEquals(copyBuff2.getStart(), 0);
+    assertEquals(copyBuff2.getPosition(), 0);
+  }
+
+  @Test
+  public void testBB() {
+    int n = 25;
+    ByteBuffer bb = ByteBuffer.allocate(n);
+    for (byte i = 0; i < n; i++) { bb.put(i, i); }
+    assertEquals(bb.position(), 0);
+    assertEquals(bb.limit(), n);
+    assertEquals(bb.get(0), 0);
+//    print("Orig : ");
+//    printbb(bb);
+
+    bb.limit(20);
+    bb.position(5);
+    assertEquals(bb.remaining(), 15);
+//    print("Set  : ");
+//    printbb(bb);
+
+    ByteBuffer dup = bb.duplicate();
+    assertEquals(dup.position(), 5);
+    assertEquals(dup.limit(), 20);
+    assertEquals(dup.capacity(), 25);
+//    print("Dup  : ");
+//    printbb(dup);
+
+    ByteBuffer sl = bb.slice();
+    assertEquals(sl.position(), 0);
+    assertEquals(sl.limit(), 15);
+    assertEquals(sl.capacity(), 15);
+//    print("Slice: ");
+//    printbb(sl);
+  }
+
+  @Test
+  public void testBuf() {
+    int n = 25;
+    WritableBuffer buf = WritableMemory.allocate(n).asWritableBuffer();
+    for (byte i = 0; i < n; i++) { buf.putByte(i); }
+    buf.setPosition(0);
+    assertEquals(buf.getPosition(), 0);
+    assertEquals(buf.getEnd(), 25);
+    assertEquals(buf.getCapacity(), 25);
+//    print("Orig  : ");
+//    printbuf(buf);
+
+    buf.setStartPositionEnd(0, 5, 20);
+    assertEquals(buf.getRemaining(), 15);
+    assertEquals(buf.getCapacity(), 25);
+    assertEquals(buf.getByte(), 5);
+    buf.setPosition(5);
+//    print("Set   : ");
+//    printbuf(buf);
+
+    Buffer dup = buf.duplicate();
+    assertEquals(dup.getRemaining(), 15);
+    assertEquals(dup.getCapacity(), 25);
+    assertEquals(dup.getByte(), 5);
+    dup.setPosition(5);
+//    print("Dup   : ");
+//    printbuf(dup);
+
+
+    Buffer reg = buf.region();
+    assertEquals(reg.getPosition(), 0);
+    assertEquals(reg.getEnd(), 15);
+    assertEquals(reg.getRemaining(), 15);
+    assertEquals(reg.getCapacity(), 15);
+    assertEquals(reg.getByte(), 5);
+    reg.setPosition(0);
+//    print("Region: ");
+//    printbuf(reg);
+  }
+
+  @Test
+  public void testBufWrap() {
+    int n = 25;
+    ByteBuffer bb = ByteBuffer.allocate(n);
+    for (byte i = 0; i < n; i++) { bb.put(i, i); }
+
+    bb.position(5);
+    bb.limit(20);
+
+    Buffer buf = Buffer.wrap(bb);
+    assertEquals(buf.getPosition(), 5);
+    assertEquals(buf.getEnd(), 20);
+    assertEquals(buf.getRemaining(), 15);
+    assertEquals(buf.getCapacity(), 25);
+    assertEquals(buf.getByte(), 5);
+    buf.setPosition(5);
+//    print("Buf.wrap: ");
+//    printbuf(buf);
+
+    Buffer reg = buf.region();
+    assertEquals(reg.getPosition(), 0);
+    assertEquals(reg.getEnd(), 15);
+    assertEquals(reg.getRemaining(), 15);
+    assertEquals(reg.getCapacity(), 15);
+    assertEquals(reg.getByte(), 5);
+    reg.setPosition(0);
+//    print("Buf.region: ");
+//    printbuf(reg);
+  }
+
+  @Test
+  public void checkLimitsDirect() throws Exception {
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory wmem = WritableMemory.allocateDirect(100, scope, memReqSvr);
+      Buffer buf = wmem.asBuffer();
+      buf.setStartPositionEnd(40, 45, 50);
+      buf.setStartPositionEnd(0, 0, 100);
+      try {
+        buf.setStartPositionEnd(0, 0, 101);
+        fail();
+      } catch (AssertionError e) {
+        //
+      }
+    }
+  }
+
+  @Test
+  public void testRegionDirect() {
+    ByteBuffer byteBuffer = ByteBuffer.allocate(10);
+    byteBuffer.limit(7);
+    Buffer buff = Buffer.wrap(byteBuffer); //assuming buff has cap of 8
+    assertEquals(buff.getCapacity(), 10); //wrong should be 8
+    buff.getByte(); //pos moves to 1
+    Buffer copyBuff = buff.region(); //pos: 0, start: 0, end: 6: cap: 7
+    assertEquals(copyBuff.getEnd(), 6);
+    assertEquals(copyBuff.getCapacity(), 6);
+    assertEquals(copyBuff.getStart(), 0);
+    assertEquals(copyBuff.getPosition(), 0);
+
+    buff.setStartPositionEnd(1, 1, 5);
+    buff.getByte();
+    Buffer copyBuff2 = buff.region();
+    assertEquals(copyBuff2.getEnd(), 3);
+    assertEquals(copyBuff2.getCapacity(), 3);
+    assertEquals(copyBuff2.getStart(), 0);
+    assertEquals(copyBuff2.getPosition(), 0);
+  }
+
+  @Test
+  public void testBBDirect() {
+    int n = 25;
+    ByteBuffer bb = ByteBuffer.allocateDirect(n);
+    for (byte i = 0; i < n; i++) { bb.put(i, i); }
+    assertEquals(bb.position(), 0);
+    assertEquals(bb.limit(), n);
+    assertEquals(bb.get(0), 0);
+//    print("Orig : ");
+//    printbb(bb);
+
+    bb.limit(20);
+    bb.position(5);
+    assertEquals(bb.remaining(), 15);
+//    print("Set  : ");
+//    printbb(bb);
+
+    ByteBuffer dup = bb.duplicate();
+    assertEquals(dup.position(), 5);
+    assertEquals(dup.limit(), 20);
+    assertEquals(dup.capacity(), 25);
+//    print("Dup  : ");
+//    printbb(dup);
+
+    ByteBuffer sl = bb.slice();
+    assertEquals(sl.position(), 0);
+    assertEquals(sl.limit(), 15);
+    assertEquals(sl.capacity(), 15);
+//    print("Slice: ");
+//    printbb(sl);
+  }
+
+  @Test
+  public void testBufDirect() throws Exception {
+    int n = 25;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+    WritableMemory wmem = WritableMemory.allocateDirect(n, scope, memReqSvr);
+    WritableBuffer buf = wmem.asWritableBuffer();
+    for (byte i = 0; i < n; i++) { buf.putByte(i); }
+    buf.setPosition(0);
+    assertEquals(buf.getPosition(), 0);
+    assertEquals(buf.getEnd(), 25);
+    assertEquals(buf.getCapacity(), 25);
+//    print("Orig  : ");
+//    printbuf(buf);
+
+    buf.setStartPositionEnd(0, 5, 20);
+    assertEquals(buf.getRemaining(), 15);
+    assertEquals(buf.getCapacity(), 25);
+    assertEquals(buf.getByte(), 5);
+    buf.setPosition(5);
+//    print("Set   : ");
+//    printbuf(buf);
+
+    Buffer dup = buf.duplicate();
+    assertEquals(dup.getRemaining(), 15);
+    assertEquals(dup.getCapacity(), 25);
+    assertEquals(dup.getByte(), 5);
+    dup.setPosition(5);
+//    print("Dup   : ");
+//    printbuf(dup);
+
+
+    Buffer reg = buf.region();
+    assertEquals(reg.getPosition(), 0);
+    assertEquals(reg.getEnd(), 15);
+    assertEquals(reg.getRemaining(), 15);
+    assertEquals(reg.getCapacity(), 15);
+    assertEquals(reg.getByte(), 5);
+    reg.setPosition(0);
+//    print("Region: ");
+//    printbuf(reg);
+    }
+  }
+
+  @Test
+  public void testBufWrapDirect() {
+    int n = 25;
+    ByteBuffer bb = ByteBuffer.allocateDirect(n);
+    for (byte i = 0; i < n; i++) { bb.put(i, i); }
+
+    bb.position(5);
+    bb.limit(20);
+
+    Buffer buf = Buffer.wrap(bb);
+    assertEquals(buf.getPosition(), 5);
+    assertEquals(buf.getEnd(), 20);
+    assertEquals(buf.getRemaining(), 15);
+    assertEquals(buf.getCapacity(), 25);
+    assertEquals(buf.getByte(), 5);
+    buf.setPosition(5);
+//    print("Buf.wrap: ");
+//    printbuf(buf);
+
+    Buffer reg = buf.region();
+    assertEquals(reg.getPosition(), 0);
+    assertEquals(reg.getEnd(), 15);
+    assertEquals(reg.getRemaining(), 15);
+    assertEquals(reg.getCapacity(), 15);
+    assertEquals(reg.getByte(), 5);
+    reg.setPosition(0);
+//    print("Buf.region: ");
+//    printbuf(reg);
+  }
+
+
+  static void printbb(ByteBuffer bb) {
+    println("pos: " + bb.position() + ", lim: " + bb.limit() + ", cap: " + bb.capacity());
+    int rem = bb.remaining();
+    int pos = bb.position();
+    int i;
+    for (i = 0; i < (rem-1); i++) {
+      print(bb.get(i+ pos) + ", ");
+    }
+    println(bb.get(i + pos) + "\n");
+  }
+
+  static void printbuf(Buffer buf) {
+    println("pos: " + buf.getPosition() + ", end: " + buf.getEnd() + ", cap: " + buf.getCapacity());
+    long rem = buf.getRemaining();
+    long pos = buf.getPosition();
+    int i;
+    for (i = 0; i < (rem-1); i++) {
+      print(buf.getByte(i+ pos) + ", ");
+    }
+    println(buf.getByte(i + pos) + "\n");
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void println(String s) {
+    //System.out.println(s); //disable here
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void print(String s) {
+    //System.out.print(s); //disable here
+  }
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/BufferReadWriteSafetyTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/BufferReadWriteSafetyTest.java
new file mode 100644
index 0000000..4e375d6
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/BufferReadWriteSafetyTest.java
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import java.nio.ByteBuffer;
+
+import org.apache.datasketches.memory.Buffer;
+import org.apache.datasketches.memory.WritableBuffer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+public class BufferReadWriteSafetyTest {
+
+  // Test various operations with read-only Buffer
+
+  private final WritableBuffer buf = (WritableBuffer) Buffer.wrap(ByteBuffer.allocate(8));
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutByte() {
+    buf.setPosition(0);
+    buf.putByte(0, (byte) 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutBytePositional() {
+    buf.setPosition(0);
+    buf.putByte((byte) 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutShort() {
+    buf.setPosition(0);
+    buf.putShort(0, (short) 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutShortPositional() {
+    buf.setPosition(0);
+    buf.putShort((short) 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutChar() {
+    buf.setPosition(0);
+    buf.putChar(0, (char) 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutCharPositional() {
+    buf.setPosition(0);
+    buf.putChar((char) 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutInt() {
+    buf.setPosition(0);
+    buf.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutIntPositional() {
+    buf.setPosition(0);
+    buf.putInt(1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutLong() {
+    buf.setPosition(0);
+    buf.putLong(0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutLongPositional() {
+    buf.setPosition(0);
+    buf.putLong(1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutFloat() {
+    buf.setPosition(0);
+    buf.putFloat(0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutFloatPositional() {
+    buf.setPosition(0);
+    buf.putFloat(1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutDouble() {
+    buf.setPosition(0);
+    buf.putDouble(0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutDoublePositional() {
+    buf.setPosition(0);
+    buf.putDouble(1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutByteArray() {
+    buf.setPosition(0);
+    buf.putByteArray(new byte[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutShortArray() {
+    buf.setPosition(0);
+    buf.putShortArray(new short[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutCharArray() {
+    buf.setPosition(0);
+    buf.putCharArray(new char[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutIntArray() {
+    buf.setPosition(0);
+    buf.putIntArray(new int[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutLongArray() {
+    buf.setPosition(0);
+    buf.putLongArray(new long[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutFloatArray() {
+    buf.setPosition(0);
+    buf.putFloatArray(new float[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testDoubleByteArray() {
+    buf.setPosition(0);
+    buf.putDoubleArray(new double[] {1}, 0, 1);
+  }
+
+  // Now, test that various ways to obtain a read-only buffer produce a read-only buffer indeed
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testWritableMemoryAsBuffer() {
+    WritableBuffer buf1 = (WritableBuffer) WritableMemory.allocate(8).asBuffer();
+    buf1.putInt(1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testWritableBufferRegion() {
+    WritableBuffer buf1 = (WritableBuffer) WritableMemory.allocate(8).asWritableBuffer().region();
+    buf1.putInt(1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testWritableBufferDuplicate() {
+    WritableBuffer buf1 = (WritableBuffer) WritableMemory.allocate(8).asWritableBuffer().duplicate();
+    buf1.putInt(1);
+  }
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/BufferTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/BufferTest.java
new file mode 100644
index 0000000..c9e58f0
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/BufferTest.java
@@ -0,0 +1,327 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.testng.Assert.assertEquals;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.List;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.Buffer;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableBuffer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+import org.testng.collections.Lists;
+
+import jdk.incubator.foreign.ResourceScope;
+
+public class BufferTest {
+  private final MemoryRequestServer memReqSvr = BaseState.defaultMemReqSvr;
+  @Test
+  public void checkDirectRoundTrip() throws Exception {
+    int n = 1024; //longs
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+    WritableMemory wmem = WritableMemory.allocateDirect(n * 8, scope, memReqSvr);
+      WritableBuffer wbuf = wmem.asWritableBuffer();
+      for (int i = 0; i < n; i++) {
+        wbuf.putLong(i);
+      }
+      wbuf.resetPosition();
+      for (int i = 0; i < n; i++) {
+        long v = wbuf.getLong();
+        assertEquals(v, i);
+      }
+    }
+  }
+
+  @Test
+  public void checkAutoHeapRoundTrip() {
+    int n = 1024; //longs
+    WritableBuffer wbuf = WritableMemory.allocate(n * 8).asWritableBuffer();
+    for (int i = 0; i < n; i++) {
+      wbuf.putLong(i);
+    }
+    wbuf.resetPosition();
+    for (int i = 0; i < n; i++) {
+      long v = wbuf.getLong();
+      assertEquals(v, i);
+    }
+  }
+
+  @Test
+  public void checkArrayWrap() {
+    int n = 1024; //longs
+    byte[] arr = new byte[n * 8];
+    WritableBuffer wbuf = WritableMemory.writableWrap(arr).asWritableBuffer();
+    for (int i = 0; i < n; i++) {
+      wbuf.putLong(i);
+    }
+    wbuf.resetPosition();
+    for (int i = 0; i < n; i++) {
+      long v = wbuf.getLong();
+      assertEquals(v, i);
+    }
+    Buffer buf = Memory.wrap(arr).asBuffer();
+    buf.resetPosition();
+    for (int i = 0; i < n; i++) {
+      long v = buf.getLong();
+      assertEquals(v, i);
+    }
+    // Check Zero length array wraps
+    Memory mem = Memory.wrap(new byte[0]);
+    Buffer buffZeroLengthArrayWrap = mem.asBuffer();
+    assertEquals(buffZeroLengthArrayWrap.getCapacity(), 0);
+    // check 0 length array wraps
+    List<Buffer> buffersToCheck = Lists.newArrayList();
+    buffersToCheck.add(WritableMemory.allocate(0).asBuffer());
+    buffersToCheck.add(WritableBuffer.writableWrap(ByteBuffer.allocate(0)));
+    buffersToCheck.add(Buffer.wrap(ByteBuffer.allocate(0)));
+    buffersToCheck.add(Memory.wrap(new byte[0]).asBuffer());
+    buffersToCheck.add(Memory.wrap(new char[0]).asBuffer());
+    buffersToCheck.add(Memory.wrap(new short[0]).asBuffer());
+    buffersToCheck.add(Memory.wrap(new int[0]).asBuffer());
+    buffersToCheck.add(Memory.wrap(new long[0]).asBuffer());
+    buffersToCheck.add(Memory.wrap(new float[0]).asBuffer());
+    buffersToCheck.add(Memory.wrap(new double[0]).asBuffer());
+    //Check the buffer lengths
+    for (Buffer buffer : buffersToCheck) {
+      assertEquals(buffer.getCapacity(), 0);
+    }
+  }
+
+  @Test
+  public void simpleBBTest() {
+    int n = 1024; //longs
+    byte[] arr = new byte[n * 8];
+    ByteBuffer bb = ByteBuffer.wrap(arr);
+    bb.order(ByteOrder.nativeOrder());
+
+    WritableBuffer wbuf = WritableBuffer.writableWrap(bb);
+    for (int i = 0; i < n; i++) { //write to wbuf
+      wbuf.putLong(i);
+    }
+    wbuf.resetPosition();
+    for (int i = 0; i < n; i++) { //read from wbuf
+      long v = wbuf.getLong();
+      assertEquals(v, i);
+    }
+    for (int i = 0; i < n; i++) { //read from BB
+      long v = bb.getLong();
+      assertEquals(v, i);
+    }
+  }
+
+  @Test
+  public void checkByteBufHeap() {
+    int n = 1024; //longs
+    byte[] arr = new byte[n * 8];
+    ByteBuffer bb = ByteBuffer.wrap(arr);
+    bb.order(ByteOrder.nativeOrder());
+
+    WritableBuffer wbuf = WritableBuffer.writableWrap(bb);
+    for (int i = 0; i < n; i++) { //write to wbuf
+      wbuf.putLong(i);
+    }
+    wbuf.resetPosition();
+    for (int i = 0; i < n; i++) { //read from wbuf
+      long v = wbuf.getLong();
+      assertEquals(v, i);
+    }
+    for (int i = 0; i < n; i++) { //read from BB
+      long v = bb.getLong(i * 8);
+      assertEquals(v, i);
+    }
+    Buffer buf1 = Memory.wrap(arr).asBuffer();
+    for (int i = 0; i < n; i++) { //read from wrapped arr
+      long v = buf1.getLong();
+      assertEquals(v, i);
+    }
+    //convert to wbuf to RO
+    Buffer buf = wbuf;
+    buf.resetPosition();
+    for (int i = 0; i < n; i++) {
+      long v = buf.getLong();
+      assertEquals(v, i);
+    }
+  }
+
+  @Test
+  public void checkByteBufDirect() {
+    int n = 1024; //longs
+    ByteBuffer bb = ByteBuffer.allocateDirect(n * 8);
+    bb.order(ByteOrder.nativeOrder());
+
+    WritableBuffer wbuf = WritableBuffer.writableWrap(bb);
+    for (int i = 0; i < n; i++) { //write to wmem
+      wbuf.putLong(i);
+    }
+    wbuf.resetPosition();
+    for (int i = 0; i < n; i++) { //read from wmem
+      long v = wbuf.getLong();
+      assertEquals(v, i);
+    }
+    for (int i = 0; i < n; i++) { //read from BB
+      long v = bb.getLong(i * 8);
+      assertEquals(v, i);
+    }
+    Buffer buf1 = Buffer.wrap(bb);
+    for (int i = 0; i < n; i++) { //read from wrapped bb RO
+      long v = buf1.getLong();
+      assertEquals(v, i);
+    }
+    //convert to RO
+    Buffer buf = wbuf;
+    buf.resetPosition();
+    for (int i = 0; i < n; i++) {
+      long v = buf.getLong();
+      assertEquals(v, i);
+    }
+  }
+
+  @Test
+  public void checkByteBufBigEndianOrder() {
+    int n = 1024; //longs
+    ByteBuffer bb = ByteBuffer.allocate(n * 8);
+    bb.order(BaseState.NON_NATIVE_BYTE_ORDER);
+    Buffer buf = Buffer.wrap(bb);
+    assertEquals(buf.getByteOrder(), ByteOrder.nativeOrder());
+  }
+
+  @Test
+  public void checkReadOnlyHeapByteBuffer() {
+    ByteBuffer bb = ByteBuffer.allocate(128);
+    bb.order(ByteOrder.nativeOrder());
+    for (int i = 0; i < 128; i++) { bb.put(i, (byte)i); }
+
+    bb.position(64);
+    ByteBuffer slice = bb.slice().asReadOnlyBuffer();
+    slice.order(ByteOrder.nativeOrder());
+
+    Buffer buf = Buffer.wrap(slice);
+    for (int i = 0; i < 64; i++) {
+      assertEquals(buf.getByte(), 64 + i);
+    }
+    buf.toHexString("slice", 0, slice.capacity(), true);
+    //println(s);
+  }
+
+  @Test
+  public void checkPutGetArraysHeap() {
+    int n = 1024; //longs
+    long[] arr = new long[n];
+    for (int i = 0; i < n; i++) { arr[i] = i; }
+
+    WritableBuffer wbuf = WritableMemory.allocate(n * 8).asWritableBuffer();
+    wbuf.putLongArray(arr, 0, n);
+    long[] arr2 = new long[n];
+    wbuf.resetPosition();
+    wbuf.getLongArray(arr2, 0, n);
+    for (int i = 0; i < n; i++) {
+      assertEquals(arr2[i], i);
+    }
+  }
+
+  @Test
+  public void checkRORegions() {
+    int n = 16;
+    int n2 = n / 2;
+    long[] arr = new long[n];
+    for (int i = 0; i < n; i++) { arr[i] = i; }
+
+    Buffer buf = Memory.wrap(arr).asBuffer();
+    buf.setPosition(n2 * 8);
+    Buffer reg = buf.region();
+    for (int i = 0; i < n2; i++) {
+      long v = reg.getLong();
+      assertEquals(v, i + n2);
+      //println("" + v);
+    }
+  }
+
+  @Test
+  public void checkWRegions() {
+    int n = 16;
+    int n2 = n / 2;
+    long[] arr = new long[n];
+    for (int i = 0; i < n; i++) { arr[i] = i; }
+    WritableBuffer wbuf = WritableMemory.writableWrap(arr).asWritableBuffer();
+    for (int i = 0; i < n; i++) {
+      assertEquals(wbuf.getLong(), i); //write all
+      //println("" + wmem.getLong(i * 8));
+    }
+    //println("");
+    wbuf.setPosition(n2 * 8);
+    WritableBuffer reg = wbuf.writableRegion();
+    for (int i = 0; i < n2; i++) { reg.putLong(i); } //rewrite top half
+    wbuf.resetPosition();
+    for (int i = 0; i < n; i++) {
+      assertEquals(wbuf.getLong(), i % 8);
+      //println("" + wmem.getLong(i * 8));
+    }
+  }
+
+  @SuppressWarnings("resource")
+  @Test(expectedExceptions = IllegalStateException.class)
+  public void checkParentUseAfterFree() throws Exception {
+    int bytes = 64 * 8;
+    WritableMemory wmem = WritableMemory.allocateDirect(bytes, ResourceScope.newConfinedScope(), memReqSvr);
+    WritableBuffer wbuf = wmem.asWritableBuffer();
+    wbuf.close();
+    //with -ea assert: Memory not valid.
+    //with -da sometimes segfaults, sometimes passes!
+    wbuf.getLong();
+  }
+
+  @SuppressWarnings("resource")
+  @Test(expectedExceptions = IllegalStateException.class)
+  public void checkRegionUseAfterFree() throws Exception {
+    int bytes = 64;
+    WritableMemory wmem = WritableMemory.allocateDirect(bytes, ResourceScope.newConfinedScope(), memReqSvr);
+    Buffer region = wmem.asBuffer().region();
+    region.close();
+    //with -ea assert: Memory not valid.
+    //with -da sometimes segfaults, sometimes passes!
+    region.getByte();
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void checkBaseBufferInvariants() {
+    WritableBuffer wbuf = WritableMemory.allocate(64).asWritableBuffer();
+    wbuf.setStartPositionEnd(1, 0, 2); //out of order
+  }
+
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  /**
+   * @param s String to print
+   */
+  static void println(final String s) {
+    //System.out.println(s);
+  }
+
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/CommonBufferTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/CommonBufferTest.java
new file mode 100644
index 0000000..8d3b519
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/CommonBufferTest.java
@@ -0,0 +1,430 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.testng.Assert.assertEquals;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableBuffer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+public class CommonBufferTest {
+  private final MemoryRequestServer memReqSvr = BaseState.defaultMemReqSvr;
+  @Test
+  public void checkSetGet() throws Exception {
+    int memCapacity = 60; //must be at least 60
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      WritableBuffer buf = mem.asWritableBuffer();
+      assertEquals(buf.getCapacity(), memCapacity);
+      setGetTests(buf);
+      setGetTests2(buf);
+    }
+  }
+
+  public static void setGetTests(WritableBuffer buf) {
+    buf.putBoolean(true);
+    buf.putBoolean(false);
+    buf.putByte((byte) -1);
+    buf.putByte((byte) 0);
+    buf.putChar('A');
+    buf.putChar('Z');
+    buf.putShort(Short.MAX_VALUE);
+    buf.putShort(Short.MIN_VALUE);
+    buf.putInt(Integer.MAX_VALUE);
+    buf.putInt(Integer.MIN_VALUE);
+    buf.putFloat(Float.MAX_VALUE);
+    buf.putFloat(Float.MIN_VALUE);
+    buf.putLong(Long.MAX_VALUE);
+    buf.putLong(Long.MIN_VALUE);
+    buf.putDouble(Double.MAX_VALUE);
+    buf.putDouble(Double.MIN_VALUE);
+
+    buf.resetPosition();
+
+    assertEquals(buf.getBoolean(buf.getPosition()), true);
+    assertEquals(buf.getBoolean(), true);
+    assertEquals(buf.getBoolean(buf.getPosition()), false);
+    assertEquals(buf.getBoolean(), false);
+    assertEquals(buf.getByte(buf.getPosition()), (byte) -1);
+    assertEquals(buf.getByte(), (byte) -1);
+    assertEquals(buf.getByte(buf.getPosition()), (byte)0);
+    assertEquals(buf.getByte(), (byte)0);
+    assertEquals(buf.getChar(buf.getPosition()), 'A');
+    assertEquals(buf.getChar(), 'A');
+    assertEquals(buf.getChar(buf.getPosition()), 'Z');
+    assertEquals(buf.getChar(), 'Z');
+    assertEquals(buf.getShort(buf.getPosition()), Short.MAX_VALUE);
+    assertEquals(buf.getShort(), Short.MAX_VALUE);
+    assertEquals(buf.getShort(buf.getPosition()), Short.MIN_VALUE);
+    assertEquals(buf.getShort(), Short.MIN_VALUE);
+    assertEquals(buf.getInt(buf.getPosition()), Integer.MAX_VALUE);
+    assertEquals(buf.getInt(), Integer.MAX_VALUE);
+    assertEquals(buf.getInt(buf.getPosition()), Integer.MIN_VALUE);
+    assertEquals(buf.getInt(), Integer.MIN_VALUE);
+    assertEquals(buf.getFloat(buf.getPosition()), Float.MAX_VALUE);
+    assertEquals(buf.getFloat(), Float.MAX_VALUE);
+    assertEquals(buf.getFloat(buf.getPosition()), Float.MIN_VALUE);
+    assertEquals(buf.getFloat(), Float.MIN_VALUE);
+    assertEquals(buf.getLong(buf.getPosition()), Long.MAX_VALUE);
+    assertEquals(buf.getLong(), Long.MAX_VALUE);
+    assertEquals(buf.getLong(buf.getPosition()), Long.MIN_VALUE);
+    assertEquals(buf.getLong(), Long.MIN_VALUE);
+    assertEquals(buf.getDouble(buf.getPosition()), Double.MAX_VALUE);
+    assertEquals(buf.getDouble(), Double.MAX_VALUE);
+    assertEquals(buf.getDouble(buf.getPosition()), Double.MIN_VALUE);
+    assertEquals(buf.getDouble(), Double.MIN_VALUE);
+  }
+
+  public static void setGetTests2(WritableBuffer buf) {
+    buf.putBoolean(0, true);
+    buf.putBoolean(1, false);
+    buf.putByte(2, (byte) -1);
+    buf.putByte(3, (byte) 0);
+    buf.putChar(4,'A');
+    buf.putChar(6,'Z');
+    buf.putShort(8, Short.MAX_VALUE);
+    buf.putShort(10, Short.MIN_VALUE);
+    buf.putInt(12, Integer.MAX_VALUE);
+    buf.putInt(16, Integer.MIN_VALUE);
+    buf.putFloat(20, Float.MAX_VALUE);
+    buf.putFloat(24, Float.MIN_VALUE);
+    buf.putLong(28, Long.MAX_VALUE);
+    buf.putLong(36, Long.MIN_VALUE);
+    buf.putDouble(44, Double.MAX_VALUE);
+    buf.putDouble(52, Double.MIN_VALUE);
+
+    assertEquals(buf.getBoolean(0), true);
+    assertEquals(buf.getBoolean(1), false);
+    assertEquals(buf.getByte(2), (byte) -1);
+    assertEquals(buf.getByte(3), (byte)0);
+    assertEquals(buf.getChar(4), 'A');
+    assertEquals(buf.getChar(6), 'Z');
+    assertEquals(buf.getShort(8), Short.MAX_VALUE);
+    assertEquals(buf.getShort(10), Short.MIN_VALUE);
+    assertEquals(buf.getInt(12), Integer.MAX_VALUE);
+    assertEquals(buf.getInt(16), Integer.MIN_VALUE);
+    assertEquals(buf.getFloat(20), Float.MAX_VALUE);
+    assertEquals(buf.getFloat(24), Float.MIN_VALUE);
+    assertEquals(buf.getLong(28), Long.MAX_VALUE);
+    assertEquals(buf.getLong(36), Long.MIN_VALUE);
+    assertEquals(buf.getDouble(44), Double.MAX_VALUE);
+    assertEquals(buf.getDouble(52), Double.MIN_VALUE);
+  }
+
+  @Test
+  public void checkSetGetArrays() throws Exception {
+    int memCapacity = 32;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      WritableBuffer buf = mem.asWritableBuffer();
+      assertEquals(buf.getCapacity(), memCapacity);
+      setGetArraysTests(buf);
+    }
+  }
+
+  public static void setGetArraysTests(WritableBuffer buf) {
+    int words = 4;
+
+    byte[] srcArray2 = { 1, -2, 3, -4 };
+    byte[] dstArray2 = new byte[4];
+    buf.resetPosition();
+    buf.putByteArray(srcArray2, 0, words);
+    buf.resetPosition();
+    buf.getByteArray(dstArray2, 0, words);
+    for (int i=0; i<words; i++) {
+      assertEquals(dstArray2[i], srcArray2[i]);
+    }
+
+    char[] srcArray3 = { 'A', 'B', 'C', 'D' };
+    char[] dstArray3 = new char[words];
+    buf.resetPosition();
+    buf.putCharArray(srcArray3, 0, words);
+    buf.resetPosition();
+    buf.getCharArray(dstArray3, 0, words);
+    for (int i=0; i<words; i++) {
+      assertEquals(dstArray3[i], srcArray3[i]);
+    }
+
+    double[] srcArray4 = { 1.0, -2.0, 3.0, -4.0 };
+    double[] dstArray4 = new double[words];
+    buf.resetPosition();
+    buf.putDoubleArray(srcArray4, 0, words);
+    buf.resetPosition();
+    buf.getDoubleArray(dstArray4, 0, words);
+    for (int i=0; i<words; i++) {
+      assertEquals(dstArray4[i], srcArray4[i], 0.0);
+    }
+
+    float[] srcArray5 = { 1.0F, -2.0F, 3.0F, -4.0F };
+    float[] dstArray5 = new float[words];
+    buf.resetPosition();
+    buf.putFloatArray(srcArray5, 0, words);
+    buf.resetPosition();
+    buf.getFloatArray(dstArray5, 0, words);
+    for (int i=0; i<words; i++) {
+      assertEquals(dstArray5[i], srcArray5[i], 0.0);
+    }
+
+    int[] srcArray6 = { 1, -2, 3, -4 };
+    int[] dstArray6 = new int[words];
+    buf.resetPosition();
+    buf.putIntArray(srcArray6, 0, words);
+    buf.resetPosition();
+    buf.getIntArray(dstArray6, 0, words);
+    for (int i=0; i<words; i++) {
+      assertEquals(dstArray6[i], srcArray6[i]);
+    }
+
+    long[] srcArray7 = { 1, -2, 3, -4 };
+    long[] dstArray7 = new long[words];
+    buf.resetPosition();
+    buf.putLongArray(srcArray7, 0, words);
+    buf.resetPosition();
+    buf.getLongArray(dstArray7, 0, words);
+    for (int i=0; i<words; i++) {
+      assertEquals(dstArray7[i], srcArray7[i]);
+    }
+
+    short[] srcArray8 = { 1, -2, 3, -4 };
+    short[] dstArray8 = new short[words];
+    buf.resetPosition();
+    buf.putShortArray(srcArray8, 0, words);
+    buf.resetPosition();
+    buf.getShortArray(dstArray8, 0, words);
+    for (int i=0; i<words; i++) {
+      assertEquals(dstArray8[i], srcArray8[i]);
+    }
+  }
+
+  @Test
+  public void checkSetGetPartialArraysWithOffset() throws Exception {
+    int memCapacity = 32;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      WritableBuffer buf = mem.asWritableBuffer();
+      assertEquals(buf.getCapacity(), memCapacity);
+      setGetPartialArraysWithOffsetTests(buf);
+    }
+  }
+
+  public static void setGetPartialArraysWithOffsetTests(WritableBuffer buf) {
+    int items= 4;
+
+    byte[] srcArray2 = { 1, -2, 3, -4 };
+    byte[] dstArray2 = new byte[items];
+    buf.resetPosition();
+    buf.putByteArray(srcArray2, 2, items/2);
+    buf.resetPosition();
+    buf.getByteArray(dstArray2, 2, items/2);
+    for (int i=2; i<items; i++) {
+      assertEquals(dstArray2[i], srcArray2[i]);
+    }
+
+    char[] srcArray3 = { 'A', 'B', 'C', 'D' };
+    char[] dstArray3 = new char[items];
+    buf.resetPosition();
+    buf.putCharArray(srcArray3, 2, items/2);
+    buf.resetPosition();
+    buf.getCharArray(dstArray3, 2, items/2);
+    for (int i=2; i<items; i++) {
+      assertEquals(dstArray3[i], srcArray3[i]);
+    }
+
+    double[] srcArray4 = { 1.0, -2.0, 3.0, -4.0 };
+    double[] dstArray4 = new double[items];
+    buf.resetPosition();
+    buf.putDoubleArray(srcArray4, 2, items/2);
+    buf.resetPosition();
+    buf.getDoubleArray(dstArray4, 2, items/2);
+    for (int i=2; i<items; i++) {
+      assertEquals(dstArray4[i], srcArray4[i], 0.0);
+    }
+
+    float[] srcArray5 = { 1.0F, -2.0F, 3.0F, -4.0F };
+    float[] dstArray5 = new float[items];
+    buf.resetPosition();
+    buf.putFloatArray(srcArray5, 2, items/2);
+    buf.resetPosition();
+    buf.getFloatArray(dstArray5, 2, items/2);
+    for (int i=2; i<items; i++) {
+      assertEquals(dstArray5[i], srcArray5[i], 0.0);
+    }
+
+    int[] srcArray6 = { 1, -2, 3, -4 };
+    int[] dstArray6 = new int[items];
+    buf.resetPosition();
+    buf.putIntArray(srcArray6, 2, items/2);
+    buf.resetPosition();
+    buf.getIntArray(dstArray6, 2, items/2);
+    for (int i=2; i<items; i++) {
+      assertEquals(dstArray6[i], srcArray6[i]);
+    }
+
+    long[] srcArray7 = { 1, -2, 3, -4 };
+    long[] dstArray7 = new long[items];
+    buf.resetPosition();
+    buf.putLongArray(srcArray7, 2, items/2);
+    buf.resetPosition();
+    buf.getLongArray(dstArray7, 2, items/2);
+    for (int i=2; i<items; i++) {
+      assertEquals(dstArray7[i], srcArray7[i]);
+    }
+
+    short[] srcArray8 = { 1, -2, 3, -4 };
+    short[] dstArray8 = new short[items];
+    buf.resetPosition();
+    buf.putShortArray(srcArray8, 2, items/2);
+    buf.resetPosition();
+    buf.getShortArray(dstArray8, 2, items/2);
+    for (int i=2; i<items; i++) {
+      assertEquals(dstArray8[i], srcArray8[i]);
+    }
+  }
+
+  @Test
+  public void checkSetClearMemoryRegions() throws Exception {
+    int memCapacity = 64; //must be 64
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      WritableBuffer buf = mem.asWritableBuffer();
+      assertEquals(buf.getCapacity(), memCapacity);
+
+      setClearMemoryRegionsTests(buf); //requires println enabled to visually check
+      buf.resetPosition();
+      for (int i = 0; i < memCapacity; i++) {
+        assertEquals(mem.getByte(i), 0);
+      }
+    }
+  }
+
+  //enable println statements to visually check
+  public static void setClearMemoryRegionsTests(WritableBuffer buf) {
+    int accessCapacity = (int)buf.getCapacity();
+
+  //define regions
+    int reg1Start = 0;
+    int reg1Len = 28;
+    int reg2Start = 28;
+    int reg2Len = 32;
+
+    //set region 1
+    byte b1 = 5;
+    buf.setStartPositionEnd(reg1Start, reg1Start, reg1Len);
+    buf.fill(b1);
+    buf.resetPosition();
+    for (int i=reg1Start; i<(reg1Len+reg1Start); i++) {
+      assertEquals(buf.getByte(), b1);
+    }
+    //println(buf.toHexString("Region1 to 5", reg1Start, reg1Len));
+
+    //set region 2
+    byte b2 = 7;
+    buf.setStartPositionEnd(reg2Start, reg2Start, reg2Start + reg2Len);
+    buf.fill(b2);
+    //println(mem.toHexString("Fill", 0, (int)mem.getCapacity()));
+    buf.resetPosition();
+    for (int i=reg2Start; i<(reg2Start+reg2Len); i++) {
+      assertEquals(buf.getByte(), b2);
+    }
+    //println(buf.toHexString("Region2 to 7", reg2Start, reg2Len));
+
+    //clear region 1
+    byte zeroByte = 0;
+    buf.setStartPositionEnd(reg1Start, reg1Start, reg2Len);
+    buf.resetPosition();
+    buf.clear();
+    buf.resetPosition();
+    for (int i=reg1Start; i<(reg1Start+reg1Len); i++) {
+      assertEquals(buf.getByte(), zeroByte);
+    }
+    //println(buf.toHexString("Region1 cleared", reg1Start, reg1Len));
+
+    //clear region 2
+    buf.setStartPositionEnd(reg2Start, reg2Start, reg2Start + reg2Len);
+    buf.resetPosition();
+    buf.clear();
+    buf.resetPosition();
+    for (int i=reg2Start; i<(reg2Len+reg2Start); i++) {
+      assertEquals(buf.getByte(), zeroByte);
+    }
+    //println(buf.toHexString("Region2 cleared", reg2Start, reg2Len));
+
+    //set all to ones
+    buf.setStartPositionEnd(reg1Start, reg1Start, accessCapacity);
+    byte b4 = 127;
+    buf.resetPosition();
+    buf.fill(b4);
+    buf.resetPosition();
+    for (int i=0; i<accessCapacity; i++) {
+      assertEquals(buf.getByte(), b4);
+    }
+    //println(buf.toHexString("Region1 + Region2 all ones", 0, accessCapacity));
+
+    //clear all
+    buf.resetPosition();
+    buf.clear();
+    buf.resetPosition();
+    for (int i=0; i<accessCapacity; i++) {
+      assertEquals(buf.getByte(), zeroByte);
+    }
+    //println(buf.toHexString("Region1 + Region2 cleared", 0, accessCapacity));
+  }
+
+  @Test
+  public void checkToHexStringAllMem() throws Exception {
+    int memCapacity = 48; //must be 48
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      WritableBuffer buf = mem.asWritableBuffer();
+      assertEquals(buf.getCapacity(), memCapacity);
+      toHexStringAllMemTests(buf); //requires println enabled to visually check
+    }
+  }
+
+  //enable println to visually check
+  public static void toHexStringAllMemTests(WritableBuffer buf) {
+    int memCapacity = (int)buf.getCapacity();
+
+    for (int i=0; i<memCapacity; i++) {
+      buf.putByte((byte)i);
+    }
+
+    //println(buf.toHexString("Check toHexString(0, 48) to integers", 0, memCapacity));
+    //println(buf.toHexString("Check toHexString(8, 40)", 8, 40));
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void println(String s) {
+    //System.out.println(s); //disable here
+  }
+
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/CommonMemoryTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/CommonMemoryTest.java
new file mode 100644
index 0000000..9245a59
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/CommonMemoryTest.java
@@ -0,0 +1,375 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.apache.datasketches.memory.internal.Util.isAllBitsClear;
+import static org.apache.datasketches.memory.internal.Util.isAllBitsSet;
+import static org.apache.datasketches.memory.internal.Util.isAnyBitsClear;
+import static org.apache.datasketches.memory.internal.Util.isAnyBitsSet;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+public class CommonMemoryTest {
+  private final MemoryRequestServer memReqSvr = BaseState.defaultMemReqSvr;
+  @Test
+  public void checkSetGet() throws Exception {
+    int memCapacity = 16; //must be at least 8
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      assertEquals(mem.getCapacity(), memCapacity);
+      setGetTests(mem);
+    }
+  }
+
+  public static void setGetTests(WritableMemory mem) {
+    mem.putBoolean(0, true);
+    assertTrue(mem.getBoolean(0));
+    mem.putBoolean(0, false);
+    assertFalse(mem.getBoolean(0));
+
+    mem.putByte(0, (byte) -1);
+    assertEquals(mem.getByte(0), (byte) -1);
+    mem.putByte(0, (byte) 0);
+    assertEquals(mem.getByte(0), (byte) 0);
+
+    mem.putChar(0, 'A');
+    assertEquals(mem.getChar(0), 'A');
+    mem.putChar(0, 'Z');
+    assertEquals(mem.getChar(0), 'Z');
+
+    mem.putShort(0, Short.MAX_VALUE);
+    assertEquals(mem.getShort(0), Short.MAX_VALUE);
+    mem.putShort(0, Short.MIN_VALUE);
+    assertEquals(mem.getShort(0), Short.MIN_VALUE);
+
+    mem.putInt(0, Integer.MAX_VALUE);
+    assertEquals(mem.getInt(0), Integer.MAX_VALUE);
+    mem.putInt(0, Integer.MIN_VALUE);
+    assertEquals(mem.getInt(0), Integer.MIN_VALUE);
+
+    mem.putFloat(0, Float.MAX_VALUE);
+    assertEquals(mem.getFloat(0), Float.MAX_VALUE);
+    mem.putFloat(0, Float.MIN_VALUE);
+    assertEquals(mem.getFloat(0), Float.MIN_VALUE);
+
+    mem.putLong(0, Long.MAX_VALUE);
+    assertEquals(mem.getLong(0), Long.MAX_VALUE);
+    mem.putLong(0, Long.MIN_VALUE);
+    assertEquals(mem.getLong(0), Long.MIN_VALUE);
+
+    mem.putDouble(0, Double.MAX_VALUE);
+    assertEquals(mem.getDouble(0), Double.MAX_VALUE);
+    mem.putDouble(0, Double.MIN_VALUE);
+    assertEquals(mem.getDouble(0), Double.MIN_VALUE);
+  }
+
+  @Test
+  public void checkSetGetArrays() throws Exception {
+    int memCapacity = 32;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      assertEquals(memCapacity, mem.getCapacity());
+      setGetArraysTests(mem);
+    }
+  }
+
+  public static void setGetArraysTests(WritableMemory mem) {
+    int words = 4;
+
+    byte[] srcArray2 = { 1, -2, 3, -4 };
+    byte[] dstArray2 = new byte[4];
+    mem.putByteArray(0, srcArray2, 0, words);
+    mem.getByteArray(0, dstArray2, 0, words);
+    for (int i = 0; i < words; i++) {
+      assertEquals(dstArray2[i], srcArray2[i]);
+    }
+
+    char[] srcArray3 = { 'A', 'B', 'C', 'D' };
+    char[] dstArray3 = new char[words];
+    mem.putCharArray(0, srcArray3, 0, words);
+    mem.getCharArray(0, dstArray3, 0, words);
+    for (int i = 0; i < words; i++) {
+      assertEquals(dstArray3[i], srcArray3[i]);
+    }
+
+    double[] srcArray4 = { 1.0, -2.0, 3.0, -4.0 };
+    double[] dstArray4 = new double[words];
+    mem.putDoubleArray(0, srcArray4, 0, words);
+    mem.getDoubleArray(0, dstArray4, 0, words);
+    for (int i = 0; i < words; i++) {
+      assertEquals(dstArray4[i], srcArray4[i], 0.0);
+    }
+
+    float[] srcArray5 = { (float)1.0, (float)-2.0, (float)3.0, (float)-4.0 };
+    float[] dstArray5 = new float[words];
+    mem.putFloatArray(0, srcArray5, 0, words);
+    mem.getFloatArray(0, dstArray5, 0, words);
+    for (int i = 0; i < words; i++) {
+      assertEquals(dstArray5[i], srcArray5[i], 0.0);
+    }
+
+    int[] srcArray6 = { 1, -2, 3, -4 };
+    int[] dstArray6 = new int[words];
+    mem.putIntArray(0, srcArray6, 0, words);
+    mem.getIntArray(0, dstArray6, 0, words);
+    for (int i = 0; i < words; i++) {
+      assertEquals(dstArray6[i], srcArray6[i]);
+    }
+
+    long[] srcArray7 = { 1, -2, 3, -4 };
+    long[] dstArray7 = new long[words];
+    mem.putLongArray(0, srcArray7, 0, words);
+    mem.getLongArray(0, dstArray7, 0, words);
+    for (int i = 0; i < words; i++) {
+      assertEquals(dstArray7[i], srcArray7[i]);
+    }
+
+    short[] srcArray8 = { 1, -2, 3, -4 };
+    short[] dstArray8 = new short[words];
+    mem.putShortArray(0, srcArray8, 0, words);
+    mem.getShortArray(0, dstArray8, 0, words);
+    for (int i = 0; i < words; i++) {
+      assertEquals(dstArray8[i], srcArray8[i]);
+    }
+  }
+
+  @Test
+  public void checkSetGetPartialArraysWithOffset() throws Exception {
+    int memCapacity = 32;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      assertEquals(memCapacity, mem.getCapacity());
+      setGetPartialArraysWithOffsetTests(mem);
+    }
+  }
+
+  public static void setGetPartialArraysWithOffsetTests(WritableMemory mem) {
+    int items= 4;
+
+    byte[] srcArray2 = { 1, -2, 3, -4 };
+    byte[] dstArray2 = new byte[items];
+    mem.putByteArray(0, srcArray2, 2, items/2);
+    mem.getByteArray(0, dstArray2, 2, items/2);
+    for (int i = 2; i < items; i++) {
+      assertEquals(dstArray2[i], srcArray2[i]);
+    }
+
+    char[] srcArray3 = { 'A', 'B', 'C', 'D' };
+    char[] dstArray3 = new char[items];
+    mem.putCharArray(0, srcArray3, 2, items/2);
+    mem.getCharArray(0, dstArray3, 2, items/2);
+    for (int i = 2; i < items; i++) {
+      assertEquals(dstArray3[i], srcArray3[i]);
+    }
+
+    double[] srcArray4 = { 1.0, -2.0, 3.0, -4.0 };
+    double[] dstArray4 = new double[items];
+    mem.putDoubleArray(0, srcArray4, 2, items/2);
+    mem.getDoubleArray(0, dstArray4, 2, items/2);
+    for (int i = 2; i < items; i++) {
+      assertEquals(dstArray4[i], srcArray4[i], 0.0);
+    }
+
+    float[] srcArray5 = { (float)1.0, (float)-2.0, (float)3.0, (float)-4.0 };
+    float[] dstArray5 = new float[items];
+    mem.putFloatArray(0, srcArray5, 2, items/2);
+    mem.getFloatArray(0, dstArray5, 2, items/2);
+    for (int i = 2; i < items; i++) {
+      assertEquals(dstArray5[i], srcArray5[i], 0.0);
+    }
+
+    int[] srcArray6 = { 1, -2, 3, -4 };
+    int[] dstArray6 = new int[items];
+    mem.putIntArray(0, srcArray6, 2, items/2);
+    mem.getIntArray(0, dstArray6, 2, items/2);
+    for (int i = 2; i < items; i++) {
+      assertEquals(dstArray6[i], srcArray6[i]);
+    }
+
+    long[] srcArray7 = { 1, -2, 3, -4 };
+    long[] dstArray7 = new long[items];
+    mem.putLongArray(0, srcArray7, 2, items/2);
+    mem.getLongArray(0, dstArray7, 2, items/2);
+    for (int i = 2; i < items; i++) {
+      assertEquals(dstArray7[i], srcArray7[i]);
+    }
+
+    short[] srcArray8 = { 1, -2, 3, -4 };
+    short[] dstArray8 = new short[items];
+    mem.putShortArray(0, srcArray8, 2, items/2);
+    mem.getShortArray(0, dstArray8, 2, items/2);
+    for (int i = 2; i < items; i++) {
+      assertEquals(dstArray8[i], srcArray8[i]);
+    }
+  }
+
+  @Test
+  public void checkSetClearIsBits() throws Exception {
+    int memCapacity = 8;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      assertEquals(memCapacity, mem.getCapacity());
+      mem.clear();
+      setClearIsBitsTests(mem);
+    }
+  }
+
+  public static void setClearIsBitsTests(WritableMemory mem) {
+  //single bits
+    for (int i = 0; i < 8; i++) {
+      long bitMask = (1 << i);
+      long v = mem.getByte(0) & 0XFFL;
+      assertTrue(isAnyBitsClear(v, bitMask));
+      mem.setBits(0, (byte) bitMask);
+      v = mem.getByte(0) & 0XFFL;
+      assertTrue(isAnyBitsSet(v, bitMask));
+      mem.clearBits(0, (byte) bitMask);
+      v = mem.getByte(0) & 0XFFL;
+      assertTrue(isAnyBitsClear(v, bitMask));
+    }
+
+    //multiple bits
+    for (int i = 0; i < 7; i++) {
+      long bitMask1 = (1 << i);
+      long bitMask2 = (3 << i);
+      long v = mem.getByte(0) & 0XFFL;
+      assertTrue(isAnyBitsClear(v, bitMask1));
+      assertTrue(isAnyBitsClear(v, bitMask2));
+      mem.setBits(0, (byte) bitMask1); //set one bit
+      v = mem.getByte(0) & 0XFFL;
+      assertTrue(isAnyBitsSet(v, bitMask2));
+      assertTrue(isAnyBitsClear(v, bitMask2));
+      assertFalse(isAllBitsSet(v, bitMask2));
+      assertFalse(isAllBitsClear(v, bitMask2));
+    }
+  }
+
+  @Test
+  public void checkSetClearMemoryRegions() throws Exception {
+    int memCapacity = 64; //must be 64
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+
+      setClearMemoryRegionsTests(mem); //requires println enabled to visually check
+      for (int i = 0; i < memCapacity; i++) {
+        assertEquals(mem.getByte(i), 0);
+      }
+    }
+  }
+
+  //enable println stmts to visually check
+  public static void setClearMemoryRegionsTests(WritableMemory mem) {
+    int accessCapacity = (int)mem.getCapacity();
+
+  //define regions
+    int reg1Start = 0;
+    int reg1Len = 28;
+    int reg2Start = 28;
+    int reg2Len = 32;
+
+    //set region 1
+    byte b1 = 5;
+    mem.fill(reg1Start, reg1Len, b1);
+    for (int i = reg1Start; i < (reg1Len+reg1Start); i++) {
+      assertEquals(mem.getByte(i), b1);
+    }
+    //println(mem.toHexString("Region1 to 5", reg1Start, reg1Len));
+
+    //set region 2
+    byte b2 = 7;
+    mem.fill(reg2Start, reg2Len, b2);
+    //println(mem.toHexString("Fill", 0, (int)mem.getCapacity()));
+    for (int i = reg2Start; i < (reg2Len+reg2Start); i++) {
+      assertEquals(mem.getByte(i), b2);
+    }
+    //println(mem.toHexString("Region2 to 7", reg2Start, reg2Len));
+
+    //clear region 1
+    byte zeroByte = 0;
+    mem.clear(reg1Start, reg1Len);
+    for (int i = reg1Start; i < (reg1Len+reg1Start); i++) {
+      assertEquals(mem.getByte(i), zeroByte);
+    }
+    //println(mem.toHexString("Region1 cleared", reg1Start, reg1Len));
+
+    //clear region 2
+    mem.clear(reg2Start, reg2Len);
+    for (int i = reg2Start; i < (reg2Len+reg2Start); i++) {
+      assertEquals(mem.getByte(i), zeroByte);
+    }
+    //println(mem.toHexString("Region2 cleared", reg2Start, reg2Len));
+
+    //set all to ones
+    byte b4 = 127;
+    mem.fill(b4);
+    for (int i=0; i<accessCapacity; i++) {
+      assertEquals(mem.getByte(i), b4);
+    }
+    //println(mem.toHexString("Region1 + Region2 all ones", 0, accessCapacity));
+
+    //clear all
+    mem.clear();
+    for (int i = 0; i < accessCapacity; i++) {
+      assertEquals(mem.getByte(i), zeroByte);
+    }
+    //println(mem.toHexString("Region1 + Region2 cleared", 0, accessCapacity));
+  }
+
+  @Test
+  public void checkToHexStringAllMem() throws Exception {
+    int memCapacity = 48; //must be 48
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      toHexStringAllMemTests(mem); //requires println enabled to visually check
+    }
+  }
+
+  //enable println to visually check
+  public static void toHexStringAllMemTests(WritableMemory mem) {
+    int memCapacity = (int)mem.getCapacity();
+
+    for (int i = 0; i < memCapacity; i++) {
+      mem.putByte(i, (byte)i);
+    }
+
+    //println(mem.toHexString("Check toHexString(0, 48) to integers", 0, memCapacity));
+    //println(mem.toHexString("Check toHexString(8, 40)", 8, 40));
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void println(String s) {
+    //System.out.println(s); //disable here
+  }
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/CopyMemoryOverlapTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/CopyMemoryOverlapTest.java
new file mode 100644
index 0000000..8a4bdc0
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/CopyMemoryOverlapTest.java
@@ -0,0 +1,187 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.testng.Assert.assertEquals;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+/**
+ * @author Lee Rhodes
+ */
+public class CopyMemoryOverlapTest {
+  private static final MemoryRequestServer memReqSvr = BaseState.defaultMemReqSvr;
+
+  @Test
+  public void checkOverlapUsingMemory() throws Exception {
+    long copyLongs = 1 << 20;
+    double overlap = 0.5;
+    long start_mS = System.currentTimeMillis();
+
+    copyUsingDirectMemory(copyLongs, overlap, true);
+    long end1_mS = System.currentTimeMillis();
+
+    copyUsingDirectMemory(copyLongs, overlap, false);
+    long end2_mS = System.currentTimeMillis();
+
+    println("CopyUp Time Sec: " + ((end1_mS - start_mS)/1000.0));
+    println("CopyDn Time Sec: " + ((end2_mS - end1_mS)/1000.0));
+  }
+
+  @Test
+  public void checkOverlapUsingRegions() throws Exception {
+    long copyLongs = 1 << 20;
+    double overlap = 0.5;
+    long start_mS = System.currentTimeMillis();
+
+    copyUsingDirectRegions(copyLongs, overlap, true);
+    long end1_mS = System.currentTimeMillis();
+
+    copyUsingDirectRegions(copyLongs, overlap, false);
+    long end2_mS = System.currentTimeMillis();
+
+    println("CopyUp Time Sec: " + ((end1_mS - start_mS)/1000.0));
+    println("CopyDn Time Sec: " + ((end2_mS - end1_mS)/1000.0));
+  }
+
+  private static final void copyUsingDirectMemory(long copyLongs, double overlap, boolean copyUp) throws Exception {
+    println("Copy Using Direct Memory");
+    long overlapLongs = (long) (overlap * copyLongs);
+    long backingLongs = (2 * copyLongs) - overlapLongs;
+
+    long fromOffsetLongs;
+    long toOffsetLongs;
+    //long deltaLongs;
+
+    if (copyUp) {
+      fromOffsetLongs = 0;
+      toOffsetLongs = copyLongs - overlapLongs;
+      //deltaLongs = toOffsetLongs - fromOffsetLongs;
+    } else {
+      fromOffsetLongs = copyLongs - overlapLongs;
+      toOffsetLongs = 0;
+      //deltaLongs = toOffsetLongs - fromOffsetLongs;
+    }
+
+    long backingBytes = backingLongs << 3;
+    long copyBytes = copyLongs << 3;
+    long fromOffsetBytes = fromOffsetLongs << 3;
+    long toOffsetBytes = toOffsetLongs << 3;
+    //long deltaBytes = deltaLongs << 3;
+    println("Copy longs   : " + copyLongs    + "\t bytes: " + copyBytes);
+    println("Overlap      : " + (overlap * 100.0) + "%");
+    println("CopyUp       : " + copyUp);
+    println("Backing longs: " + backingLongs + "\t bytes: " + backingBytes);
+
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory backingMem = WritableMemory.allocateDirect(backingBytes, scope, memReqSvr);
+      fill(backingMem); //fill mem with 0 thru copyLongs -1
+      //listMem(backingMem, "Original");
+      backingMem.copyTo(fromOffsetBytes, backingMem, toOffsetBytes, copyBytes);
+      //listMem(backingMem, "After");
+      checkMemLongs(backingMem, fromOffsetLongs, toOffsetLongs, copyLongs);
+    }
+    println("");
+  }
+
+  private static final void copyUsingDirectRegions(long copyLongs, double overlap, boolean copyUp) throws Exception {
+    println("Copy Using Direct Memory");
+    long overlapLongs = (long) (overlap * copyLongs);
+    long backingLongs = (2 * copyLongs) - overlapLongs;
+
+    long fromOffsetLongs;
+    long toOffsetLongs;
+    //long deltaLongs;
+
+    if (copyUp) {
+      fromOffsetLongs = 0;
+      toOffsetLongs = copyLongs - overlapLongs;
+      //deltaLongs = toOffsetLongs - fromOffsetLongs;
+    } else {
+      fromOffsetLongs = copyLongs - overlapLongs;
+      toOffsetLongs = 0;
+      //deltaLongs = toOffsetLongs - fromOffsetLongs;
+    }
+
+    long backingBytes = backingLongs << 3;
+    long copyBytes = copyLongs << 3;
+    long fromOffsetBytes = fromOffsetLongs << 3;
+    long toOffsetBytes = toOffsetLongs << 3;
+    //long deltaBytes = deltaLongs << 3;
+    println("Copy longs   : " + copyLongs    + "\t bytes: " + copyBytes);
+    println("Overlap      : " + (overlap * 100.0) + "%");
+    println("CopyUp       : " + copyUp);
+    println("Backing longs: " + backingLongs + "\t bytes: " + backingBytes);
+
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory backingMem = WritableMemory.allocateDirect(backingBytes, scope, memReqSvr);
+      fill(backingMem); //fill mem with 0 thru copyLongs -1
+      //listMem(backingMem, "Original");
+      WritableMemory reg1 = backingMem.writableRegion(fromOffsetBytes, copyBytes);
+      WritableMemory reg2 = backingMem.writableRegion(toOffsetBytes, copyBytes);
+
+      reg1.copyTo(0, reg2, 0, copyBytes);
+      //listMem(backingMem, "After");
+      checkMemLongs(reg2, fromOffsetLongs, 0, copyLongs);
+    }
+    println("");
+  }
+
+  private static final void fill(WritableMemory wmem) {
+    long longs = wmem.getCapacity() >>> 3;
+    for (long i = 0; i < longs; i++) { wmem.putLong(i << 3, i); } //fill with 0 .. (longs - 1)
+    //checkMemLongs(wmem, 0L, 0L, longs);
+  }
+
+  private static final void checkMemLongs(Memory mem, long fromOffsetLongs, long toOffsetLongs, long copyLongs) {
+    for (long i = 0; i < copyLongs; i++) {
+      long memVal = mem.getLong((toOffsetLongs + i) << 3);
+      assertEquals(memVal, fromOffsetLongs + i);
+    }
+  }
+
+  @SuppressWarnings("unused")
+  private static final void listMem(Memory mem, String comment) {
+    println(comment);
+    println("Idx\tValue");
+    long longs = mem.getCapacity() >>> 3;
+    for (long i = 0; i < longs; i++) {
+      println(i + "\t" + mem.getLong(i << 3));
+    }
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void println(String s) {
+    //System.out.println(s); //disable here
+  }
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/CopyMemoryTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/CopyMemoryTest.java
new file mode 100644
index 0000000..f0af8c4
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/CopyMemoryTest.java
@@ -0,0 +1,182 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.concurrent.ThreadLocalRandom;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+public class CopyMemoryTest {
+  private static final MemoryRequestServer memReqSvr = BaseState.defaultMemReqSvr;
+
+  @Test
+  public void heapWSource() {
+    int k1 = 1 << 20; //longs
+    int k2 = 2 * k1;
+    WritableMemory srcMem = genMem(k1, false); //!empty
+    //println(srcMem.toHexString("src: ", 0, k1 << 3));
+    WritableMemory dstMem = genMem(k2, true);
+    srcMem.copyTo(0, dstMem, k1 << 3, k1 << 3);
+    //println(dstMem.toHexString("dst: ", 0, k2 << 3));
+    check(dstMem, k1, k1, 1);
+  }
+
+  @Test
+  public void heapROSource() {
+    int k1 = 1 << 20; //longs
+    int k2 = 2 * k1;
+    Memory srcMem = genMem(k1, false); //!empty
+    WritableMemory dstMem = genMem(k2, true);
+    srcMem.copyTo(0, dstMem, k1 << 3, k1 << 3);
+    check(dstMem, k1, k1, 1);
+  }
+
+  @Test
+  public void directWSource() throws Exception {
+    int k1 = 1 << 20; //longs
+    int k2 = 2 * k1;
+    WritableMemory srcMem = genWmem(k1, false);
+    WritableMemory dstMem = genMem(k2, true);
+    srcMem.copyTo(0, dstMem, k1 << 3, k1 << 3);
+    check(dstMem, k1, k1, 1);
+    srcMem.close();
+  }
+
+  @Test
+  public void directROSource() throws Exception {
+    int k1 = 1 << 20; //longs
+    int k2 = 2 * k1;
+    Memory srcMem = genWmem(k1, false);
+    WritableMemory dstMem = genMem(k2, true);
+    srcMem.copyTo(0, dstMem, k1 << 3, k1 << 3);
+    check(dstMem, k1, k1, 1);
+    srcMem.close();
+  }
+
+  @Test
+  public void heapWSrcRegion() {
+    int k1 = 1 << 20; //longs
+    //gen baseMem of k1 longs w data
+    WritableMemory baseMem = genMem(k1, false); //!empty
+    //gen src region of k1/2 longs, off= k1/2
+    WritableMemory srcReg = baseMem.writableRegion((k1/2) << 3, (k1/2) << 3);
+    WritableMemory dstMem = genMem(2 * k1, true); //empty
+    srcReg.copyTo(0, dstMem, k1 << 3, (k1/2) << 3);
+    //println(dstMem.toHexString("dstMem: ", k1 << 3, (k1/2) << 3));
+    check(dstMem, k1, k1/2, (k1/2) + 1);
+  }
+
+  @Test
+  public void heapROSrcRegion() {
+    int k1 = 1 << 20; //longs
+    //gen baseMem of k1 longs w data
+    WritableMemory baseMem = genMem(k1, false); //!empty
+    //gen src region of k1/2 longs, off= k1/2
+    Memory srcReg = baseMem.region((k1/2) << 3, (k1/2) << 3);
+    WritableMemory dstMem = genMem(2 * k1, true); //empty
+    srcReg.copyTo(0, dstMem, k1 << 3, (k1/2) << 3);
+    check(dstMem, k1, k1/2, (k1/2) + 1);
+  }
+
+  @Test
+  public void directROSrcRegion() throws Exception {
+    int k1 = 1 << 20; //longs
+    //gen baseMem of k1 longs w data, direct
+    Memory baseMem = genWmem(k1, false);
+    //gen src region of k1/2 longs, off= k1/2
+    Memory srcReg = baseMem.region((k1/2) << 3, (k1/2) << 3);
+
+    WritableMemory dstMem = genMem(2 * k1, true); //empty
+    srcReg.copyTo(0, dstMem, k1 << 3, (k1/2) << 3);
+    check(dstMem, k1, k1/2, (k1/2) + 1);
+    baseMem.close();
+  }
+
+  @Test
+  public void testOverlappingCopyLeftToRight() {
+    byte[] bytes = new byte[(((1 << 20) * 5) / 2) + 1];
+    ThreadLocalRandom.current().nextBytes(bytes);
+    byte[] referenceBytes = bytes.clone();
+    Memory referenceMem = Memory.wrap(referenceBytes);
+    WritableMemory mem = WritableMemory.writableWrap(bytes);
+    long copyLen = (1 << 20) * 2;
+    mem.copyTo(0, mem, (1 << 20) / 2, copyLen);
+    Assert.assertEquals(0, mem.compareTo((1 << 20) / 2, copyLen, referenceMem, 0, copyLen));
+  }
+
+  @Test
+  public void testOverlappingCopyRightToLeft() {
+    byte[] bytes = new byte[(((1 << 20) * 5) / 2) + 1];
+    ThreadLocalRandom.current().nextBytes(bytes);
+    byte[] referenceBytes = bytes.clone();
+    Memory referenceMem = Memory.wrap(referenceBytes);
+    WritableMemory mem = WritableMemory.writableWrap(bytes);
+    long copyLen = (1 << 20) * 2;
+    mem.copyTo((1 << 20) / 2, mem, 0, copyLen);
+    Assert.assertEquals(0, mem.compareTo(0, copyLen, referenceMem, (1 << 20) / 2, copyLen));
+  }
+
+  private static void check(Memory mem, int offsetLongs, int lengthLongs, int startValue) {
+    int offBytes = offsetLongs << 3;
+    for (long i = 0; i < lengthLongs; i++) {
+      assertEquals(mem.getLong(offBytes + (i << 3)), i + startValue);
+    }
+  }
+
+  @SuppressWarnings("resource")
+  private static WritableMemory genWmem(int longs, boolean empty) {
+    WritableMemory wmem = WritableMemory.allocateDirect(longs << 3, ResourceScope.newConfinedScope(), memReqSvr);
+    if (empty) {
+      wmem.clear();
+    } else {
+      for (int i = 0; i < longs; i++) { wmem.putLong(i << 3, i + 1); }
+    }
+    return wmem;
+  }
+
+  private static WritableMemory genMem(int longs, boolean empty) {
+    WritableMemory mem = WritableMemory.allocate(longs << 3);
+    if (!empty) {
+      for (int i = 0; i < longs; i++) { mem.putLong(i << 3, i + 1); }
+    }
+    return mem;
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void println(String s) {
+    //System.out.println(s); //disable here
+  }
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/DruidIssue11544Test.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/DruidIssue11544Test.java
new file mode 100644
index 0000000..a9fce8a
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/DruidIssue11544Test.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+/**
+ * The original design provided the MemoryRequestServer callback only for Memory segments allocated via
+ * <i>WritableMemory.allocateDirect(...)</i> calls.  Memory segments allocated via
+ * <i>WritableMemory.wrap(ByteBuffer)</i> did not have this capability.  This was a major oversight since
+ * all off-heap memory in Druid is allocated using ByteBuffers!  It is unusual that no one has
+ * uncovered this until August 2021.  Nonetheless, the fix involves instrumenting all the paths involved
+ * in providing this callback mechanism for wrapped ByteBuffers.
+ *
+ * This issues was first identified in Druid Issue #11544 and then posted as DataSketches-java Issue #358.
+ * But the actual source of the problem was in Memory.
+ *
+ * This test mimics the Druid issue but at a much smaller scale.
+ *
+ * @author Lee Rhodes
+ *
+ */
+public class DruidIssue11544Test {
+  private static final MemoryRequestServer memReqSvr = BaseState.defaultMemReqSvr;
+
+  @Test
+  public void withByteBuffer() {
+    int initialLongs = 1000;
+    int size1 = initialLongs * 8;
+
+    //Start with a ByteBuffer
+    ByteBuffer bb = ByteBuffer.allocateDirect(size1);
+    bb.order(ByteOrder.nativeOrder());
+
+    //Wrap bb into WritableMemory
+    WritableMemory mem1 = WritableMemory.writableWrap(bb);
+    assertTrue(mem1.isDirect()); //confirm mem1 is off-heap
+
+    //Request Bigger Memory
+    int size2 = size1 * 2;
+    WritableMemory mem2 = memReqSvr.request(mem1, size2);
+
+    //Confirm that mem2 is on the heap (the default) and 2X size1
+    assertFalse(mem2.isDirect());
+    assertEquals(mem2.getCapacity(), size2);
+
+    //Move data to new memory
+    mem1.copyTo(0, mem2, 0, size1);
+
+    //Prepare to request deallocation
+    //In the DefaultMemoryRequestServer, this is a no-op, so nothing is actually deallocated.
+    memReqSvr.requestClose(mem1, mem2);
+    assertTrue(mem1.isAlive());
+    assertTrue(mem2.isAlive());
+
+    //Now we are on the heap and need to grow again:
+    int size3 = size2 * 2;
+    WritableMemory mem3 = memReqSvr.request(mem2, size3);
+
+    //Confirm that mem3 is still on the heap and 2X of size2
+    assertFalse(mem3.isDirect());
+    assertEquals(mem3.getCapacity(), size3);
+
+    //Move data to new memory
+    mem2.copyTo(0, mem3, 0, size2);
+
+    //Prepare to request deallocation
+
+    memReqSvr.requestClose(mem2, mem3); //No-op
+    assertTrue(mem2.isAlive());
+    assertTrue(mem3.isAlive());
+  }
+
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/ExampleMemoryRequestServerTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/ExampleMemoryRequestServerTest.java
new file mode 100644
index 0000000..eacc079
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/ExampleMemoryRequestServerTest.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+/**
+ * Examples of how to use the MemoryRequestServer with a memory hungry client.
+ * @author Lee Rhodes
+ */
+public class ExampleMemoryRequestServerTest {
+
+  /**
+   * This version is without a TWR block. All of the memory allocations are done through the MemoryRequestServer
+   * and each is closed by the MemoryClient when it is done with each.
+   * @throws Exception
+   */
+  @SuppressWarnings("resource")
+  @Test
+  public void checkExampleMemoryRequestServer1() throws Exception {
+    int bytes = 8;
+    ExampleMemoryRequestServer svr = new ExampleMemoryRequestServer(true);
+    WritableMemory memStart = null;
+    ResourceScope scope = ResourceScope.newConfinedScope();
+    memStart = WritableMemory.allocateDirect(bytes, 8, scope, ByteOrder.nativeOrder(), svr);
+    MemoryClient client = new MemoryClient(memStart);
+    client.process();
+  }
+
+  /**
+   * This little client is never happy with how much memory it has been allocated and keeps
+   * requesting for more. When it does ask for more, it must copy its old data into the new
+   * memory, release the prior memory, and then continue working from there.
+   *
+   * <p>In reality, these memory requests should be quite rare.</p>
+   */
+  static class MemoryClient {
+    WritableMemory smallMem;
+    MemoryRequestServer svr;
+
+    MemoryClient(WritableMemory memStart) {
+      smallMem = memStart;
+      svr = memStart.getMemoryRequestServer();
+    }
+
+    void process() {
+      long cap1 = smallMem.getCapacity();
+      smallMem.fill((byte) 1);                //fill it, but not big enough
+      println(smallMem.toHexString("Small", 0, (int)cap1, true));
+
+      WritableMemory bigMem = svr.request(smallMem, 2 * cap1); //get bigger mem
+      long cap2 = bigMem.getCapacity();
+      smallMem.copyTo(0, bigMem, 0, cap1);    //copy data from small to big
+      svr.requestClose(smallMem, bigMem);     //done with smallMem, release it, if offheap
+
+      bigMem.fill(cap1, cap1, (byte) 2);      //fill the rest of bigMem, still not big enough
+      println(bigMem.toHexString("Big", 0, (int)cap2, true));
+
+      WritableMemory giantMem = svr.request(bigMem, 2 * cap2); //get giant mem
+      long cap3 = giantMem.getCapacity();
+      bigMem.copyTo(0, giantMem, 0, cap2);    //copy data from small to big
+      svr.requestClose(bigMem, giantMem);     //done with bigMem, release it, if offheap
+
+      giantMem.fill(cap2, cap2, (byte) 3);    //fill the rest of giantMem
+      println(giantMem.toHexString("Giant", 0, (int)cap3, true));
+      svr.requestClose(giantMem, null);       //done with giantMem, release it
+    }
+  }
+
+  /**
+   * This example MemoryRequestServer is simplistic but demonstrates one of many ways to
+   * possibly manage the continuous requests for larger memory.
+   */
+  public static class ExampleMemoryRequestServer implements MemoryRequestServer {
+    final boolean offHeap;
+
+    public ExampleMemoryRequestServer(final boolean offHeap) {
+      this.offHeap = offHeap;
+    }
+
+    @SuppressWarnings("resource")
+    @Override
+    public WritableMemory request(WritableMemory currentWMem, long newCapacityBytes) {
+     ByteOrder order = currentWMem.getByteOrder();
+     WritableMemory wmem;
+     if (offHeap) {
+       wmem = WritableMemory.allocateDirect(newCapacityBytes, 8, ResourceScope.newConfinedScope(), order, this);
+     } else {
+       if (newCapacityBytes > Integer.MAX_VALUE) {
+         throw new IllegalArgumentException("Requested capacity exceeds Integer.MAX_VALUE.");
+       }
+       wmem = WritableMemory.allocate((int)newCapacityBytes, order, this);
+     }
+     return wmem;
+    }
+
+    @Override
+    //here we actually release it, in reality it might be a lot more complex.
+    public void requestClose(WritableMemory memToRelease, WritableMemory newMemory) {
+      memToRelease.close();
+    }
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  /**
+   * @param o value to print
+   */
+  static void println(Object o) {
+    //System.out.println(o); //disable here
+  }
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/IgnoredArrayOverflowTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/IgnoredArrayOverflowTest.java
new file mode 100644
index 0000000..c9d3b4b
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/IgnoredArrayOverflowTest.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+public class IgnoredArrayOverflowTest {
+  private static final MemoryRequestServer memReqSvr = BaseState.defaultMemReqSvr;
+
+  private WritableMemory memory;
+  private static final long MAX_SIZE = (1L << 10); // use 1L << 31 to test int overrange
+
+  @SuppressWarnings("resource")
+  @BeforeClass
+  public void allocate() {
+    ResourceScope scope = ResourceScope.newConfinedScope();
+    memory = WritableMemory.allocateDirect(MAX_SIZE, 8L, scope, ByteOrder.nativeOrder(), memReqSvr);
+  }
+
+  @AfterClass
+  public void close() throws Exception {
+    memory.close();
+  }
+
+  @Test
+  public void testCharArray() {
+    int size = (int) (memory.getCapacity() / 2);
+    char[] array = new char[size];
+    memory.getCharArray(0, array, 0, size);
+    memory.asBuffer().getCharArray(array, 0, size);
+    memory.putCharArray(0, array, 0, size);
+    memory.asWritableBuffer().putCharArray(array, 0, size);
+  }
+
+  @Test
+  public void testShortArray() {
+    int size = (int) (memory.getCapacity() / 2);
+    short[] array = new short[size];
+    memory.getShortArray(0, array, 0, size);
+    memory.asBuffer().getShortArray(array, 0, size);
+    memory.putShortArray(0, array, 0, size);
+    memory.asWritableBuffer().putShortArray(array, 0, size);
+  }
+
+  @Test
+  public void testIntArray() {
+    int size = (int) (memory.getCapacity() / 4);
+    int[] array = new int[size];
+    memory.getIntArray(0, array, 0, size);
+    memory.asBuffer().getIntArray(array, 0, size);
+    memory.putIntArray(0, array, 0, size);
+    memory.asWritableBuffer().putIntArray(array, 0, size);
+  }
+
+  @Test
+  public void testFloatArray() {
+    int size = (int) (memory.getCapacity() / 4);
+    float[] array = new float[size];
+    memory.getFloatArray(0, array, 0, size);
+    memory.asBuffer().getFloatArray(array, 0, size);
+    memory.putFloatArray(0, array, 0, size);
+    memory.asWritableBuffer().putFloatArray(array, 0, size);
+  }
+
+  @Test
+  public void testLongArray() {
+    int size = (int) (memory.getCapacity() / 8);
+    long[] array = new long[size];
+    memory.getLongArray(0, array, 0, size);
+    memory.asBuffer().getLongArray(array, 0, size);
+    memory.putLongArray(0, array, 0, size);
+    memory.asWritableBuffer().putLongArray(array, 0, size);
+  }
+
+  @Test
+  public void testDoubleArray() {
+    int size = (int) (memory.getCapacity() / 8);
+    double[] array = new double[size];
+    memory.getDoubleArray(0, array, 0, size);
+    memory.asBuffer().getDoubleArray(array, 0, size);
+    memory.putDoubleArray(0, array, 0, size);
+    memory.asWritableBuffer().putDoubleArray(array, 0, size);
+  }
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/LeafImplTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/LeafImplTest.java
new file mode 100644
index 0000000..a56410a
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/LeafImplTest.java
@@ -0,0 +1,259 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableBuffer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+/**
+ * @author Lee Rhodes
+ */
+public class LeafImplTest {
+  private static final ByteOrder NBO = ByteOrder.nativeOrder();
+  private static final ByteOrder NNBO = BaseState.NON_NATIVE_BYTE_ORDER;
+  private static final MemoryRequestServer dummyMemReqSvr = new DummyMemoryRequestServer();
+
+  static class DummyMemoryRequestServer implements MemoryRequestServer {
+    @Override
+    public WritableMemory request(WritableMemory currentWMem, long capacityBytes) { return null; }
+    @Override
+    public void requestClose(WritableMemory memToClose, WritableMemory newMemory) { }
+  }
+
+  public static ByteOrder otherByteOrder(final ByteOrder order) {
+    return (order == ByteOrder.nativeOrder()) ? NNBO : ByteOrder.nativeOrder();
+  }
+
+  @Test
+  public void checkDirectLeafs() throws Exception {
+    long off = 0;
+    long cap = 128;
+    // Off Heap, Native order, No ByteBuffer, has MemReqSvr
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory memNO = WritableMemory.allocateDirect(cap, 8, scope, NBO, dummyMemReqSvr);
+      memNO.putShort(0, (short) 1);
+      assertTrue(memNO.isDirect());
+      checkCombinations(memNO, off, cap, memNO.isDirect(), NBO, false, true);
+    }
+    // Off Heap, Non Native order, No ByteBuffer, has MemReqSvr
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory memNNO = WritableMemory.allocateDirect(cap, 8, scope, NNBO, dummyMemReqSvr);
+      memNNO.putShort(0, (short) 1);
+      assertTrue(memNNO.isDirect());
+      checkCombinations(memNNO, off, cap, memNNO.isDirect(), NNBO, false, true);
+    }
+  }
+
+  @Test
+  public void checkByteBufferLeafs() {
+    long off = 0;
+    long cap = 128;
+    //BB on heap, native order, has ByteBuffer, has MemReqSvr
+    ByteBuffer bb = ByteBuffer.allocate((int)cap);
+    bb.order(NBO);
+    bb.putShort(0, (short) 1);
+    WritableMemory mem = WritableMemory.writableWrap(bb, NBO, dummyMemReqSvr);
+    assertEquals(bb.isDirect(), mem.isDirect());
+
+    checkCombinations(mem, off, cap, mem.isDirect(), mem.getByteOrder(), true, false);
+
+    //BB off heap, native order, has ByteBuffer, has MemReqSvr
+    ByteBuffer dbb = ByteBuffer.allocateDirect((int)cap);
+    dbb.order(NBO);
+    dbb.putShort(0, (short) 1);
+    mem = WritableMemory.writableWrap(dbb, NBO, dummyMemReqSvr);
+    assertEquals(dbb.isDirect(), mem.isDirect());
+
+    checkCombinations(mem, off, cap,  mem.isDirect(), mem.getByteOrder(), true, false);
+
+    //BB on heap, non native order, has ByteBuffer, has MemReqSvr
+    bb = ByteBuffer.allocate((int)cap);
+    bb.order(NNBO);
+    bb.putShort(0, (short) 1);
+    mem = WritableMemory.writableWrap(bb, NNBO, dummyMemReqSvr);
+    assertEquals(bb.isDirect(), mem.isDirect());
+
+    checkCombinations(mem, off, cap, mem.isDirect(), mem.getByteOrder(), true, false);
+
+    //BB off heap, non native order, has ByteBuffer, has MemReqSvr
+    dbb = ByteBuffer.allocateDirect((int)cap);
+    dbb.order(NNBO);
+    dbb.putShort(0, (short) 1);
+    mem = WritableMemory.writableWrap(dbb, NNBO, dummyMemReqSvr);
+    assertEquals(dbb.isDirect(), mem.isDirect());
+
+    checkCombinations(mem, off, cap,  mem.isDirect(), mem.getByteOrder(), true, false);
+  }
+
+  @Test
+  public void checkMapLeafs() throws IOException {
+    long off = 0;
+    long cap = 128;
+    File file = new File("TestFile2.bin");
+    if (file.exists()) {
+      java.nio.file.Files.delete(file.toPath());
+    }
+    assertTrue(file.createNewFile());
+    assertTrue(file.setWritable(true, false)); //writable=true, ownerOnly=false
+    assertTrue(file.isFile());
+    file.deleteOnExit();  //comment out if you want to examine the file.
+    // Off Heap, Native order, No ByteBuffer, No MemReqSvr
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory memNO = WritableMemory.writableMap(file, off, cap, scope, NBO);
+      memNO.putShort(0, (short) 1);
+      assertTrue(memNO.isDirect());
+      checkCombinations(memNO, off, cap, memNO.isDirect(), NBO, false, false);
+    }
+    // Off heap, Non Native order, No ByteBuffer, no MemReqSvr
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory memNNO = WritableMemory.writableMap(file, off, cap, scope, NNBO);
+      memNNO.putShort(0, (short) 1);
+      assertTrue(memNNO.isDirect());
+      checkCombinations(memNNO, off, cap, memNNO.isDirect(), NNBO, false, false);
+    }
+  }
+
+  @Test
+  public void checkHeapLeafs() {
+    long off = 0;
+    long cap = 128;
+    // On Heap, Native order, No ByteBuffer, MemReqSvr
+    WritableMemory memNO = WritableMemory.allocate((int)cap, NBO, dummyMemReqSvr); //assumes NBO
+    memNO.putShort(0, (short) 1);
+    assertFalse(memNO.isDirect());
+    checkCombinations(memNO, off, cap, memNO.isDirect(), NBO, false, true);
+
+    // On Heap, Non-native order, No ByteBuffer, MemReqSvr
+    WritableMemory memNNO = WritableMemory.allocate((int)cap, NNBO, dummyMemReqSvr);
+    memNNO.putShort(0, (short) 1);
+    assertFalse(memNNO.isDirect());
+    checkCombinations(memNNO, off, cap, memNNO.isDirect(), NNBO, false, true);
+  }
+
+  private static void checkCombinations(WritableMemory mem, long off, long cap,
+      boolean direct, ByteOrder bo, boolean fromByteBuffer, boolean hasMemReqSvr) {
+    ByteOrder oo = otherByteOrder(bo);
+
+    //### Start with given mem
+    assertEquals(mem.writableRegion(off, cap, bo).getShort(0), 1);
+    assertEquals(mem.writableRegion(off, cap, oo).getShort(0), 256);
+    assertEquals(mem.asWritableBuffer(bo).getShort(0), 1);
+    assertEquals(mem.asWritableBuffer(oo).getShort(0), 256);
+    assertTrue(mem.getByteOrder() == bo);
+
+    if (fromByteBuffer) { assertTrue(mem.hasByteBuffer()); }
+    else { assertFalse(mem.hasByteBuffer()); }
+
+    if (hasMemReqSvr) {
+      assertTrue(mem.hasMemoryRequestServer());
+      assertTrue(mem.getMemoryRequestServer() instanceof DummyMemoryRequestServer);
+    }
+
+    if (direct) {
+      assertTrue(mem.isDirect());
+    } else {
+      assertFalse(mem.isDirect());
+    }
+    assertTrue(mem.isAlive() == true);
+
+    //### Convert to writable buffer
+    WritableBuffer buf = mem.asWritableBuffer();
+
+    assertEquals(buf.writableRegion(off, cap, bo).getShort(0), 1);
+    assertEquals(buf.writableRegion(off, cap, oo).getShort(0), 256);
+    assertEquals(buf.writableDuplicate(bo).getShort(0), 1);
+    assertEquals(buf.writableDuplicate(oo).getShort(0), 256);
+    assertTrue(buf.getByteOrder() == bo);
+
+    if (fromByteBuffer) { assertTrue(buf.hasByteBuffer()); }
+
+    if (hasMemReqSvr) {
+      assertTrue(buf.hasMemoryRequestServer());
+      assertTrue(buf.getMemoryRequestServer() instanceof DummyMemoryRequestServer);
+    }
+
+    if (direct) {
+      assertTrue(buf.isDirect());
+    } else {
+      assertFalse(buf.isDirect());
+    }
+    assertTrue(buf.isAlive() == true);
+
+    //### Convert to non native writable Region
+    WritableMemory nnMem = mem.writableRegion(off, cap, oo);
+
+    assertEquals(nnMem.writableRegion(off, cap, bo).getShort(0), 1);
+    assertEquals(nnMem.writableRegion(off, cap, oo).getShort(0), 256);
+    assertEquals(nnMem.asWritableBuffer(bo).getShort(0), 1);
+    assertEquals(nnMem.asWritableBuffer(oo).getShort(0), 256);
+
+    assertTrue(nnMem.getByteOrder() == oo);
+
+    if (fromByteBuffer) { assertTrue(nnMem.hasByteBuffer()); }
+
+    if (hasMemReqSvr) {
+      assertTrue(nnMem.hasMemoryRequestServer());
+      assertTrue(nnMem.getMemoryRequestServer() instanceof DummyMemoryRequestServer);
+    }
+
+    if (direct) {
+      assertTrue(nnMem.isDirect());
+    } else {
+      assertFalse(nnMem.isDirect());
+    }
+    assertTrue(nnMem.isAlive() == true);
+
+    //### Convert to non native buffer
+    WritableBuffer nnBuf = mem.asWritableBuffer(oo);
+
+    assertEquals(nnBuf.writableRegion(off, cap, bo).getShort(0), 1);
+    assertEquals(nnBuf.writableRegion(off, cap, oo).getShort(0), 256);
+    assertEquals(nnBuf.writableDuplicate(bo).getShort(0), 1);
+    assertEquals(nnBuf.writableDuplicate(oo).getShort(0), 256);
+
+    assertTrue(nnBuf.getByteOrder() == oo);
+
+    if (fromByteBuffer) { assertTrue(nnBuf.hasByteBuffer()); }
+
+    if (hasMemReqSvr) { assertTrue(nnBuf.getMemoryRequestServer() instanceof DummyMemoryRequestServer); }
+
+    if (direct) {
+      assertTrue(nnBuf.isDirect());
+    } else {
+      assertFalse(nnBuf.isDirect());
+    }
+    assertTrue(nnBuf.isAlive() == true);
+  }
+
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/MemoryBoundaryCheckTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/MemoryBoundaryCheckTest.java
new file mode 100644
index 0000000..46b69d8
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/MemoryBoundaryCheckTest.java
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.testng.Assert.fail;
+
+import org.apache.datasketches.memory.WritableBuffer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+public class MemoryBoundaryCheckTest {
+
+  private final WritableBuffer writableBuffer = WritableMemory.allocate(8).asWritableBuffer();
+
+  @Test
+  public void testGetByte() {
+    writableBuffer.getByte(7);
+    try {
+      writableBuffer.getByte(8);
+      fail();
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutByte() {
+    writableBuffer.putByte(7, (byte) 1);
+    try {
+      writableBuffer.putByte(8, (byte) 1);
+      fail();
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetChar() {
+    writableBuffer.getChar(6);
+    try {
+      writableBuffer.getChar(7);
+      fail();
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutChar() {
+    writableBuffer.putChar(6, 'a');
+    try {
+      writableBuffer.putChar(7, 'a');
+      fail();
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetShort() {
+    writableBuffer.getShort(6);
+    try {
+      writableBuffer.getShort(7);
+      fail();
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutShort() {
+    writableBuffer.putShort(6, (short) 1);
+    try {
+      writableBuffer.putShort(7, (short) 1);
+      fail();
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetInt() {
+    writableBuffer.getInt(4);
+    try {
+      writableBuffer.getInt(5);
+      fail();
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutInt() {
+    writableBuffer.putInt(4, 1);
+    try {
+      writableBuffer.putInt(5, 1);
+      fail();
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetFloat() {
+    writableBuffer.getFloat(4);
+    try {
+      writableBuffer.getFloat(5);
+      fail();
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutFloat() {
+    writableBuffer.putFloat(4, 1f);
+    try {
+      writableBuffer.putFloat(5, 1f);
+      fail();
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetLong() {
+    writableBuffer.getLong(0);
+    try {
+      writableBuffer.getLong(1);
+      fail();
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutLong() {
+    writableBuffer.putLong(0, 1L);
+    try {
+      writableBuffer.putLong(1, 1L);
+      fail();
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetDouble() {
+    writableBuffer.getDouble(0);
+    try {
+      writableBuffer.getDouble(1);
+      fail();
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutDouble() {
+    writableBuffer.putDouble(0, 1d);
+    try {
+      writableBuffer.putDouble(1, 1d);
+      fail();
+    } catch (final IndexOutOfBoundsException expected) {
+      // ignore
+    }
+  }
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/MemoryReadWriteSafetyTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/MemoryReadWriteSafetyTest.java
new file mode 100644
index 0000000..0b3b8fb
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/MemoryReadWriteSafetyTest.java
@@ -0,0 +1,216 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+public class MemoryReadWriteSafetyTest {
+
+  // Test various operations with read-only Memory
+
+  final WritableMemory mem = (WritableMemory) Memory.wrap(new byte[8]);
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutByte() {
+    mem.putByte(0, (byte) 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutShort() {
+    mem.putShort(0, (short) 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutChar() {
+    mem.putChar(0, (char) 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutInt() {
+    mem.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutLong() {
+    mem.putLong(0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutFloat() {
+    mem.putFloat(0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutDouble() {
+    mem.putDouble(0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutByteArray() {
+    mem.putByteArray(0, new byte[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutShortArray() {
+    mem.putShortArray(0, new short[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutCharArray() {
+    mem.putCharArray(0, new char[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutIntArray() {
+    mem.putIntArray(0, new int[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutLongArray() {
+    mem.putLongArray(0, new long[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testPutFloatArray() {
+    mem.putFloatArray(0, new float[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testDoubleByteArray() {
+    mem.putDoubleArray(0, new double[] {1}, 0, 1);
+  }
+
+  // Now, test that various ways to obtain a read-only memory produce a read-only memory indeed
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testWritableMemoryRegion() {
+    WritableMemory mem1 = (WritableMemory) WritableMemory.allocate(8).region(0, 8);
+    mem1.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testByteArrayWrap() {
+    WritableMemory mem1 = (WritableMemory) Memory.wrap(new byte[8]);
+    mem1.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testByteArrayWrapWithBO() {
+    WritableMemory mem1 = (WritableMemory) Memory.wrap(new byte[8], ByteOrder.nativeOrder());
+    mem1.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testByteArrayWrapWithOffsetsAndBO() {
+    WritableMemory mem1 = (WritableMemory) Memory.wrap(new byte[8], 0, 4, ByteOrder.nativeOrder());
+    mem1.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testShortArrayWrap() {
+    WritableMemory mem1 = (WritableMemory) Memory.wrap(new short[8]);
+    mem1.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testCharArrayWrap() {
+    WritableMemory mem1 = (WritableMemory) Memory.wrap(new char[8]);
+    mem1.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testIntArrayWrap() {
+    WritableMemory mem1 = (WritableMemory) Memory.wrap(new int[8]);
+    mem1.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testLongArrayWrap() {
+    WritableMemory mem1 = (WritableMemory) Memory.wrap(new long[8]);
+    mem1.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testFloatArrayWrap() {
+    WritableMemory mem1 = (WritableMemory) Memory.wrap(new float[8]);
+    mem1.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testDoubleArrayWrap() {
+    WritableMemory mem1 = (WritableMemory) Memory.wrap(new double[8]);
+    mem1.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testByteBufferWrap() {
+    WritableMemory mem1 = (WritableMemory) Memory.wrap(ByteBuffer.allocate(8));
+    mem1.putInt(0, 1);
+  }
+
+  //@SuppressWarnings("resource")
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testMapFile() throws Exception {
+    File tempFile = File.createTempFile("test", null);
+    tempFile.deleteOnExit();
+    try (RandomAccessFile raf = new RandomAccessFile(tempFile, "rw")) {
+      raf.setLength(8);
+      //System.out.println(UtilTest.getFileAttributes(tempFile));
+      try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+        Memory mem = Memory.map(tempFile, scope);
+        ((WritableMemory) mem).putInt(0, 1);
+      }
+    }
+  }
+
+  @SuppressWarnings("resource")
+  @Test(expectedExceptions = UnsupportedOperationException.class)
+  public void testMapFileWithOffsetsAndBO() throws Exception {
+    File tempFile = File.createTempFile("test", "test");
+    tempFile.deleteOnExit();
+    new RandomAccessFile(tempFile, "rw").setLength(8);
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      Memory mem = Memory.map(tempFile, 0, 4, scope, ByteOrder.nativeOrder());
+      ((WritableMemory) mem).putInt(0, 1);
+    }
+  }
+
+  @Test(expectedExceptions = IOException.class)
+  public void testMapFileBeyondTheFileSize() throws Exception {
+    File tempFile = File.createTempFile("test", "test");
+    tempFile.deleteOnExit();
+    try (RandomAccessFile raf = new RandomAccessFile(tempFile, "rw")) {
+      raf.setLength(8);
+      try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+        Memory.map(tempFile, 0, 16, scope, ByteOrder.nativeOrder());
+      }
+    }
+  }
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/MemoryTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/MemoryTest.java
new file mode 100644
index 0000000..bc0796c
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/MemoryTest.java
@@ -0,0 +1,461 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * Note: Lincoln's Gettysburg Address is in the public domain. See LICENSE.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.List;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableBuffer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import org.testng.collections.Lists;
+
+import jdk.incubator.foreign.ResourceScope;
+
+public class MemoryTest {
+  private static final String LS = System.getProperty("line.separator");
+  private static final MemoryRequestServer memReqSvr = BaseState.defaultMemReqSvr;
+
+
+  @BeforeClass
+  public void setReadOnly() throws IOException {
+    UtilTest.setGettysburgAddressFileToReadOnly();
+  }
+
+  @Test
+  public void checkDirectRoundTrip() throws Exception {
+    int n = 1024; //longs
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(n * 8, scope, memReqSvr);
+      for (int i = 0; i < n; i++) {
+        mem.putLong(i * 8, i);
+      }
+      for (int i = 0; i < n; i++) {
+        long v = mem.getLong(i * 8);
+        assertEquals(v, i);
+      }
+    }
+  }
+
+  @Test
+  public void checkAutoHeapRoundTrip() {
+    int n = 1024; //longs
+    WritableMemory wmem = WritableMemory.allocate(n * 8);
+    for (int i = 0; i < n; i++) {
+      wmem.putLong(i * 8, i);
+    }
+    for (int i = 0; i < n; i++) {
+      long v = wmem.getLong(i * 8);
+      assertEquals(v, i);
+    }
+  }
+
+  @Test
+  public void checkArrayWrap() {
+    int n = 1024; //longs
+    byte[] arr = new byte[n * 8];
+    WritableMemory wmem = WritableMemory.writableWrap(arr);
+    for (int i = 0; i < n; i++) {
+      wmem.putLong(i * 8, i);
+    }
+    for (int i = 0; i < n; i++) {
+      long v = wmem.getLong(i * 8);
+      assertEquals(v, i);
+    }
+    Memory mem = Memory.wrap(arr, ByteOrder.nativeOrder());
+    for (int i = 0; i < n; i++) {
+      long v = mem.getLong(i * 8);
+      assertEquals(v, i);
+    }
+    // check 0 length array wraps
+    Memory memZeroLengthArrayByte = WritableMemory.writableWrap(new byte[0]);
+    Memory memZeroLengthArrayChar = WritableMemory.writableWrap(new char[0]);
+    Memory memZeroLengthArrayShort = WritableMemory.writableWrap(new short[0]);
+    Memory memZeroLengthArrayInt = WritableMemory.writableWrap(new int[0]);
+    Memory memZeroLengthArrayLong = WritableMemory.writableWrap(new long[0]);
+    Memory memZeroLengthArrayFloat = WritableMemory.writableWrap(new float[0]);
+    Memory memZeroLengthArrayDouble = WritableMemory.writableWrap(new double[0]);
+    assertEquals(memZeroLengthArrayByte.getCapacity(), 0);
+    assertEquals(memZeroLengthArrayChar.getCapacity(), 0);
+    assertEquals(memZeroLengthArrayShort.getCapacity(), 0);
+    assertEquals(memZeroLengthArrayInt.getCapacity(), 0);
+    assertEquals(memZeroLengthArrayLong.getCapacity(), 0);
+    assertEquals(memZeroLengthArrayFloat.getCapacity(), 0);
+    assertEquals(memZeroLengthArrayDouble.getCapacity(), 0);
+
+    // check 0 length array wraps
+    List<Memory> memoryToCheck = Lists.newArrayList();
+    memoryToCheck.add(WritableMemory.allocate(0));
+    memoryToCheck.add(WritableMemory.writableWrap(ByteBuffer.allocate(0)));
+    memoryToCheck.add(WritableMemory.writableWrap(new byte[0]));
+    memoryToCheck.add(WritableMemory.writableWrap(new char[0]));
+    memoryToCheck.add(WritableMemory.writableWrap(new short[0]));
+    memoryToCheck.add(WritableMemory.writableWrap(new int[0]));
+    memoryToCheck.add(WritableMemory.writableWrap(new long[0]));
+    memoryToCheck.add(WritableMemory.writableWrap(new float[0]));
+    memoryToCheck.add(WritableMemory.writableWrap(new double[0]));
+    memoryToCheck.add(Memory.wrap(ByteBuffer.allocate(0)));
+    memoryToCheck.add(Memory.wrap(new byte[0]));
+    memoryToCheck.add(Memory.wrap(new char[0]));
+    memoryToCheck.add(Memory.wrap(new short[0]));
+    memoryToCheck.add(Memory.wrap(new int[0]));
+    memoryToCheck.add(Memory.wrap(new long[0]));
+    memoryToCheck.add(Memory.wrap(new float[0]));
+    memoryToCheck.add(Memory.wrap(new double[0]));
+    //Check the Memory lengths
+    for (Memory memory : memoryToCheck) {
+      assertEquals(memory.getCapacity(), 0);
+    }
+  }
+
+  @Test
+  public void checkByteBufHeap() {
+    int n = 1024; //longs
+    byte[] arr = new byte[n * 8];
+    ByteBuffer bb = ByteBuffer.wrap(arr);
+    bb.order(ByteOrder.nativeOrder());
+    WritableMemory wmem = WritableMemory.writableWrap(bb);
+    for (int i = 0; i < n; i++) { //write to wmem
+      wmem.putLong(i * 8, i);
+    }
+    for (int i = 0; i < n; i++) { //read from wmem
+      long v = wmem.getLong(i * 8);
+      assertEquals(v, i);
+    }
+    for (int i = 0; i < n; i++) { //read from BB
+      long v = bb.getLong(i * 8);
+      assertEquals(v, i);
+    }
+    Memory mem1 = Memory.wrap(arr);
+    for (int i = 0; i < n; i++) { //read from wrapped arr
+      long v = mem1.getLong(i * 8);
+      assertEquals(v, i);
+    }
+    //convert to RO
+    Memory mem = wmem;
+    for (int i = 0; i < n; i++) {
+      long v = mem.getLong(i * 8);
+      assertEquals(v, i);
+    }
+  }
+
+  @Test
+  public void checkByteBufferNonNativeHeap() {
+    int n = 10; //longs
+    byte[] arr = new byte[n * 8];
+    ByteBuffer bb = ByteBuffer.wrap(arr); //non-native order
+    WritableMemory wmem = WritableMemory.writableWrap(bb, BaseState.NON_NATIVE_BYTE_ORDER, memReqSvr);
+    for (int i = 0; i < n; i++) { //write to wmem
+      wmem.putLong(i * 8, i);
+    }
+    for (int i = 0; i < n; i++) { //read from wmem
+      long v = wmem.getLong(i * 8);
+      assertEquals(v, i);
+    }
+    for (int i = 0; i < n; i++) { //read from BB
+      long v = bb.getLong(i * 8);
+      assertEquals(v, i);
+    }
+    Memory mem1 = Memory.wrap(arr, BaseState.NON_NATIVE_BYTE_ORDER);
+    for (int i = 0; i < n; i++) { //read from wrapped arr
+      long v = mem1.getLong(i * 8);
+      assertEquals(v, i);
+    }
+    //convert to RO
+    Memory mem = wmem;
+    for (int i = 0; i < n; i++) {
+      long v = mem.getLong(i * 8);
+      assertEquals(v, i);
+    }
+  }
+
+  @Test
+  public void checkByteBufDirect() {
+    int n = 1024; //longs
+    ByteBuffer bb = ByteBuffer.allocateDirect(n * 8);
+    bb.order(ByteOrder.nativeOrder());
+    WritableMemory wmem = WritableMemory.writableWrap(bb);
+    for (int i = 0; i < n; i++) { //write to wmem
+      wmem.putLong(i * 8, i);
+    }
+    for (int i = 0; i < n; i++) { //read from wmem
+      long v = wmem.getLong(i * 8);
+      assertEquals(v, i);
+    }
+    for (int i = 0; i < n; i++) { //read from BB
+      long v = bb.getLong(i * 8);
+      assertEquals(v, i);
+    }
+    Memory mem1 = Memory.wrap(bb);
+    for (int i = 0; i < n; i++) { //read from wrapped bb RO
+      long v = mem1.getLong(i * 8);
+      assertEquals(v, i);
+    }
+    //convert to RO
+    Memory mem = wmem;
+    for (int i = 0; i < n; i++) {
+      long v = mem.getLong(i * 8);
+      assertEquals(v, i);
+    }
+  }
+
+  @Test
+  public void checkByteBufOrderIgnored() {
+    int n = 1024; //longs
+    ByteBuffer bb = ByteBuffer.allocate(n * 8);
+    bb.order(ByteOrder.BIG_ENDIAN); //ignored
+    Memory mem = Memory.wrap(bb); //Defaults to LE
+    assertTrue(mem.getByteOrder() == ByteOrder.nativeOrder());
+    assertEquals(mem.getByteOrder(), ByteOrder.LITTLE_ENDIAN);
+    //Now explicitly set it
+    mem = Memory.wrap(bb, BaseState.NON_NATIVE_BYTE_ORDER);
+    assertFalse(mem.getByteOrder() == ByteOrder.nativeOrder());
+    assertEquals(mem.getByteOrder(), ByteOrder.BIG_ENDIAN);
+  }
+
+  @Test
+  public void checkReadOnlyHeapByteBuffer() {
+    ByteBuffer bb = ByteBuffer.allocate(128);
+    bb.order(ByteOrder.nativeOrder());
+    for (int i = 0; i < 128; i++) { bb.put(i, (byte)i); }
+    bb.position(64);
+    ByteBuffer slice = bb.slice().asReadOnlyBuffer();
+    slice.order(ByteOrder.nativeOrder());
+    Memory mem = Memory.wrap(slice);
+    for (int i = 0; i < 64; i++) {
+      assertEquals(mem.getByte(i), 64 + i);
+    }
+    mem.toHexString("slice", 0, slice.capacity(), true);
+    //println(s);
+  }
+
+  @Test
+  public void checkPutGetArraysHeap() {
+    int n = 1024; //longs
+    long[] arr = new long[n];
+    for (int i = 0; i < n; i++) { arr[i] = i; }
+    WritableMemory wmem = WritableMemory.allocate(n * 8);
+    wmem.putLongArray(0, arr, 0, n);
+    long[] arr2 = new long[n];
+    wmem.getLongArray(0, arr2, 0, n);
+    for (int i = 0; i < n; i++) {
+      assertEquals(arr2[i], i);
+    }
+  }
+
+  @Test
+  public void checkRORegions() {
+    int n = 16;
+    int n2 = n / 2;
+    long[] arr = new long[n];
+    for (int i = 0; i < n; i++) { arr[i] = i; }
+    Memory mem = Memory.wrap(arr);
+    Memory reg = mem.region(n2 * 8, n2 * 8); //top half
+    for (int i = 0; i < n2; i++) {
+      long v = reg.getLong(i * 8);
+      long e = i + n2;
+      assertEquals(v, e);
+    }
+  }
+
+  @Test
+  public void checkRORegionsReverseBO() {
+    int n = 16;
+    int n2 = n / 2;
+    long[] arr = new long[n];
+    for (int i = 0; i < n; i++) { arr[i] = i; }
+    Memory mem = Memory.wrap(arr);
+    Memory reg = mem.region(n2 * 8, n2 * 8, BaseState.NON_NATIVE_BYTE_ORDER); //top half
+    for (int i = 0; i < n2; i++) {
+      long v = Long.reverseBytes(reg.getLong(i * 8));
+      long e = i + n2;
+      assertEquals(v, e);
+    }
+  }
+
+  @Test
+  public void checkWRegions() {
+    int n = 16;
+    int n2 = n / 2;
+    long[] arr = new long[n];
+    for (int i = 0; i < n; i++) { arr[i] = i; }
+    WritableMemory wmem = WritableMemory.writableWrap(arr);
+    for (int i = 0; i < n; i++) {
+      assertEquals(wmem.getLong(i * 8), i);
+      //println("" + wmem.getLong(i * 8));
+    }
+    //println("");
+    WritableMemory reg = wmem.writableRegion(n2 * 8, n2 * 8);
+    for (int i = 0; i < n2; i++) { reg.putLong(i * 8, i); }
+    for (int i = 0; i < n; i++) {
+      assertEquals(wmem.getLong(i * 8), i % 8);
+      //println("" + wmem.getLong(i * 8));
+    }
+  }
+
+  @Test
+  public void checkWRegionsReverseBO() {
+    int n = 16;
+    int n2 = n / 2;
+    long[] arr = new long[n];
+    for (int i = 0; i < n; i++) { arr[i] = i; }
+    WritableMemory wmem = WritableMemory.writableWrap(arr);
+    for (int i = 0; i < n; i++) {
+      assertEquals(wmem.getLong(i * 8), i);
+      //println("" + wmem.getLong(i * 8));
+    }
+    //println("");
+    WritableMemory reg = wmem.writableRegion(n2 * 8, n2 * 8, BaseState.NON_NATIVE_BYTE_ORDER);
+    for (int i = 0; i < n2; i++) { reg.putLong(i * 8, i); }
+    for (int i = 0; i < n; i++) {
+      long v = wmem.getLong(i * 8);
+      if (i < n2) {
+        assertEquals(v, i % 8);
+      } else {
+        assertEquals(Long.reverseBytes(v), i % 8);
+      }
+      //println("" + wmem.getLong(i * 8));
+    }
+  }
+
+  @SuppressWarnings("resource")
+  @Test(expectedExceptions = IllegalStateException.class)
+  public void checkParentUseAfterFree() throws Exception {
+    int bytes = 64 * 8;
+    ResourceScope scope = ResourceScope.newConfinedScope();
+    WritableMemory wmem = WritableMemory.allocateDirect(bytes, scope, memReqSvr);
+    wmem.close();
+    //with -ea assert: Memory not valid.
+    //with -da sometimes segfaults, sometimes passes!
+    wmem.getLong(0);
+  }
+
+  @SuppressWarnings("resource")
+  @Test(expectedExceptions = IllegalStateException.class)
+  public void checkRegionUseAfterFree() throws Exception {
+    int bytes = 64;
+    ResourceScope scope = ResourceScope.newConfinedScope();
+    WritableMemory wmem = WritableMemory.allocateDirect(bytes, scope, memReqSvr);
+    Memory region = wmem.region(0L, bytes);
+    wmem.close();
+    //with -ea assert: Memory not valid.
+    //with -da sometimes segfaults, sometimes passes!
+    region.getByte(0);
+  }
+
+  @Test
+  public void checkMemReqSvr() throws Exception {
+    WritableMemory wmem;
+    WritableBuffer wbuf;
+
+    //ON HEAP
+    wmem = WritableMemory.writableWrap(new byte[16]);
+    assertNull(wmem.getMemoryRequestServer());
+    wbuf = wmem.asWritableBuffer();
+    assertNull(wbuf.getMemoryRequestServer());
+    //OFF HEAP
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+       wmem = WritableMemory.allocateDirect(16, scope, memReqSvr);  //OFF HEAP
+      assertNotNull(wmem.getMemoryRequestServer());
+      wbuf = wmem.asWritableBuffer();
+      assertNotNull(wbuf.getMemoryRequestServer());
+    }
+    //ByteBuffer
+    ByteBuffer bb = ByteBuffer.allocate(16);
+    wmem = WritableMemory.writableWrap(bb);
+    assertNull(wmem.getMemoryRequestServer());
+    wbuf = wmem.asWritableBuffer();
+    assertNull(wbuf.getMemoryRequestServer());
+
+    //ON HEAP
+    wmem = WritableMemory.writableWrap(new byte[16], 0, 16, BaseState.NATIVE_BYTE_ORDER, memReqSvr);
+    assertNotNull(wmem.getMemoryRequestServer());
+    wbuf = wmem.asWritableBuffer();
+    assertNotNull(wbuf.getMemoryRequestServer());
+    //OFF HEAP
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory wmem2 = WritableMemory.allocateDirect(16, scope, memReqSvr);
+      assertNotNull(wmem2.getMemoryRequestServer());
+      wbuf = wmem.asWritableBuffer();
+      assertNotNull(wbuf.getMemoryRequestServer());
+    }
+    //ByteBuffer
+    bb = ByteBuffer.allocate(16);
+    wmem = WritableMemory.writableWrap(bb);
+    assertNull(wmem.getMemoryRequestServer());
+    wbuf = wmem.asWritableBuffer();
+    assertNull(wbuf.getMemoryRequestServer());
+  }
+
+  @Test
+  public void checkSelfEqualsToAndCompareTo() {
+    int len = 64;
+    WritableMemory wmem = WritableMemory.allocate(len);
+    for (int i = 0; i < len; i++) { wmem.putByte(i, (byte) i); }
+    assertTrue(wmem.equalTo(0, wmem, 0, len));
+    assertFalse(wmem.equalTo(0, wmem, len/2, len/2));
+    assertEquals(wmem.compareTo(0, len, wmem, 0, len), 0);
+    assertTrue(wmem.compareTo(0, 0, wmem, len/2, len/2) < 0);
+  }
+
+  @Test
+  public void wrapBigEndianAsLittle() {
+    ByteBuffer bb = ByteBuffer.allocate(64);
+    bb.putChar(0, (char)1); //as NNO
+    Memory mem = Memory.wrap(bb, ByteOrder.LITTLE_ENDIAN);
+    assertEquals(mem.getChar(0), 256);
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  static void println(final Object o) {
+    if (o == null) { print(LS); }
+    else { print(o.toString() + LS); }
+  }
+
+  /**
+   * @param o value to print
+   */
+  static void print(final Object o) {
+    if (o != null) {
+      //System.out.print(o.toString()); //disable here
+    }
+  }
+
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/MemoryWriteToTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/MemoryWriteToTest.java
new file mode 100644
index 0000000..f995154
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/MemoryWriteToTest.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.concurrent.ThreadLocalRandom;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+public class MemoryWriteToTest {
+  private static final MemoryRequestServer memReqSvr = BaseState.defaultMemReqSvr;
+
+  @Test
+  public void testOnHeapBytes() throws IOException {
+    testWriteTo(createRandomBytesMemory(0));
+    testWriteTo(createRandomBytesMemory(7));
+    testWriteTo(createRandomBytesMemory(1023));
+    testWriteTo(createRandomBytesMemory(10_000));
+    testWriteTo(createRandomBytesMemory((1 << 20) * 5));
+    testWriteTo(createRandomBytesMemory(((1 << 20) * 5) + 10));
+  }
+
+  @Test
+  public void testOnHeapInts() throws IOException {
+    testWriteTo(createRandomIntsMemory(0));
+    testWriteTo(createRandomIntsMemory(7));
+    testWriteTo(createRandomIntsMemory(1023));
+    testWriteTo(createRandomIntsMemory(10_000));
+    testWriteTo(createRandomIntsMemory((1 << 20) * 5));
+    testWriteTo(createRandomIntsMemory(((1 << 20) * 5) + 10));
+  }
+
+  @Test
+  public void testOffHeap() throws Exception {
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(((1 << 20) * 5) + 10, scope, memReqSvr);
+      testWriteTo(mem.region(0, 0));
+      testOffHeap(mem, 7);
+      testOffHeap(mem, 1023);
+      testOffHeap(mem, 10_000);
+      testOffHeap(mem, (1 << 20) * 5);
+      testOffHeap(mem, ((1 << 20) * 5) + 10);
+    }
+  }
+
+  private static void testOffHeap(WritableMemory mem, int size) throws IOException {
+    createRandomBytesMemory(size).copyTo(0, mem, 0, size);
+    testWriteTo(mem.region(0, size));
+  }
+
+  private static Memory createRandomBytesMemory(int size) {
+    byte[] bytes = new byte[size];
+    ThreadLocalRandom.current().nextBytes(bytes);
+    return Memory.wrap(bytes);
+  }
+
+  private static Memory createRandomIntsMemory(int size) {
+    int[] ints = ThreadLocalRandom.current().ints(size).toArray();
+    return Memory.wrap(ints);
+  }
+
+  private static void testWriteTo(Memory mem) throws IOException {
+    int cap = (int)mem.getCapacity();
+    ByteArrayOutputStream baos = new ByteArrayOutputStream(cap);
+    mem.writeToByteStream(0, cap, baos);
+    byte[] result = baos.toByteArray();
+    assertTrue(mem.equalTo(0, Memory.wrap(result), 0, cap));
+    //OR
+    byte[] barr = new byte[cap];
+    mem.getByteArray(0, barr, 0, cap);
+    assertEquals(barr, result);
+  }
+
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/MurmurHash3v3Test.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/MurmurHash3v3Test.java
new file mode 100644
index 0000000..3d4ce07
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/MurmurHash3v3Test.java
@@ -0,0 +1,421 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.apache.datasketches.memory.MurmurHash3.*;
+import static org.testng.Assert.fail;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.MemorySegment;
+import jdk.incubator.foreign.ResourceScope;
+
+/**
+ * Tests the MurmurHash3 against specific, known hash results given known
+ * inputs obtained from the public domain C++ version 150.
+ *
+ * @author Lee Rhodes
+ */
+public class MurmurHash3v3Test {
+  private static final MemoryRequestServer memReqSvr = BaseState.defaultMemReqSvr;
+
+  @Test
+  public void checkByteArrRemainderGT8() { //byte[], remainder > 8
+    String keyStr = "The quick brown fox jumps over the lazy dog";
+    byte[] key = keyStr.getBytes(UTF_8);
+    long[] result = hash(key, 0);
+    //Should be:
+    long h1 = 0xe34bbc7bbc071b6cL;
+    long h2 = 0x7a433ca9c49a9347L;
+    Assert.assertEquals(result[0], h1);
+    Assert.assertEquals(result[1], h2);
+  }
+
+  @Test
+  public void checkByteArrRemainderGT8withSegment() { //byte[], remainder > 8
+    String keyStr = "The quick brown fox jumps over the lazy dog";
+    byte[] key = keyStr.getBytes(UTF_8);
+    long[] out = new long[2];
+    MemorySegment seg = MemorySegment.ofArray(key);
+    long[] result = hash(seg, 0, seg.byteSize(), 0, out);
+    //Should be:
+    long h1 = 0xe34bbc7bbc071b6cL;
+    long h2 = 0x7a433ca9c49a9347L;
+    Assert.assertEquals(result[0], h1);
+    Assert.assertEquals(result[1], h2);
+  }
+
+  @Test
+  public void checkByteArrChange1bit() { //byte[], change one bit
+    String keyStr = "The quick brown fox jumps over the lazy eog";
+    byte[] key = keyStr.getBytes(UTF_8);
+    long[] result = hash(key, 0);
+    //Should be:
+    long h1 = 0x362108102c62d1c9L;
+    long h2 = 0x3285cd100292b305L;
+    Assert.assertEquals(result[0], h1);
+    Assert.assertEquals(result[1], h2);
+  }
+
+  @Test
+  public void checkByteArrRemainderLt8() { //byte[], test a remainder < 8
+    String keyStr = "The quick brown fox jumps over the lazy dogdogdog";
+    byte[] key = keyStr.getBytes(UTF_8);
+    long[] result = hash(key, 0);
+    //Should be;
+    long h1 = 0x9c8205300e612fc4L;
+    long h2 = 0xcbc0af6136aa3df9L;
+    Assert.assertEquals(result[0], h1);
+    Assert.assertEquals(result[1], h2);
+  }
+
+  @Test
+  public void checkByteArrReaminderEQ8() { //byte[], test a remainder = 8
+    String keyStr = "The quick brown fox jumps over the lazy1";
+    byte[] key = keyStr.getBytes(UTF_8);
+    long[] result = hash(key, 0);
+    //Should be:
+    long h1 = 0xe3301a827e5cdfe3L;
+    long h2 = 0xbdbf05f8da0f0392L;
+    Assert.assertEquals(result[0], h1);
+    Assert.assertEquals(result[1], h2);
+
+  }
+
+  /**
+   * This test should have the exact same output as Test4
+   */
+  @Test
+  public void checkLongArrRemainderEQ8() { //long[], test a remainder = 8
+    String keyStr = "The quick brown fox jumps over the lazy1";
+    long[] key = stringToLongs(keyStr);
+    long[] result = hash(key, 0);
+    //Should be:
+    long h1 = 0xe3301a827e5cdfe3L;
+    long h2 = 0xbdbf05f8da0f0392L;
+    Assert.assertEquals(result[0], h1);
+    Assert.assertEquals(result[1], h2);
+
+  }
+
+  /**
+   * This test should have the exact same output as Test4
+   */
+  @Test
+  public void checkIntArrRemainderEQ8() { //int[], test a remainder = 8
+    String keyStr = "The quick brown fox jumps over the lazy1"; //40B
+    int[] key = stringToInts(keyStr);
+    long[] result = hash(key, 0);
+    //Should be:
+    long h1 = 0xe3301a827e5cdfe3L;
+    long h2 = 0xbdbf05f8da0f0392L;
+    Assert.assertEquals(result[0], h1);
+    Assert.assertEquals(result[1], h2);
+  }
+
+  @Test
+  public void checkIntArrRemainderEQ0() { //int[], test a remainder = 0
+    String keyStr = "The quick brown fox jumps over t"; //32B
+    int[] key = stringToInts(keyStr);
+    long[] result = hash(key, 0);
+    //Should be:
+    long h1 = 0xdf6af91bb29bdacfL;
+    long h2 = 0x91a341c58df1f3a6L;
+    Assert.assertEquals(result[0], h1);
+    Assert.assertEquals(result[1], h2);
+  }
+
+
+  /**
+   * Tests an odd remainder of int[].
+   */
+  @Test
+  public void checkIntArrOddRemainder() { //int[], odd remainder
+    String keyStr = "The quick brown fox jumps over the lazy dog"; //43B
+    int[] key = stringToInts(keyStr);
+    long[] result = hash(key, 0);
+    //Should be:
+    long h1 = 0x1eb232b0087543f5L;
+    long h2 = 0xfc4c1383c3ace40fL;
+    Assert.assertEquals(result[0], h1);
+    Assert.assertEquals(result[1], h2);
+  }
+
+
+  /**
+   * Tests an odd remainder of int[].
+   */
+  @Test
+  public void checkCharArrOddRemainder() { //char[], odd remainder
+    String keyStr = "The quick brown fox jumps over the lazy dog.."; //45B
+    char[] key = keyStr.toCharArray();
+    long[] result = hash(key, 0);
+    //Should be:
+    long h1 = 0xca77b498ea9ed953L;
+    long h2 = 0x8b8f8ec3a8f4657eL;
+    Assert.assertEquals(result[0], h1);
+    Assert.assertEquals(result[1], h2);
+  }
+
+  /**
+   * Tests an odd remainder of int[].
+   */
+  @Test
+  public void checkCharArrRemainderEQ0() { //char[], remainder of 0
+    String keyStr = "The quick brown fox jumps over the lazy "; //40B
+    char[] key = keyStr.toCharArray();
+    long[] result = hash(key, 0);
+    //Should be:
+    long h1 = 0x51b15e9d0887f9f1L;
+    long h2 = 0x8106d226786511ebL;
+    Assert.assertEquals(result[0], h1);
+    Assert.assertEquals(result[1], h2);
+  }
+
+  @Test
+  public void checkByteArrAllOnesZeros() { //byte[], test a ones byte and a zeros byte
+    byte[] key = {
+      0x54, 0x68, 0x65, 0x20, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x20, 0x62, 0x72, 0x6f, 0x77, 0x6e,
+      0x20, 0x66, 0x6f, 0x78, 0x20, 0x6a, 0x75, 0x6d, 0x70, 0x73, 0x20, 0x6f, 0x76, 0x65,
+      0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x61, 0x7a, 0x79, 0x20, 0x64, 0x6f, 0x67,
+      (byte) 0xff, 0x64, 0x6f, 0x67, 0x00
+    };
+    long[] result = MurmurHash3v3.hash(key, 0);
+
+    //Should be:
+    long h1 = 0xe88abda785929c9eL;
+    long h2 = 0x96b98587cacc83d6L;
+    Assert.assertEquals(result[0], h1);
+    Assert.assertEquals(result[1], h2);
+  }
+
+  /**
+   * This test demonstrates that the hash of byte[], char[], int[], or long[] will produce the
+   * same hash result if, and only if, all the arrays have the same exact length in bytes, and if
+   * the contents of the values in the arrays have the same byte endianness and overall order.
+   */
+  @Test
+  public void checkCrossTypeHashConsistency() {
+    long[] out;
+    println("Bytes");
+    byte[] bArr = {1,2,3,4,5,6,7,8,   9,10,11,12,13,14,15,16,  17,18,19,20,21,22,23,24};
+    long[] out1 = hash(bArr, 0L);
+    println(longToHexBytes(out1[0]));
+    println(longToHexBytes(out1[1]));
+
+    println("Chars");
+    char[] cArr = {0X0201, 0X0403, 0X0605, 0X0807,   0X0a09, 0X0c0b, 0X0e0d, 0X100f,
+        0X1211, 0X1413, 0X1615, 0X1817};
+    out = hash(cArr, 0L);
+    Assert.assertEquals(out, out1);
+    println(longToHexBytes(out[0]));
+    println(longToHexBytes(out[1]));
+
+    println("Ints");
+    int[] iArr = {0X04030201, 0X08070605,   0X0c0b0a09, 0X100f0e0d,   0X14131211,   0X18171615};
+    out = hash(iArr, 0L);
+    Assert.assertEquals(out, out1);
+    println(longToHexBytes(out[0]));
+    println(longToHexBytes(out[1]));
+
+    println("Longs");
+    long[] lArr = {0X0807060504030201L, 0X100f0e0d0c0b0a09L, 0X1817161514131211L};
+    out = hash(lArr, 0L);
+    Assert.assertEquals(out, out1);
+    println(longToHexBytes(out[0]));
+    println(longToHexBytes(out[1]));
+  }
+
+  @Test
+  public void checkEmptyOrNullExceptions() {
+    try {
+      long[] arr = null;
+      hash(arr, 1L);
+      fail();
+    } catch (final IllegalArgumentException e) { }
+    try {
+      int[] arr = null; hash(arr, 1L); fail();
+    } catch (final IllegalArgumentException e) { }
+    try {
+      char[] arr = null; hash(arr, 1L); fail();
+    } catch (final IllegalArgumentException e) { }
+    try {
+      byte[] arr = null; hash(arr, 1L); fail();
+    } catch (final IllegalArgumentException e) { }
+    try {
+      long[] out = new long[2];
+      String in = null; hash(in, 1L, out); fail();
+    } catch (final IllegalArgumentException e) { }
+    try {
+      long[] out = new long[2];
+      Memory mem = Memory.wrap(new byte[0]);
+      out = hash(mem, 0L, 4L, 1L, out);
+    } catch (final IllegalArgumentException e) { }
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      Memory mem = WritableMemory.allocateDirect(8, scope, memReqSvr);
+      long[] out = new long[2];
+      out = hash(mem, 0L, 4L, 1L, out);
+    } catch (Exception ee) {}
+  }
+
+  @Test
+  public void checkHashTails() {
+    long[] out = new long[2];
+    WritableMemory mem = WritableMemory.allocate(32);
+    mem.fill((byte)85);
+
+    for (int i = 16; i <= 32; i++) {
+      out = hash(mem, 0, i, 1L, out);
+    }
+  }
+
+  @Test
+  public void checkSinglePrimitives() {
+    long[] out = new long[2];
+    out = hash(1L, 1L, out);
+    out = hash(0.0, 1L, out);
+    out = hash("123", 1L, out);
+  }
+
+  //Helper methods
+
+  private static long[] stringToLongs(String in) {
+    byte[] bArr = in.getBytes(UTF_8);
+    int inLen = bArr.length;
+    int outLen = (inLen / 8) + (((inLen % 8) != 0) ? 1 : 0);
+    long[] out = new long[outLen];
+
+    for (int i = 0; i < (outLen - 1); i++ ) {
+      for (int j = 0; j < 8; j++ ) {
+        out[i] |= ((bArr[(i * 8) + j] & 0xFFL) << (j * 8));
+      }
+    }
+    int inTail = 8 * (outLen - 1);
+    int rem = inLen - inTail;
+    for (int j = 0; j < rem; j++ ) {
+      out[outLen - 1] |= ((bArr[inTail + j] & 0xFFL) << (j * 8));
+    }
+    return out;
+  }
+
+  private static int[] stringToInts(String in) {
+    byte[] bArr = in.getBytes(UTF_8);
+    int inLen = bArr.length;
+    int outLen = (inLen / 4) + (((inLen % 4) != 0) ? 1 : 0);
+    int[] out = new int[outLen];
+
+    for (int i = 0; i < (outLen - 1); i++ ) {
+      for (int j = 0; j < 4; j++ ) {
+        out[i] |= ((bArr[(i * 4) + j] & 0xFFL) << (j * 8));
+      }
+    }
+    int inTail = 4 * (outLen - 1);
+    int rem = inLen - inTail;
+    for (int j = 0; j < rem; j++ ) {
+      out[outLen - 1] |= ((bArr[inTail + j] & 0xFFL) << (j * 8));
+    }
+    return out;
+  }
+
+  /**
+   * Returns a string of spaced hex bytes in Big-Endian order.
+   * @param v the given long
+   * @return string of spaced hex bytes in Big-Endian order.
+   */
+  private static String longToHexBytes(final long v) {
+    final long mask = 0XFFL;
+    final StringBuilder sb = new StringBuilder();
+    for (int i = 8; i-- > 0; ) {
+      final String s = Long.toHexString((v >>> (i * 8)) & mask);
+      sb.append(zeroPad(s, 2)).append(" ");
+    }
+    return sb.toString();
+  }
+
+  /**
+   * 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.
+   */
+  private 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 padCharacters to the end of the string.
+   * @return prepended or postpended given string with the given character to fill the given field
+   * length.
+   */
+  private 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);
+    }
+    return s;
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void println(String s) {
+    //System.out.println(s); //disable here
+  }
+
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/NativeWritableBufferImplTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/NativeWritableBufferImplTest.java
new file mode 100644
index 0000000..31957de
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/NativeWritableBufferImplTest.java
@@ -0,0 +1,559 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.Buffer;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableBuffer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+public class NativeWritableBufferImplTest {
+  private static final MemoryRequestServer memReqSvr = BaseState.defaultMemReqSvr;
+
+  //Simple Native direct
+
+  @SuppressWarnings("resource")
+  @Test
+  public void checkNativeCapacityAndClose() throws Exception {
+    int memCapacity = 64;
+    ResourceScope scope = ResourceScope.newConfinedScope();
+    WritableMemory wmem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+    WritableBuffer wbuf = wmem.asWritableBuffer();
+    assertEquals(wbuf.getCapacity(), memCapacity);
+
+    wmem.close(); //intentional
+    assertFalse(wbuf.isAlive());
+    wmem.close(); //intentional, nothing to free
+  }
+
+  //Simple Heap arrays
+
+  @Test
+  public void checkByteArray() {
+    byte[] srcArray = { 1, -2, 3, -4, 5, -6, 7, -8 };
+    byte[] dstArray = new byte[8];
+
+    Buffer buf = Memory.wrap(srcArray).asBuffer();
+    buf.getByteArray(dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+
+    WritableBuffer wbuf = WritableMemory.writableWrap(srcArray).asWritableBuffer();
+    wbuf.getByteArray(dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+  }
+
+  @Test
+  public void checkCharArray() {
+    char[] srcArray = { 1, 2, 3, 4, 5, 6, 7, 8 };
+    char[] dstArray = new char[8];
+
+    Buffer buf = Memory.wrap(srcArray).asBuffer();
+    buf.getCharArray(dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+
+    WritableBuffer wbuf = WritableMemory.writableWrap(srcArray).asWritableBuffer();
+    wbuf.getCharArray(dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+  }
+
+  @Test
+  public void checkShortArray() {
+    short[] srcArray = { 1, -2, 3, -4, 5, -6, 7, -8 };
+    short[] dstArray = new short[8];
+
+    Buffer buf = Memory.wrap(srcArray).asBuffer();
+    buf.getShortArray(dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+
+    WritableBuffer wbuf = WritableMemory.writableWrap(srcArray).asWritableBuffer();
+    wbuf.getShortArray(dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+  }
+
+  @Test
+  public void checkIntArray() {
+    int[] srcArray = { 1, -2, 3, -4, 5, -6, 7, -8 };
+    int[] dstArray = new int[8];
+
+    Buffer buf = Memory.wrap(srcArray).asBuffer();
+    buf.getIntArray(dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+
+    WritableBuffer wbuf = WritableMemory.writableWrap(srcArray).asWritableBuffer();
+    wbuf.getIntArray(dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+  }
+
+  @Test
+  public void checkLongArray() {
+    long[] srcArray = { 1, -2, 3, -4, 5, -6, 7, -8 };
+    long[] dstArray = new long[8];
+
+    Buffer buf = Memory.wrap(srcArray).asBuffer();
+    buf.getLongArray(dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+
+    WritableBuffer wbuf = WritableMemory.writableWrap(srcArray).asWritableBuffer();
+    wbuf.getLongArray(dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+  }
+
+  @Test
+  public void checkFloatArray() {
+    float[] srcArray = { 1, -2, 3, -4, 5, -6, 7, -8 };
+    float[] dstArray = new float[8];
+
+    Buffer buf = Memory.wrap(srcArray).asBuffer();
+    buf.getFloatArray(dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+
+    WritableBuffer wbuf = WritableMemory.writableWrap(srcArray).asWritableBuffer();
+    wbuf.getFloatArray(dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+  }
+
+  @Test
+  public void checkDoubleArray() {
+    double[] srcArray = { 1, -2, 3, -4, 5, -6, 7, -8 };
+    double[] dstArray = new double[8];
+
+    Buffer buf = Memory.wrap(srcArray).asBuffer();
+    buf.getDoubleArray(dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+
+    WritableBuffer wbuf = WritableMemory.writableWrap(srcArray).asWritableBuffer();
+    wbuf.getDoubleArray(dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+  }
+
+  @Test
+  public void checkNativeBaseBound() throws Exception {
+    int memCapacity = 64;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory wmem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      WritableBuffer wbuf = wmem.asWritableBuffer();
+      wbuf.toHexString("Force Assertion Error", memCapacity, 8, false);
+    } catch (IllegalArgumentException e) {
+      //ok
+    }
+  }
+
+  @Test
+  public void checkNativeSrcArrayBound() throws Exception {
+    long memCapacity = 64;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory wmem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      WritableBuffer wbuf = wmem.asWritableBuffer();
+      byte[] srcArray = { 1, -2, 3, -4 };
+      wbuf.putByteArray(srcArray, 0, 5); //wrong!
+    } catch (IndexOutOfBoundsException e) {
+      //pass
+    }
+  }
+
+  @Test(expectedExceptions = IndexOutOfBoundsException.class)
+  public void checkRegionBounds() throws Exception {
+    int memCapacity = 64;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory wmem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      WritableBuffer wbuf = wmem.asWritableBuffer();
+      wbuf.writableRegion(1, 64, wbuf.getByteOrder()); //wrong!
+    }
+  }
+
+  @Test
+  public void checkByteBufferWrap() {
+    int memCapacity = 64;
+    ByteBuffer byteBuf = ByteBuffer.allocate(memCapacity);
+    byteBuf.order(ByteOrder.nativeOrder());
+
+    for (int i=0; i<memCapacity; i++) {
+      byteBuf.put(i, (byte) i);
+    }
+
+    WritableBuffer wbuf = WritableBuffer.writableWrap(byteBuf);
+
+    for (int i=0; i<memCapacity; i++) {
+      assertEquals(wbuf.getByte(), byteBuf.get(i));
+    }
+
+    assertTrue(wbuf.hasByteBuffer());
+    ByteBuffer byteBuf2 = wbuf.toByteBuffer(ByteOrder.nativeOrder());
+    assertEquals(byteBuf2, byteBuf);
+    //println( mem.toHexString("HeapBB", 0, memCapacity));
+  }
+
+  @Test
+  public void checkWrapWithBBReadonly1() {
+    int memCapacity = 64;
+    ByteBuffer byteBuf = ByteBuffer.allocate(memCapacity);
+    byteBuf.order(ByteOrder.nativeOrder());
+
+    for (int i = 0; i < memCapacity; i++) {
+      byteBuf.put(i, (byte) i);
+    }
+
+    Buffer buf = WritableBuffer.writableWrap(byteBuf);
+
+    for (int i = 0; i < memCapacity; i++) {
+      assertEquals(buf.getByte(), byteBuf.get(i));
+    }
+
+    //println(mem.toHexString("HeapBB", 0, memCapacity));
+  }
+
+  @Test(expectedExceptions = IllegalArgumentException.class)
+  public void checkWrapWithBBReadonly2() {
+    int memCapacity = 64;
+    ByteBuffer byteBuf = ByteBuffer.allocate(memCapacity);
+    byteBuf.order(ByteOrder.nativeOrder());
+    ByteBuffer byteBufRO = byteBuf.asReadOnlyBuffer();
+    byteBufRO.order(ByteOrder.nativeOrder());
+    assertTrue(true);
+    WritableBuffer wbuf = WritableBuffer.writableWrap(byteBufRO);
+    assertTrue(wbuf.isReadOnly());
+  }
+
+  @Test
+  public void checkWrapWithDirectBBReadonly() {
+    int memCapacity = 64;
+    ByteBuffer byteBuf = ByteBuffer.allocateDirect(memCapacity);
+    byteBuf.order(ByteOrder.nativeOrder());
+
+    for (int i = 0; i < memCapacity; i++) {
+      byteBuf.put(i, (byte) i);
+    }
+    ByteBuffer byteBufRO = byteBuf.asReadOnlyBuffer();
+    byteBufRO.order(ByteOrder.nativeOrder());
+
+    Buffer buf = Buffer.wrap(byteBufRO);
+
+    for (int i = 0; i < memCapacity; i++) {
+      assertEquals(buf.getByte(), byteBuf.get(i));
+    }
+
+    //println(mem.toHexString("HeapBB", 0, memCapacity));
+  }
+
+  @Test(expectedExceptions = IllegalArgumentException.class)
+  public void checkWrapWithDirectBBReadonlyPut() {
+    int memCapacity = 64;
+    ByteBuffer byteBuf = ByteBuffer.allocateDirect(memCapacity);
+    ByteBuffer byteBufRO = byteBuf.asReadOnlyBuffer();
+    byteBufRO.order(ByteOrder.nativeOrder());
+
+    WritableBuffer.writableWrap(byteBufRO);
+  }
+
+  @Test
+  public void checkByteBufferWrapDirectAccess() {
+    int memCapacity = 64;
+    ByteBuffer byteBuf = ByteBuffer.allocateDirect(memCapacity);
+    byteBuf.order(ByteOrder.nativeOrder());
+
+    for (int i=0; i<memCapacity; i++) {
+      byteBuf.put(i, (byte) i);
+    }
+
+    Buffer buf = Buffer.wrap(byteBuf);
+
+    for (int i=0; i<memCapacity; i++) {
+      assertEquals(buf.getByte(), byteBuf.get(i));
+    }
+
+    //println( mem.toHexString("HeapBB", 0, memCapacity));
+  }
+
+  @SuppressWarnings("resource")
+  @Test
+  public void checkIsDirect() throws Exception {
+    int memCapacity = 64;
+    WritableBuffer mem = WritableMemory.allocate(memCapacity).asWritableBuffer();
+    assertFalse(mem.isDirect());
+    ResourceScope scope = ResourceScope.newConfinedScope();
+    WritableMemory wmem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+    WritableBuffer wbuf = wmem.asWritableBuffer();
+    assertTrue(wbuf.isDirect());
+    wmem.close(); //immediate close
+  }
+
+  @Test
+  public void checkIsReadOnly() {
+    long[] srcArray = { 1, -2, 3, -4, 5, -6, 7, -8 };
+
+    WritableBuffer wbuf = WritableMemory.writableWrap(srcArray).asWritableBuffer();
+    assertFalse(wbuf.isReadOnly());
+
+    Buffer buf = wbuf;
+    assertFalse(buf.isReadOnly());
+
+    for (int i = 0; i < srcArray.length; i++) {
+      assertEquals(buf.getLong(), srcArray[i]);
+    }
+  }
+
+  @Test
+  public void checkGoodBounds() {
+   BaseStateImpl.checkBounds(50, 50, 100);
+  }
+
+  @Test
+  public void checkCompareToHeap() {
+    byte[] arr1 = new byte[] {0, 1, 2, 3};
+    byte[] arr2 = new byte[] {0, 1, 2, 4};
+    byte[] arr3 = new byte[] {0, 1, 2, 3, 4};
+
+    Buffer buf1 = Memory.wrap(arr1).asBuffer();
+    Buffer buf2 = Memory.wrap(arr2).asBuffer();
+    Buffer buf3 = Memory.wrap(arr3).asBuffer();
+
+    int comp = buf1.compareTo(0, 3, buf2, 0, 3);
+    assertEquals(comp, 0);
+    comp = buf1.compareTo(0, 4, buf2, 0, 4);
+    assertEquals(comp, -1);
+    comp = buf2.compareTo(0, 4, buf1, 0, 4);
+    assertEquals(comp, 1);
+    //different lengths
+    comp = buf1.compareTo(0, 4, buf3, 0, 5);
+    assertEquals(comp, -1);
+    comp = buf3.compareTo(0, 5, buf1, 0, 4);
+    assertEquals(comp, 1);
+  }
+
+  @Test
+  public void checkCompareToDirect() throws Exception {
+    byte[] arr1 = new byte[] {0, 1, 2, 3};
+    byte[] arr2 = new byte[] {0, 1, 2, 4};
+    byte[] arr3 = new byte[] {0, 1, 2, 3, 4};
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem1 = WritableMemory.allocateDirect(4, scope, memReqSvr);
+      WritableMemory mem2 = WritableMemory.allocateDirect(4, scope, memReqSvr);
+      WritableMemory mem3 = WritableMemory.allocateDirect(5, scope, memReqSvr);
+
+      mem1.putByteArray(0, arr1, 0, 4);
+      mem2.putByteArray(0, arr2, 0, 4);
+      mem3.putByteArray(0, arr3, 0, 5);
+
+      Buffer buf1 = mem1.asBuffer();
+      Buffer buf2 = mem2.asBuffer();
+      Buffer buf3 = mem3.asBuffer();
+
+      int comp = buf1.compareTo(0, 3, buf2, 0, 3);
+      assertEquals(comp, 0);
+      comp = buf1.compareTo(0, 4, buf2, 0, 4);
+      assertEquals(comp, -1);
+      comp = buf2.compareTo(0, 4, buf1, 0, 4);
+      assertEquals(comp, 1);
+      //different lengths
+      comp = buf1.compareTo(0, 4, buf3, 0, 5);
+      assertEquals(comp, -1);
+      comp = buf3.compareTo(0, 5, buf1, 0, 4);
+      assertEquals(comp, 1);
+    }
+  }
+
+  @Test
+  public void checkAsBuffer() {
+    WritableMemory wmem = WritableMemory.allocate(64);
+    WritableBuffer wbuf = wmem.asWritableBuffer();
+    wbuf.setPosition(32);
+    for (int i = 32; i < 64; i++) { wbuf.putByte((byte)i); }
+    //println(wbuf.toHexString("Buf", 0, (int)wbuf.getCapacity()));
+
+    Buffer buf = wmem.asBuffer();
+    buf.setPosition(32);
+    for (int i = 32; i < 64; i++) {
+      assertEquals(buf.getByte(), i);
+    }
+  }
+
+  @Test
+  public void checkDuplicate() {
+    WritableMemory wmem = WritableMemory.allocate(64);
+    for (int i = 0; i < 64; i++) { wmem.putByte(i, (byte)i); }
+
+    WritableBuffer wbuf = wmem.asWritableBuffer().writableDuplicate();
+
+    for (int i = 0; i < 64; i++) {
+      assertEquals(wbuf.getByte(), i);
+    }
+    Buffer buf = wmem.asBuffer().duplicate();
+    for (int i = 0; i < 64; i++) {
+      assertEquals(buf.getByte(), i);
+    }
+
+    WritableMemory wmem2 = wbuf.asWritableMemory();
+    for (int i = 0; i < 64; i++) {
+      assertEquals(wmem2.getByte(i), i);
+    }
+    wbuf.asWritableMemory();
+
+  }
+
+  @Test
+  public void checkDegenerateRegionReturn() {
+    Memory mem = Memory.wrap(new byte[0]);
+    Buffer buf = mem.asBuffer();
+    Buffer reg = buf.region();
+    assertEquals(reg.getCapacity(), 0);
+  }
+
+  @Test
+  public void checkAsWritableMemoryRO() {
+    ByteBuffer bb = ByteBuffer.allocate(64);
+    WritableBuffer wbuf = WritableBuffer.writableWrap(bb);
+    WritableMemory wmem = wbuf.asWritableMemory(); //OK
+    assertNotNull(wmem);
+
+    try {
+      Buffer buf = Buffer.wrap(bb.asReadOnlyBuffer());
+      wbuf = (WritableBuffer) buf;
+      wmem = wbuf.asWritableMemory();
+      Assert.fail();
+    } catch (IllegalArgumentException expected) {
+      // expected
+    }
+  }
+
+  @Test
+  public void checkWritableDuplicateRO() {
+    ByteBuffer bb = ByteBuffer.allocate(64);
+    WritableBuffer wbuf = WritableBuffer.writableWrap(bb);
+    @SuppressWarnings("unused")
+    WritableBuffer wdup = wbuf.writableDuplicate();
+
+    try {
+      Buffer buf = Buffer.wrap(bb);
+      wbuf = (WritableBuffer) buf;
+      @SuppressWarnings("unused")
+      WritableBuffer wdup2 = wbuf.writableDuplicate();
+      Assert.fail();
+    } catch (IllegalArgumentException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void checkWritableRegionRO() {
+    ByteBuffer bb = ByteBuffer.allocate(64);
+    WritableBuffer wbuf = WritableBuffer.writableWrap(bb);
+    @SuppressWarnings("unused")
+    WritableBuffer wreg = wbuf.writableRegion();
+
+    try {
+      Buffer buf = Buffer.wrap(bb);
+      wbuf = (WritableBuffer) buf;
+      @SuppressWarnings("unused")
+      WritableBuffer wreg2 = wbuf.writableRegion();
+      Assert.fail();
+    } catch (IllegalArgumentException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void checkWritableRegionWithParamsRO() {
+    ByteBuffer bb = ByteBuffer.allocate(64);
+    WritableBuffer wbuf = WritableBuffer.writableWrap(bb);
+    @SuppressWarnings("unused")
+    WritableBuffer wreg = wbuf.writableRegion(0, 1, wbuf.getByteOrder());
+
+    try {
+      Buffer buf = Buffer.wrap(bb);
+      wbuf = (WritableBuffer) buf;
+      @SuppressWarnings("unused")
+      WritableBuffer wreg2 = wbuf.writableRegion(0, 1, wbuf.getByteOrder());
+      Assert.fail();
+    } catch (IllegalArgumentException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void checkZeroBuffer() {
+    WritableMemory wmem = WritableMemory.allocate(8);
+    WritableBuffer wbuf = wmem.asWritableBuffer();
+    WritableBuffer reg = wbuf.writableRegion(0, 0, wbuf.getByteOrder());
+    assertEquals(reg.getCapacity(), 0);
+  }
+
+  @Test
+  public void checkDuplicateNonNative() {
+    WritableMemory wmem = WritableMemory.allocate(64);
+    wmem.putShort(0, (short) 1);
+    Buffer buf = wmem.asWritableBuffer().duplicate(BaseState.NON_NATIVE_BYTE_ORDER);
+    assertEquals(buf.getShort(0), 256);
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void println(String s) {
+    //System.out.println(s); //disable here
+  }
+
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/NativeWritableMemoryImplTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/NativeWritableMemoryImplTest.java
new file mode 100644
index 0000000..8e5e082
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/NativeWritableMemoryImplTest.java
@@ -0,0 +1,679 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.Buffer;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableBuffer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+public class NativeWritableMemoryImplTest {
+  private static final MemoryRequestServer memReqSvr = BaseState.defaultMemReqSvr;
+
+  //Simple Native direct
+
+  @SuppressWarnings("resource")
+  @Test
+  public void checkNativeCapacityAndClose() throws Exception {
+    int memCapacity = 64;
+    ResourceScope scope = ResourceScope.newConfinedScope();
+    WritableMemory wmem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+    assertEquals(memCapacity, wmem.getCapacity());
+
+    wmem.close(); //intentional
+    assertFalse(wmem.isAlive());
+
+    wmem.close(); //intentional, nothing to free
+  }
+
+  //Simple Native arrays
+
+  @Test
+  public void checkByteArray() {
+    byte[] srcArray = { 1, -2, 3, -4, 5, -6, 7, -8 };
+    byte[] dstArray = new byte[8];
+
+    Memory mem = Memory.wrap(srcArray);
+    mem.getByteArray(0, dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+
+    WritableMemory wmem = WritableMemory.writableWrap(srcArray);
+    wmem.getByteArray(0, dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+  }
+
+  @Test
+  public void checkCharArray() {
+    char[] srcArray = { 1, 2, 3, 4, 5, 6, 7, 8 };
+    char[] dstArray = new char[8];
+
+    Memory mem = Memory.wrap(srcArray);
+    mem.getCharArray(0, dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+
+    WritableMemory wmem = WritableMemory.writableWrap(srcArray);
+    wmem.getCharArray(0, dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+  }
+
+  @Test
+  public void checkShortArray() {
+    short[] srcArray = { 1, -2, 3, -4, 5, -6, 7, -8 };
+    short[] dstArray = new short[8];
+
+    Memory mem = Memory.wrap(srcArray);
+    mem.getShortArray(0, dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+
+    WritableMemory wmem = WritableMemory.writableWrap(srcArray);
+    wmem.getShortArray(0, dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+  }
+
+  @Test
+  public void checkIntArray() {
+    int[] srcArray = { 1, -2, 3, -4, 5, -6, 7, -8 };
+    int[] dstArray = new int[8];
+
+    Memory mem = Memory.wrap(srcArray);
+    mem.getIntArray(0, dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+
+    WritableMemory wmem = WritableMemory.writableWrap(srcArray);
+    wmem.getIntArray(0, dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+  }
+
+  @Test
+  public void checkLongArray() {
+    long[] srcArray = { 1, -2, 3, -4, 5, -6, 7, -8 };
+    long[] dstArray = new long[8];
+
+    Memory mem = Memory.wrap(srcArray);
+    mem.getLongArray(0, dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+
+    WritableMemory wmem = WritableMemory.writableWrap(srcArray);
+    wmem.getLongArray(0, dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+  }
+
+  @Test
+  public void checkFloatArray() {
+    float[] srcArray = { 1, -2, 3, -4, 5, -6, 7, -8 };
+    float[] dstArray = new float[8];
+
+    Memory mem = Memory.wrap(srcArray);
+    mem.getFloatArray(0, dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+
+    WritableMemory wmem = WritableMemory.writableWrap(srcArray);
+    wmem.getFloatArray(0, dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+  }
+
+  @Test
+  public void checkDoubleArray() {
+    double[] srcArray = { 1, -2, 3, -4, 5, -6, 7, -8 };
+    double[] dstArray = new double[8];
+
+    Memory mem = Memory.wrap(srcArray);
+    mem.getDoubleArray(0, dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+
+    WritableMemory wmem = WritableMemory.writableWrap(srcArray);
+    wmem.getDoubleArray(0, dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+  }
+
+  @Test
+  public void checkNativeBaseBound() throws Exception {
+    int memCapacity = 64;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory wmem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      wmem.toHexString("Force Assertion Error", memCapacity, 8, false);
+    } catch (IllegalArgumentException e) {
+      //ok
+    }
+  }
+
+  @Test
+  public void checkNativeSrcArrayBound() throws Exception {
+    long memCapacity = 64;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory wmem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      byte[] srcArray = { 1, -2, 3, -4 };
+      wmem.putByteArray(0L, srcArray, 0, 5);
+    } catch (IndexOutOfBoundsException e) {
+      //pass
+    }
+  }
+
+  //Copy Within tests
+
+  @Test
+  public void checkDegenerateCopyTo() {
+    WritableMemory wmem = WritableMemory.allocate(64);
+    wmem.copyTo(0, wmem, 0, 64);
+  }
+
+  @Test
+  public void checkCopyWithinNativeSmall() throws Exception {
+    int memCapacity = 64;
+    int half = memCapacity/2;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory wmem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      wmem.clear();
+
+      for (int i=0; i<half; i++) { //fill first half
+        wmem.putByte(i, (byte) i);
+      }
+
+      wmem.copyTo(0, wmem, half, half);
+
+      for (int i=0; i<half; i++) {
+        assertEquals(wmem.getByte(i+half), (byte) i);
+      }
+    }
+  }
+
+  @Test
+  public void checkCopyWithinNativeLarge() throws Exception {
+    int memCapacity = (2 << 20) + 64;
+    int memCapLongs = memCapacity / 8;
+    int halfBytes = memCapacity / 2;
+    int halfLongs = memCapLongs / 2;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory wmem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      wmem.clear();
+
+      for (int i=0; i < halfLongs; i++) {
+        wmem.putLong(i*8, i);
+      }
+
+      wmem.copyTo(0, wmem, halfBytes, halfBytes);
+
+      for (int i=0; i < halfLongs; i++) {
+        assertEquals(wmem.getLong((i + halfLongs)*8), i);
+      }
+    }
+  }
+
+  @Test
+  public void checkCopyWithinNativeSrcBound() throws Exception {
+    int memCapacity = 64;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory wmem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      wmem.copyTo(32, wmem, 32, 33);  //hit source bound check
+      fail("Did Not Catch Assertion Error: source bound");
+    }
+    catch (IndexOutOfBoundsException e) {
+      //pass
+    }
+  }
+
+  @Test
+  public void checkCopyWithinNativeDstBound() throws Exception {
+    int memCapacity = 64;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory wmem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      wmem.copyTo(0, wmem, 32, 33);  //hit dst bound check
+      fail("Did Not Catch Assertion Error: dst bound");
+    }
+    catch (IndexOutOfBoundsException e) {
+      //pass
+    }
+  }
+
+  @Test
+  public void checkCopyCrossNativeSmall() throws Exception {
+    int memCapacity = 64;
+
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory wmem1 = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      WritableMemory wmem2 = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+
+      for (int i=0; i < memCapacity; i++) {
+        wmem1.putByte(i, (byte) i);
+      }
+      wmem2.clear();
+      wmem1.copyTo(0, wmem2, 0, memCapacity);
+
+      for (int i=0; i<memCapacity; i++) {
+        assertEquals(wmem2.getByte(i), (byte) i);
+      }
+    }
+  }
+
+  @Test
+  public void checkCopyCrossNativeLarge() throws Exception {
+    int memCapacity = (2<<20) + 64;
+    int memCapLongs = memCapacity / 8;
+
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory wmem1 = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      WritableMemory wmem2 = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+
+      for (int i=0; i < memCapLongs; i++) {
+        wmem1.putLong(i*8, i);
+      }
+      wmem2.clear();
+
+      wmem1.copyTo(0, wmem2, 0, memCapacity);
+
+      for (int i=0; i<memCapLongs; i++) {
+        assertEquals(wmem2.getLong(i*8), i);
+      }
+    }
+  }
+
+  @Test
+  public void checkCopyCrossNativeAndByteArray() throws Exception {
+    int memCapacity = 64;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory wmem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+
+      for (int i= 0; i < wmem.getCapacity(); i++) {
+        wmem.putByte(i, (byte) i);
+      }
+
+      WritableMemory wmem2 = WritableMemory.allocate(memCapacity);
+      wmem.copyTo(8, wmem2, 16, 16);
+
+      for (int i=0; i<16; i++) {
+        assertEquals(wmem.getByte(8+i), wmem2.getByte(16+i));
+      }
+      //println(mem2.toHexString("Mem2", 0, (int)mem2.getCapacity()));
+    }
+  }
+
+  @Test
+  public void checkCopyCrossRegionsSameNative() throws Exception {
+    int memCapacity = 128;
+
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory wmem1 = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+
+      for (int i= 0; i < wmem1.getCapacity(); i++) {
+        wmem1.putByte(i, (byte) i);
+      }
+      //println(mem1.toHexString("Mem1", 0, (int)mem1.getCapacity()));
+
+      Memory reg1 = wmem1.region(8, 16);
+      //println(reg1.toHexString("Reg1", 0, (int)reg1.getCapacity()));
+
+      WritableMemory reg2 = wmem1.writableRegion(24, 16);
+      //println(reg2.toHexString("Reg2", 0, (int)reg2.getCapacity()));
+      reg1.copyTo(0, reg2, 0, 16);
+
+      for (int i=0; i<16; i++) {
+        assertEquals(reg1.getByte(i), reg2.getByte(i));
+        assertEquals(wmem1.getByte(8+i), wmem1.getByte(24+i));
+      }
+      //println(mem1.toHexString("Mem1", 0, (int)mem1.getCapacity()));
+    }
+  }
+
+  @Test
+  public void checkCopyCrossNativeArrayAndHierarchicalRegions() throws Exception {
+    int memCapacity = 64;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory wmem1 = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+
+      for (int i= 0; i < wmem1.getCapacity(); i++) { //fill with numbers
+        wmem1.putByte(i, (byte) i);
+      }
+      //println(mem1.toHexString("Mem1", 0, (int)mem1.getCapacity()));
+
+      WritableMemory wmem2 = WritableMemory.allocate(memCapacity);
+
+      Memory reg1 = wmem1.region(8, 32);
+      Memory reg1B = reg1.region(8, 16);
+      //println(reg1.toHexString("Reg1", 0, (int)reg1.getCapacity()));
+      //println(reg1B.toHexString("Reg1B", 0, (int)reg1B.getCapacity()));
+
+      WritableMemory reg2 = wmem2.writableRegion(32, 16);
+      reg1B.copyTo(0, reg2, 0, 16);
+      //println(reg2.toHexString("Reg2", 0, (int)reg2.getCapacity()));
+
+      //println(mem2.toHexString("Mem2", 0, (int)mem2.getCapacity()));
+      for (int i = 32, j = 16; i < 40; i++, j++) {
+        assertEquals(wmem2.getByte(i), j);
+      }
+    }
+
+  }
+
+  @Test(expectedExceptions = IndexOutOfBoundsException.class)
+  public void checkRegionBounds() throws Exception {
+    int memCapacity = 64;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory wmem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      wmem.writableRegion(1, 64);
+    }
+  }
+
+  @Test
+  public void checkByteBufferWrap() {
+    int memCapacity = 64;
+    ByteBuffer byteBuf = ByteBuffer.allocate(memCapacity);
+    byteBuf.order(ByteOrder.nativeOrder());
+
+    for (int i=0; i<memCapacity; i++) {
+      byteBuf.put(i, (byte) i);
+    }
+
+    WritableMemory wmem = WritableMemory.writableWrap(byteBuf);
+
+    for (int i=0; i<memCapacity; i++) {
+      assertEquals(wmem.getByte(i), byteBuf.get(i));
+    }
+
+    assertTrue(wmem.hasByteBuffer());
+    ByteBuffer byteBuf2 = wmem.toByteBuffer(ByteOrder.nativeOrder());
+    assertEquals(byteBuf2, byteBuf);
+    //println( mem.toHexString("HeapBB", 0, memCapacity));
+  }
+
+  @Test
+  public void checkWrapWithBBReadonly1() {
+    int memCapacity = 64;
+    ByteBuffer byteBuf = ByteBuffer.allocate(memCapacity);
+    byteBuf.order(ByteOrder.nativeOrder());
+
+    for (int i = 0; i < memCapacity; i++) {
+      byteBuf.put(i, (byte) i);
+    }
+
+    Memory mem = WritableMemory.writableWrap(byteBuf);
+
+    for (int i = 0; i < memCapacity; i++) {
+      assertEquals(mem.getByte(i), byteBuf.get(i));
+    }
+
+    //println(mem.toHexString("HeapBB", 0, memCapacity));
+  }
+
+  @Test(expectedExceptions = IllegalArgumentException.class)
+  public void checkWrapWithBBReadonly2() {
+    int memCapacity = 64;
+    ByteBuffer byteBuf = ByteBuffer.allocate(memCapacity);
+    byteBuf.order(ByteOrder.nativeOrder());
+    ByteBuffer byteBufRO = byteBuf.asReadOnlyBuffer();
+
+    WritableMemory.writableWrap(byteBufRO);
+  }
+
+  @Test
+  public void checkWrapWithDirectBBReadonly() {
+    int memCapacity = 64;
+    ByteBuffer byteBuf = ByteBuffer.allocateDirect(memCapacity);
+    byteBuf.order(ByteOrder.nativeOrder());
+
+    for (int i = 0; i < memCapacity; i++) {
+      byteBuf.put(i, (byte) i);
+    }
+    ByteBuffer byteBufRO = byteBuf.asReadOnlyBuffer();
+    byteBufRO.order(ByteOrder.nativeOrder());
+
+    Memory mem = Memory.wrap(byteBufRO);
+
+    for (int i = 0; i < memCapacity; i++) {
+      assertEquals(mem.getByte(i), byteBuf.get(i));
+    }
+
+    //println(mem.toHexString("HeapBB", 0, memCapacity));
+  }
+
+  @Test(expectedExceptions = IllegalArgumentException.class)
+  public void checkWrapWithDirectBBReadonlyPut() {
+    int memCapacity = 64;
+    ByteBuffer byteBuf = ByteBuffer.allocateDirect(memCapacity);
+    ByteBuffer byteBufRO = byteBuf.asReadOnlyBuffer();
+    byteBufRO.order(ByteOrder.nativeOrder());
+
+    WritableMemory.writableWrap(byteBufRO);
+  }
+
+  @Test
+  public void checkByteBufferWrapDirectAccess() {
+    int memCapacity = 64;
+    ByteBuffer byteBuf = ByteBuffer.allocateDirect(memCapacity);
+    byteBuf.order(ByteOrder.nativeOrder());
+
+    for (int i=0; i<memCapacity; i++) {
+      byteBuf.put(i, (byte) i);
+    }
+
+    Memory mem = Memory.wrap(byteBuf);
+
+    for (int i=0; i<memCapacity; i++) {
+      assertEquals(mem.getByte(i), byteBuf.get(i));
+    }
+
+    //println( mem.toHexString("HeapBB", 0, memCapacity));
+  }
+
+  @Test
+  public void checkIsDirect() throws Exception {
+    int memCapacity = 64;
+    WritableMemory mem = WritableMemory.allocate(memCapacity);
+    assertFalse(mem.isDirect());
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory wmem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      assertTrue(wmem.isDirect());
+    }
+  }
+
+  @Test
+  public void checkIsReadOnly() {
+    long[] srcArray = { 1, -2, 3, -4, 5, -6, 7, -8 };
+
+    WritableMemory wmem = WritableMemory.writableWrap(srcArray);
+    assertFalse(wmem.isReadOnly());
+
+    Memory memRO = wmem;
+    assertFalse(memRO.isReadOnly());
+
+    for (int i = 0; i < wmem.getCapacity(); i++) {
+      assertEquals(wmem.getByte(i), memRO.getByte(i));
+    }
+  }
+
+  @Test
+  public void checkGoodBounds() {
+    BaseStateImpl.checkBounds(50, 50, 100);
+  }
+
+  @Test
+  public void checkCompareToHeap() {
+    byte[] arr1 = new byte[] {0, 1, 2, 3};
+    byte[] arr2 = new byte[] {0, 1, 2, 4};
+    byte[] arr3 = new byte[] {0, 1, 2, 3, 4};
+
+    Memory mem1 = Memory.wrap(arr1);
+    Memory mem2 = Memory.wrap(arr2);
+    Memory mem3 = Memory.wrap(arr3);
+    Memory mem4 = Memory.wrap(arr3); //same resource
+
+    int comp = mem1.compareTo(0, 3, mem2, 0, 3);
+    assertEquals(comp, 0);
+    comp = mem1.compareTo(0, 4, mem2, 0, 4);
+    assertEquals(comp, -1);
+    comp = mem2.compareTo(0, 4, mem1, 0, 4);
+    assertEquals(comp, 1);
+    //different lengths
+    comp = mem1.compareTo(0, 4, mem3, 0, 5);
+    assertEquals(comp, -1);
+    comp = mem3.compareTo(0, 5, mem1, 0, 4);
+    assertEquals(comp, 1);
+    comp = mem3.compareTo(0, 5, mem4, 0, 5);
+    assertEquals(comp, 0);
+    comp = mem3.compareTo(0, 4, mem4, 1, 4);
+    assertEquals(comp, -1);
+    BaseStateImpl.checkBounds(0, 5, mem3.getCapacity());
+  }
+
+  @Test
+  public void checkCompareToDirect() throws Exception {
+    byte[] arr1 = new byte[] {0, 1, 2, 3};
+    byte[] arr2 = new byte[] {0, 1, 2, 4};
+    byte[] arr3 = new byte[] {0, 1, 2, 3, 4};
+
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem1 = WritableMemory.allocateDirect(4, scope, memReqSvr);
+      WritableMemory mem2 = WritableMemory.allocateDirect(4, scope, memReqSvr);
+      WritableMemory mem3 = WritableMemory.allocateDirect(5, scope, memReqSvr);
+
+      mem1.putByteArray(0, arr1, 0, 4);
+      mem2.putByteArray(0, arr2, 0, 4);
+      mem3.putByteArray(0, arr3, 0, 5);
+
+      int comp = mem1.compareTo(0, 3, mem2, 0, 3);
+      assertEquals(comp, 0);
+      comp = mem1.compareTo(0, 4, mem2, 0, 4);
+      assertEquals(comp, -1);
+      comp = mem2.compareTo(0, 4, mem1, 0, 4);
+      assertEquals(comp, 1);
+      //different lengths
+      comp = mem1.compareTo(0, 4, mem3, 0, 5);
+      assertEquals(comp, -1);
+      comp = mem3.compareTo(0, 5, mem1, 0, 4);
+      assertEquals(comp, 1);
+    }
+  }
+
+  @Test
+  public void testCompareToSameStart() {
+    Memory mem = WritableMemory.allocate(3);
+    assertEquals(-1, mem.compareTo(0, 1, mem, 0, 2));
+    assertEquals(0, mem.compareTo(1, 1, mem, 1, 1));
+    assertEquals(1, mem.compareTo(1, 2, mem, 1, 1));
+  }
+
+  @Test
+  public void checkAsBuffer() {
+    WritableMemory wmem = WritableMemory.allocate(64);
+    WritableBuffer wbuf = wmem.asWritableBuffer();
+    wbuf.setPosition(32);
+    for (int i = 32; i < 64; i++) { wbuf.putByte((byte)i); }
+    //println(wbuf.toHexString("Buf", 0, (int)wbuf.getCapacity()));
+
+    Buffer buf = wmem.asBuffer();
+    buf.setPosition(32);
+    for (int i = 32; i < 64; i++) {
+      assertEquals(buf.getByte(), i);
+    }
+  }
+
+  @Test
+  public void checkAsWritableBufferWithBB() {
+    ByteBuffer byteBuf = ByteBuffer.allocate(64);
+    byteBuf.position(16);
+    byteBuf.limit(48);
+    WritableMemory wmem = WritableMemory.writableWrap(byteBuf);
+    WritableBuffer wbuf = wmem.asWritableBuffer();
+    assertEquals(wbuf.getCapacity(), 64);
+    assertEquals(wbuf.getPosition(), 0);
+    assertEquals(wbuf.getEnd(), 64);
+  }
+
+  @Test(expectedExceptions = IllegalArgumentException.class)
+  public void checkAsWritableRegionRO() {
+    ByteBuffer byteBuf = ByteBuffer.allocate(64);
+    WritableMemory wmem = (WritableMemory) Memory.wrap(byteBuf);
+    wmem.writableRegion(0, 1);
+  }
+
+  @Test(expectedExceptions = IllegalArgumentException.class)
+  public void checkAsWritableBufferRO() {
+    ByteBuffer byteBuf = ByteBuffer.allocate(64);
+    WritableMemory wmem = (WritableMemory) Memory.wrap(byteBuf);
+    wmem.asWritableBuffer();
+  }
+
+  @Test void checkZeroMemory() {
+    WritableMemory wmem = WritableMemory.allocate(8);
+    WritableMemory reg = wmem.writableRegion(0, 0);
+    assertEquals(reg.getCapacity(), 0);
+  }
+
+  @Test
+  public void checkAsBufferNonNative() {
+    WritableMemory wmem = WritableMemory.allocate(64);
+    wmem.putShort(0, (short) 1);
+    Buffer buf = wmem.asBuffer(BaseState.NON_NATIVE_BYTE_ORDER);
+    assertEquals(buf.getShort(0), 256);
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void println(String s) {
+    //System.out.println(s); //disable here
+  }
+
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/NonNativeWritableBufferImplTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/NonNativeWritableBufferImplTest.java
new file mode 100644
index 0000000..ab42ba6
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/NonNativeWritableBufferImplTest.java
@@ -0,0 +1,279 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.testng.Assert.assertEquals;
+
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.Buffer;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.WritableBuffer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+/**
+ * @author Lee Rhodes
+ */
+public class NonNativeWritableBufferImplTest {
+
+//Check primitives
+  @Test
+  public void checkCharacters() {
+    int n = 8;
+    int m = Character.BYTES;
+    byte[] arr1 = new byte[n * m]; //non-native
+    //put & get
+    WritableMemory wmem = WritableMemory.writableWrap(arr1, ByteOrder.BIG_ENDIAN);
+    WritableBuffer wbuf = wmem.asWritableBuffer();
+    char ch = 'a';
+    for (int i = 0; i < n; i++) { wbuf.putChar(i * m, ch++); }
+    ch = 'a';
+    for (int i = 0; i < n; i++) {
+      assertEquals(wbuf.getChar(i * m), ch++);
+    }
+    ch = 'a';
+    wbuf.setPosition(0);
+    for (int i = 0; i < n; i++) { wbuf.putChar(ch++); }
+    ch = 'a';
+    wbuf.setPosition(0);
+    for (int i = 0; i < n; i++) {
+      assertEquals(wbuf.getChar(), ch++);
+    }
+    //getArr & putArr
+    char[] cArr = new char[n]; //native
+    wbuf.setPosition(0);
+    wbuf.getCharArray(cArr, 0, n); //wmem is non-native
+    byte[] arr2 = new byte[n * m];
+    WritableMemory wmem2 = WritableMemory.writableWrap(arr2, ByteOrder.BIG_ENDIAN);
+    WritableBuffer wbuf2 = wmem2.asWritableBuffer();
+    wbuf2.putCharArray(cArr, 0, n);
+    assertEquals(arr2, arr1);
+  }
+
+  @Test
+  public void checkDoubles() {
+    int n = 8;
+    int m = Double.BYTES;
+    byte[] arr1 = new byte[n * m]; //non-native
+    //put & get
+    WritableMemory wmem = WritableMemory.writableWrap(arr1, ByteOrder.BIG_ENDIAN);
+    WritableBuffer wbuf = wmem.asWritableBuffer();
+    double dbl = 1.0;
+    for (int i = 0; i < n; i++) { wbuf.putDouble(i * m, dbl++); }
+    dbl = 1.0;
+    for (int i = 0; i < n; i++) {
+      assertEquals(wbuf.getDouble(i * m), dbl++);
+    }
+    dbl = 1.0;
+    wbuf.setPosition(0);
+    for (int i = 0; i < n; i++) { wbuf.putDouble(dbl++); }
+    dbl = 1.0;
+    wbuf.setPosition(0);
+    for (int i = 0; i < n; i++) {
+      assertEquals(wbuf.getDouble(), dbl++);
+    }
+    //getArr & putArr
+    double[] dblArr = new double[n]; //native
+    wbuf.setPosition(0);
+    wbuf.getDoubleArray(dblArr, 0, n); //wmem is non-native
+    byte[] arr2 = new byte[n * m];
+    WritableMemory wmem2 = WritableMemory.writableWrap(arr2, ByteOrder.BIG_ENDIAN);
+    WritableBuffer wbuf2 = wmem2.asWritableBuffer();
+    wbuf2.putDoubleArray(dblArr, 0, n);
+    assertEquals(arr2, arr1);
+  }
+
+  @Test
+  public void checkFloats() {
+    int n = 8;
+    int m = Float.BYTES;
+    byte[] arr1 = new byte[n * m]; //non-native
+    //put & get
+    WritableMemory wmem = WritableMemory.writableWrap(arr1, ByteOrder.BIG_ENDIAN);
+    WritableBuffer wbuf = wmem.asWritableBuffer();
+    float flt = 1.0F;
+    for (int i = 0; i < n; i++) { wbuf.putFloat(i * m, flt++); }
+    flt = 1.0F;
+    for (int i = 0; i < n; i++) {
+      assertEquals(wbuf.getFloat(i * m), flt++);
+    }
+    flt = 1.0F;
+    wbuf.setPosition(0);
+    for (int i = 0; i < n; i++) { wbuf.putFloat(flt++); }
+    flt = 1.0F;
+    wbuf.setPosition(0);
+    for (int i = 0; i < n; i++) {
+      assertEquals(wbuf.getFloat(), flt++);
+    }
+    //getArr & putArr
+    float[] fltArr = new float[n]; //native
+    wbuf.setPosition(0);
+    wbuf.getFloatArray(fltArr, 0, n); //wmem is non-native
+    byte[] arr2 = new byte[n * m];
+    WritableMemory wmem2 = WritableMemory.writableWrap(arr2, ByteOrder.BIG_ENDIAN);
+    WritableBuffer wbuf2 = wmem2.asWritableBuffer();
+    wbuf2.putFloatArray(fltArr, 0, n);
+    assertEquals(arr2, arr1);
+  }
+
+  @Test
+  public void checkInts() {
+    int n = 8;
+    int m = Integer.BYTES;
+    byte[] arr1 = new byte[n * m]; //non-native
+    //put & get
+    WritableMemory wmem = WritableMemory.writableWrap(arr1, ByteOrder.BIG_ENDIAN);
+    WritableBuffer wbuf = wmem.asWritableBuffer();
+    int intg = 1;
+    for (int i = 0; i < n; i++) { wbuf.putInt(i * m, intg++); }
+    intg = 1;
+    for (int i = 0; i < n; i++) {
+      assertEquals(wbuf.getInt(i * m), intg++);
+    }
+    intg = 1;
+    wbuf.setPosition(0);
+    for (int i = 0; i < n; i++) { wbuf.putInt(intg++); }
+    intg = 1;
+    wbuf.setPosition(0);
+    for (int i = 0; i < n; i++) {
+      assertEquals(wbuf.getInt(), intg++);
+    }
+    //getArr & putArr
+    int[] intArr = new int[n]; //native
+    wbuf.setPosition(0);
+    wbuf.getIntArray(intArr, 0, n); //wmem is non-native
+    byte[] arr2 = new byte[n * m];
+    WritableMemory wmem2 = WritableMemory.writableWrap(arr2, ByteOrder.BIG_ENDIAN);
+    WritableBuffer wbuf2 = wmem2.asWritableBuffer();
+    wbuf2.putIntArray(intArr, 0, n);
+    assertEquals(arr2, arr1);
+  }
+
+  @Test
+  public void checkLongs() {
+    int n = 8;
+    int m = Long.BYTES;
+    byte[] arr1 = new byte[n * m]; //non-native
+    //put & get
+    WritableMemory wmem = WritableMemory.writableWrap(arr1, ByteOrder.BIG_ENDIAN);
+    WritableBuffer wbuf = wmem.asWritableBuffer();
+    long lng = 1;
+    for (int i = 0; i < n; i++) { wbuf.putLong(i * m, lng++); }
+    lng = 1;
+    for (int i = 0; i < n; i++) {
+      assertEquals(wbuf.getLong(i * m), lng++);
+    }
+    lng = 1;
+    wbuf.setPosition(0);
+    for (int i = 0; i < n; i++) { wbuf.putLong(lng++); }
+    lng = 1;
+    wbuf.setPosition(0);
+    for (int i = 0; i < n; i++) {
+      assertEquals(wbuf.getLong(), lng++);
+    }
+    //getArr & putArr
+    long[] longArr = new long[n]; //native
+    wbuf.setPosition(0);
+    wbuf.getLongArray(longArr, 0, n); //wmem is non-native
+    byte[] arr2 = new byte[n * m];
+    WritableMemory wmem2 = WritableMemory.writableWrap(arr2, ByteOrder.BIG_ENDIAN);
+    WritableBuffer wbuf2 = wmem2.asWritableBuffer();
+    wbuf2.putLongArray(longArr, 0, n);
+    assertEquals(arr2, arr1);
+  }
+
+  @Test
+  public void checkShorts() {
+    int n = 8;
+    int m = Short.BYTES;
+    byte[] arr1 = new byte[n * m]; //non-native
+    //put & get
+    WritableMemory wmem = WritableMemory.writableWrap(arr1, ByteOrder.BIG_ENDIAN);
+    WritableBuffer wbuf = wmem.asWritableBuffer();
+    short sht = 1;
+    for (int i = 0; i < n; i++) { wbuf.putShort(i * m, sht++); }
+    sht = 1;
+    for (int i = 0; i < n; i++) {
+      assertEquals(wbuf.getShort(i * m), sht++);
+    }
+    sht = 1;
+    wbuf.setPosition(0);
+    for (int i = 0; i < n; i++) { wbuf.putShort(sht++); }
+    sht = 1;
+    wbuf.setPosition(0);
+    for (int i = 0; i < n; i++) {
+      assertEquals(wbuf.getShort(), sht++);
+    }
+    //getArr & putArr
+    short[] shortArr = new short[n]; //native
+    wbuf.setPosition(0);
+    wbuf.getShortArray(shortArr, 0, n); //wmem is non-native
+    byte[] arr2 = new byte[n * m];
+    WritableMemory wmem2 = WritableMemory.writableWrap(arr2, ByteOrder.BIG_ENDIAN);
+    WritableBuffer wbuf2 = wmem2.asWritableBuffer();
+    wbuf2.putShortArray(shortArr, 0, n);
+    assertEquals(arr2, arr1);
+  }
+
+  //check Duplicate, Region
+  @Test
+  public void checkDuplicate() {
+    byte[] bArr = new byte[8];
+    WritableMemory wmem = WritableMemory.writableWrap(bArr, ByteOrder.BIG_ENDIAN);
+    WritableBuffer wbuf = wmem.asWritableBuffer();
+    WritableBuffer wdup = wbuf.writableDuplicate();
+    assertEquals(wdup.getByteOrder(), ByteOrder.BIG_ENDIAN);
+
+    WritableBuffer wreg = wbuf.writableRegion();
+    assertEquals(wreg.getByteOrder(), ByteOrder.BIG_ENDIAN);
+  }
+
+  @Test
+  public void checkConversionByteOrder() {
+    byte[] bArr = new byte[8];
+    bArr[1] = 1;
+    WritableMemory wmem = WritableMemory.writableWrap(bArr, ByteOrder.BIG_ENDIAN);
+    assertEquals(wmem.getByteOrder(), ByteOrder.BIG_ENDIAN);
+    assertEquals(wmem.getChar(0), 1);
+
+    Buffer buf = wmem.asBuffer();
+    assertEquals(buf.getByteOrder(), ByteOrder.BIG_ENDIAN); //
+    assertEquals(buf.getChar(0), 1);
+
+    Buffer dup = buf.duplicate();
+    assertEquals(dup.getByteOrder(), ByteOrder.BIG_ENDIAN);
+    assertEquals(dup.getChar(0), 1);
+
+    Buffer reg = buf.region();
+    assertEquals(reg.getByteOrder(), ByteOrder.BIG_ENDIAN);
+    assertEquals(reg.getChar(0), 1);
+
+    Memory mem = reg.asMemory();
+    assertEquals(mem.getByteOrder(), ByteOrder.BIG_ENDIAN);
+    assertEquals(mem.getChar(0), 1);
+
+    Memory mreg = mem.region(0, 8);
+    assertEquals(mreg.getByteOrder(), ByteOrder.BIG_ENDIAN);
+    assertEquals(mreg.getChar(0), 1);
+
+  }
+
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/NonNativeWritableMemoryImplTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/NonNativeWritableMemoryImplTest.java
new file mode 100644
index 0000000..5746390
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/NonNativeWritableMemoryImplTest.java
@@ -0,0 +1,176 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.testng.Assert.assertEquals;
+
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+/**
+ * @author Lee Rhodes
+ */
+public class NonNativeWritableMemoryImplTest {
+  private byte[] bArr = new byte[8];
+  private final WritableMemory wmem = WritableMemory.writableWrap(bArr, ByteOrder.BIG_ENDIAN);
+
+//Check primitives
+  @Test
+  public void checkCharacters() {
+    int m = Character.BYTES;
+    int n = ((1 << 20) / m) + m;
+    byte[] arr1 = new byte[n * m]; //non-native
+    //put & get
+    WritableMemory wmem1 = WritableMemory.writableWrap(arr1, ByteOrder.BIG_ENDIAN);
+    for (int i = 0; i < n; i++) { wmem1.putChar(i * m, (char) i++); }
+    for (int i = 0; i < n; i++) {
+      assertEquals(wmem1.getChar(i * m), (char) i++);
+    }
+    //getArr & putArr
+    char[] cArr = new char[n]; //native
+    wmem1.getCharArray(0, cArr, 0, n); //wmem is non-native
+    byte[] arr2 = new byte[n * m];
+    WritableMemory wmem2 = WritableMemory.writableWrap(arr2, ByteOrder.BIG_ENDIAN);
+    wmem2.putCharArray(0, cArr, 0, n);
+    assertEquals(arr2, arr1);
+  }
+
+  @Test
+  public void checkDoubles() {
+    int m = Double.BYTES;
+    int n = ((1 << 20) / m) + m;
+    byte[] arr1 = new byte[n * m]; //non-native
+    //put & get
+    WritableMemory wmem1 = WritableMemory.writableWrap(arr1, ByteOrder.BIG_ENDIAN);
+    double dbl = 1.0;
+    for (int i = 0; i < n; i++) { wmem1.putDouble(i * m, dbl++); }
+    dbl = 1.0;
+    for (int i = 0; i < n; i++) {
+      assertEquals(wmem1.getDouble(i * m), dbl++);
+    }
+    //getArr & putArr
+    double[] dblArr = new double[n]; //native
+    wmem1.getDoubleArray(0, dblArr, 0, n); //wmem is non-native
+    byte[] arr2 = new byte[n * m];
+    WritableMemory wmem2 = WritableMemory.writableWrap(arr2, ByteOrder.BIG_ENDIAN);
+    wmem2.putDoubleArray(0, dblArr, 0, n);
+    assertEquals(arr2, arr1);
+  }
+
+  @Test
+  public void checkFloats() {
+    int m = Float.BYTES;
+    int n = ((1 << 20) / m) + m;
+    byte[] arr1 = new byte[n * m]; //non-native
+    //put & get
+    WritableMemory wmem1 = WritableMemory.writableWrap(arr1, ByteOrder.BIG_ENDIAN);
+    float flt = 1.0F;
+    for (int i = 0; i < n; i++) { wmem1.putFloat(i * m, flt++); }
+    flt = 1.0F;
+    for (int i = 0; i < n; i++) {
+      assertEquals(wmem1.getFloat(i * m), flt++);
+    }
+    //getArr & putArr
+    float[] fltArr = new float[n]; //native
+    wmem1.getFloatArray(0, fltArr, 0, n); //wmem is non-native
+    byte[] arr2 = new byte[n * m];
+    WritableMemory wmem2 = WritableMemory.writableWrap(arr2, ByteOrder.BIG_ENDIAN);
+    wmem2.putFloatArray(0, fltArr, 0, n);
+    assertEquals(arr2, arr1);
+  }
+
+  @Test
+  public void checkInts() {
+    int m = Integer.BYTES;
+    int n = ((1 << 20) / m) + m;
+    byte[] arr1 = new byte[n * m]; //non-native
+    //put & get
+    WritableMemory wmem1 = WritableMemory.writableWrap(arr1, ByteOrder.BIG_ENDIAN);
+    int intg = 1;
+    for (int i = 0; i < n; i++) { wmem1.putInt(i * m, intg++); }
+    intg = 1;
+    for (int i = 0; i < n; i++) {
+      assertEquals(wmem1.getInt(i * m), intg++);
+    }
+    //getArr & putArr
+    int[] intArr = new int[n]; //native
+    wmem1.getIntArray(0, intArr, 0, n); //wmem is non-native
+    byte[] arr2 = new byte[n * m];
+    WritableMemory wmem2 = WritableMemory.writableWrap(arr2, ByteOrder.BIG_ENDIAN);
+    wmem2.putIntArray(0, intArr, 0, n);
+    assertEquals(arr2, arr1);
+  }
+
+  @Test
+  public void checkLongs() {
+    int m = Long.BYTES;
+    int n = ((1 << 20) / m) + m;
+    byte[] arr1 = new byte[n * m]; //non-native
+    //put & get
+    WritableMemory wmem1 = WritableMemory.writableWrap(arr1, ByteOrder.BIG_ENDIAN);
+    long lng = 1;
+    for (int i = 0; i < n; i++) { wmem1.putLong(i * m, lng++); }
+    lng = 1;
+    for (int i = 0; i < n; i++) {
+      assertEquals(wmem1.getLong(i * m), lng++);
+    }
+    //getArr & putArr
+    long[] longArr = new long[n]; //native
+    wmem1.getLongArray(0, longArr, 0, n); //wmem is non-native
+    byte[] arr2 = new byte[n * m];
+    WritableMemory wmem2 = WritableMemory.writableWrap(arr2, ByteOrder.BIG_ENDIAN);
+    wmem2.putLongArray(0, longArr, 0, n);
+    assertEquals(arr2, arr1);
+  }
+
+  @Test
+  public void checkShorts() {
+    int m = Short.BYTES;
+    int n = ((1 << 20) / m) + m;
+    byte[] arr1 = new byte[n * m]; //non-native
+    //put & get
+    WritableMemory wmem1 = WritableMemory.writableWrap(arr1, ByteOrder.BIG_ENDIAN);
+    short sht = 1;
+    for (int i = 0; i < n; i++) { wmem1.putShort(i * m, sht++); }
+    sht = 1;
+    for (int i = 0; i < n; i++) {
+      assertEquals(wmem1.getShort(i * m), sht++);
+    }
+    //getArr & putArr
+    short[] shortArr = new short[n]; //native
+    wmem1.getShortArray(0, shortArr, 0, n); //wmem is non-native
+    byte[] arr2 = new byte[n * m];
+    WritableMemory wmem2 = WritableMemory.writableWrap(arr2, ByteOrder.BIG_ENDIAN);
+    wmem2.putShortArray(0, shortArr, 0, n);
+    assertEquals(arr2, arr1);
+  }
+
+  //check Atomic Write Methods
+
+  //check Region
+  @Test
+  public void checkRegion() {
+    WritableMemory wreg = wmem.writableRegion(0, wmem.getCapacity());
+    assertEquals(wreg.getByteOrder(), ByteOrder.BIG_ENDIAN);
+  }
+
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/SpecificLeafTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/SpecificLeafTest.java
new file mode 100644
index 0000000..962097d
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/SpecificLeafTest.java
@@ -0,0 +1,202 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.Buffer;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+/**
+ * @author Lee Rhodes
+ */
+public class SpecificLeafTest {
+  private static final MemoryRequestServer memReqSvr = BaseState.defaultMemReqSvr;
+
+  @Test
+  public void checkByteBufferLeafs() {
+    int bytes = 128;
+    ByteBuffer bb = ByteBuffer.allocate(bytes);
+    bb.order(ByteOrder.nativeOrder());
+
+    Memory mem = Memory.wrap(bb).region(0, bytes, ByteOrder.nativeOrder());
+    assertTrue(mem.hasByteBuffer());
+    assertTrue(mem.isReadOnly());
+    assertTrue(mem.isMemory());
+    assertFalse(mem.isDirect());
+    assertFalse(mem.isMapped());
+    checkCrossLeafTypeIds(mem);
+    Buffer buf = mem.asBuffer().region(0, bytes, ByteOrder.nativeOrder());
+    assertEquals(buf.getByteOrder(), BaseState.NATIVE_BYTE_ORDER);
+
+    bb.order(BaseState.NON_NATIVE_BYTE_ORDER);
+    Memory mem2 = Memory.wrap(bb).region(0, bytes, BaseState.NON_NATIVE_BYTE_ORDER);
+    Buffer buf2 = mem2.asBuffer().region(0, bytes, BaseState.NON_NATIVE_BYTE_ORDER);
+    Buffer buf3 = buf2.duplicate();
+
+    assertTrue(mem.isRegion());
+    assertTrue(mem2.isRegion());
+    assertTrue(buf.isRegion());
+    assertTrue(buf2.isRegion());
+    assertTrue(buf3.isDuplicate());
+  }
+
+  @Test
+  public void checkDirectLeafs() throws Exception {
+    int bytes = 128;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory wmem = WritableMemory.allocateDirect(bytes, scope, memReqSvr);
+      assertFalse(((BaseStateImpl)wmem).isReadOnly());
+      assertTrue(wmem.isDirect());
+      assertFalse(wmem.isHeap());
+      assertFalse(wmem.isReadOnly());
+      checkCrossLeafTypeIds(wmem);
+      WritableMemory nnwmem = wmem.writableRegion(0, bytes, BaseState.NON_NATIVE_BYTE_ORDER);
+
+      Memory mem = wmem.region(0, bytes, ByteOrder.nativeOrder());
+      Buffer buf = mem.asBuffer().region(0, bytes, ByteOrder.nativeOrder());
+
+
+      Memory mem2 = nnwmem.region(0, bytes, BaseState.NON_NATIVE_BYTE_ORDER);
+      Buffer buf2 = mem2.asBuffer().region(0, bytes, BaseState.NON_NATIVE_BYTE_ORDER);
+      Buffer buf3 = buf2.duplicate();
+
+      assertTrue(mem.isRegion());
+      assertTrue(mem2.isRegion());
+      assertTrue(buf.isRegion());
+      assertTrue(buf2.isRegion());
+      assertTrue(buf3.isDuplicate());
+      assertTrue(mem2.isMemory());
+    }
+  }
+
+  @Test
+  public void checkMapLeafs() throws IOException {
+    File file = new File("TestFile2.bin");
+    if (file.exists()) {
+      java.nio.file.Files.delete(file.toPath());
+    }
+    assertTrue(file.createNewFile());
+    assertTrue(file.setWritable(true, false)); //writable=true, ownerOnly=false
+    assertTrue(file.isFile());
+    file.deleteOnExit();  //comment out if you want to examine the file.
+
+    final long bytes = 128;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.writableMap(file, 0L, bytes, scope, ByteOrder.nativeOrder());
+      assertTrue(mem.isMapped());
+      assertFalse(mem.isReadOnly());
+      checkCrossLeafTypeIds(mem);
+      Memory nnreg = mem.region(0, bytes, BaseState.NON_NATIVE_BYTE_ORDER);
+
+      Memory reg = mem.region(0, bytes, ByteOrder.nativeOrder());
+      Buffer buf = reg.asBuffer().region(0, bytes, ByteOrder.nativeOrder());
+      Buffer buf4 = buf.duplicate();
+
+      Memory reg2 = nnreg.region(0, bytes, BaseState.NON_NATIVE_BYTE_ORDER);
+      Buffer buf2 = reg2.asBuffer().region(0, bytes, BaseState.NON_NATIVE_BYTE_ORDER);
+      Buffer buf3 = buf2.duplicate();
+
+      assertTrue(reg.isRegion());
+      assertTrue(reg2.isRegion());
+      assertEquals(reg2.getByteOrder(), BaseState.NON_NATIVE_BYTE_ORDER);
+      assertTrue(buf.isRegion());
+      assertFalse(buf.isMemory());
+      assertTrue(buf2.isRegion());
+      assertTrue(buf3.isDuplicate());
+      assertTrue(buf4.isDuplicate());
+    }
+  }
+
+  @Test
+  public void checkHeapLeafs() {
+    int bytes = 128;
+    Memory mem = Memory.wrap(new byte[bytes]);
+    assertTrue(mem.isHeap());
+    assertTrue(((BaseStateImpl)mem).isReadOnly());
+    checkCrossLeafTypeIds(mem);
+    Memory nnreg = mem.region(0, bytes, BaseState.NON_NATIVE_BYTE_ORDER);
+
+    Memory reg = mem.region(0, bytes, ByteOrder.nativeOrder());
+    Buffer buf = reg.asBuffer().region(0, bytes, ByteOrder.nativeOrder());
+    Buffer buf4 = buf.duplicate();
+
+    Memory reg2 = nnreg.region(0, bytes, BaseState.NON_NATIVE_BYTE_ORDER);
+    Buffer buf2 = reg2.asBuffer().region(0, bytes, BaseState.NON_NATIVE_BYTE_ORDER);
+    Buffer buf3 = buf2.duplicate();
+
+    assertFalse(mem.isRegion());
+    assertTrue(reg2.isRegion());
+    assertTrue(buf.isRegion());
+    assertTrue(buf2.isRegion());
+    assertTrue(buf3.isDuplicate());
+    assertTrue(buf4.isDuplicate());
+  }
+
+  private static void checkCrossLeafTypeIds(Memory mem) {
+    Memory reg1 = mem.region(0, mem.getCapacity());
+    assertTrue(reg1.isRegion());
+
+    Buffer buf1 = reg1.asBuffer();
+    assertTrue(buf1.isRegion());
+    assertTrue(buf1.isBuffer());
+    assertTrue(buf1.isReadOnly());
+
+    Buffer buf2 = buf1.duplicate();
+    assertTrue(buf2.isRegion());
+    assertTrue(buf2.isBuffer());
+    assertTrue(buf2.isDuplicate());
+    assertTrue(buf2.isReadOnly());
+
+    Memory mem2 = buf1.asMemory(); //
+    assertTrue(mem2.isRegion());
+    assertFalse(mem2.isBuffer());
+    assertFalse(mem2.isDuplicate());
+    assertTrue(mem2.isReadOnly());
+
+    Buffer buf3 = buf1.duplicate(BaseState.NON_NATIVE_BYTE_ORDER);
+    assertTrue(buf3.isRegion());
+    assertTrue(buf3.isBuffer());
+    assertTrue(buf3.isDuplicate());
+    assertEquals(buf3.getByteOrder(), BaseState.NON_NATIVE_BYTE_ORDER);
+    assertTrue(buf3.isReadOnly());
+
+    Memory mem3 = buf3.asMemory();
+    assertTrue(mem3.isRegion());
+    assertFalse(mem3.isBuffer());
+    assertTrue(mem3.isDuplicate());
+    assertEquals(mem3.getByteOrder(), BaseState.NON_NATIVE_BYTE_ORDER);
+    assertTrue(mem3.isReadOnly());
+  }
+
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/UtilTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/UtilTest.java
new file mode 100644
index 0000000..2e1c57f
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/UtilTest.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * Note: Lincoln's Gettysburg Address is in the public domain. See LICENSE.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.apache.datasketches.memory.internal.Util.getResourceBytes;
+import static org.apache.datasketches.memory.internal.Util.getResourceFile;
+import static org.testng.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.attribute.PosixFileAttributeView;
+import java.nio.file.attribute.PosixFileAttributes;
+import java.nio.file.attribute.PosixFilePermissions;
+
+import org.testng.annotations.Test;
+
+public class UtilTest {
+  private static final String LS = System.getProperty("line.separator");
+
+
+  static final String getFileAttributes(File file) throws IOException {
+    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;
+  }
+
+  static final void setGettysburgAddressFileToReadOnly() throws IOException {
+    File file = getResourceFile("GettysburgAddress.txt");
+    Files.setPosixFilePermissions(file.toPath(), PosixFilePermissions.fromString("r--r--r--"));
+  }
+
+  //Resources
+
+  @Test
+  public void resourceFileExits() {
+    final String shortFileName = "GettysburgAddress.txt";
+    final File file = getResourceFile(shortFileName);
+    assertTrue(file.exists());
+  }
+
+  @Test(expectedExceptions = NullPointerException.class)
+  public void resourceFileNotFound() {
+    final String shortFileName = "GettysburgAddress.txt";
+    getResourceFile(shortFileName + "123");
+  }
+
+  @Test
+  public void resourceBytesCorrect() {
+    final String shortFileName = "GettysburgAddress.txt";
+    final byte[] bytes = getResourceBytes(shortFileName);
+    assertTrue(bytes.length == 1541);
+  }
+
+  @Test(expectedExceptions = NullPointerException.class)
+  public void resourceBytesFileNotFound() {
+    final String shortFileName = "GettysburgAddress.txt";
+    getResourceBytes(shortFileName + "123");
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  static void println(final Object o) {
+    if (o == null) { print(LS); }
+    else { print(o.toString() + LS); }
+  }
+
+  /**
+   * @param o value to print
+   */
+  static void print(final Object o) {
+    if (o != null) {
+      //System.out.print(o.toString()); //disable here
+    }
+  }
+
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/WritableDirectCopyTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/WritableDirectCopyTest.java
new file mode 100644
index 0000000..0c3afab
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/WritableDirectCopyTest.java
@@ -0,0 +1,253 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+/**
+ * @author Lee Rhodes
+ */
+public class WritableDirectCopyTest {
+  private static final MemoryRequestServer memReqSvr = BaseState.defaultMemReqSvr;
+
+//Copy Within tests
+
+  @Test
+  public void checkCopyWithinNativeSmall() throws Exception {
+    int memCapacity = 64;
+    int half = memCapacity / 2;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      mem.clear();
+
+      for (int i = 0; i < half; i++) { //fill first half
+        mem.putByte(i, (byte) i);
+      }
+
+      mem.copyTo(0, mem, half, half);
+
+      for (int i = 0; i < half; i++) {
+        assertEquals(mem.getByte(i + half), (byte) i);
+      }
+    }
+  }
+
+  @Test
+  public void checkCopyWithinNativeLarge() throws Exception {
+    int memCapacity = (2 << 20) + 64;
+    int memCapLongs = memCapacity / 8;
+    int halfBytes = memCapacity / 2;
+    int halfLongs = memCapLongs / 2;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      mem.clear();
+
+      for (int i = 0; i < halfLongs; i++) {
+        mem.putLong(i * 8, i);
+      }
+
+      mem.copyTo(0, mem, halfBytes, halfBytes);
+
+      for (int i = 0; i < halfLongs; i++) {
+        assertEquals(mem.getLong((i + halfLongs) * 8), i);
+      }
+    }
+  }
+
+  @Test
+  public void checkCopyWithinNativeOverlap() throws Exception {
+    int memCapacity = 64;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      mem.clear();
+      //println(mem.toHexString("Clear 64", 0, memCapacity));
+
+      for (int i = 0; i < (memCapacity / 2); i++) {
+        mem.putByte(i, (byte) i);
+      }
+      //println(mem.toHexString("Set 1st 32 to ints ", 0, memCapacity));
+      mem.copyTo(0, mem, memCapacity / 4, memCapacity / 2);  //overlap is OK
+    }
+  }
+
+  @Test
+  public void checkCopyWithinNativeSrcBound() throws Exception {
+    int memCapacity = 64;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      mem.copyTo(32, mem, 32, 33);  //hit source bound check
+      fail("Did Not Catch Assertion Error: source bound");
+    } catch (IndexOutOfBoundsException e) {
+      //pass
+    }
+  }
+
+  @Test
+  public void checkCopyWithinNativeDstBound() throws Exception {
+    int memCapacity = 64;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      mem.copyTo(0, mem, 32, 33);  //hit dst bound check
+      fail("Did Not Catch Assertion Error: dst bound");
+    } catch (IndexOutOfBoundsException e) {
+      //pass
+    }
+  }
+
+  @Test
+  public void checkCopyCrossNativeSmall() throws Exception {
+    int memCapacity = 64;
+
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem1 = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      WritableMemory mem2 = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+
+      for (int i = 0; i < memCapacity; i++) {
+        mem1.putByte(i, (byte) i);
+      }
+      mem2.clear();
+      mem1.copyTo(0, mem2, 0, memCapacity);
+
+      for (int i = 0; i < memCapacity; i++) {
+        assertEquals(mem2.getByte(i), (byte) i);
+      }
+    }
+  }
+
+  @Test
+  public void checkCopyCrossNativeLarge() throws Exception {
+    int memCapacity = (2 << 20) + 64;
+    int memCapLongs = memCapacity / 8;
+
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem1 = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+      WritableMemory mem2 = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+
+      for (int i = 0; i < memCapLongs; i++) {
+        mem1.putLong(i * 8, i);
+      }
+      mem2.clear();
+
+      mem1.copyTo(0, mem2, 0, memCapacity);
+
+      for (int i = 0; i < memCapLongs; i++) {
+        assertEquals(mem2.getLong(i * 8), i);
+      }
+    }
+  }
+
+  @Test
+  public void checkCopyCrossNativeAndByteArray() throws Exception {
+    int memCapacity = 64;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem1 = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+
+      for (int i = 0; i < mem1.getCapacity(); i++) {
+        mem1.putByte(i, (byte) i);
+      }
+
+      WritableMemory mem2 = WritableMemory.allocate(memCapacity);
+      mem1.copyTo(8, mem2, 16, 16);
+
+      for (int i = 0; i < 16; i++) {
+        assertEquals(mem1.getByte(8 + i), mem2.getByte(16 + i));
+      }
+      //println(mem2.toHexString("Mem2", 0, (int)mem2.getCapacity()));
+    }
+  }
+
+  @Test
+  public void checkCopyCrossRegionsSameNative() throws Exception {
+    int memCapacity = 128;
+
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem1 = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+
+      for (int i = 0; i < mem1.getCapacity(); i++) {
+        mem1.putByte(i, (byte) i);
+      }
+      //println(mem1.toHexString("Mem1", 0, (int)mem1.getCapacity()));
+
+      Memory reg1 = mem1.region(8, 16);
+      //println(reg1.toHexString("Reg1", 0, (int)reg1.getCapacity()));
+
+      WritableMemory reg2 = mem1.writableRegion(24, 16);
+      //println(reg2.toHexString("Reg2", 0, (int)reg2.getCapacity()));
+      reg1.copyTo(0, reg2, 0, 16);
+
+      for (int i = 0; i < 16; i++) {
+        assertEquals(reg1.getByte(i), reg2.getByte(i));
+        assertEquals(mem1.getByte(8 + i), mem1.getByte(24 + i));
+      }
+      //println(mem1.toHexString("Mem1", 0, (int)mem1.getCapacity()));
+    }
+  }
+
+  @Test
+  public void checkCopyCrossNativeArrayAndHierarchicalRegions() throws Exception {
+    int memCapacity = 64;
+    try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+      WritableMemory mem1 = WritableMemory.allocateDirect(memCapacity, scope, memReqSvr);
+
+      for (int i = 0; i < mem1.getCapacity(); i++) { //fill with numbers
+        mem1.putByte(i, (byte) i);
+      }
+      //println(mem1.toHexString("Mem1", 0, (int)mem1.getCapacity()));
+
+      WritableMemory mem2 = WritableMemory.allocate(memCapacity);
+
+      Memory reg1 = mem1.region(8, 32);
+      Memory reg1B = reg1.region(8, 16);
+      //println(reg1.toHexString("Reg1", 0, (int)reg1.getCapacity()));
+      //println(reg1B.toHexString("Reg1B", 0, (int)reg1B.getCapacity()));
+
+      WritableMemory reg2 = mem2.writableRegion(32, 16);
+      reg1B.copyTo(0, reg2, 0, 16);
+      //println(reg2.toHexString("Reg2", 0, (int)reg2.getCapacity()));
+
+      //println(mem2.toHexString("Mem2", 0, (int)mem2.getCapacity()));
+      for (int i = 32, j = 16; i < 40; i++, j++) {
+        assertEquals(mem2.getByte(i), j);
+      }
+    }
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: " + this.getClass().getName());
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void println(String s) {
+    //System.out.println(s); //disable here
+  }
+
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/WritableMemoryTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/WritableMemoryTest.java
new file mode 100644
index 0000000..27981ba
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/WritableMemoryTest.java
@@ -0,0 +1,184 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.concurrent.ThreadLocalRandom;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+public class WritableMemoryTest {
+
+  @Test
+  public void wrapBigEndian() {
+    ByteBuffer bb = ByteBuffer.allocate(64); //big endian
+    WritableMemory wmem = WritableMemory.writableWrap(bb);
+    assertEquals(wmem.getByteOrder(), ByteOrder.LITTLE_ENDIAN); //ignore BB endianness
+    wmem = WritableMemory.writableWrap(bb, ByteOrder.nativeOrder(), BaseState.defaultMemReqSvr);
+    assertEquals(wmem.getByteOrder(), ByteOrder.LITTLE_ENDIAN);
+  }
+
+  @Test
+  public void wrapBigEndianAsLittle() {
+    ByteBuffer bb = ByteBuffer.allocate(64);
+    bb.putChar(0, (char)1); //as NNO
+    WritableMemory wmem = WritableMemory.writableWrap(bb, ByteOrder.LITTLE_ENDIAN, BaseState.defaultMemReqSvr);
+    assertEquals(wmem.getChar(0), 256);
+  }
+
+  @Test
+  public void allocateWithByteOrder() {
+    WritableMemory wmem = WritableMemory.allocate(64, ByteOrder.BIG_ENDIAN);
+    assertEquals(wmem.getByteOrder(), ByteOrder.BIG_ENDIAN);
+    wmem = WritableMemory.allocate(64, ByteOrder.LITTLE_ENDIAN);
+    assertEquals(wmem.getByteOrder(), ByteOrder.LITTLE_ENDIAN);
+    wmem = WritableMemory.writableWrap(new byte[64], 32, 32, ByteOrder.BIG_ENDIAN);
+    assertEquals(wmem.getByteOrder(), ByteOrder.BIG_ENDIAN);
+  }
+
+  @Test
+  public void checkSelfArrayCopy() {
+    byte[] srcAndDst = new byte[128];
+    WritableMemory wmem = WritableMemory.writableWrap(srcAndDst);
+    wmem.getByteArray(0, srcAndDst, 64, 64);  //non-overlapping
+  }
+
+  @Test
+  public void checkEquals() {
+    int len = 7;
+    WritableMemory wmem1 = WritableMemory.allocate(len);
+    //@SuppressWarnings({"EqualsWithItself", "SelfEquals"}) //unsupported
+    //SelfEquals for Plexus, EqualsWithItself for IntelliJ
+    //boolean eq1 = wmem1.equals(wmem1); //strict profile complains
+    //assertTrue(eq1);
+
+    WritableMemory wmem2 = WritableMemory.allocate(len + 1);
+    assertFalse(wmem1.equals(wmem2));
+
+    WritableMemory reg1 = wmem1.writableRegion(0, wmem1.getCapacity());
+    assertTrue(wmem1.equalTo(0, reg1, 0, wmem1.getCapacity()));
+
+    wmem2 = WritableMemory.allocate(len);
+    for (int i = 0; i < len; i++) {
+      wmem1.putByte(i, (byte) i);
+      wmem2.putByte(i, (byte) i);
+    }
+    assertTrue(wmem1.equalTo(0, wmem2, 0, len));
+    assertTrue(wmem1.equalTo(0, wmem1, 0, len));
+
+    reg1 = wmem1.writableRegion(0, wmem1.getCapacity());
+    assertTrue(wmem1.equalTo(0, reg1, 0, len));
+
+    len = 24;
+    wmem1 = WritableMemory.allocate(len);
+    wmem2 = WritableMemory.allocate(len);
+    for (int i = 0; i < len; i++) {
+      wmem1.putByte(i, (byte) i);
+      wmem2.putByte(i, (byte) i);
+    }
+    assertTrue(wmem1.equalTo(0, wmem2, 0, len - 1));
+    assertTrue(wmem1.equalTo(0, wmem2, 0, len));
+    wmem2.putByte(0, (byte) 10);
+    assertFalse(wmem1.equalTo(0, wmem2, 0, len));
+    wmem2.putByte(0, (byte) 0);
+    wmem2.putByte(len - 2, (byte) 0);
+    assertFalse(wmem1.equalTo(0, wmem2, 0, len - 1));
+  }
+
+  @Test
+  public void checkEquals2() {
+    int len = 23;
+    WritableMemory wmem1 = WritableMemory.allocate(len);
+    assertFalse(wmem1.equals(null));
+
+    WritableMemory wmem2 = WritableMemory.allocate(len + 1);
+    assertTrue(wmem1.equalTo(0, wmem2, 0, len));
+
+    for (int i = 0; i < len; i++) {
+      wmem1.putByte(i, (byte) i);
+      wmem2.putByte(i, (byte) i);
+    }
+    assertTrue(wmem1.equalTo(0, wmem2, 0, len));
+    assertTrue(wmem1.equalTo(1, wmem2, 1, len - 1));
+  }
+
+  @Test
+  public void checkLargeEquals() {
+    final int thresh = 1 << 20;
+    final int len = thresh * 2 + 7;
+    byte[] byteArr1 = new byte[len];
+    ThreadLocalRandom.current().nextBytes(byteArr1);
+    byte[] byteArr2 = byteArr1.clone();
+    Memory mem1 = Memory.wrap(byteArr1);
+    Memory mem2 = Memory.wrap(byteArr2);
+    assertTrue(mem1.equalTo(0, mem2, 0, len));
+
+    byteArr2[thresh + 10] = (byte) (byteArr1[thresh + 10] + 1);
+    assertFalse(mem1.equalTo(0, mem2, 0, len));
+
+    byteArr2[thresh + 10] = byteArr1[thresh + 10];
+    byteArr2[(thresh * 2) + 3] = (byte) (byteArr1[(thresh * 2) + 3] + 1);
+    assertFalse(mem1.equalTo(0,mem2, 0, len));
+  }
+
+  @Test
+  public void checkWrapWithBO() {
+    WritableMemory wmem = WritableMemory.writableWrap(new byte[0], ByteOrder.BIG_ENDIAN);
+    boolean nativeBO = wmem.getByteOrder() == ByteOrder.nativeOrder();
+    assertFalse(nativeBO);
+    println("" + nativeBO);
+    wmem = WritableMemory.writableWrap(new byte[8], ByteOrder.BIG_ENDIAN);
+    nativeBO = wmem.getByteOrder() == ByteOrder.nativeOrder();
+    assertFalse(nativeBO);
+    println("" + nativeBO);
+  }
+
+  @Test
+  @SuppressWarnings("unused")
+  public void checkOwnerClientCase() {
+    WritableMemory owner = WritableMemory.allocate(64);
+    Memory client1 = owner; //Client1 cannot write (no API)
+    owner.putInt(0, 1); //But owner can write
+    ((WritableMemory)client1).putInt(0, 2); //Client1 can write, but with explicit effort.
+    Memory client2 = owner.region(0, owner.getCapacity()); //client2 cannot write (no API)
+    owner.putInt(0, 3); //But Owner should be able to write
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void println(final String s) {
+    //System.out.println(s);
+  }
+
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/XxHash64LoopingTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/XxHash64LoopingTest.java
new file mode 100644
index 0000000..6fc4f81
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/XxHash64LoopingTest.java
@@ -0,0 +1,1082 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.testng.Assert.assertEquals;
+
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+/**
+ * @author Lee Rhodes
+ */
+public class XxHash64LoopingTest {
+
+  /*
+   * This test is adapted from
+   * <a href="https://github.com/OpenHFT/Zero-Allocation-Hashing/blob/master/src/test/java/net/openhft/hashing/XxHashTest.java">
+   * OpenHFT/Zero-Allocation-Hashing</a> to test hash compatibility with that implementation.
+   * See LICENSE.
+   */
+  @Test
+  public void testWithSeed() {
+    long seed = 42L;
+    for (int i = 0; i < 1025; i++) {
+      byte[] byteArr = new byte[i];
+      for (int j = 0; j < byteArr.length; j++) { byteArr[j] = (byte) j; }
+      WritableMemory wmem = WritableMemory.writableWrap(byteArr);
+      long hash = wmem.xxHash64(0, byteArr.length, seed);
+      assertEquals(hash, HASHES_OF_LOOPING_BYTES_WITH_SEED_42[i]);
+    }
+  }
+
+  /*This data is from
+   * <a href="https://github.com/OpenHFT/Zero-Allocation-Hashing/blob/master/src/test/java/net/openhft/hashing/XxHashTest.java">
+   * OpenHFT/Zero-Allocation-Hashing</a> to test hash compatibility with that implementation.
+   * See LICENSE.
+   */
+  private static final long[] HASHES_OF_LOOPING_BYTES_WITH_SEED_42 = {
+    -7444071767201028348L,
+    -8959994473701255385L,
+    7116559933691734543L,
+    6019482000716350659L,
+    -6625277557348586272L,
+    -5507563483608914162L,
+    1540412690865189709L,
+    4522324563441226749L,
+    -7143238906056518746L,
+    -7989831429045113014L,
+    -7103973673268129917L,
+    -2319060423616348937L,
+    -7576144055863289344L,
+    -8903544572546912743L,
+    6376815151655939880L,
+    5913754614426879871L,
+    6466567997237536608L,
+    -869838547529805462L,
+    -2416009472486582019L,
+    -3059673981515537339L,
+    4211239092494362041L,
+    1414635639471257331L,
+    166863084165354636L,
+    -3761330575439628223L,
+    3524931906845391329L,
+    6070229753198168844L,
+    -3740381894759773016L,
+    -1268276809699008557L,
+    1518581707938531581L,
+    7988048690914090770L,
+    -4510281763783422346L,
+    -8988936099728967847L,
+    -8644129751861931918L,
+    2046936095001747419L,
+    339737284852751748L,
+    -8493525091666023417L,
+    -3962890767051635164L,
+    -5799948707353228709L,
+    -6503577434416464161L,
+    7718729912902936653L,
+    191197390694726650L,
+    -2677870679247057207L,
+    20411540801847004L,
+    2738354376741059902L,
+    -3754251900675510347L,
+    -3208495075154651980L,
+    5505877218642938179L,
+    6710910171520780908L,
+    -9060809096139575515L,
+    6936438027860748388L,
+    -6675099569841255629L,
+    -5358120966884144380L,
+    -4970515091611332076L,
+    -1810965683604454696L,
+    -516197887510505242L,
+    1240864593087756274L,
+    6033499571835033332L,
+    7223146028771530185L,
+    909128106589125206L,
+    1567720774747329341L,
+    -1867353301780159863L,
+    4655107429511759333L,
+    5356891185236995950L,
+    182631115370802890L,
+    -3582744155969569138L,
+    595148673029792797L,
+    495183136068540256L,
+    5536689004903505647L,
+    -8472683670935785889L,
+    -4335021702965928166L,
+    7306662983232020244L,
+    4285260837125010956L,
+    8288813008819191181L,
+    -3442351913745287612L,
+    4883297703151707194L,
+    9135546183059994964L,
+    123663780425483012L,
+    509606241253238381L,
+    5940344208569311369L,
+    -2650142344608291176L,
+    3232776678942440459L,
+    -922581627593772181L,
+    7617977317085633049L,
+    7154902266379028518L,
+    -5806388675416795571L,
+    4368003766009575737L,
+    -2922716024457242064L,
+    4771160713173250118L,
+    3275897444752647349L,
+    -297220751499763878L,
+    5095659287766176401L,
+    1181843887132908826L,
+    9058283605301070357L,
+    3984713963471276643L,
+    6050484112980480005L,
+    1551535065359244224L,
+    565337293533335618L,
+    7412521035272884309L,
+    -4735469481351389369L,
+    6998597101178745656L,
+    -9107075101236275961L,
+    5879828914430779796L,
+    6034964979406620806L,
+    5666406915264701514L,
+    -4666218379625258428L,
+    2749972203764815656L,
+    -782986256139071446L,
+    6830581400521008570L,
+    2588852022632995043L,
+    -5484725487363818922L,
+    -3319556935687817112L,
+    6481961252981840893L,
+    2204492445852963006L,
+    -5301091763401031066L,
+    -2615065677047206256L,
+    -6769817545131782460L,
+    -8421640685322953142L,
+    -3669062629317949176L,
+    -9167016978640750490L,
+    2783671191687959562L,
+    -7599469568522039782L,
+    -7589134103255480011L,
+    -5932706841188717592L,
+    -8689756354284562694L,
+    -3934347391198581249L,
+    -1344748563236040701L,
+    2172701592984478834L,
+    -5322052340624064417L,
+    -8493945390573620511L,
+    3349021988137788403L,
+    -1806262525300459538L,
+    -8091524448239736618L,
+    4022306289903960690L,
+    -8346915997379834224L,
+    -2106001381993805461L,
+    -5784123934724688161L,
+    6775158099649720388L,
+    -3869682756870293568L,
+    4356490186652082006L,
+    8469371446702290916L,
+    -2972961082318458602L,
+    -7188106622222784561L,
+    -4961006366631572412L,
+    3199991182014172900L,
+    2917435868590434179L,
+    8385845305547872127L,
+    7706824402560674655L,
+    -1587379863634865277L,
+    -4212156212298809650L,
+    -1305209322000720233L,
+    -7866728337506665880L,
+    8195089740529247049L,
+    -4876930125798534239L,
+    798222697981617129L,
+    -2441020897729372845L,
+    -3926158482651178666L,
+    -1254795122048514130L,
+    5192463866522217407L,
+    -5426289318796042964L,
+    -3267454004443530826L,
+    471043133625225785L,
+    -660956397365869974L,
+    -6149209189144999161L,
+    -2630977660039166559L,
+    8512219789663151219L,
+    -3309844068134074620L,
+    -6211275327487847132L,
+    -2130171729366885995L,
+    6569302074205462321L,
+    4855778342281619706L,
+    3867211421508653033L,
+    -3002480002418725542L,
+    -8297543107467502696L,
+    8049642289208775831L,
+    -5439825716055425635L,
+    7251760070798756432L,
+    -4774526021749797528L,
+    -3892389575184442548L,
+    5162451061244344424L,
+    6000530226398686578L,
+    -5713092252241819676L,
+    8740913206879606081L,
+    -8693282419677309723L,
+    1576205127972543824L,
+    5760354502610401246L,
+    3173225529903529385L,
+    1785166236732849743L,
+    -1024443476832068882L,
+    -7389053248306187459L,
+    1171021620017782166L,
+    1471572212217428724L,
+    7720766400407679932L,
+    -8844781213239282804L,
+    -7030159830170200877L,
+    2195066352895261150L,
+    1343620937208608634L,
+    9178233160016731645L,
+    -757883447602665223L,
+    3303032934975960867L,
+    -3685775162104101116L,
+    -4454903657585596656L,
+    -5721532367620482629L,
+    8453227136542829644L,
+    5397498317904798888L,
+    7820279586106842836L,
+    -2369852356421022546L,
+    3910437403657116169L,
+    6072677490463894877L,
+    -2651044781586183960L,
+    5173762670440434510L,
+    -2970017317595590978L,
+    -1024698859439768763L,
+    -3098335260967738522L,
+    -1983156467650050768L,
+    -8132353894276010246L,
+    -1088647368768943835L,
+    -3942884234250555927L,
+    7169967005748210436L,
+    2870913702735953746L,
+    -2207022373847083021L,
+    1104181306093040609L,
+    5026420573696578749L,
+    -5874879996794598513L,
+    -4777071762424874671L,
+    -7506667858329720470L,
+    -2926679936584725232L,
+    -5530649174168373609L,
+    5282408526788020384L,
+    3589529249264153135L,
+    -6220724706210580398L,
+    -7141769650716479812L,
+    5142537361821482047L,
+    -7029808662366864423L,
+    -6593520217660744466L,
+    1454581737122410695L,
+    -139542971769349865L,
+    1727752089112067235L,
+    -775001449688420017L,
+    -5011311035350652032L,
+    -8671171179275033159L,
+    -2850915129917664667L,
+    -5258897903906998781L,
+    -6954153088230718761L,
+    -4070351752166223959L,
+    -6902592976462171099L,
+    -7850366369290661391L,
+    -4562443925864904705L,
+    3186922928616271015L,
+    2208521081203400591L,
+    -2727824999830592777L,
+    -3817861137262331295L,
+    2236720618756809066L,
+    -4888946967413746075L,
+    -446884183491477687L,
+    -43021963625359034L,
+    -5857689226703189898L,
+    -2156533592262354883L,
+    -2027655907961967077L,
+    7151844076490292500L,
+    -5029149124756905464L,
+    526404452686156976L,
+    8741076980297445408L,
+    7962851518384256467L,
+    -105985852299572102L,
+    -2614605270539434398L,
+    -8265006689379110448L,
+    8158561071761524496L,
+    -6923530157382047308L,
+    5551949335037580397L,
+    565709346370307061L,
+    -4780869469938333359L,
+    6931895917517004830L,
+    565234767538051407L,
+    -8663136372880869656L,
+    1427340323685448983L,
+    6492705666640232290L,
+    1481585578088475369L,
+    -1712711110946325531L,
+    3281685342714380741L,
+    6441384790483098576L,
+    -1073539554682358394L,
+    5704050067194788964L,
+    -5495724689443043319L,
+    -5425043165837577535L,
+    8349736730194941321L,
+    -4123620508872850061L,
+    4687874980541143573L,
+    -468891940172550975L,
+    -3212254545038049829L,
+    -6830802881920725628L,
+    9033050533972480988L,
+    4204031879107709260L,
+    -677513987701096310L,
+    -3286978557209370155L,
+    1644111582609113135L,
+    2040089403280131741L,
+    3323690950628902653L,
+    -7686964480987925756L,
+    -4664519769497402737L,
+    3358384147145476542L,
+    -4699919744264452277L,
+    -4795197464927839170L,
+    5051607253379734527L,
+    -8987703459734976898L,
+    8993686795574431834L,
+    -2688919474688811047L,
+    375938183536293311L,
+    1049459889197081920L,
+    -1213022037395838295L,
+    4932989235110984138L,
+    -6647247877090282452L,
+    -7698817539128166242L,
+    -3264029336002462659L,
+    6487828018122309795L,
+    -2660821091484592878L,
+    7104391069028909121L,
+    -1765840012354703384L,
+    85428166783788931L,
+    -6732726318028261938L,
+    7566202549055682933L,
+    229664898114413280L,
+    -1474237851782211353L,
+    -1571058880058007603L,
+    -7926453582850712144L,
+    2487148368914275243L,
+    8740031015380673473L,
+    1908345726881363169L,
+    -2510061320536523178L,
+    7854780026906019630L,
+    -6023415596650016493L,
+    -6264841978089051107L,
+    4024998278016087488L,
+    -4266288992025826072L,
+    -3222176619422665563L,
+    -1999258726038299316L,
+    1715270077442385636L,
+    6764658837948099754L,
+    -8646962299105812577L,
+    -51484064212171546L,
+    -1482515279051057493L,
+    -8663965522608868414L,
+    -256555202123523670L,
+    1973279596140303801L,
+    -7280796173024508575L,
+    -5691760367231354704L,
+    -5915786562256300861L,
+    -3697715074906156565L,
+    3710290115318541949L,
+    6796151623958134374L,
+    -935299482515386356L,
+    -7078378973978660385L,
+    5379481350768846927L,
+    -9011221735308556302L,
+    5936568631579608418L,
+    -6060732654964511813L,
+    -4243141607840017809L,
+    3198488845875349355L,
+    -7809288876010447646L,
+    4371587872421472389L,
+    -1304197371105522943L,
+    7389861473143460103L,
+    -1892352887992004024L,
+    2214828764044713398L,
+    6347546952883613388L,
+    1275694314105480954L,
+    -5262663163358903733L,
+    1524757505892047607L,
+    1474285098416162746L,
+    -7976447341881911786L,
+    4014100291977623265L,
+    8994982266451461043L,
+    -7737118961020539453L,
+    -2303955536994331092L,
+    1383016539349937136L,
+    1771516393548245271L,
+    -5441914919967503849L,
+    5449813464890411403L,
+    -3321280356474552496L,
+    4084073849712624363L,
+    4290039323210935932L,
+    2449523715173349652L,
+    7494827882138362156L,
+    9035007221503623051L,
+    5722056230130603177L,
+    -5443061851556843748L,
+    -7554957764207092109L,
+    447883090204372074L,
+    533916651576859197L,
+    -3104765246501904165L,
+    -4002281505194601516L,
+    -8402008431255610992L,
+    -408273018037005304L,
+    214196458752109430L,
+    6458513309998070914L,
+    2665048360156607904L,
+    96698248584467992L,
+    -3238403026096269033L,
+    6759639479763272920L,
+    -4231971627796170796L,
+    -2149574977639731179L,
+    -1437035755788460036L,
+    -6000005629185669767L,
+    145244292800946348L,
+    -3056352941404947199L,
+    3748284277779018970L,
+    7328354565489106580L,
+    -2176895260373660284L,
+    3077983936372755601L,
+    1215485830019410079L,
+    683050801367331140L,
+    -3173237622987755212L,
+    -1951990779107873701L,
+    -4714366021269652421L,
+    4934690664256059008L,
+    1674823104333774474L,
+    -3974408282362828040L,
+    2001478896492417760L,
+    -4115105568354384199L,
+    -2039694725495941666L,
+    -587763432329933431L,
+    -391276713546911316L,
+    -5543400904809469053L,
+    1882564440421402418L,
+    -4991793588968693036L,
+    3454088185914578321L,
+    2290855447126188424L,
+    3027910585026909453L,
+    2136873580213167431L,
+    -6243562989966916730L,
+    5887939953208193029L,
+    -3491821629467655741L,
+    -3138303216306660662L,
+    8572629205737718669L,
+    4154439973110146459L,
+    5542921963475106759L,
+    -2025215496720103521L,
+    -4047933760493641640L,
+    -169455456138383823L,
+    -1164572689128024473L,
+    -8551078127234162906L,
+    -7247713218016599028L,
+    8725299775220778242L,
+    6263466461599623132L,
+    7931568057263751768L,
+    7365493014712655238L,
+    -7343740914722477108L,
+    8294118602089088477L,
+    7677867223984211483L,
+    -7052188421655969232L,
+    -3739992520633991431L,
+    772835781531324307L,
+    881441588914692737L,
+    6321450879891466401L,
+    5682516032668315027L,
+    8493068269270840662L,
+    -3895212467022280567L,
+    -3241911302335746277L,
+    -7199586338775635848L,
+    -4606922569968527974L,
+    -806850906331637768L,
+    2433670352784844513L,
+    -5787982146811444512L,
+    7852193425348711165L,
+    8669396209073850051L,
+    -6898875695148963118L,
+    6523939610287206782L,
+    -8084962379210153174L,
+    8159432443823995836L,
+    -2631068535470883494L,
+    -338649779993793113L,
+    6514650029997052016L,
+    3926259678521802094L,
+    5443275905907218528L,
+    7312187582713433551L,
+    -2993773587362997676L,
+    -1068335949405953411L,
+    4499730398606216151L,
+    8538015793827433712L,
+    -4057209365270423575L,
+    -1504284818438273559L,
+    -6460688570035010846L,
+    1765077117408991117L,
+    8278320303525164177L,
+    8510128922449361533L,
+    1305722765578569816L,
+    7250861238779078656L,
+    -576624504295396147L,
+    -4363714566147521011L,
+    -5932111494795524073L,
+    1837387625936544674L,
+    -4186755953373944712L,
+    -7657073597826358867L,
+    140408487263951108L,
+    5578463635002659628L,
+    3400326044813475885L,
+    -6092804808386714986L,
+    -2410324417287268694L,
+    3222007930183458970L,
+    4932471983280850419L,
+    3554114546976144528L,
+    -7216067928362857082L,
+    -6115289896923351748L,
+    -6769646077108881947L,
+    4263895947722578066L,
+    2939136721007694271L,
+    1426030606447416658L,
+    -1316192446807442076L,
+    5366182640480055129L,
+    6527003877470258527L,
+    5849680119000207603L,
+    5263993237214222328L,
+    -6936533648789185663L,
+    -9063642143790846605L,
+    3795892210758087672L,
+    4987213125282940176L,
+    2505500970421590750L,
+    -1014022559552365387L,
+    -3574736245968367770L,
+    1180676507127340259L,
+    -2261908445207512503L,
+    -8416682633172243509L,
+    1114990703652673283L,
+    7753746660364401380L,
+    1874908722469707905L,
+    2033421444403047677L,
+    21412168602505589L,
+    385957952615286205L,
+    2053171460074727107L,
+    1915131899400103774L,
+    6680879515029368390L,
+    568807208929724162L,
+    -6211541450459087674L,
+    -5026690733412145448L,
+    1384781941404886235L,
+    -98027820852587266L,
+    1806580495924249669L,
+    6322077317403503963L,
+    9078162931419569939L,
+    -2809061215428363978L,
+    7697867577577415733L,
+    -5270063855897737274L,
+    5649864555290587388L,
+    -6970990547695444247L,
+    579684606137331754L,
+    3871931565451195154L,
+    2030008578322050218L,
+    -5012357307111799829L,
+    -2271365921756144065L,
+    4551962665158074190L,
+    -3385474923040271312L,
+    -7647625164191633577L,
+    6634635380316963029L,
+    -5201190933687061585L,
+    8864818738548593973L,
+    2855828214210882907L,
+    9154512990734024165L,
+    -6945306719789457786L,
+    1200243352799481087L,
+    875998327415853787L,
+    1275313054449881011L,
+    -6105772045375948736L,
+    -2926927684328291437L,
+    9200050852144954779L,
+    5188726645765880663L,
+    5197037323312705176L,
+    3434926231010121611L,
+    -5054013669361906544L,
+    2582959199749224670L,
+    -6053757512723474059L,
+    -5016308176846054473L,
+    -2509827316698626133L,
+    7700343644503853204L,
+    -1997627249894596731L,
+    3993168688325352290L,
+    -8181743677541277704L,
+    3719056119682565597L,
+    -7264411659282947790L,
+    7177028972346484464L,
+    -5460831176884283278L,
+    1799904662416293978L,
+    -6549616005092764514L,
+    5472403994001122052L,
+    8683463751708388502L,
+    -7873363037838316398L,
+    689134758256487260L,
+    -1287443614028696450L,
+    4452712919702709507L,
+    762909374167538893L,
+    6594302592326281411L,
+    1183786629674781984L,
+    5021847859620133476L,
+    -2490098069181538915L,
+    5105145136026716679L,
+    4437836948098585718L,
+    1987270426215858862L,
+    6170312798826946249L,
+    634297557126003407L,
+    -1672811625495999581L,
+    6282971595586218191L,
+    4549149305727581687L,
+    -5652165370435317782L,
+    1064501550023753890L,
+    -5334885527127139723L,
+    -6904378001629481237L,
+    -1807576691784201230L,
+    -205688432992053911L,
+    7621619053293393289L,
+    6258649161313982470L,
+    -1111634238359342096L,
+    -8044260779481691987L,
+    400270655839010807L,
+    -7806833581382890725L,
+    -2970563349459508036L,
+    -7392591524816802798L,
+    2918924613160219805L,
+    -6444161627929149002L,
+    6096497501321778876L,
+    -1477975665655830038L,
+    1690651307597306138L,
+    -2364076888826085362L,
+    -6521987420014905821L,
+    -4419193480146960582L,
+    3538587780233092477L,
+    8374665961716940404L,
+    7492412312405424500L,
+    6311662249091276767L,
+    -1240235198282023566L,
+    5478559631401166447L,
+    3476714419313462133L,
+    377427285984503784L,
+    2570472638778991109L,
+    -2741381313777447835L,
+    -7123472905503039596L,
+    2493658686946955193L,
+    1024677789035847585L,
+    -2916713904339582981L,
+    -4532003852004642304L,
+    -2202143560366234111L,
+    5832267856442755135L,
+    -261740607772957384L,
+    239435959690278014L,
+    5755548341947719409L,
+    6138795458221887696L,
+    -7709506987360146385L,
+    -6657487758065140444L,
+    -7006376793203657499L,
+    6544409861846502033L,
+    3171929352014159247L,
+    1051041925048792869L,
+    2617300158375649749L,
+    952652799620095175L,
+    -576661730162168147L,
+    -1634191369221345988L,
+    4833656816115993519L,
+    647566759700005786L,
+    2473810683785291822L,
+    3005977181064745326L,
+    -3321881966853149523L,
+    7595337666427588699L,
+    6004093624251057224L,
+    -563917505657690279L,
+    6117428527147449302L,
+    -6287297509522976113L,
+    -4527219334756214406L,
+    742626429298092489L,
+    3057351806086972041L,
+    645967551210272605L,
+    -4428701157828864227L,
+    3236379103879435414L,
+    -8477089892132066300L,
+    -6127365537275859058L,
+    -4052490484706946358L,
+    -8004854976625046469L,
+    -3679456917426613424L,
+    -8212793762082595299L,
+    -818288739465424130L,
+    1358812099481667095L,
+    7835987612195254310L,
+    -3663247409614323059L,
+    -2931105150130396604L,
+    7296136776835614792L,
+    -2014557408985889628L,
+    7267662411237959788L,
+    3699280615819277743L,
+    -212010675469091396L,
+    -6518374332458360120L,
+    145026010541628849L,
+    1879297324213501001L,
+    -7146296067751816833L,
+    -5002958800391379931L,
+    6060682439924517608L,
+    -432234782921170964L,
+    -6669688947353256956L,
+    7728943532792041267L,
+    830911367341171721L,
+    3396934884314289432L,
+    -779464156662780749L,
+    2330041851883352285L,
+    -4783350380736276693L,
+    -5758476056890049254L,
+    -7551552301614791791L,
+    1253334187723911710L,
+    -2685018208308798978L,
+    5379636036360946454L,
+    6154668487114681217L,
+    -8641287462255458898L,
+    4676087643800649558L,
+    -2405142641398691475L,
+    1088685126864246881L,
+    6431149082338374041L,
+    -607357695335069155L,
+    -720970692129524140L,
+    2648766932394044468L,
+    8408344790179354573L,
+    -6193808387735667350L,
+    7722524628524697419L,
+    -6975433852560238120L,
+    -2925851029234475295L,
+    -4274458387165211028L,
+    -8355836377702147319L,
+    5278146397877332061L,
+    8502098812383680707L,
+    2292836642336580326L,
+    -6127608082651070062L,
+    2222301962240611208L,
+    -1930887695854799378L,
+    7640503480494894592L,
+    1162652186586436094L,
+    -1918002592943761683L,
+    7648998601717261840L,
+    -8472603250832757057L,
+    -988877663117552456L,
+    2368458128168026494L,
+    -6480813811998475245L,
+    -5896967824416018967L,
+    -2593783161701820446L,
+    6950098417530252598L,
+    6362589545555771236L,
+    7981389665448567125L,
+    3954017080198558850L,
+    1626078615050230622L,
+    6650159066527969109L,
+    697345338922935394L,
+    -1226816215461768626L,
+    8740408765973837440L,
+    -4194155864629568323L,
+    7016680023232424746L,
+    6043281358142429469L,
+    -4201005667174376809L,
+    1216727117859013155L,
+    6367202436544203935L,
+    35414869396444636L,
+    3715622794033998412L,
+    488654435687670554L,
+    -2503747297224687460L,
+    3147101919441470388L,
+    -8248611218693190922L,
+    970697264481229955L,
+    3411465763826851418L,
+    9117405004661599969L,
+    -5204346498331519734L,
+    -19637460819385174L,
+    -5039124225167977219L,
+    2990108874601696668L,
+    -2623857460235459202L,
+    4256291692861397446L,
+    6724147860870760443L,
+    3558616688507246537L,
+    6487680097936412800L,
+    -6470792832935928161L,
+    4314814550912237614L,
+    -1292878983006062345L,
+    6791915152630414174L,
+    5971652079925815310L,
+    2557529546662864312L,
+    466175054322801580L,
+    -585216717310746872L,
+    -2486640422147349036L,
+    7212029603994220134L,
+    3958995069888972500L,
+    4950471855791412790L,
+    -3721948842035712763L,
+    -6184503487488243051L,
+    4079570444585775332L,
+    -3952156172546996872L,
+    4543894231118208322L,
+    -1739995588466209963L,
+    9155948355455935530L,
+    5821980345462207860L,
+    -2431287667309520417L,
+    -3890108130519441316L,
+    -558124689277030490L,
+    6079823537335801717L,
+    5409742395192364262L,
+    -2329885777717160453L,
+    -7332804342513677651L,
+    1466490574975950555L,
+    -420549419907427929L,
+    -5249909814389692516L,
+    -5145692168206210661L,
+    5934113980649113921L,
+    3241618428555359661L,
+    -6622110266160980250L,
+    5048250878669516223L,
+    5747219637359976174L,
+    2975906212588223728L,
+    5730216838646273215L,
+    -176713127129024690L,
+    6734624279336671146L,
+    5127866734316017180L,
+    7111761230887705595L,
+    3457811808274317235L,
+    3362961434604932375L,
+    -1877869936854991246L,
+    7171428594877765665L,
+    -8252167178400462374L,
+    -6306888185035821047L,
+    -6684702191247683887L,
+    -7754928454824190529L,
+    -1902605599135704386L,
+    -4037319846689421239L,
+    8493746058123583457L,
+    -8156648963857047193L,
+    2051510355149839497L,
+    -1256416624177218909L,
+    -3344927996254072010L,
+    -1838853051925943568L,
+    316927471680974556L,
+    -1502257066700798003L,
+    -5836095610125837606L,
+    -1594125583615895424L,
+    1442211486559637962L,
+    -144295071206619569L,
+    5159850900959273410L,
+    4589139881166423678L,
+    -7038726987463097509L,
+    2886082400772974595L,
+    2780759114707171916L,
+    5694649587906297495L,
+    1260349041268169667L,
+    4921517488271434890L,
+    644696475796073018L,
+    6262811963753436289L,
+    -6128198676595868773L,
+    -3625352083004760261L,
+    -8751453332943236675L,
+    8749249479868749221L,
+    -2450808199545048250L,
+    -6517435817046180917L,
+    -3433321727429234998L,
+    -2591586258908763451L,
+    3847750870868804507L,
+    6603614438546398643L,
+    -7598682191291031287L,
+    8710261565627204971L,
+    4753389483755344355L,
+    -4645333069458786881L,
+    -6742695046613492214L,
+    643070478568866643L,
+    -7543096104151965610L,
+    7171495384655926161L,
+    595063872610714431L,
+    3292310150781130424L,
+    4326847806055440904L,
+    -4580020566072794152L,
+    3142286571820373678L,
+    5530356537440155930L,
+    546372639737516181L,
+    7401214477400367500L,
+    7406531960402873109L,
+    3287639667219172570L,
+    4977301681213633671L,
+    5253257820925174498L,
+    2906216636104297878L,
+    6142955758238347523L,
+    -3498651268741727235L,
+    -5875053958265588593L,
+    3896719087169993883L,
+    -910904726885775073L,
+    380107493197368177L,
+    -4993591912695447004L,
+    2970487257212582761L,
+    2551762717569548774L,
+    953061649962736812L,
+    8949739538606589463L,
+    -2962839167079475801L,
+    -1375673191272573835L,
+    3761793818361866390L,
+    -389577789190726878L,
+    5661262051502180269L,
+    -6558556411143987683L,
+    -702798336372315031L,
+    -336662820551371779L,
+    998576401126580155L,
+    -5945021269112582755L,
+    6108533925730179871L,
+    2207095297001999618L,
+    -9042779159998880435L,
+    -6177868444342118372L,
+    6775965402605895077L,
+    -3788428885163306576L,
+    7790055010527190387L,
+    3581587652196995358L,
+    -6176354155561607694L,
+    -5859381340906321207L,
+    395898765763528395L,
+    8132967590863909348L,
+    -3329092504090544483L,
+    -6785855381158040247L,
+    1497218517051796750L,
+    -5352392845588925911L,
+    -6271364901230559194L,
+    2314830370653350118L,
+    -7617588269001325450L,
+    1423166885758213795L,
+    8538612578307869519L,
+    -61918791718295474L,
+    -8177103503192338593L,
+    -4740086042584326695L,
+    3677931948215558698L,
+    6558856291580149558L,
+    2674975452453336335L,
+    5133796555646930522L,
+    5139252693299337100L,
+    7949476871295347205L,
+    4407815324662880678L,
+    -3758305875280581215L,
+    6066309507576587415L,
+    -7368508486398350973L,
+    -3181640264332856492L,
+    6905100869343314145L,
+    3677177673848733417L,
+    8862933624870506941L,
+    -8575223195813810568L,
+    9178470351355678144L,
+    4677809017145408358L,
+    -1194833416287894989L,
+    3436364743255571183L,
+    -5204770725795363579L,
+    560599448536335263L,
+    -3192077522964776200L,
+    -751575299648803575L,
+    6334581746534596579L,
+    -8358187891202563300L,
+    -1462480609823525055L,
+    5605961062646987941L,
+    4968399805931440889L,
+    7968693270782626653L,
+    -5868205923557518188L,
+    1830234928743560617L,
+    -8435261076693154407L,
+    2138416970728681332L,
+    8088740745199685138L,
+    806532400344230520L,
+    1800590379902909333L,
+    -8909128842071238901L,
+    -7357495566969170860L,
+    3679766664126940553L,
+    2060050474865839094L,
+    2363972840121763414L,
+    525695004292982714L,
+    -1224842191746529593L,
+    7011317848855545003L,
+    -6337167558180299938L,
+    -5184688833363785939L,
+    -8426673387248359061L,
+    -5035438815930785229L,
+    3521810320608058994L,
+    4803742557254962242L,
+    6623527039545786598L,
+    -1221475882122634738L,
+    -3344794405518401087L,
+    6510298498414053658L,
+    2844753907937720338L,
+    90502309714994895L,
+    -750403235344282494L,
+    -4825474181021465833L,
+    -3405519947983849510L,
+    3503875590944089793L,
+    7286294700691822468L,
+    7828126881500292486L,
+    8437899353709338096L,
+    136052254470293480L,
+    1113259077339995086L,
+    -8244887265606191121L,
+    8089569503800461649L,
+    -1429698194850157567L,
+    1575595674002364989L,
+    3576095286627428675L,
+    -7653655285807569222L,
+    -6053506977362539111L,
+    -3923855345805787169L,
+    -8001149080454232377L,
+    -4382867706931832271L,
+    4212860258835896297L,
+    4207674254247034014L,
+    5519424058779519159L,
+    -754483042161434654L,
+    1434113479814210082L,
+    -6416645032698336896L,
+    5624329676066514819L,
+    -8229557208322175959L,
+    3922640911653270376L,
+    7826932478782081910L,
+    -4862787164488635842L,
+    1449234668827944573L,
+    -1781657689570106327L,
+    5442827552725289699L,
+    3589862161007644641L,
+    4787115581650652778L,
+    -3512152721942525726L,
+    -6750103117958685206L,
+    5012970446659949261L,
+    6797752795961689017L,
+    5086454597639943700L,
+    -7616068364979994076L,
+    1492846825433110217L,
+    2967476304433704510L,
+    -8413824338284112078L,
+    -1319049442043273974L,
+    -1756090916806844109L,
+    -9061091728950139525L,
+    -6864767830358160810L,
+    4879532090226251157L,
+    5528644708740739488L
+  };
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/XxHash64Test.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/XxHash64Test.java
new file mode 100644
index 0000000..81a682a
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/XxHash64Test.java
@@ -0,0 +1,179 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.apache.datasketches.memory.XxHash.*;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+import net.openhft.hashing.LongHashFunction;
+
+/**
+ * @author Lee Rhodes
+ */
+public class XxHash64Test {
+
+  @Test
+  public void offsetChecks() {
+    long seed = 12345;
+    int blocks = 6;
+    int cap = blocks * 16;
+
+    long hash;
+
+    WritableMemory wmem = WritableMemory.allocate(cap);
+    for (int i = 0; i < cap; i++) { wmem.putByte(i, (byte)(-128 + i)); }
+
+    for (int offset = 0; offset < 16; offset++) {
+      int arrLen = cap - offset;
+      hash = wmem.xxHash64(offset, arrLen, seed);
+      assertTrue(hash != 0);
+    }
+  }
+
+  @Test
+  public void byteArrChecks() {
+    long seed = 0;
+    int offset = 0;
+    int bytes = 16;
+
+    for (int j = 1; j < bytes; j++) {
+      byte[] in = new byte[bytes];
+
+      WritableMemory wmem = WritableMemory.writableWrap(in);
+      for (int i = 0; i < j; i++) { wmem.putByte(i, (byte) (-128 + i)); }
+
+      long hash =wmem.xxHash64(offset, bytes, seed);
+      assertTrue(hash != 0);
+    }
+  }
+
+  /*
+   * This test is adapted from
+   * <a href="https://github.com/OpenHFT/Zero-Allocation-Hashing/blob/master/
+   * src/test/java/net/openhft/hashing/XxHashCollisionTest.java">
+   * OpenHFT/Zero-Allocation-Hashing</a> to test hash compatibility with that implementation.
+   * It is licensed under Apache License, version 2.0. See LICENSE.
+   */
+  @Test
+  public void collisionTest() {
+    WritableMemory wmem = WritableMemory.allocate(128);
+    wmem.putLong(0, 1);
+    wmem.putLong(16, 42);
+    wmem.putLong(32, 2);
+    long h1 = wmem.xxHash64(0, wmem.getCapacity(), 0);
+
+    wmem.putLong(0, 1L + 0xBA79078168D4BAFL);
+    wmem.putLong(32, 2L + 0x9C90005B80000000L);
+    long h2 = wmem.xxHash64(0, wmem.getCapacity(), 0);
+    assertEquals(h1, h2);
+
+    wmem.putLong(0, 1L + (0xBA79078168D4BAFL * 2));
+    wmem.putLong(32, 2L + (0x392000b700000000L)); //= (0x9C90005B80000000L * 2) fix overflow false pos
+
+    long h3 = wmem.xxHash64(0, wmem.getCapacity(), 0);
+    assertEquals(h2, h3);
+  }
+
+  /**
+   * This simple test compares the output of {@link BaseState#xxHash64(long, long, long)} with the
+   * output of {@link net.openhft.hashing.LongHashFunction}, that itself is tested against the
+   * reference implementation in C.  This increases confidence that the xxHash function implemented
+   * in this package is in fact the same xxHash function implemented in C.
+   *
+   * @author Roman Leventov
+   * @author Lee Rhodes
+   */
+  @Test
+  public void testXxHash() {
+    Random random = ThreadLocalRandom.current();
+    for (int len = 0; len < 100; len++) {
+      byte[] bytes = new byte[len];
+      for (int i = 0; i < 10; i++) {
+        long zahXxHash = LongHashFunction.xx().hashBytes(bytes);
+        long memoryXxHash = Memory.wrap(bytes).xxHash64(0, len, 0);
+        assertEquals(memoryXxHash, zahXxHash);
+        random.nextBytes(bytes);
+      }
+    }
+  }
+
+  private static final byte[] barr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+
+  @Test
+  public void testArrHashes() {
+    WritableMemory wmem = WritableMemory.writableWrap(barr);
+    long hash0 = wmem.xxHash64(8, 8, 0);
+    long hash1 = hashByteArr(barr, 8, 8, 0);
+    assertEquals(hash1, hash0);
+
+    char[] carr = new char[8];
+    wmem.getCharArray(0, carr, 0, 8);
+    hash1 = hashCharArr(carr, 4, 4, 0);
+    assertEquals(hash1, hash0);
+
+    short[] sarr = new short[8];
+    wmem.getShortArray(0, sarr, 0, 8);
+    hash1 = hashShortArr(sarr, 4, 4, 0);
+    assertEquals(hash1, hash0);
+
+    int[] iarr = new int[4];
+    wmem.getIntArray(0, iarr, 0, 4);
+    hash1 = hashIntArr(iarr, 2, 2, 0);
+    assertEquals(hash1, hash0);
+
+    float[] farr = new float[4];
+    wmem.getFloatArray(0, farr, 0, 4);
+    hash1 = hashFloatArr(farr, 2, 2, 0);
+    assertEquals(hash1, hash0);
+
+    long[] larr = new long[2];
+    wmem.getLongArray(0, larr, 0, 2);
+    hash1 = hashLongArr(larr, 1, 1, 0);
+    long in = wmem.getLong(8);
+    long hash2 = hashLong(in, 00); //tests the single long hash
+    assertEquals(hash1, hash0);
+    assertEquals(hash2, hash0);
+
+    double[] darr = new double[2];
+    wmem.getDoubleArray(0, darr, 0, 2);
+    hash1 = hashDoubleArr(darr, 1, 1, 0);
+    assertEquals(hash1, hash0);
+
+  }
+
+  @Test
+  public void testString() {
+    String s = "Now is the time for all good men to come to the aid of their country.";
+    char[] arr = s.toCharArray();
+    long hash0 = hashString(s, 0, s.length(), 0);
+    long hash1 = hashCharArr(arr, 0, arr.length, 0);
+    assertEquals(hash1, hash0);
+  }
+
+}
diff --git a/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/ZeroCapacityTest.java b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/ZeroCapacityTest.java
new file mode 100644
index 0000000..e54b6d9
--- /dev/null
+++ b/datasketches-memory-java17/src/test/java17/org/apache/datasketches/memory/internal/ZeroCapacityTest.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.testng.Assert.assertEquals;
+
+import java.nio.ByteBuffer;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import jdk.incubator.foreign.ResourceScope;
+
+/**
+ * @author Lee Rhodes
+ */
+public class ZeroCapacityTest {
+  private static final MemoryRequestServer memReqSvr = BaseState.defaultMemReqSvr;
+
+  @SuppressWarnings("resource")
+  @Test
+  public void checkZeroCapacity() throws Exception {
+    WritableMemory wmem = WritableMemory.allocate(0);
+    assertEquals(wmem.getCapacity(), 0);
+
+    Memory.wrap(new byte[0]);
+    Memory.wrap(ByteBuffer.allocate(0));
+    Memory mem3 = Memory.wrap(ByteBuffer.allocateDirect(0));
+    mem3.region(0, 0);
+    WritableMemory nullMem = null;
+    ResourceScope scope = ResourceScope.newConfinedScope();
+    try { //Invalid allocation size : 0
+      nullMem = WritableMemory.allocateDirect(0, scope, memReqSvr);
+      Assert.fail();
+    } catch (IllegalArgumentException ignore) {
+      if (nullMem != null) {
+        nullMem.close();
+      }
+      // expected
+    }
+  }
+
+  @Test
+  public void printlnTest() {
+    //println("PRINTING: "+this.getClass().getName());
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void println(String s) {
+    //System.out.println(s); //disable here
+  }
+
+}
diff --git a/datasketches-memory-java17/src/test/resources/GettysburgAddress.txt b/datasketches-memory-java17/src/test/resources/GettysburgAddress.txt
new file mode 100644
index 0000000..3969d17
--- /dev/null
+++ b/datasketches-memory-java17/src/test/resources/GettysburgAddress.txt
@@ -0,0 +1,7 @@
+Abraham Lincoln's Gettysburg Address:
+
+    Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal.
+
+    Now we are engaged in a great civil war, testing whether that nation, or any nation so conceived and so dedicated, can long endure. We are met on a great battle-field of that war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this.
+
+    But, in a larger sense, we can not dedicate —- we can not consecrate —- we can not hallow —- this ground. The brave men, living and dead, who struggled here, have consecrated it, far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us  [...]
diff --git a/pom.xml b/pom.xml
index 9b28552..db6febd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -83,7 +83,7 @@ under the License.
   </developers>
 
   <!--
-       NOTE:
+       N O T E:
        The datasketches-memory submodule uses the Maven project-aggregation feature and does not inherit
        from this root module as a parent; so that there is no runtime dependency on the parent project (root module).
        As a result, some properties from this POM (including the version) are duplicated in the datasketches-memory
@@ -95,7 +95,7 @@ under the License.
     <!-- UNIQUE FOR THIS JAVA COMPONENT -->
     <protobuf-java.version>4.0.0-rc-2</protobuf-java.version>
     <!-- Used for UTF8 testing -->
-    <zero-allocation-hashing.version>0.15</zero-allocation-hashing.version>
+    <zero-allocation-hashing.version>0.16</zero-allocation-hashing.version>
     <!-- END:UNIQUE FOR THIS JAVA COMPONENT -->
 
     <!-- Test -->


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