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/06/20 00:01:17 UTC

[datasketches-memory] 02/02: Moved tests from module -java8-tests to module -java8

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

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

commit cc0040e61208b801232bf722ad970413c9efdfc4
Author: Lee Rhodes <le...@users.noreply.github.com>
AuthorDate: Sun Jun 19 16:52:25 2022 -0700

    Moved tests from module -java8-tests to module -java8
---
 .../WritableDirectCopyTest.java                    |  253 +++++
 .../WritableMemoryTest.java                        |  199 ++++
 .../XxHash64LoopingTest.java                       | 1082 ++++++++++++++++++++
 datasketches-memory-java8-tests/XxHash64Test.java  |  183 ++++
 .../ZeroCapacityTest.java                          |   68 ++
 .../memory/test/AllocateDirectMapMemoryTest.java   |  170 +++
 .../memory/internal/AllocateDirectMemoryTest.java  |    7 +-
 .../AllocateDirectWritableMapMemoryTest.java       |  253 +++++
 .../memory/internal/BaseBufferTest.java            |   89 ++
 .../memory/internal/BaseStateTest.java             |  142 +++
 .../datasketches/memory/internal/Buffer2Test.java  |  462 +++++++++
 .../memory/internal/BufferBoundaryCheckTest.java   |  237 +++++
 .../memory/internal/BufferInvariantsTest.java      |  341 ++++++
 .../memory/internal/BufferReadWriteSafetyTest.java |  175 ++++
 .../datasketches/memory/internal/BufferTest.java   |  326 ++++++
 .../memory/internal/CommonBufferTest.java          |  448 ++++++++
 .../memory/internal/CommonMemoryTest.java          |  416 ++++++++
 .../memory/internal/CopyMemoryOverlapTest.java     |  183 ++++
 .../memory/internal/CopyMemoryTest.java            |  184 ++++
 .../memory/internal/DruidIssue11544Test.java       |  110 ++
 .../internal/ExampleMemoryRequestServerTest.java   |  177 ++++
 .../memory/internal/IgnoredArrayOverflowTest.java  |  104 ++
 .../memory/internal/IsValidUtf8TestUtil.java       |   64 ++
 .../datasketches/memory/internal/LeafImplTest.java |  276 +++++
 .../memory/internal/MemoryBoundaryCheckTest.java   |  205 ++++
 .../memory/internal/MemoryCleanerTest.java         |   62 ++
 .../memory/internal/MemoryCloseExceptionTest.java  |   39 +
 .../memory/internal/MemoryReadWriteSafetyTest.java |  227 ++++
 .../datasketches/memory/internal/MemoryTest.java   |  479 +++++++++
 .../memory/internal/MemoryWriteToTest.java         |   96 ++
 .../memory/internal/MurmurHash3v2Test.java         |  401 ++++++++
 .../internal/NativeWritableBufferImplTest.java     |  600 +++++++++++
 .../internal/NativeWritableMemoryImplTest.java     |  723 +++++++++++++
 .../datasketches/memory/internal/NioBitsTest.java  |   78 ++
 .../internal/NonNativeWritableBufferImplTest.java  |  260 +++++
 .../internal/NonNativeWritableMemoryImplTest.java  |  219 ++++
 .../memory/internal/SpecificLeafTest.java          |  194 ++++
 .../memory/internal/UnsafeUtilTest.java            |  151 +++
 .../datasketches/memory/internal/Utf8Test.java     |  516 ++++++++++
 .../datasketches/memory/internal/UtilTest.java     |    2 -
 .../memory/internal/VirtualMachineMemoryTest.java  |   39 +
 .../memory/internal/WritableDirectCopyTest.java    |  253 +++++
 .../memory/internal/WritableMemoryTest.java        |  198 ++++
 .../memory/internal/XxHash64LoopingTest.java       | 1082 ++++++++++++++++++++
 .../datasketches/memory/internal/XxHash64Test.java |  183 ++++
 .../memory/internal/ZeroCapacityTest.java          |   68 ++
 46 files changed, 12018 insertions(+), 6 deletions(-)

diff --git a/datasketches-memory-java8-tests/WritableDirectCopyTest.java b/datasketches-memory-java8-tests/WritableDirectCopyTest.java
new file mode 100644
index 0000000..f52aa34
--- /dev/null
+++ b/datasketches-memory-java8-tests/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.WritableHandle;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+/**
+ * @author Lee Rhodes
+ */
+public class WritableDirectCopyTest {
+
+//Copy Within tests
+
+  @Test
+  public void checkCopyWithinNativeSmall() throws Exception {
+    int memCapacity = 64;
+    int half = memCapacity / 2;
+    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem = wrh.getWritable();
+      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 (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem = wrh.getWritable();
+      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 (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem = wrh.getWritable();
+      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 (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem = wrh.getWritable();
+      mem.copyTo(32, mem, 32, 33);  //hit source bound check
+      fail("Did Not Catch Assertion Error: source bound");
+    } catch (IllegalArgumentException e) {
+      //pass
+    }
+  }
+
+  @Test
+  public void checkCopyWithinNativeDstBound() throws Exception {
+    int memCapacity = 64;
+    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem = wrh.getWritable();
+      mem.copyTo(0, mem, 32, 33);  //hit dst bound check
+      fail("Did Not Catch Assertion Error: dst bound");
+    } catch (IllegalArgumentException e) {
+      //pass
+    }
+  }
+
+  @Test
+  public void checkCopyCrossNativeSmall() throws Exception {
+    int memCapacity = 64;
+
+    try (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity);
+         WritableHandle wrh2 = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem1 = wrh1.getWritable();
+      WritableMemory mem2 = wrh2.getWritable();
+
+      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);
+      }
+      wrh1.close();
+      wrh2.close();
+    }
+  }
+
+  @Test
+  public void checkCopyCrossNativeLarge() throws Exception {
+    int memCapacity = (2 << 20) + 64;
+    int memCapLongs = memCapacity / 8;
+
+    try (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity);
+         WritableHandle wrh2 = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem1 = wrh1.getWritable();
+      WritableMemory mem2 = wrh2.getWritable();
+
+      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 (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem1 = wrh1.getWritable();
+
+      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 (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem1 = wrh1.getWritable();
+
+      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 (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem1 = wrh1.getWritable();
+
+      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-java8-tests/WritableMemoryTest.java b/datasketches-memory-java8-tests/WritableMemoryTest.java
new file mode 100644
index 0000000..0c4cbab
--- /dev/null
+++ b/datasketches-memory-java8-tests/WritableMemoryTest.java
@@ -0,0 +1,199 @@
+/*
+ * 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.Memory;
+import org.apache.datasketches.memory.WritableBuffer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.apache.datasketches.memory.internal.Util;
+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.getTypeByteOrder(), ByteOrder.BIG_ENDIAN);
+    wmem = WritableMemory.writableWrap(bb, ByteOrder.nativeOrder());
+    assertEquals(wmem.getTypeByteOrder(), 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, null);
+    assertEquals(wmem.getChar(0), 256);
+  }
+
+  @Test
+  public void allocateWithByteOrder() {
+    WritableMemory wmem = WritableMemory.allocate(64, ByteOrder.BIG_ENDIAN);
+    assertEquals(wmem.getTypeByteOrder(), ByteOrder.BIG_ENDIAN);
+    wmem = WritableMemory.allocate(64, ByteOrder.LITTLE_ENDIAN);
+    assertEquals(wmem.getTypeByteOrder(), ByteOrder.LITTLE_ENDIAN);
+    wmem = WritableMemory.writableWrap(new byte[64], 32, 32, ByteOrder.BIG_ENDIAN);
+    assertEquals(wmem.getTypeByteOrder(), ByteOrder.BIG_ENDIAN);
+  }
+
+  @Test
+  public void checkGetArray() {
+    byte[] byteArr = new byte[64];
+    WritableMemory wmem = WritableMemory.writableWrap(byteArr);
+    assertTrue(wmem.getArray() == byteArr);
+    WritableBuffer wbuf = wmem.asWritableBuffer();
+    assertTrue(wbuf.getArray() == byteArr);
+  }
+
+  @Test(expectedExceptions = IllegalArgumentException.class)
+  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.equals(reg1));
+
+    wmem2 = WritableMemory.allocate(len);
+    for (int i = 0; i < len; i++) {
+      wmem1.putByte(i, (byte) i);
+      wmem2.putByte(i, (byte) i);
+    }
+    assertTrue(wmem1.equals(wmem2));
+    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));
+    //@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));
+
+    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() {
+    // Size bigger than UNSAFE_COPY_MEMORY_THRESHOLD; size with "reminder" = 7, to test several
+    // traits of the implementation
+    final int thresh = Util.UNSAFE_COPY_THRESHOLD_BYTES;
+    byte[] bytes1 = new byte[(thresh * 2) + 7];
+    ThreadLocalRandom.current().nextBytes(bytes1);
+    byte[] bytes2 = bytes1.clone();
+    Memory mem1 = Memory.wrap(bytes1);
+    Memory mem2 = Memory.wrap(bytes2);
+    assertTrue(mem1.equals(mem2));
+
+    bytes2[thresh + 10] = (byte) (bytes1[thresh + 10] + 1);
+    assertFalse(mem1.equals(mem2));
+
+    bytes2[thresh + 10] = bytes1[thresh + 10];
+    bytes2[(thresh * 2) + 3] = (byte) (bytes1[(thresh * 2) + 3] + 1);
+    assertFalse(mem1.equals(mem2));
+  }
+
+  @Test
+  public void checkWrapWithBO() {
+    WritableMemory wmem = WritableMemory.writableWrap(new byte[0], ByteOrder.BIG_ENDIAN);
+    boolean nativeBO = wmem.getTypeByteOrder() == ByteOrder.nativeOrder();
+    assertFalse(nativeBO);
+    println("" + nativeBO);
+    wmem = WritableMemory.writableWrap(new byte[8], ByteOrder.BIG_ENDIAN);
+    nativeBO = wmem.getTypeByteOrder() == 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-java8-tests/XxHash64LoopingTest.java b/datasketches-memory-java8-tests/XxHash64LoopingTest.java
new file mode 100644
index 0000000..6fc4f81
--- /dev/null
+++ b/datasketches-memory-java8-tests/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-java8-tests/XxHash64Test.java b/datasketches-memory-java8-tests/XxHash64Test.java
new file mode 100644
index 0000000..9656420
--- /dev/null
+++ b/datasketches-memory-java8-tests/XxHash64Test.java
@@ -0,0 +1,183 @@
+/*
+ * 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 increase 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);
+
+    boolean[] blarr = new boolean[16];
+    wmem.getBooleanArray(0, blarr, 0, 16); //any byte != 0 is true
+    hash1 = hashBooleanArr(blarr, 8, 8, 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-java8-tests/ZeroCapacityTest.java b/datasketches-memory-java8-tests/ZeroCapacityTest.java
new file mode 100644
index 0000000..5979e37
--- /dev/null
+++ b/datasketches-memory-java8-tests/ZeroCapacityTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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.Memory;
+import org.apache.datasketches.memory.WritableHandle;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * @author Lee Rhodes
+ */
+public class ZeroCapacityTest {
+
+  @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);
+    WritableHandle wh = null;
+    try {
+      wh = WritableMemory.allocateDirect(0);
+      Assert.fail();
+    } catch (IllegalArgumentException ignore) {
+      if (wh != null) { wh.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-java8-tests/src/test/java/org/apache/datasketches/memory/test/AllocateDirectMapMemoryTest.java b/datasketches-memory-java8-tests/src/test/java/org/apache/datasketches/memory/test/AllocateDirectMapMemoryTest.java
new file mode 100644
index 0000000..e33d8ad
--- /dev/null
+++ b/datasketches-memory-java8-tests/src/test/java/org/apache/datasketches/memory/test/AllocateDirectMapMemoryTest.java
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * Note: Lincoln's Gettysburg Address is in the public domain. See LICENSE.
+ */
+
+package org.apache.datasketches.memory.test;
+
+import static org.apache.datasketches.memory.internal.Util.*;
+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.MapHandle;
+import org.apache.datasketches.memory.Memory;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class AllocateDirectMapMemoryTest {
+  private static final String LS = System.getProperty("line.separator");
+  MapHandle hand = null;
+
+  @BeforeClass
+  public void setReadOnly() {
+    UtilTest.setGettysburgAddressFileToReadOnly();
+  }
+
+  @Test
+  public void simpleMap() throws Exception {
+    File file = getResourceFile("GettysburgAddress.txt");
+    assertTrue(ReflectUtil.isFileReadOnly(file));
+    try (MapHandle rh = Memory.map(file)) {
+      rh.close();
+    }
+  }
+
+  @Test
+  public void testIllegalArguments() throws Exception {
+    File file = getResourceFile("GettysburgAddress.txt");
+    try (MapHandle rh = Memory.map(file, -1, Integer.MAX_VALUE, ByteOrder.nativeOrder())) {
+      fail("Failed: testIllegalArgumentException: Position was negative.");
+    } catch (IllegalArgumentException e) {
+      //ok
+    }
+
+    try (MapHandle rh = Memory.map(file, 0, -1, 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();
+    try (MapHandle rh = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder())) {
+      Memory map = rh.get();
+      assertEquals(memCapacity, map.getCapacity());
+      rh.close();
+      rh.close();
+      map.getCapacity(); //throws assertion error
+    } catch (AssertionError e) {
+      //OK
+    }
+  }
+
+  @Test
+  public void testReadFailAfterClose() throws Exception {
+    File file = getResourceFile("GettysburgAddress.txt");
+    long memCapacity = file.length();
+    try (MapHandle rh = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder())) {
+      Memory mmf = rh.get();
+      rh.close();
+      mmf.getByte(0);
+    } catch (AssertionError e) {
+      //OK
+    }
+  }
+
+  @Test
+  public void testLoad() throws Exception {
+    File file = getResourceFile("GettysburgAddress.txt");
+    long memCapacity = file.length();
+    try (MapHandle rh = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder())) {
+      rh.load();
+      assertTrue(rh.isLoaded());
+      rh.close();
+    }
+  }
+
+  @Test
+  public void testHandlerHandoffWithTWR() throws Exception {
+    File file = getResourceFile("GettysburgAddress.txt");
+    long memCapacity = file.length();
+    Memory mem;
+    try (MapHandle rh = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder())) {
+      rh.load();
+      assertTrue(rh.isLoaded());
+      hand = rh;
+      mem = rh.get();
+    } //TWR closes
+    assertFalse(mem.isValid());
+    //println(""+mem.isValid());
+  }
+
+  @Test
+  public void testHandoffWithoutClose() throws Exception {
+    File file = getResourceFile("GettysburgAddress.txt");
+    long memCapacity = file.length();
+    MapHandle rh = Memory.map(file, 0, memCapacity, ByteOrder.nativeOrder());
+    rh.load();
+    assertTrue(rh.isLoaded());
+    hand = rh;
+    //The receiver of the handler must close the resource, in this case it is the class.
+  }
+
+  @AfterClass
+  public void afterAllTests() throws Exception {
+      if (hand != null) {
+      Memory mem = hand.get();
+      if ((mem != null) && mem.isValid()) {
+        hand.close();
+        assertFalse(mem.isValid());
+      }
+    }
+  }
+
+  @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
+    }
+  }
+
+}
\ No newline at end of file
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectMemoryTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectMemoryTest.java
index f14e3ec..7ebe3e5 100644
--- a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectMemoryTest.java
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectMemoryTest.java
@@ -23,12 +23,11 @@ import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.fail;
 
-import static org.apache.datasketches.memory.BaseState.*;
+import org.apache.datasketches.memory.BaseState;
 import org.apache.datasketches.memory.DefaultMemoryRequestServer;
 import org.apache.datasketches.memory.MemoryRequestServer;
 import org.apache.datasketches.memory.WritableHandle;
 import org.apache.datasketches.memory.WritableMemory;
-import org.apache.datasketches.memory.internal.Util;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.Test;
 
@@ -45,12 +44,12 @@ public class AllocateDirectMemoryTest {
         assertEquals(wMem.getLong(i << 3), i);
       }
       //inside the TWR block the memory should be valid
-      BaseState.checkValid(wMem);
+      ((BaseStateImpl)wMem).checkValid();
       //OK
     }
     //The TWR block has exited, so the memory should be invalid
     try {
-      ReflectUtil.checkValid(wMem);
+      ((BaseStateImpl)wMem).checkValid();
       fail();
     } catch (final RuntimeException e) {
       //OK
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectWritableMapMemoryTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectWritableMapMemoryTest.java
new file mode 100644
index 0000000..9cecaaa
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/AllocateDirectWritableMapMemoryTest.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.
+ */
+
+/*
+ * 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.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.MapHandle;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.ReadOnlyException;
+import org.apache.datasketches.memory.WritableHandle;
+import org.apache.datasketches.memory.WritableMapHandle;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class AllocateDirectWritableMapMemoryTest {
+  private static final String LS = System.getProperty("line.separator");
+
+  @BeforeClass
+  public void setReadOnly() {
+    UtilTest.setGettysburgAddressFileToReadOnly();
+  }
+
+  @Test
+  public void simpleMap() throws Exception {
+    File file = getResourceFile("GettysburgAddress.txt");
+    try (MapHandle h = Memory.map(file); WritableMapHandle wh = (WritableMapHandle) h) {
+      Memory mem = h.get();
+      byte[] bytes = new byte[(int)mem.getCapacity()];
+      mem.getByteArray(0, bytes, 0, bytes.length);
+      String text = new String(bytes, UTF_8);
+      println(text);
+      try {
+        wh.force();
+        fail();
+      } catch (ReadOnlyException e) {
+        //OK
+      }
+    }
+  }
+
+  @Test
+  public void copyOffHeapToMemoryMappedFile() throws Exception {
+    long bytes = 1L << 10; //small for unit tests.  Make it larger than 2GB if you like.
+    long longs = bytes >>> 3;
+
+    File file = new File("TestFile.bin");
+    if (file.exists()) {
+      try {
+        java.nio.file.Files.delete(file.toPath());
+      } catch (IOException e) {
+        throw new RuntimeException(e);
+      }
+    }
+    assertTrue(file.createNewFile());
+    assertTrue (file.setWritable(true, false)); //writable=true, ownerOnly=false
+    assertTrue (file.isFile());
+    file.deleteOnExit();  //comment out if you want to examine the file.
+
+    try (
+        WritableMapHandle dstHandle
+          = WritableMemory.writableMap(file, 0, bytes, ByteOrder.nativeOrder());
+        WritableHandle srcHandle = WritableMemory.allocateDirect(bytes)) {
+
+      WritableMemory dstMem = dstHandle.getWritable();
+      WritableMemory srcMem = srcHandle.getWritable();
+
+      for (long i = 0; i < longs; i++) {
+        srcMem.putLong(i << 3, i); //load source with consecutive longs
+      }
+
+      srcMem.copyTo(0, dstMem, 0, srcMem.getCapacity()); //off-heap to off-heap copy
+
+      dstHandle.force(); //push any remaining to the file
+
+      //check end value
+      assertEquals(dstMem.getLong(longs - 1L << 3), longs - 1L);
+    }
+  }
+
+  @Test
+  public void checkNonNativeFile() throws Exception {
+    File file = new File("TestFile2.bin");
+    if (file.exists()) {
+      try {
+        java.nio.file.Files.delete(file.toPath());
+      } catch (IOException e) {
+        throw new RuntimeException(e);
+      }
+    }
+    assertTrue(file.createNewFile());
+    assertTrue(file.setWritable(true, false)); //writable=true, ownerOnly=false
+    assertTrue(file.isFile());
+    file.deleteOnExit();  //comment out if you want to examine the file.
+
+    final long bytes = 8;
+    try (WritableMapHandle h = WritableMemory.writableMap(file, 0L, bytes, Util.NON_NATIVE_BYTE_ORDER)) {
+      WritableMemory wmem = h.getWritable();
+      wmem.putChar(0, (char) 1);
+      assertEquals(wmem.getByte(1), (byte) 1);
+    }
+  }
+
+  @Test(expectedExceptions = RuntimeException.class)
+  public void testMapException() throws IOException {
+    File dummy = createFile("dummy.txt", ""); //zero length
+    //throws java.lang.reflect.InvocationTargetException
+    Memory.map(dummy, 0, dummy.length(), ByteOrder.nativeOrder());
+  }
+
+  @Test(expectedExceptions = ReadOnlyException.class)
+  public void simpleMap2() throws Exception {
+    File file = getResourceFile("GettysburgAddress.txt");
+    assertTrue(file.canRead() && !file.canWrite());
+    try (WritableMapHandle rh =
+        WritableMemory.writableMap(file)) { //throws
+      //
+    }
+  }
+
+  @Test(expectedExceptions = ReadOnlyException.class)
+  public void checkOverLength() throws Exception  {
+    File file = getResourceFile("GettysburgAddress.txt");
+    try (WritableMapHandle rh =
+        WritableMemory.writableMap(file, 0, 1 << 20, ByteOrder.nativeOrder())) {
+      //
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  @Test
+  public void testForce() throws Exception {
+    String origStr = "Corectng spellng mistks";
+    File origFile = createFile("force_original.txt", origStr); //23
+    assertTrue(origFile.setWritable(true, false));
+    long origBytes = origFile.length();
+    String correctStr = "Correcting spelling mistakes"; //28
+    byte[] correctByteArr = correctStr.getBytes(UTF_8);
+    long corrBytes = correctByteArr.length;
+
+    try (MapHandle rh = Memory.map(origFile, 0, origBytes, ByteOrder.nativeOrder())) {
+      Memory map = rh.get();
+      rh.load();
+      assertTrue(rh.isLoaded());
+      //confirm orig string
+      byte[] buf = new byte[(int)origBytes];
+      map.getByteArray(0, buf, 0, (int)origBytes);
+      String bufStr = new String(buf, UTF_8);
+      assertEquals(bufStr, origStr);
+    }
+
+    try (WritableMapHandle wrh = WritableMemory.writableMap(origFile, 0, corrBytes,
+        ByteOrder.nativeOrder())) {
+      WritableMemory wMap = wrh.getWritable();
+      wrh.load();
+      assertTrue(wrh.isLoaded());
+      // over write content
+      wMap.putByteArray(0, correctByteArr, 0, (int)corrBytes);
+      wrh.force();
+      //confirm correct string
+      byte[] buf = new byte[(int)corrBytes];
+      wMap.getByteArray(0, buf, 0, (int)corrBytes);
+      String bufStr = new String(buf, UTF_8);
+      assertEquals(bufStr, 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 checkExplicitClose() throws Exception {
+    File file = getResourceFile("GettysburgAddress.txt");
+    try (MapHandle wmh = Memory.map(file)) {
+      wmh.close(); //explicit close.
+    } //end of scope call to Cleaner/Deallocator also will be redundant
+  }
+
+  @AfterClass
+  public void checkDirectCounter() {
+    long count =  BaseState.getCurrentDirectMemoryMapAllocations();
+      if (count != 0) {
+        println(""+count);
+        fail();
+      }
+    }
+
+  @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-java8/src/test/java/org/apache/datasketches/memory/internal/BaseBufferTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BaseBufferTest.java
new file mode 100644
index 0000000..4e8bfff
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BaseBufferTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.Buffer;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.WritableHandle;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+/**
+ * @author Lee Rhodes
+ */
+public class BaseBufferTest {
+
+  @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 checkCheckValid() throws Exception {
+    WritableMemory wmem;
+    Buffer buf;
+    try (WritableHandle hand = WritableMemory.allocateDirect(100)) {
+      wmem = hand.getWritable();
+      buf = wmem.asBuffer();
+    }
+    try {
+      @SuppressWarnings("unused")
+      Memory mem = buf.asMemory();
+    } catch (AssertionError ae) { }
+  }
+}
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BaseStateTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BaseStateTest.java
new file mode 100644
index 0000000..430dfa1
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BaseStateTest.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.apache.datasketches.memory.internal.UnsafeUtil.ARRAY_DOUBLE_INDEX_SCALE;
+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.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;
+
+public class BaseStateTest {
+
+  @Test
+  public void checkPrimOffset() {
+    int off = (int)Prim.BYTE.off();
+    assertTrue(off > 0);
+  }
+
+  @Test
+  public void checkIsSameResource() {
+    WritableMemory wmem = WritableMemory.allocate(16);
+    Memory mem = wmem;
+    assertFalse(wmem.isSameResource(null));
+    assertTrue(wmem.isSameResource(mem));
+
+    WritableBuffer wbuf = wmem.asWritableBuffer();
+    Buffer buf = wbuf;
+    assertFalse(wbuf.isSameResource(null));
+    assertTrue(wbuf.isSameResource(buf));
+  }
+
+  @Test
+  public void checkNotEqualTo() {
+    byte[] arr = new byte[8];
+    Memory mem = Memory.wrap(arr);
+    assertFalse(mem.equalTo(0, arr, 0, 8));
+  }
+
+  //StepBoolean checks
+  @Test
+  public void checkStepBoolean() {
+    checkStepBoolean(true);
+    checkStepBoolean(false);
+  }
+
+  private static void checkStepBoolean(boolean initialState) {
+    StepBoolean step = new StepBoolean(initialState);
+    assertTrue(step.get() == initialState); //confirm initialState
+    step.change();
+    assertTrue(step.hasChanged());      //1st change was successful
+    assertTrue(step.get() != initialState); //confirm it is different from initialState
+    step.change();
+    assertTrue(step.get() != initialState); //Still different from initialState
+    assertTrue(step.hasChanged());  //confirm it was changed from initialState value
+  }
+
+  @Test
+  public void checkPrim() {
+    assertEquals(Prim.DOUBLE.scale(), ARRAY_DOUBLE_INDEX_SCALE);
+  }
+
+  @Test
+  public void checkGetNativeBaseOffset_Heap() throws Exception {
+    WritableMemory wmem = WritableMemory.allocate(8); //heap
+    final long offset = ((BaseStateImpl)wmem).getNativeBaseOffset();
+    assertEquals(offset, 0L);
+  }
+
+  @Test
+  public void checkIsByteOrderCompatible() {
+    WritableMemory wmem = WritableMemory.allocate(8);
+    assertTrue(wmem.isByteOrderCompatible(ByteOrder.nativeOrder()));
+  }
+
+  @Test(expectedExceptions = IllegalArgumentException.class)
+  public void checkByteOrderNull() {
+    Util.isNativeByteOrder(null);
+    fail();
+  }
+
+  @Test
+  public void checkIsNativeByteOrder() {
+    assertTrue(BaseStateImpl.isNativeByteOrder(ByteOrder.nativeOrder()));
+    try {
+      BaseStateImpl.isNativeByteOrder(null);
+      fail();
+    } catch (final IllegalArgumentException e) {}
+  }
+
+  @Test
+  public void checkXxHash64() {
+    WritableMemory mem = WritableMemory.allocate(8);
+    long out = mem.xxHash64(mem.getLong(0), 1L);
+    assertTrue(out != 0);
+  }
+
+  @Test
+  public void checkTypeDecode() {
+    for (int i = 0; i < 128; i++) {
+      BaseStateImpl.typeDecode(i);
+    }
+  }
+
+  /********************/
+  @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-java8/src/test/java/org/apache/datasketches/memory/internal/Buffer2Test.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/Buffer2Test.java
new file mode 100644
index 0000000..e625cb4
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/Buffer2Test.java
@@ -0,0 +1,462 @@
+/*
+ * 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.Buffer;
+import org.apache.datasketches.memory.DefaultMemoryRequestServer;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.ReadOnlyException;
+import org.apache.datasketches.memory.WritableBuffer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+public class Buffer2Test {
+
+  @Test
+  public void testWrapByteBuf() {
+    ByteBuffer bb = ByteBuffer.allocate(64).order(ByteOrder.nativeOrder());
+
+    Byte b = 0;
+    while (bb.hasRemaining()) {
+      bb.put(b);
+      b++;
+    }
+    bb.position(0);
+
+    Buffer buffer = Buffer.wrap(bb.asReadOnlyBuffer().order(ByteOrder.nativeOrder()));
+    while (buffer.hasRemaining()) {
+      assertEquals(bb.get(), buffer.getByte());
+    }
+
+    assertEquals(true, buffer.hasArray());
+    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(false, buffer.hasArray());
+    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(true, buffer.hasArray());
+    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 testWrapBooleanArray() {
+    boolean[] booleanArray = new boolean[64];
+
+    for (int i = 0; i < 64; i++) {
+      if ((i % 3) == 0) {
+        booleanArray[i] = true;
+      }
+    }
+
+    Buffer buffer = Memory.wrap(booleanArray).asBuffer();
+    int i = 0;
+    while (buffer.hasRemaining()) {
+      assertEquals(booleanArray[i++], buffer.getBoolean());
+    }
+
+    buffer.setPosition(0);
+    boolean[] copyBooleanArray = new boolean[64];
+    buffer.getBooleanArray(copyBooleanArray, 0, 64);
+    for (int j = 0; j < copyBooleanArray.length; j++) {
+      assertEquals(booleanArray[j], copyBooleanArray[j]);
+    }
+  }
+
+  @Test
+  public void testByteBufferPositionPreservation() {
+    ByteBuffer bb = ByteBuffer.allocate(64).order(ByteOrder.nativeOrder());
+
+    Byte b = 0;
+    while (bb.hasRemaining()) {
+      bb.put(b);
+      b++;
+    }
+    bb.position(10);
+
+    Buffer buffer = Buffer.wrap(bb);
+    while (buffer.hasRemaining()) {
+      assertEquals(bb.get(), buffer.getByte());
+    }
+  }
+
+  @Test
+  public void testGetAndHasRemaining() {
+    ByteBuffer bb = ByteBuffer.allocate(64).order(ByteOrder.nativeOrder());
+
+    Byte b = 0;
+    while (bb.hasRemaining()) {
+      bb.put(b);
+      b++;
+    }
+    bb.position(10);
+
+    Buffer buffer = Buffer.wrap(bb);
+    assertEquals(bb.hasRemaining(), buffer.hasRemaining());
+    assertEquals(bb.remaining(), buffer.getRemaining());
+  }
+
+  @Test
+  public void testGetSetIncResetPosition() {
+    ByteBuffer bb = ByteBuffer.allocate(64).order(ByteOrder.nativeOrder());
+
+    Byte b = 0;
+    while (bb.hasRemaining()) {
+      bb.put(b);
+      b++;
+    }
+    bb.position(10);
+
+    Buffer buffer = Buffer.wrap(bb);
+    assertEquals(bb.position(), buffer.getPosition());
+    assertEquals(30, buffer.setPosition(30).getPosition());
+    assertEquals(40, buffer.incrementPosition(10).getPosition());
+    assertEquals(0, buffer.resetPosition().getPosition());
+  }
+
+  @Test
+  public void testByteBufferSlice() {
+    ByteBuffer bb = ByteBuffer.allocate(64).order(ByteOrder.nativeOrder());
+
+    Byte b = 0;
+    while (bb.hasRemaining()) {
+      bb.put(b);
+      b++;
+    }
+    bb.position(10);
+
+    Buffer buffer = Buffer.wrap(bb.slice().order(ByteOrder.nativeOrder()));
+    while (buffer.hasRemaining()) {
+      assertEquals(bb.get(), buffer.getByte());
+    }
+
+    assertEquals(bb.position(), buffer.getPosition() + 10);
+    assertEquals(30, buffer.setPosition(30).getPosition());
+    assertEquals(40, buffer.incrementPosition(10).getPosition());
+    assertEquals(0, buffer.resetPosition().getPosition());
+  }
+
+  @Test
+  public void testDuplicateAndRegion() {
+    ByteBuffer bb = ByteBuffer.allocate(64).order(ByteOrder.nativeOrder());
+
+    Byte b = 0;
+    while (bb.hasRemaining()) {
+      bb.put(b);
+      b++;
+    }
+    bb.position(10);
+
+    Buffer buffer = Buffer.wrap(bb.slice().order(ByteOrder.nativeOrder())); //slice = 54
+    buffer.setPosition(30);//remaining = 24
+    Buffer dupBuffer = buffer.duplicate(); //all 54
+    Buffer regionBuffer = buffer.region(); //24
+
+    assertEquals(dupBuffer.getStart(), buffer.getStart());
+    assertEquals(regionBuffer.getStart(), buffer.getStart());
+    assertEquals(dupBuffer.getEnd(), buffer.getEnd());
+    assertEquals(regionBuffer.getEnd(), buffer.getRemaining());
+    assertEquals(dupBuffer.getPosition(), buffer.getPosition());
+    assertEquals(regionBuffer.getPosition(), 0);
+    assertEquals(dupBuffer.getCapacity(), buffer.getCapacity());
+    assertEquals(regionBuffer.getCapacity(), buffer.getCapacity() - 30);
+  }
+
+  @Test
+  public void checkRORegions() {
+    int n = 16;
+    int n2 = n / 2;
+    long[] arr = new long[n];
+    for (int i = 0; i < n; i++) { arr[i] = i; }
+    Memory mem = Memory.wrap(arr);
+    Buffer buf = mem.asBuffer();
+    Buffer reg = buf.region(n2 * 8, n2 * 8, buf.getTypeByteOrder()); //top half
+    for (int i = 0; i < n2; i++) {
+      long v = reg.getLong(i * 8);
+      long e = i + n2;
+      assertEquals(v, e);
+    }
+  }
+
+  @Test
+  public void testAsMemory() {
+    ByteBuffer bb = ByteBuffer.allocate(64).order(ByteOrder.nativeOrder());
+
+    Byte b = 0;
+    while (bb.hasRemaining()) {
+      bb.put(b);
+      b++;
+    }
+    bb.position(10);
+
+    Buffer buffer = Buffer.wrap(bb);
+    Memory memory = buffer.asMemory();
+
+    assertEquals(buffer.getCapacity(), memory.getCapacity());
+
+    while(buffer.hasRemaining()){
+      assertEquals(memory.getByte(buffer.getPosition()), buffer.getByte());
+    }
+  }
+
+  @Test(expectedExceptions = AssertionError.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 = ReadOnlyException.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 = ReadOnlyException.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(), null);
+    assertNotNull(buf);
+    buf = WritableBuffer.writableWrap(bb, ByteOrder.nativeOrder(), new DefaultMemoryRequestServer());
+    assertNotNull(buf);
+  }
+
+  @Test
+  public void testWritableDuplicate() {
+    WritableMemory wmem = WritableMemory.writableWrap(new byte[1]);
+    WritableBuffer wbuf = wmem.asWritableBuffer();
+    WritableBuffer wbuf2 = wbuf.writableDuplicate();
+    assertEquals(wbuf2.getCapacity(), 1);
+    Buffer buf = wmem.asBuffer();
+    assertEquals(buf.getCapacity(), 1);
+  }
+
+  @Test
+  public void checkIndependence() {
+    int cap = 64;
+    WritableMemory wmem = WritableMemory.allocate(cap);
+    WritableBuffer wbuf1 = wmem.asWritableBuffer();
+    WritableBuffer wbuf2 = wmem.asWritableBuffer();
+    assertFalse(wbuf1 == wbuf2);
+    assertTrue(wbuf1.isSameResource(wbuf2));
+
+    WritableMemory reg1 = wmem.writableRegion(0, cap);
+    WritableMemory reg2 = wmem.writableRegion(0, cap);
+    assertFalse(reg1 == reg2);
+    assertTrue(reg1.isSameResource(reg2));
+
+
+    WritableBuffer wbuf3 = wbuf1.writableRegion();
+    WritableBuffer wbuf4 = wbuf1.writableRegion();
+    assertFalse(wbuf3 == wbuf4);
+    assertTrue(wbuf3.isSameResource(wbuf4));
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: "+this.getClass().getName());
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void println(String s) {
+    //System.out.println(s); //disable here
+  }
+
+}
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferBoundaryCheckTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferBoundaryCheckTest.java
new file mode 100644
index 0000000..535b0ca
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferBoundaryCheckTest.java
@@ -0,0 +1,237 @@
+/*
+ * 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 org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+public class BufferBoundaryCheckTest {
+
+  private final WritableMemory writableMemory = WritableMemory.allocate(8);
+
+  @Test
+  public void testGetBoolean() {
+    writableMemory.getBoolean(7);
+    try {
+      writableMemory.getBoolean(8);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutBoolean() {
+    writableMemory.putBoolean(7, true);
+    try {
+      writableMemory.putBoolean(8, true);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetByte() {
+    writableMemory.getByte(7);
+    try {
+      writableMemory.getByte(8);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutByte() {
+    writableMemory.putByte(7, (byte) 1);
+    try {
+      writableMemory.putByte(8, (byte) 1);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetChar() {
+    writableMemory.getChar(6);
+    try {
+      writableMemory.getChar(7);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutChar() {
+    writableMemory.putChar(6, 'a');
+    try {
+      writableMemory.putChar(7, 'a');
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetShort() {
+    writableMemory.getShort(6);
+    try {
+      writableMemory.getShort(7);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutShort() {
+    writableMemory.putShort(6, (short) 1);
+    try {
+      writableMemory.putShort(7, (short) 1);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetInt() {
+    writableMemory.getInt(4);
+    try {
+      writableMemory.getInt(5);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutInt() {
+    writableMemory.putInt(4, 1);
+    try {
+      writableMemory.putInt(5, 1);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetFloat() {
+    writableMemory.getFloat(4);
+    try {
+      writableMemory.getFloat(5);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutFloat() {
+    writableMemory.putFloat(4, 1f);
+    try {
+      writableMemory.putFloat(5, 1f);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetLong() {
+    writableMemory.getLong(0);
+    try {
+      writableMemory.getLong(1);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutLong() {
+    writableMemory.putLong(0, 1L);
+    try {
+      writableMemory.putLong(1, 1L);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetDouble() {
+    writableMemory.getDouble(0);
+    try {
+      writableMemory.getDouble(1);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutDouble() {
+    writableMemory.putDouble(0, 1d);
+    try {
+      writableMemory.putDouble(1, 1d);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetAndAddLong() {
+    writableMemory.getAndAddLong(0, 1L);
+    try {
+      writableMemory.getAndAddLong(1, 1L);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetAndSetLong() {
+    writableMemory.getAndSetLong(0, 1L);
+    try {
+      writableMemory.getAndSetLong(1, 1L);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testCompareAndSwapLong() {
+    writableMemory.compareAndSwapLong(0, 0L, 1L);
+    try {
+      writableMemory.compareAndSwapLong(1, 0L, 1L);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+}
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferInvariantsTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferInvariantsTest.java
new file mode 100644
index 0000000..735c6b0
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferInvariantsTest.java
@@ -0,0 +1,341 @@
+/*
+ * 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.Buffer;
+import org.apache.datasketches.memory.WritableBuffer;
+import org.apache.datasketches.memory.WritableHandle;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+/**
+ * @author Lee Rhodes
+ */
+public class BufferInvariantsTest {
+
+  @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 (WritableHandle hand = WritableMemory.allocateDirect(100)) {
+      WritableMemory wmem = hand.getWritable();
+      Buffer buf = wmem.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 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 (WritableHandle whand = WritableMemory.allocateDirect(n)) {
+    WritableMemory wmem = whand.getWritable();
+    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-java8/src/test/java/org/apache/datasketches/memory/internal/BufferReadWriteSafetyTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferReadWriteSafetyTest.java
new file mode 100644
index 0000000..6f9f62a
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferReadWriteSafetyTest.java
@@ -0,0 +1,175 @@
+/*
+ * 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.ReadOnlyException;
+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 = AssertionError.class)
+  public void testPutByte() {
+    buf.putByte(0, (byte) 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testPutBytePositional() {
+    buf.putByte((byte) 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testPutBoolean() {
+    buf.putBoolean(0, true);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testPutBooleanPositional() {
+    buf.putBoolean(true);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testPutShort() {
+    buf.putShort(0, (short) 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testPutShortPositional() {
+    buf.putShort((short) 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testPutChar() {
+    buf.putChar(0, (char) 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testPutCharPositional() {
+    buf.putChar((char) 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testPutInt() {
+    buf.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testPutIntPositional() {
+    buf.putInt(1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testPutLong() {
+    buf.putLong(0, 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testPutLongPositional() {
+    buf.putLong(1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testPutFloat() {
+    buf.putFloat(0, 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testPutFloatPositional() {
+    buf.putFloat(1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testPutDouble() {
+    buf.putDouble(0, 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testPutDoublePositional() {
+    buf.putDouble(1);
+  }
+
+  @Test(expectedExceptions = ReadOnlyException.class)
+  public void testPutByteArray() {
+    buf.putByteArray(new byte[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = ReadOnlyException.class)
+  public void testPutBooleanArray() {
+    buf.putBooleanArray(new boolean[] {true}, 0, 1);
+  }
+
+  @Test(expectedExceptions = ReadOnlyException.class)
+  public void testPutShortArray() {
+    buf.putShortArray(new short[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = ReadOnlyException.class)
+  public void testPutCharArray() {
+    buf.putCharArray(new char[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = ReadOnlyException.class)
+  public void testPutIntArray() {
+    buf.putIntArray(new int[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = ReadOnlyException.class)
+  public void testPutLongArray() {
+    buf.putLongArray(new long[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = ReadOnlyException.class)
+  public void testPutFloatArray() {
+    buf.putFloatArray(new float[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = ReadOnlyException.class)
+  public void testDoubleByteArray() {
+    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 = AssertionError.class)
+  public void testWritableMemoryAsBuffer() {
+    WritableBuffer buf1 = (WritableBuffer) WritableMemory.allocate(8).asBuffer();
+    buf1.putInt(1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testWritableBufferRegion() {
+    WritableBuffer buf1 = (WritableBuffer) WritableMemory.allocate(8).asWritableBuffer().region();
+    buf1.putInt(1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testWritableBufferDuplicate() {
+    WritableBuffer buf1 = (WritableBuffer) WritableMemory.allocate(8).asWritableBuffer().duplicate();
+    buf1.putInt(1);
+  }
+}
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferTest.java
new file mode 100644
index 0000000..64b3c77
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/BufferTest.java
@@ -0,0 +1,326 @@
+/*
+ * 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.WritableHandle;
+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 org.testng.collections.Lists;
+
+public class BufferTest {
+
+  @Test
+  public void checkDirectRoundTrip() throws Exception {
+    int n = 1024; //longs
+    try (WritableHandle wh = WritableMemory.allocateDirect(n * 8)) {
+      WritableMemory wmem = wh.getWritable();
+      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 boolean[0]).asBuffer());
+    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(ByteOrder.BIG_ENDIAN);
+    Buffer buf = Buffer.wrap(bb);
+    assertEquals(buf.getTypeByteOrder(), 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());
+
+    Buffer buf = Buffer.wrap(slice);
+    for (int i = 0; i < 64; i++) {
+      assertEquals(buf.getByte(), 64 + i);
+    }
+    buf.toHexString("slice", 0, slice.capacity());
+    //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));
+    }
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void checkParentUseAfterFree() throws Exception {
+    int bytes = 64 * 8;
+    WritableHandle wh = WritableMemory.allocateDirect(bytes);
+    WritableMemory wmem = wh.getWritable();
+    WritableBuffer wbuf = wmem.asWritableBuffer();
+    wh.close();
+    //with -ea assert: Memory not valid.
+    //with -da sometimes segfaults, sometimes passes!
+    wbuf.getLong();
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void checkRegionUseAfterFree() throws Exception {
+    int bytes = 64;
+    WritableHandle wh = WritableMemory.allocateDirect(bytes);
+    Memory wmem = wh.get();
+
+    Buffer reg = wmem.asBuffer().region();
+    wh.close();
+    //with -ea assert: Memory not valid.
+    //with -da sometimes segfaults, sometimes passes!
+    reg.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-java8/src/test/java/org/apache/datasketches/memory/internal/CommonBufferTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/CommonBufferTest.java
new file mode 100644
index 0000000..e5033a2
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/CommonBufferTest.java
@@ -0,0 +1,448 @@
+/*
+ * 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.WritableHandle;
+import org.apache.datasketches.memory.WritableBuffer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+public class CommonBufferTest {
+
+  @Test
+  public void checkSetGet() throws Exception {
+    int memCapacity = 60; //must be at least 60
+    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem = wrh.getWritable();
+      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 (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem = wrh.getWritable();
+      WritableBuffer buf = mem.asWritableBuffer();
+      assertEquals(buf.getCapacity(), memCapacity);
+      setGetArraysTests(buf);
+    }
+  }
+
+  public static void setGetArraysTests(WritableBuffer buf) {
+    int words = 4;
+
+    boolean[] srcArray1 = {true, false, true, false};
+    boolean[] dstArray1 = new boolean[words];
+    buf.resetPosition();
+    buf.fill((byte)127);
+    buf.resetPosition();
+    buf.putBooleanArray(srcArray1, 0, words);
+    buf.resetPosition();
+    buf.getBooleanArray(dstArray1, 0, words);
+    for (int i=0; i<words; i++) {
+      assertEquals(dstArray1[i], srcArray1[i]);
+    }
+
+    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 = { (float)1.0, (float)-2.0, (float)3.0, (float)-4.0 };
+    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 (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem = wrh.getWritable();
+      WritableBuffer buf = mem.asWritableBuffer();
+      assertEquals(buf.getCapacity(), memCapacity);
+      setGetPartialArraysWithOffsetTests(buf);
+    }
+  }
+
+  public static void setGetPartialArraysWithOffsetTests(WritableBuffer buf) {
+    int items= 4;
+    boolean[] srcArray1 = {true, false, true, false};
+    boolean[] dstArray1 = new boolean[items];
+    buf.resetPosition();
+    buf.putBooleanArray(srcArray1, 2, items/2);
+    buf.resetPosition();
+    buf.getBooleanArray(dstArray1, 2, items/2);
+    for (int i=2; i<items; i++) {
+      assertEquals(dstArray1[i], srcArray1[i]);
+    }
+
+    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 = { (float)1.0, (float)-2.0, (float)3.0, (float)-4.0 };
+    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 (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem = wrh1.getWritable();
+      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 (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem = wrh1.getWritable();
+      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-java8/src/test/java/org/apache/datasketches/memory/internal/CommonMemoryTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/CommonMemoryTest.java
new file mode 100644
index 0000000..322352f
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/CommonMemoryTest.java
@@ -0,0 +1,416 @@
+/*
+ * 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.WritableHandle;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+public class CommonMemoryTest {
+
+  @Test
+  public void checkSetGet() throws Exception {
+    int memCapacity = 16; //must be at least 8
+    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem = wrh.getWritable();
+      assertEquals(mem.getCapacity(), memCapacity);
+      setGetTests(mem);
+    }
+  }
+
+  public static void setGetTests(WritableMemory mem) {
+    mem.putBoolean(0, true);
+    assertEquals(mem.getBoolean(0), true);
+    mem.putBoolean(0, false);
+    assertEquals(mem.getBoolean(0), false);
+
+    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 (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem = wrh.getWritable();
+      assertEquals(memCapacity, mem.getCapacity());
+      setGetArraysTests(mem);
+    }
+  }
+
+  public static void setGetArraysTests(WritableMemory mem) {
+    int accessCapacity = (int)mem.getCapacity();
+
+    int words = 4;
+    boolean[] srcArray1 = {true, false, true, false};
+    boolean[] dstArray1 = new boolean[words];
+    mem.fill(0, accessCapacity, (byte)127);
+    mem.putBooleanArray(0, srcArray1, 0, words);
+    mem.getBooleanArray(0, dstArray1, 0, words);
+    for (int i = 0; i < words; i++) {
+      assertEquals(dstArray1[i], srcArray1[i]);
+    }
+
+    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 (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem = wrh.getWritable();
+      assertEquals(memCapacity, mem.getCapacity());
+      setGetPartialArraysWithOffsetTests(mem);
+    }
+  }
+
+  public static void setGetPartialArraysWithOffsetTests(WritableMemory mem) {
+    int items= 4;
+    boolean[] srcArray1 = {true, false, true, false};
+    boolean[] dstArray1 = new boolean[items];
+    mem.putBooleanArray(0, srcArray1, 2, items/2);
+    mem.getBooleanArray(0, dstArray1, 2, items/2);
+    for (int i = 2; i < items; i++) {
+      assertEquals(dstArray1[i], srcArray1[i]);
+    }
+
+    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 (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem = wrh.getWritable();
+      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 checkAtomicMethods() throws Exception {
+    int memCapacity = 8;
+    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem = wrh.getWritable();
+      assertEquals(mem.getCapacity(), memCapacity);
+      atomicMethodTests(mem);
+    }
+  }
+
+  public static void atomicMethodTests(WritableMemory mem) {
+    mem.putLong(0, 500);
+    mem.getAndAddLong(0, 1);
+    assertEquals(mem.getLong(0), 501);
+
+    mem.putInt(0, 500);
+    boolean b = mem.compareAndSwapLong(0, 500, 501);
+    assertTrue(b);
+    assertEquals(mem.getLong(0), 501);
+
+    mem.putLong(0, 500);
+    long oldLong = mem.getAndSetLong(0, 501);
+    long newLong = mem.getLong(0);
+    assertEquals(oldLong, 500);
+    assertEquals(newLong, 501);
+  }
+
+  @Test
+  public void checkSetClearMemoryRegions() throws Exception {
+    int memCapacity = 64; //must be 64
+    try (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem = wrh1.getWritable();
+
+      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 (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem = wrh1.getWritable();
+      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-java8/src/test/java/org/apache/datasketches/memory/internal/CopyMemoryOverlapTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/CopyMemoryOverlapTest.java
new file mode 100644
index 0000000..962b12f
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/CopyMemoryOverlapTest.java
@@ -0,0 +1,183 @@
+/*
+ * 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.WritableHandle;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+/**
+ * @author Lee Rhodes
+ */
+public class CopyMemoryOverlapTest {
+
+  @Test
+  public void checkOverlapUsingMemory() throws Exception {
+    long copyLongs = 1 << 20;
+    double overlap = 0.5;
+    long start_mS = System.currentTimeMillis();
+
+    copyUsingDirectMemory(copyLongs, overlap, true);
+    long end1_mS = System.currentTimeMillis();
+
+    copyUsingDirectMemory(copyLongs, overlap, false);
+    long end2_mS = System.currentTimeMillis();
+
+    println("CopyUp Time Sec: " + ((end1_mS - start_mS)/1000.0));
+    println("CopyDn Time Sec: " + ((end2_mS - end1_mS)/1000.0));
+  }
+
+  @Test
+  public void checkOverlapUsingRegions() throws Exception {
+    long copyLongs = 1 << 20;
+    double overlap = 0.5;
+    long start_mS = System.currentTimeMillis();
+
+    copyUsingDirectRegions(copyLongs, overlap, true);
+    long end1_mS = System.currentTimeMillis();
+
+    copyUsingDirectRegions(copyLongs, overlap, false);
+    long end2_mS = System.currentTimeMillis();
+
+    println("CopyUp Time Sec: " + ((end1_mS - start_mS)/1000.0));
+    println("CopyDn Time Sec: " + ((end2_mS - end1_mS)/1000.0));
+  }
+
+  private static final void copyUsingDirectMemory(long copyLongs, double overlap, boolean copyUp) throws Exception {
+    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 (WritableHandle backHandle = WritableMemory.allocateDirect(backingBytes)) {
+      WritableMemory backingMem = backHandle.getWritable();
+      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 (WritableHandle backHandle = WritableMemory.allocateDirect(backingBytes)) {
+      WritableMemory backingMem = backHandle.getWritable();
+      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-java8/src/test/java/org/apache/datasketches/memory/internal/CopyMemoryTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/CopyMemoryTest.java
new file mode 100644
index 0000000..fe37aad
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/CopyMemoryTest.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.apache.datasketches.memory.internal.Util.UNSAFE_COPY_THRESHOLD_BYTES;
+import static org.testng.Assert.assertEquals;
+
+import java.util.concurrent.ThreadLocalRandom;
+
+import org.apache.datasketches.memory.WritableHandle;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class CopyMemoryTest {
+
+  @Test
+  public void heapWSource() {
+    int k1 = 1 << 20; //longs
+    int k2 = 2 * k1;
+    WritableMemory srcMem = genMem(k1, false); //!empty
+    //println(srcMem.toHexString("src: ", 0, k1 << 3));
+    WritableMemory dstMem = genMem(k2, true);
+    srcMem.copyTo(0, dstMem, k1 << 3, k1 << 3);
+    //println(dstMem.toHexString("dst: ", 0, k2 << 3));
+    check(dstMem, k1, k1, 1);
+  }
+
+  @Test
+  public void heapROSource() {
+    int k1 = 1 << 20; //longs
+    int k2 = 2 * k1;
+    Memory srcMem = genMem(k1, false); //!empty
+    WritableMemory dstMem = genMem(k2, true);
+    srcMem.copyTo(0, dstMem, k1 << 3, k1 << 3);
+    check(dstMem, k1, k1, 1);
+  }
+
+  @Test
+  public void directWSource() throws Exception {
+    int k1 = 1 << 20; //longs
+    int k2 = 2 * k1;
+    try (WritableHandle wrh = genWRH(k1, false)) {
+      WritableMemory srcMem = wrh.getWritable();
+      WritableMemory dstMem = genMem(k2, true);
+      srcMem.copyTo(0, dstMem, k1 << 3, k1 << 3);
+      check(dstMem, k1, k1, 1);
+    }
+  }
+
+  @Test
+  public void directROSource() throws Exception {
+    int k1 = 1 << 20; //longs
+    int k2 = 2 * k1;
+    try (WritableHandle wrh = genWRH(k1, false)) {
+      Memory srcMem = wrh.get();
+      WritableMemory dstMem = genMem(k2, true);
+      srcMem.copyTo(0, dstMem, k1 << 3, k1 << 3);
+      check(dstMem, k1, k1, 1);
+    }
+  }
+
+  @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
+    try (WritableHandle wrh = genWRH(k1, false)) {
+      Memory baseMem = wrh.get();
+      //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 testOverlappingCopyLeftToRight() {
+    byte[] bytes = new byte[((UNSAFE_COPY_THRESHOLD_BYTES * 5) / 2) + 1];
+    ThreadLocalRandom.current().nextBytes(bytes);
+    byte[] referenceBytes = bytes.clone();
+    Memory referenceMem = Memory.wrap(referenceBytes);
+    WritableMemory mem = WritableMemory.writableWrap(bytes);
+    long copyLen = UNSAFE_COPY_THRESHOLD_BYTES * 2;
+    mem.copyTo(0, mem, UNSAFE_COPY_THRESHOLD_BYTES / 2, copyLen);
+    Assert.assertEquals(0, mem.compareTo(UNSAFE_COPY_THRESHOLD_BYTES / 2, copyLen, referenceMem, 0,
+        copyLen));
+  }
+
+  @Test
+  public void testOverlappingCopyRightToLeft() {
+    byte[] bytes = new byte[((UNSAFE_COPY_THRESHOLD_BYTES * 5) / 2) + 1];
+    ThreadLocalRandom.current().nextBytes(bytes);
+    byte[] referenceBytes = bytes.clone();
+    Memory referenceMem = Memory.wrap(referenceBytes);
+    WritableMemory mem = WritableMemory.writableWrap(bytes);
+    long copyLen = UNSAFE_COPY_THRESHOLD_BYTES * 2;
+    mem.copyTo(UNSAFE_COPY_THRESHOLD_BYTES / 2, mem, 0, copyLen);
+    Assert.assertEquals(0, mem.compareTo(0, copyLen, referenceMem, UNSAFE_COPY_THRESHOLD_BYTES / 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);
+    }
+  }
+
+  private static WritableHandle genWRH(int longs, boolean empty) {
+    WritableHandle wrh = WritableMemory.allocateDirect(longs << 3);
+    WritableMemory mem = wrh.getWritable();
+    if (empty) {
+      mem.clear();
+    } else {
+      for (int i = 0; i < longs; i++) { mem.putLong(i << 3, i + 1); }
+    }
+    return wrh;
+  }
+
+
+  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-java8/src/test/java/org/apache/datasketches/memory/internal/DruidIssue11544Test.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/DruidIssue11544Test.java
new file mode 100644
index 0000000..581bdda
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/DruidIssue11544Test.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 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.DefaultMemoryRequestServer;
+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 {
+
+  @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
+
+    //Acquire the DefaultMemoryRequestServer
+    //NOTE: it is a policy decision to allow the DefaultMemoryServer to be set as a default.
+    // It might be set to null. So we need to check what the current policy is.
+    MemoryRequestServer svr = mem1.getMemoryRequestServer();
+    if (svr == null) {
+      svr = new DefaultMemoryRequestServer();
+    }
+    assertNotNull(svr);
+
+    //Request Bigger Memory
+    int size2 = size1 * 2;
+    WritableMemory mem2 = svr.request(mem1, size2);
+
+    //Confirm that mem2 is on the heap (the default) and 2X size1
+    assertFalse(mem2.isDirect());
+    assertEquals(mem2.getCapacity(), size2);
+
+    //Move data to new memory
+    mem1.copyTo(0, mem2, 0, size1);
+
+    //Prepare to request deallocation
+    //In the DefaultMemoryRequestServer, this is a no-op, so nothing is actually deallocated.
+    svr.requestClose(mem1, mem2);
+    assertTrue(mem1.isValid());
+    assertTrue(mem2.isValid());
+
+    //Now we are on the heap and need to grow again:
+    int size3 = size2 * 2;
+    WritableMemory mem3 = svr.request(mem2, size3);
+
+    //Confirm that mem3 is still on the heap and 2X of size2
+    assertFalse(mem3.isDirect());
+    assertEquals(mem3.getCapacity(), size3);
+
+    //Move data to new memory
+    mem2.copyTo(0, mem3, 0, size2);
+
+    //Prepare to request deallocation
+
+    svr.requestClose(mem2, mem3); //No-op
+    assertTrue(mem2.isValid());
+    assertTrue(mem3.isValid());
+  }
+
+}
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/ExampleMemoryRequestServerTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/ExampleMemoryRequestServerTest.java
new file mode 100644
index 0000000..b970e4b
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/ExampleMemoryRequestServerTest.java
@@ -0,0 +1,177 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import static org.testng.Assert.assertFalse;
+
+import java.nio.ByteOrder;
+import java.util.IdentityHashMap;
+
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableHandle;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+/**
+ * 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
+   */
+  @Test
+  public void checkExampleMemoryRequestServer1() throws Exception {
+    int bytes = 8;
+    ExampleMemoryRequestServer svr = new ExampleMemoryRequestServer();
+    try (WritableHandle wh = WritableMemory.allocateDirect(8)) {
+      WritableMemory memStart = wh.getWritable();
+      WritableMemory wMem = svr.request(memStart, bytes);
+      MemoryClient client = new MemoryClient(wMem);
+      client.process();
+      svr.cleanup();
+    }
+  }
+
+  /**
+   * In this version the first memory allocation is done up front in a TWR block.
+   * And then the MemoryClient allocates new memories as needed, which are then closed
+   * by the MemoryClient when it is done with the new memory allocations.
+   * The initial allocation stays open until the end where it is closed at the end of the
+   * TWR scope.
+   * @throws Exception
+   */
+  @Test
+  public void checkExampleMemoryRequestServer2() throws Exception {
+    int bytes = 8;
+    ExampleMemoryRequestServer svr = new ExampleMemoryRequestServer();
+    try (WritableHandle handle = WritableMemory.allocateDirect(bytes, ByteOrder.nativeOrder(), svr)) {
+      WritableMemory memStart = handle.getWritable();
+      MemoryClient client = new MemoryClient(memStart);
+      client.process();
+      svr.cleanup(); //just to be sure all are closed.
+    }
+  }
+
+  @Test(expectedExceptions = IllegalArgumentException.class)
+  public void checkZeroCapacity() throws Exception {
+    ExampleMemoryRequestServer svr = new ExampleMemoryRequestServer();
+    try (WritableHandle wh = WritableMemory.allocateDirect(0, ByteOrder.nativeOrder(), svr)) {
+
+    }
+  }
+
+  /**
+   * 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));
+
+      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
+
+      bigMem.fill(cap1, cap1, (byte) 2);      //fill the rest of bigMem, still not big enough
+      println(bigMem.toHexString("Big", 0, (int)cap2));
+
+      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
+
+      giantMem.fill(cap2, cap2, (byte) 3);    //fill the rest of giantMem
+      println(giantMem.toHexString("Giant", 0, (int)cap3));
+      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 and to track the associations between
+   * handles and their associated memory.
+   */
+  public static class ExampleMemoryRequestServer implements MemoryRequestServer {
+    IdentityHashMap<WritableMemory, WritableHandle> map = new IdentityHashMap<>();
+
+    @Override
+    public WritableMemory request(WritableMemory currentWMem, long capacityBytes) {
+     ByteOrder order = currentWMem.getTypeByteOrder();
+     WritableHandle handle = WritableMemory.allocateDirect(capacityBytes, order, this);
+     WritableMemory wmem = handle.getWritable();
+     map.put(wmem, handle); //We track the newly allocated memory and its handle.
+     return wmem;
+    }
+
+    @Override
+    //here we actually release it, in reality it might be a lot more complex.
+    public void requestClose(WritableMemory memToRelease, WritableMemory newMemory) {
+      WritableHandle handle = map.get(memToRelease);
+      if (handle != null && handle.getWritable() == memToRelease) {
+        try {
+          handle.close();
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      }
+    }
+
+    public void cleanup() {
+      map.forEach((k,v) -> {
+        assertFalse(k.isValid()); //all entries in the map should be invalid
+        try {
+          v.close();
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      });
+    }
+  }
+
+  @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-java8/src/test/java/org/apache/datasketches/memory/internal/IgnoredArrayOverflowTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/IgnoredArrayOverflowTest.java
new file mode 100644
index 0000000..d9e0773
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/IgnoredArrayOverflowTest.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+import org.apache.datasketches.memory.WritableHandle;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class IgnoredArrayOverflowTest {
+
+  private WritableHandle h;
+  private WritableMemory memory;
+  private static final long MAX_SIZE = (1L << 10); // use 1L << 31 to test int overrange
+
+  @BeforeClass
+  public void allocate() {
+    h = WritableMemory.allocateDirect(MAX_SIZE);
+    memory = h.getWritable();
+  }
+
+  @AfterClass
+  public void close() throws Exception {
+    h.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-java8/src/test/java/org/apache/datasketches/memory/internal/IsValidUtf8TestUtil.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/IsValidUtf8TestUtil.java
new file mode 100644
index 0000000..cf01920
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/IsValidUtf8TestUtil.java
@@ -0,0 +1,64 @@
+/*
+ * 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;
+
+/**
+ * Stripped down version of
+ * https://github.com/protocolbuffers/protobuf/blob/master/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java
+ *
+ * <p>Copyright 2008 Google Inc.  All rights reserved.
+ * https://developers.google.com/protocol-buffers/
+ * See LICENSE.
+ */
+public class IsValidUtf8TestUtil {
+
+  // 128 - [chars 0x0000 to 0x007f]
+  static final long ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS = (0x007f - 0x0000) + 1;
+
+  // 128
+  static final long EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT = ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS;
+
+  // 1920 [chars 0x0080 to 0x07FF]
+  static final long TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS = (0x07FF - 0x0080) + 1;
+
+  // 18,304
+  static final long EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT =
+      // Both bytes are one byte characters
+      (long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 2)
+      // The possible number of two byte characters
+      + TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS;
+
+  // 2048
+  static final long THREE_BYTE_SURROGATES = 2 * 1024;
+
+  // 61,440 [chars 0x0800 to 0xFFFF, minus surrogates]
+  static final long THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS =
+      ((0xFFFF - 0x0800) + 1) - THREE_BYTE_SURROGATES;
+
+  // 2,650,112
+  static final long EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT =
+      // All one byte characters
+      (long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 3)
+      // One two byte character and a one byte character
+      + (2 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS * ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS)
+      // Three byte characters
+      + THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS;
+
+}
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/LeafImplTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/LeafImplTest.java
new file mode 100644
index 0000000..f1ef17e
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/LeafImplTest.java
@@ -0,0 +1,276 @@
+/*
+ * 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.NON_NATIVE_BYTE_ORDER;
+import static org.apache.datasketches.memory.internal.Util.otherByteOrder;
+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.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.MemoryRequestServer;
+import org.apache.datasketches.memory.WritableBuffer;
+import org.apache.datasketches.memory.WritableHandle;
+import org.apache.datasketches.memory.WritableMapHandle;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+/**
+ * @author Lee Rhodes
+ */
+public class LeafImplTest {
+  private static final ByteOrder NBO = ByteOrder.nativeOrder();
+  private static final ByteOrder NNBO = 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) { }
+  }
+
+  @Test
+  public void checkDirectLeafs() throws Exception {
+    long off = 0;
+    long cap = 128;
+    // Off Heap, Native order, No ByteBuffer, has MemReqSvr
+    try (WritableHandle wdh = WritableMemory.allocateDirect(cap, NBO, dummyMemReqSvr)) {
+      WritableMemory memNO = wdh.getWritable();
+      memNO.putShort(0, (short) 1);
+      assertNull(((BaseStateImpl)memNO).getUnsafeObject());
+      assertTrue(memNO.isDirect());
+      checkCombinations(memNO, off, cap, memNO.isDirect(), NBO, false, true);
+    }
+    // Off Heap, Non Native order, No ByteBuffer, has MemReqSvr
+    try (WritableHandle wdh = WritableMemory.allocateDirect(cap, NNBO, dummyMemReqSvr)) {
+      WritableMemory memNNO = wdh.getWritable();
+      memNNO.putShort(0, (short) 1);
+      assertNull(((BaseStateImpl)memNNO).getUnsafeObject());
+      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());
+    assertNotNull(((BaseStateImpl)mem).getUnsafeObject());
+    checkCombinations(mem, off, cap, mem.isDirect(), mem.getTypeByteOrder(), true, true);
+
+    //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());
+    assertNull(((BaseStateImpl)mem).getUnsafeObject());
+    checkCombinations(mem, off, cap,  mem.isDirect(), mem.getTypeByteOrder(), true, true);
+
+    //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());
+    assertNotNull(((BaseStateImpl)mem).getUnsafeObject());
+    checkCombinations(mem, off, cap, mem.isDirect(), mem.getTypeByteOrder(), true, true);
+
+    //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());
+    assertNull(((BaseStateImpl)mem).getUnsafeObject());
+    checkCombinations(mem, off, cap,  mem.isDirect(), mem.getTypeByteOrder(), true, true);
+  }
+
+  @Test
+  public void checkMapLeafs() throws Exception {
+    long off = 0;
+    long cap = 128;
+    File file = new File("TestFile2.bin");
+    if (file.exists()) {
+      try {
+        java.nio.file.Files.delete(file.toPath());
+      } catch (IOException e) {
+        throw new RuntimeException(e);
+      }
+    }
+    assertTrue(file.createNewFile());
+    assertTrue(file.setWritable(true, false)); //writable=true, ownerOnly=false
+    assertTrue(file.isFile());
+    file.deleteOnExit();  //comment out if you want to examine the file.
+    // Off Heap, Native order, No ByteBuffer, No MemReqSvr
+    try (WritableMapHandle wmh = WritableMemory.writableMap(file, off, cap, NBO)) {
+      WritableMemory memNO = wmh.getWritable();
+      memNO.putShort(0, (short) 1);
+      assertNull(((BaseStateImpl)memNO).getUnsafeObject());
+      assertTrue(memNO.isDirect());
+      checkCombinations(memNO, off, cap, memNO.isDirect(), NBO, false, false);
+    }
+    // Off heap, Non Native order, No ByteBuffer, no MemReqSvr
+    try (WritableMapHandle wmh = WritableMemory.writableMap(file, off, cap, NNBO)) {
+      WritableMemory memNNO = wmh.getWritable();
+      memNNO.putShort(0, (short) 1);
+      assertNull(((BaseStateImpl)memNNO).getUnsafeObject());
+      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, No MemReqSvr
+    WritableMemory memNO = WritableMemory.allocate((int)cap); //assumes NBO
+    memNO.putShort(0, (short) 1);
+    assertNotNull(((BaseStateImpl)memNO).getUnsafeObject());
+    assertFalse(memNO.isDirect());
+    checkCombinations(memNO, off, cap, memNO.isDirect(), NBO, false, false);
+    // On Heap, Non-native order, No ByteBuffer, No MemReqSvr
+    WritableMemory memNNO = WritableMemory.allocate((int)cap, NNBO);
+    memNNO.putShort(0, (short) 1);
+    assertNotNull(((BaseStateImpl)memNNO).getUnsafeObject());
+    assertFalse(memNNO.isDirect());
+    checkCombinations(memNNO, off, cap, memNNO.isDirect(), NNBO, false, false);
+  }
+
+  private static void checkCombinations(WritableMemory mem, long off, long cap,
+      boolean direct, ByteOrder bo, boolean hasByteBuffer, boolean hasMemReqSvr) {
+    ByteOrder oo = otherByteOrder(bo);
+
+    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);
+
+    ByteBuffer bb = mem.getByteBuffer();
+    assertTrue( hasByteBuffer ? bb != null : bb == null);
+
+    assertTrue(mem.getTypeByteOrder() == bo);
+
+    if (hasMemReqSvr) { assertTrue(mem.getMemoryRequestServer() instanceof DummyMemoryRequestServer); }
+
+    Object obj = ((BaseStateImpl)mem).getUnsafeObject();
+    if (direct) {
+      assertTrue(mem.isDirect());
+      assertNull(obj);
+    } else {
+      assertFalse(mem.isDirect());
+      assertNotNull(obj);
+    }
+
+    assertTrue(mem.isValid() == true);
+
+    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);
+
+    bb = buf.getByteBuffer();
+    assertTrue(hasByteBuffer ? bb != null : bb == null);
+
+    assertTrue(buf.getTypeByteOrder() == bo);
+
+    if (hasMemReqSvr) { assertTrue(buf.getMemoryRequestServer() instanceof DummyMemoryRequestServer); }
+
+    obj = ((BaseStateImpl)buf).getUnsafeObject();
+    if (direct) {
+      assertTrue(buf.isDirect());
+      assertNull(obj);
+    } else {
+      assertFalse(buf.isDirect());
+      assertNotNull(obj);
+    }
+
+    assertTrue(buf.isValid() == true);
+
+    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);
+
+    bb = nnMem.getByteBuffer();
+    assertTrue( hasByteBuffer ? bb != null : bb == null);
+
+    assertTrue(nnMem.getTypeByteOrder() == oo);
+
+    if (hasMemReqSvr) { assertTrue(nnMem.getMemoryRequestServer() instanceof DummyMemoryRequestServer); }
+
+    obj = ((BaseStateImpl)nnMem).getUnsafeObject();
+    if (direct) {
+      assertTrue(nnMem.isDirect());
+      assertNull(obj);
+    } else {
+      assertFalse(nnMem.isDirect());
+      assertNotNull(obj);
+    }
+
+    assertTrue(nnMem.isValid() == true);
+
+    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);
+
+    bb = nnBuf.getByteBuffer();
+    assertTrue( hasByteBuffer ? bb != null : bb == null);
+
+    assertTrue(nnBuf.getTypeByteOrder() == oo);
+
+    if (hasMemReqSvr) { assertTrue(nnBuf.getMemoryRequestServer() instanceof DummyMemoryRequestServer); }
+
+    obj = ((BaseStateImpl)nnBuf).getUnsafeObject();
+    if (direct) {
+      assertTrue(nnBuf.isDirect());
+      assertNull(obj);
+    } else {
+      assertFalse(nnBuf.isDirect());
+      assertNotNull(obj);
+    }
+
+    assertTrue(nnBuf.isValid() == true);
+  }
+
+}
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryBoundaryCheckTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryBoundaryCheckTest.java
new file mode 100644
index 0000000..1362f44
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryBoundaryCheckTest.java
@@ -0,0 +1,205 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.datasketches.memory.internal;
+
+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 testGetBoolean() {
+    writableBuffer.getBoolean(7);
+    try {
+      writableBuffer.getBoolean(8);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutBoolean() {
+    writableBuffer.putBoolean(7, true);
+    try {
+      writableBuffer.putBoolean(8, true);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetByte() {
+    writableBuffer.getByte(7);
+    try {
+      writableBuffer.getByte(8);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutByte() {
+    writableBuffer.putByte(7, (byte) 1);
+    try {
+      writableBuffer.putByte(8, (byte) 1);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetChar() {
+    writableBuffer.getChar(6);
+    try {
+      writableBuffer.getChar(7);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutChar() {
+    writableBuffer.putChar(6, 'a');
+    try {
+      writableBuffer.putChar(7, 'a');
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetShort() {
+    writableBuffer.getShort(6);
+    try {
+      writableBuffer.getShort(7);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutShort() {
+    writableBuffer.putShort(6, (short) 1);
+    try {
+      writableBuffer.putShort(7, (short) 1);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetInt() {
+    writableBuffer.getInt(4);
+    try {
+      writableBuffer.getInt(5);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutInt() {
+    writableBuffer.putInt(4, 1);
+    try {
+      writableBuffer.putInt(5, 1);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetFloat() {
+    writableBuffer.getFloat(4);
+    try {
+      writableBuffer.getFloat(5);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutFloat() {
+    writableBuffer.putFloat(4, 1f);
+    try {
+      writableBuffer.putFloat(5, 1f);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetLong() {
+    writableBuffer.getLong(0);
+    try {
+      writableBuffer.getLong(1);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutLong() {
+    writableBuffer.putLong(0, 1L);
+    try {
+      writableBuffer.putLong(1, 1L);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetDouble() {
+    writableBuffer.getDouble(0);
+    try {
+      writableBuffer.getDouble(1);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testPutDouble() {
+    writableBuffer.putDouble(0, 1d);
+    try {
+      writableBuffer.putDouble(1, 1d);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+}
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryCleanerTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryCleanerTest.java
new file mode 100644
index 0000000..d7b40ea
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryCleanerTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.testng.annotations.Test;
+
+public class MemoryCleanerTest {
+
+    @Test
+    public void cleanerDeallocates() {
+       SimpleDeallocator deallocator = new SimpleDeallocator();
+       MemoryCleaner cleaner = new MemoryCleaner(this, deallocator);
+       cleaner.clean();
+       assertTrue(SimpleDeallocator.getHasRun());
+    }
+
+    @Test
+    public void noDeallocation() {
+        SimpleDeallocator deallocator = new SimpleDeallocator();
+        new MemoryCleaner(this, deallocator);
+        assertFalse(SimpleDeallocator.getHasRun());
+    }
+
+    static final class SimpleDeallocator implements Runnable {
+        static final AtomicBoolean hasRun = new AtomicBoolean();
+
+        SimpleDeallocator() {
+            hasRun.set(false);
+        }
+
+        @Override
+        public void run() {
+            hasRun.compareAndSet(false, true);
+        }
+
+        public static Boolean getHasRun() {
+            return hasRun.get();
+        }
+    }
+}
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryCloseExceptionTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryCloseExceptionTest.java
new file mode 100644
index 0000000..249d432
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryCloseExceptionTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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 org.apache.datasketches.memory.MemoryCloseException;
+import org.testng.annotations.Test;
+
+public class MemoryCloseExceptionTest {
+
+  @Test
+  public void checkNoArgs() {
+    try {
+      throw new MemoryCloseException();
+    } catch (final MemoryCloseException e) {}
+
+    try {
+      throw new MemoryCloseException("Test Exception");
+    } catch (final MemoryCloseException e) {}
+  }
+}
+
+
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryReadWriteSafetyTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryReadWriteSafetyTest.java
new file mode 100644
index 0000000..553c432
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryReadWriteSafetyTest.java
@@ -0,0 +1,227 @@
+/*
+ * 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.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import org.apache.datasketches.memory.MapHandle;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.ReadOnlyException;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+public class MemoryReadWriteSafetyTest {
+
+  // Test various operations with read-only Memory
+
+  final WritableMemory mem = (WritableMemory) Memory.wrap(new byte[8]);
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testPutByte() {
+    mem.putByte(0, (byte) 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testPutBoolean() {
+    mem.putBoolean(0, true);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testPutShort() {
+    mem.putShort(0, (short) 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testPutChar() {
+    mem.putChar(0, (char) 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testPutInt() {
+    mem.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testPutLong() {
+    mem.putLong(0, 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testPutFloat() {
+    mem.putFloat(0, 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testPutDouble() {
+    mem.putDouble(0, 1);
+  }
+
+  @Test(expectedExceptions = ReadOnlyException.class)
+  public void testPutByteArray() {
+    mem.putByteArray(0, new byte[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = ReadOnlyException.class)
+  public void testPutBooleanArray() {
+    mem.putBooleanArray(0, new boolean[] {true}, 0, 1);
+  }
+
+  @Test(expectedExceptions = ReadOnlyException.class)
+  public void testPutShortArray() {
+    mem.putShortArray(0, new short[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = ReadOnlyException.class)
+  public void testPutCharArray() {
+    mem.putCharArray(0, new char[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = ReadOnlyException.class)
+  public void testPutIntArray() {
+    mem.putIntArray(0, new int[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = ReadOnlyException.class)
+  public void testPutLongArray() {
+    mem.putLongArray(0, new long[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = ReadOnlyException.class)
+  public void testPutFloatArray() {
+    mem.putFloatArray(0, new float[] {1}, 0, 1);
+  }
+
+  @Test(expectedExceptions = ReadOnlyException.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 = AssertionError.class)
+  public void testWritableMemoryRegion() {
+    WritableMemory mem1 = (WritableMemory) WritableMemory.allocate(8).region(0, 8);
+    mem1.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testByteArrayWrap() {
+    WritableMemory mem1 = (WritableMemory) Memory.wrap(new byte[8]);
+    mem1.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testByteArrayWrapWithBO() {
+    WritableMemory mem1 = (WritableMemory) Memory.wrap(new byte[8], ByteOrder.nativeOrder());
+    mem1.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testByteArrayWrapWithOffsetsAndBO() {
+    WritableMemory mem1 = (WritableMemory) Memory.wrap(new byte[8], 0, 4, ByteOrder.nativeOrder());
+    mem1.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testBooleanArrayWrap() {
+    WritableMemory mem1 = (WritableMemory) Memory.wrap(new boolean[8]);
+    mem1.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testShortArrayWrap() {
+    WritableMemory mem1 = (WritableMemory) Memory.wrap(new short[8]);
+    mem1.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testCharArrayWrap() {
+    WritableMemory mem1 = (WritableMemory) Memory.wrap(new char[8]);
+    mem1.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testIntArrayWrap() {
+    WritableMemory mem1 = (WritableMemory) Memory.wrap(new int[8]);
+    mem1.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testLongArrayWrap() {
+    WritableMemory mem1 = (WritableMemory) Memory.wrap(new long[8]);
+    mem1.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testFloatArrayWrap() {
+    WritableMemory mem1 = (WritableMemory) Memory.wrap(new float[8]);
+    mem1.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testDoubleArrayWrap() {
+    WritableMemory mem1 = (WritableMemory) Memory.wrap(new double[8]);
+    mem1.putInt(0, 1);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void testByteBufferWrap() {
+    WritableMemory mem1 = (WritableMemory) Memory.wrap(ByteBuffer.allocate(8));
+    mem1.putInt(0, 1);
+  }
+
+  //@SuppressWarnings("resource")
+  @Test(expectedExceptions = AssertionError.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 (MapHandle h = Memory.map(tempFile)) {
+        ((WritableMemory) h.get()).putInt(0, 1);
+      }
+    }
+  }
+
+  @SuppressWarnings("resource")
+  @Test(expectedExceptions = AssertionError.class)
+  public void testMapFileWithOffsetsAndBO() throws Exception {
+    File tempFile = File.createTempFile("test", "test");
+    tempFile.deleteOnExit();
+    new RandomAccessFile(tempFile, "rw").setLength(8);
+    try (MapHandle h = Memory.map(tempFile, 0, 4, ByteOrder.nativeOrder())) {
+      ((WritableMemory) h.get()).putInt(0, 1);
+    }
+  }
+
+  @SuppressWarnings("resource")
+  @Test(expectedExceptions = IllegalArgumentException.class)
+  public void testMapFileBeyondTheFileSize() throws Exception {
+    File tempFile = File.createTempFile("test", "test");
+    tempFile.deleteOnExit();
+    new RandomAccessFile(tempFile, "rw").setLength(8);
+    try (MapHandle unused = Memory.map(tempFile, 0, 16, ByteOrder.nativeOrder())) {
+    }
+  }
+}
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryTest.java
new file mode 100644
index 0000000..045c59f
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryTest.java
@@ -0,0 +1,479 @@
+/*
+ * 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.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.io.File;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.List;
+
+import org.apache.datasketches.memory.BaseState;
+import org.apache.datasketches.memory.MapHandle;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.WritableBuffer;
+import org.apache.datasketches.memory.WritableHandle;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import org.testng.collections.Lists;
+
+public class MemoryTest {
+  private static final String LS = System.getProperty("line.separator");
+
+  @BeforeClass
+  public void setReadOnly() {
+    UtilTest.setGettysburgAddressFileToReadOnly();
+  }
+
+  @Test
+  public void checkDirectRoundTrip() throws Exception {
+    int n = 1024; //longs
+    try (WritableHandle wh = WritableMemory.allocateDirect(n * 8)) {
+      WritableMemory mem = wh.getWritable();
+      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 memZeroLengthArrayBoolean = WritableMemory.writableWrap(new boolean[0]);
+    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(memZeroLengthArrayBoolean.getCapacity(), 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 boolean[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 boolean[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 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 checkByteBufWrongOrder() {
+    int n = 1024; //longs
+    ByteBuffer bb = ByteBuffer.allocate(n * 8);
+    bb.order(ByteOrder.BIG_ENDIAN);
+    Memory mem = Memory.wrap(bb);
+    assertFalse(mem.getTypeByteOrder() == ByteOrder.nativeOrder());
+    assertEquals(mem.getTypeByteOrder(), 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());
+    //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, Util.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, Util.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));
+    }
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void checkParentUseAfterFree() throws Exception {
+    int bytes = 64 * 8;
+    WritableHandle wh = WritableMemory.allocateDirect(bytes);
+    WritableMemory wmem = wh.getWritable();
+    wh.close();
+    //with -ea assert: Memory not valid.
+    //with -da sometimes segfaults, sometimes passes!
+    wmem.getLong(0);
+  }
+
+  @Test(expectedExceptions = AssertionError.class)
+  public void checkRegionUseAfterFree() throws Exception {
+    int bytes = 64;
+    WritableHandle wh = WritableMemory.allocateDirect(bytes);
+    Memory wmem = wh.get();
+    Memory region = wmem.region(0L, bytes);
+    wh.close();
+    //with -ea assert: Memory not valid.
+    //with -da sometimes segfaults, sometimes passes!
+    region.getByte(0);
+  }
+
+  @Test
+  public void checkMonitorDirectStats() throws Exception {
+    int bytes = 1024;
+    long curAllocations = BaseState.getCurrentDirectMemoryAllocations();
+    long curAllocated   = BaseState.getCurrentDirectMemoryAllocated();
+    if (curAllocations != 0) { System.err.println(curAllocations + " should be zero!"); }
+    WritableHandle wh1 = WritableMemory.allocateDirect(bytes);
+    WritableHandle wh2 = WritableMemory.allocateDirect(bytes);
+    assertEquals(BaseState.getCurrentDirectMemoryAllocations(), 2L + curAllocations);
+    assertEquals(BaseState.getCurrentDirectMemoryAllocated(), 2 * bytes + curAllocated);
+
+    wh1.close();
+    assertEquals(BaseState.getCurrentDirectMemoryAllocations(), 1L + curAllocations);
+    assertEquals(BaseState.getCurrentDirectMemoryAllocated(), bytes + curAllocated);
+
+    wh2.close();
+    wh2.close(); //check that it doesn't go negative.
+    //even though the handles are closed, these methods are static access
+    assertEquals(BaseState.getCurrentDirectMemoryAllocations(), 0L + curAllocations);
+    assertEquals(BaseState.getCurrentDirectMemoryAllocated(), 0L + curAllocated);
+  }
+
+  @Test
+  public void checkMonitorDirectMapStats() throws Exception {
+    File file = getResourceFile("GettysburgAddress.txt");
+    long bytes = file.length();
+
+    MapHandle mmh1 = Memory.map(file);
+    MapHandle mmh2 = Memory.map(file);
+
+    assertEquals(BaseState.getCurrentDirectMemoryMapAllocations(), 2L);
+    assertEquals(BaseState.getCurrentDirectMemoryMapAllocated(), 2 * bytes);
+
+    mmh1.close();
+    assertEquals(BaseState.getCurrentDirectMemoryMapAllocations(), 1L);
+    assertEquals(BaseState.getCurrentDirectMemoryMapAllocated(), bytes);
+
+    mmh2.close();
+    mmh2.close(); //check that it doesn't go negative.
+    //even though the handles are closed, these methods are static access
+    assertEquals(BaseState.getCurrentDirectMemoryMapAllocations(), 0L);
+    assertEquals(BaseState.getCurrentDirectMemoryMapAllocated(), 0L);
+  }
+
+  @Test
+  public void checkMemReqSvr() throws Exception {
+    WritableMemory wmem;
+    WritableBuffer wbuf;
+    if (BaseState.defaultMemReqSvr == null) { //This is a policy choice
+      //ON HEAP
+      wmem = WritableMemory.writableWrap(new byte[16]);
+      assertNull(wmem.getMemoryRequestServer());
+      wbuf = wmem.asWritableBuffer();
+      assertNull(wbuf.getMemoryRequestServer());
+      //OFF HEAP
+      try (WritableHandle wdh = WritableMemory.allocateDirect(16)) { //OFF HEAP
+        wmem = wdh.getWritable();
+        assertNull(wmem.getMemoryRequestServer());
+        wbuf = wmem.asWritableBuffer();
+        assertNull(wbuf.getMemoryRequestServer());
+      }
+      //ByteBuffer
+      ByteBuffer bb = ByteBuffer.allocate(16);
+      wmem = WritableMemory.writableWrap(bb);
+      assertNull(wmem.getMemoryRequestServer());
+      wbuf = wmem.asWritableBuffer();
+      assertNull(wbuf.getMemoryRequestServer());
+    } else {
+      //ON HEAP
+      wmem = WritableMemory.writableWrap(new byte[16]);
+      assertNotNull(wmem.getMemoryRequestServer());
+      wbuf = wmem.asWritableBuffer();
+      assertNotNull(wbuf.getMemoryRequestServer());
+      //OFF HEAP
+      try (WritableHandle wdh = WritableMemory.allocateDirect(16)) {
+        WritableMemory wmem2 = wdh.getWritable();
+        assertNotNull(wmem2.getMemoryRequestServer());
+        wbuf = wmem.asWritableBuffer();
+        assertNotNull(wbuf.getMemoryRequestServer());
+      }
+      //ByteBuffer
+      ByteBuffer bb = ByteBuffer.allocate(16);
+      wmem = WritableMemory.writableWrap(bb);
+      assertNotNull(wmem.getMemoryRequestServer());
+      wbuf = wmem.asWritableBuffer();
+      assertNotNull(wbuf.getMemoryRequestServer());
+    }
+  }
+
+  @Test
+  public void checkHashCode() {
+    WritableMemory wmem = WritableMemory.allocate(32 + 7);
+    int hc = wmem.hashCode();
+    assertEquals(hc, -1895166923);
+  }
+
+  @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-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryWriteToTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryWriteToTest.java
new file mode 100644
index 0000000..78e51ab
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MemoryWriteToTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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.UNSAFE_COPY_THRESHOLD_BYTES;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.channels.Channels;
+import java.nio.channels.WritableByteChannel;
+import java.util.concurrent.ThreadLocalRandom;
+
+import org.apache.datasketches.memory.WritableHandle;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class MemoryWriteToTest {
+
+  @Test
+  public void testOnHeap() throws IOException {
+    testWriteTo(createRandomBytesMemory(0));
+    testWriteTo(createRandomBytesMemory(7));
+    testWriteTo(createRandomBytesMemory(1023));
+    testWriteTo(createRandomBytesMemory(10_000));
+    testWriteTo(createRandomBytesMemory(UNSAFE_COPY_THRESHOLD_BYTES * 5));
+    testWriteTo(createRandomBytesMemory((UNSAFE_COPY_THRESHOLD_BYTES * 5) + 10));
+  }
+
+  @Test
+  public void testOnHeapInts() throws IOException {
+    testWriteTo(createRandomIntsMemory(0));
+    testWriteTo(createRandomIntsMemory(7));
+    testWriteTo(createRandomIntsMemory(1023));
+    testWriteTo(createRandomIntsMemory(10_000));
+    testWriteTo(createRandomIntsMemory(UNSAFE_COPY_THRESHOLD_BYTES * 5));
+    testWriteTo(createRandomIntsMemory((UNSAFE_COPY_THRESHOLD_BYTES * 5) + 10));
+  }
+
+  @Test
+  public void testOffHeap() throws Exception {
+    try (WritableHandle handle =
+        WritableMemory.allocateDirect((UNSAFE_COPY_THRESHOLD_BYTES * 5) + 10)) {
+      WritableMemory mem = handle.getWritable();
+      testWriteTo(mem.region(0, 0));
+      testOffHeap(mem, 7);
+      testOffHeap(mem, 1023);
+      testOffHeap(mem, 10_000);
+      testOffHeap(mem, UNSAFE_COPY_THRESHOLD_BYTES * 5);
+      testOffHeap(mem, (UNSAFE_COPY_THRESHOLD_BYTES * 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 {
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    try (WritableByteChannel out = Channels.newChannel(baos)) {
+      mem.writeTo(0, mem.getCapacity(), out);
+    }
+    byte[] result = baos.toByteArray();
+    Assert.assertTrue(mem.equals(Memory.wrap(result)));
+  }
+}
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MurmurHash3v2Test.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MurmurHash3v2Test.java
new file mode 100644
index 0000000..6949008
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/MurmurHash3v2Test.java
@@ -0,0 +1,401 @@
+/*
+ * 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.MurmurHash3v2.hash;
+import static org.testng.Assert.fail;
+
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.MurmurHash3v2;
+import org.apache.datasketches.memory.WritableHandle;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * Tests the MurmurHash3 against specific, known hash results given known
+ * inputs obtained from the public domain C++ version 150.
+ *
+ * @author Lee Rhodes
+ */
+public class MurmurHash3v2Test {
+
+  @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 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 = MurmurHash3v2.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 (WritableHandle wh = WritableMemory.allocateDirect(8)) {
+      long[] out = new long[2];
+      Memory mem = wh.get();
+      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-java8/src/test/java/org/apache/datasketches/memory/internal/NativeWritableBufferImplTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NativeWritableBufferImplTest.java
new file mode 100644
index 0000000..0461104
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NativeWritableBufferImplTest.java
@@ -0,0 +1,600 @@
+/*
+ * 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.Buffer;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.ReadOnlyException;
+import org.apache.datasketches.memory.WritableBuffer;
+import org.apache.datasketches.memory.WritableHandle;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class NativeWritableBufferImplTest {
+
+  //Simple Native direct
+
+  @Test
+  public void checkNativeCapacityAndClose() throws Exception {
+    int memCapacity = 64;
+    WritableHandle wmh = WritableMemory.allocateDirect(memCapacity);
+    WritableMemory wmem = wmh.getWritable();
+    WritableBuffer wbuf = wmem.asWritableBuffer();
+    assertEquals(wbuf.getCapacity(), memCapacity);
+
+    wmh.close(); //intentional
+    assertFalse(wbuf.isValid());
+
+    wmh.close(); //intentional, nothing to free
+  }
+
+  //Simple Heap arrays
+
+  @Test
+  public void checkBooleanArray() {
+    boolean[] srcArray = { true, false, true, false, false, true, true, false };
+    boolean[] dstArray = new boolean[8];
+
+    Buffer buf = Memory.wrap(srcArray).asBuffer();
+    buf.getBooleanArray(dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+
+    WritableBuffer wbuf = WritableMemory.writableWrap(srcArray).asWritableBuffer();
+    wbuf.getBooleanArray(dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+    assertTrue(buf.hasArray());
+  }
+
+  @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 (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory wmem = wrh.getWritable();
+      WritableBuffer wbuf = wmem.asWritableBuffer();
+      wbuf.toHexString("Force Assertion Error", memCapacity, 8);
+    } catch (IllegalArgumentException e) {
+      //ok
+    }
+  }
+
+  @Test
+  public void checkNativeSrcArrayBound() throws Exception {
+    long memCapacity = 64;
+    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory wmem = wrh.getWritable();
+      WritableBuffer wbuf = wmem.asWritableBuffer();
+      byte[] srcArray = { 1, -2, 3, -4 };
+      wbuf.putByteArray(srcArray, 0, 5); //wrong!
+    } catch (IllegalArgumentException e) {
+      //pass
+    }
+  }
+
+
+  @Test(expectedExceptions = IllegalArgumentException.class)
+  public void checkRegionBounds() throws Exception {
+    int memCapacity = 64;
+    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory wmem = wrh.getWritable();
+      WritableBuffer wbuf = wmem.asWritableBuffer();
+      wbuf.writableRegion(1, 64, wbuf.getTypeByteOrder()); //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.getByteBuffer();
+    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 = ReadOnlyException.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 = ReadOnlyException.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));
+  }
+
+  @Test
+  public void checkIsDirect() throws Exception {
+    int memCapacity = 64;
+    WritableBuffer mem = WritableMemory.allocate(memCapacity).asWritableBuffer();
+    assertFalse(mem.isDirect());
+    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem2 = wrh.getWritable();
+      WritableBuffer wbuf = mem2.asWritableBuffer();
+      assertTrue(wbuf.isDirect());
+      wrh.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() {
+    UnsafeUtil.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 (WritableHandle h1 = WritableMemory.allocateDirect(4);
+        WritableHandle h2 = WritableMemory.allocateDirect(4);
+        WritableHandle h3 = WritableMemory.allocateDirect(5))
+    {
+      WritableMemory mem1 = h1.getWritable();
+      mem1.putByteArray(0, arr1, 0, 4);
+
+      WritableMemory mem2 = h2.getWritable();
+      mem2.putByteArray(0, arr2, 0, 4);
+
+      WritableMemory mem3 = h3.getWritable();
+      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();
+    wbuf.checkValidAndBounds(0, 64);
+    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);
+    }
+    WritableMemory wmem3 = wbuf.asWritableMemory();
+    wmem3.checkValidAndBounds(0, 64);
+  }
+
+  @Test
+  public void checkCumAndRegionOffset() {
+    WritableMemory wmem = WritableMemory.allocate(64);
+    WritableMemory reg = wmem.writableRegion(32, 32);
+    WritableBuffer buf = reg.asWritableBuffer();
+    assertEquals(buf.getRegionOffset(), 32);
+    assertEquals(buf.getRegionOffset(0), 32);
+    assertEquals(buf.getCumulativeOffset(), 32 + 16);
+    assertEquals(buf.getCumulativeOffset(0), 32 + 16);
+  }
+
+  @Test
+  public void checkIsSameResource() {
+    byte[] byteArr = new byte[64];
+    WritableBuffer wbuf1 = WritableMemory.writableWrap(byteArr).asWritableBuffer();
+    WritableBuffer wbuf2 = WritableMemory.writableWrap(byteArr).asWritableBuffer();
+    assertTrue(wbuf1.isSameResource(wbuf2));
+  }
+
+  @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 (ReadOnlyException 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 (ReadOnlyException 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 (ReadOnlyException 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.getTypeByteOrder());
+
+    try {
+      Buffer buf = Buffer.wrap(bb);
+      wbuf = (WritableBuffer) buf;
+      @SuppressWarnings("unused")
+      WritableBuffer wreg2 = wbuf.writableRegion(0, 1, wbuf.getTypeByteOrder());
+      Assert.fail();
+    } catch (ReadOnlyException expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void checkZeroBuffer() {
+    WritableMemory wmem = WritableMemory.allocate(8);
+    WritableBuffer wbuf = wmem.asWritableBuffer();
+    WritableBuffer reg = wbuf.writableRegion(0, 0, wbuf.getTypeByteOrder());
+    assertEquals(reg.getCapacity(), 0);
+  }
+
+  @Test
+  public void checkDuplicateNonNative() {
+    WritableMemory wmem = WritableMemory.allocate(64);
+    wmem.putShort(0, (short) 1);
+    Buffer buf = wmem.asWritableBuffer().duplicate(Util.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-java8/src/test/java/org/apache/datasketches/memory/internal/NativeWritableMemoryImplTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NativeWritableMemoryImplTest.java
new file mode 100644
index 0000000..8d52250
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NativeWritableMemoryImplTest.java
@@ -0,0 +1,723 @@
+/*
+ * 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.WritableHandle;
+import org.apache.datasketches.memory.Buffer;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.ReadOnlyException;
+import org.apache.datasketches.memory.WritableBuffer;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+public class NativeWritableMemoryImplTest {
+
+  //Simple Native direct
+
+  @Test
+  public void checkNativeCapacityAndClose() throws Exception {
+    int memCapacity = 64;
+    WritableHandle wmh = WritableMemory.allocateDirect(memCapacity);
+    WritableMemory mem = wmh.getWritable();
+    assertEquals(memCapacity, mem.getCapacity());
+
+    wmh.close(); //intentional
+    assertFalse(mem.isValid());
+
+    wmh.close(); //intentional, nothing to free
+  }
+
+  //Simple Native arrays
+
+  @Test
+  public void checkBooleanArray() {
+    boolean[] srcArray = { true, false, true, false, false, true, true, false };
+    boolean[] dstArray = new boolean[8];
+
+    Memory mem = Memory.wrap(srcArray);
+    mem.getBooleanArray(0, dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+
+    WritableMemory wmem = WritableMemory.writableWrap(srcArray);
+    wmem.getBooleanArray(0, dstArray, 0, 8);
+    for (int i=0; i<8; i++) {
+      assertEquals(dstArray[i], srcArray[i]);
+    }
+    assertTrue(mem.hasArray());
+  }
+
+  @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 (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem = wrh.getWritable();
+      mem.toHexString("Force Assertion Error", memCapacity, 8);
+    } catch (IllegalArgumentException e) {
+      //ok
+    }
+  }
+
+  @Test
+  public void checkNativeSrcArrayBound() throws Exception {
+    long memCapacity = 64;
+    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem = wrh.getWritable();
+      byte[] srcArray = { 1, -2, 3, -4 };
+      mem.putByteArray(0L, srcArray, 0, 5);
+    } catch (IllegalArgumentException e) {
+      //pass
+    }
+  }
+
+  //Copy Within tests
+
+  @Test(expectedExceptions = IllegalArgumentException.class)
+  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 (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem = wrh.getWritable();
+      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 (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem = wrh.getWritable();
+      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 checkCopyWithinNativeSrcBound() throws Exception {
+    int memCapacity = 64;
+    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem = wrh.getWritable();
+      mem.copyTo(32, mem, 32, 33);  //hit source bound check
+      fail("Did Not Catch Assertion Error: source bound");
+    }
+    catch (IllegalArgumentException e) {
+      //pass
+    }
+  }
+
+  @Test
+  public void checkCopyWithinNativeDstBound() throws Exception {
+    int memCapacity = 64;
+    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem = wrh.getWritable();
+      mem.copyTo(0, mem, 32, 33);  //hit dst bound check
+      fail("Did Not Catch Assertion Error: dst bound");
+    }
+    catch (IllegalArgumentException e) {
+      //pass
+    }
+  }
+
+  @Test
+  public void checkCopyCrossNativeSmall() throws Exception {
+    int memCapacity = 64;
+
+    try (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity);
+        WritableHandle wrh2 = WritableMemory.allocateDirect(memCapacity))
+    {
+      WritableMemory mem1 = wrh1.getWritable();
+      WritableMemory mem2 = wrh2.getWritable();
+
+      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);
+      }
+      wrh1.close();
+      wrh2.close();
+    }
+  }
+
+  @Test
+  public void checkCopyCrossNativeLarge() throws Exception {
+    int memCapacity = (2<<20) + 64;
+    int memCapLongs = memCapacity / 8;
+
+    try (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity);
+        WritableHandle wrh2 = WritableMemory.allocateDirect(memCapacity))
+    {
+      WritableMemory mem1 = wrh1.getWritable();
+      WritableMemory mem2 = wrh2.getWritable();
+
+      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 (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem1 = wrh1.getWritable();
+
+      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 (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem1 = wrh1.getWritable();
+
+      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 (WritableHandle wrh1 = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem1 = wrh1.getWritable();
+
+      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(expectedExceptions = IllegalArgumentException.class)
+  public void checkRegionBounds() throws Exception {
+    int memCapacity = 64;
+    try (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
+      WritableMemory mem = wrh.getWritable();
+      mem.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.getByteBuffer();
+    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 = ReadOnlyException.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 = ReadOnlyException.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 (WritableHandle wrh = WritableMemory.allocateDirect(memCapacity)) {
+      mem = wrh.getWritable();
+      assertTrue(mem.isDirect());
+      wrh.close();
+    }
+  }
+
+  @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() {
+    UnsafeUtil.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);
+    mem3.checkValidAndBounds(0, 5);
+  }
+
+  @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 (WritableHandle h1 = WritableMemory.allocateDirect(4);
+        WritableHandle h2 = WritableMemory.allocateDirect(4);
+        WritableHandle h3 = WritableMemory.allocateDirect(5))
+    {
+      WritableMemory mem1 = h1.getWritable();
+      mem1.putByteArray(0, arr1, 0, 4);
+
+      WritableMemory mem2 = h2.getWritable();
+      mem2.putByteArray(0, arr2, 0, 4);
+
+      WritableMemory mem3 = h3.getWritable();
+      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 checkCumAndRegionOffset() {
+    WritableMemory wmem = WritableMemory.allocate(64);
+    WritableMemory reg = wmem.writableRegion(32, 32);
+    assertEquals(reg.getRegionOffset(), 32);
+    assertEquals(reg.getRegionOffset(0), 32);
+    assertEquals(reg.getCumulativeOffset(), 32 + 16);
+    assertEquals(reg.getCumulativeOffset(0), 32 + 16);
+  }
+
+  @Test
+  public void checkIsSameResource() {
+    byte[] byteArr = new byte[64];
+    WritableMemory wmem1 = WritableMemory.writableWrap(byteArr);
+    WritableMemory wmem2 = WritableMemory.writableWrap(byteArr);
+    assertTrue(wmem1.isSameResource(wmem2));
+  }
+
+  @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 = ReadOnlyException.class)
+  public void checkAsWritableRegionRO() {
+    ByteBuffer byteBuf = ByteBuffer.allocate(64);
+    WritableMemory wmem = (WritableMemory) Memory.wrap(byteBuf);
+    wmem.writableRegion(0, 1);
+  }
+
+  @Test(expectedExceptions = ReadOnlyException.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(Util.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-java8/src/test/java/org/apache/datasketches/memory/internal/NioBitsTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NioBitsTest.java
new file mode 100644
index 0000000..8ed5916
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NioBitsTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.testng.annotations.Test;
+
+/**
+ * @author Lee Rhodes
+ */
+public class NioBitsTest {
+
+  @Test
+  public void checkVMParams() {
+    println("Max MemoryImpl: " + NioBits.getMaxDirectByteBufferMemory());
+    println("Page Aligned: " + NioBits.isPageAligned());
+    println("Page Size: " + NioBits.pageSize());
+  }
+
+  @Test
+  public void checkGetAtomicFields() {
+    //testing this beyond 2GB may not work on JVMs < 8GB.
+    //This should be checked manually
+   // long cap = 1024L + Integer.MAX_VALUE;
+    long cap = 1L << 10;
+    printStats();
+    NioBits.reserveMemory(cap, cap);
+    printStats();
+    NioBits. unreserveMemory(cap, cap);
+    printStats();
+  }
+
+  @Test
+  public void checkPageCount() {
+    assertEquals(NioBits.pageCount(0), 0);
+    assertEquals(NioBits.pageCount(1), 1);
+  }
+
+  private static void printStats() {
+    long count = NioBits.getDirectAllocationsCount();
+    long resMem = NioBits.getReservedMemory();
+    long totCap = NioBits.getTotalCapacity();
+    long maxDBBmem = NioBits.getMaxDirectByteBufferMemory();
+    String s = String.format("%,10d\t%,15d\t%,15d\t%,15d", count, resMem, totCap, maxDBBmem);
+    println(s);
+  }
+
+  @Test
+  public void printlnTest() {
+    println("PRINTING: " + this.getClass().getName());
+  }
+
+  /**
+   * @param s value to print
+   */
+  static void println(final String s) {
+    //System.out.println(s); //disable here
+  }
+
+}
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NonNativeWritableBufferImplTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NonNativeWritableBufferImplTest.java
new file mode 100644
index 0000000..57d481a
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NonNativeWritableBufferImplTest.java
@@ -0,0 +1,260 @@
+/*
+ * 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.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.getTypeByteOrder(), ByteOrder.BIG_ENDIAN);
+
+    WritableBuffer wreg = wbuf.writableRegion();
+    assertEquals(wreg.getTypeByteOrder(), ByteOrder.BIG_ENDIAN);
+  }
+
+  @Test
+  public void checkDuplicateZeros() {
+    byte[] bArr = new byte[0];
+    WritableMemory wmem = WritableMemory.writableWrap(bArr, ByteOrder.BIG_ENDIAN);
+    Buffer buf = wmem.asBuffer();
+    Buffer dup = buf.duplicate();
+    assertEquals(dup.getTypeByteOrder(), ByteOrder.LITTLE_ENDIAN);
+
+    Buffer reg = buf.region();
+    assertEquals(reg.getTypeByteOrder(), ByteOrder.LITTLE_ENDIAN);
+  }
+
+}
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NonNativeWritableMemoryImplTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NonNativeWritableMemoryImplTest.java
new file mode 100644
index 0000000..c6bd5d0
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/NonNativeWritableMemoryImplTest.java
@@ -0,0 +1,219 @@
+/*
+ * 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.Memory;
+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
+
+
+  @Test
+  public void testGetAndAddLong() {
+    wmem.getAndAddLong(0, 1L);
+    try {
+      wmem.getAndAddLong(1, 1L);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testGetAndSetLong() {
+    wmem.getAndSetLong(0, 1L);
+    try {
+      wmem.getAndSetLong(1, 1L);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  @Test
+  public void testCompareAndSwapLong() {
+    wmem.compareAndSwapLong(0, 0L, 1L);
+    try {
+      wmem.compareAndSwapLong(1, 0L, 1L);
+      throw new RuntimeException("Expected AssertionError");
+    } catch (final AssertionError expected) {
+      // ignore
+    }
+  }
+
+  //check Region
+  @Test
+  public void checkRegion() {
+    WritableMemory wreg = wmem.writableRegion(0, wmem.getCapacity());
+    assertEquals(wreg.getTypeByteOrder(), ByteOrder.BIG_ENDIAN);
+  }
+
+  @Test
+  public void checkRegionZeros() {
+    byte[] bArr1 = new byte[0];
+    WritableMemory wmem1 = WritableMemory.writableWrap(bArr1, ByteOrder.BIG_ENDIAN);
+    Memory reg = wmem1.region(0, wmem1.getCapacity());
+    assertEquals(reg.getTypeByteOrder(), ByteOrder.LITTLE_ENDIAN);
+  }
+
+}
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/SpecificLeafTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/SpecificLeafTest.java
new file mode 100644
index 0000000..87f7e35
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/SpecificLeafTest.java
@@ -0,0 +1,194 @@
+/*
+ * 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.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.Buffer;
+import org.apache.datasketches.memory.Memory;
+import org.apache.datasketches.memory.WritableHandle;
+import org.apache.datasketches.memory.WritableMapHandle;
+import org.apache.datasketches.memory.WritableMemory;
+import org.testng.annotations.Test;
+
+/**
+ * @author Lee Rhodes
+ */
+public class SpecificLeafTest {
+
+  @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(((BaseStateImpl)mem).isBBType());
+    assertTrue(mem.isReadOnly());
+    checkCrossLeafTypeIds(mem);
+    Buffer buf = mem.asBuffer().region(0, bytes, ByteOrder.nativeOrder());
+
+    bb.order(Util.NON_NATIVE_BYTE_ORDER);
+    Memory mem2 = Memory.wrap(bb).region(0, bytes, Util.NON_NATIVE_BYTE_ORDER);
+    Buffer buf2 = mem2.asBuffer().region(0, bytes, Util.NON_NATIVE_BYTE_ORDER);
+    Buffer buf3 = buf2.duplicate();
+
+    assertTrue(((BaseStateImpl)mem).isRegionType());
+    assertTrue(((BaseStateImpl)mem2).isRegionType());
+    assertTrue(((BaseStateImpl)buf).isRegionType());
+    assertTrue(((BaseStateImpl)buf2).isRegionType());
+    assertTrue(((BaseStateImpl)buf3).isDuplicateType());
+  }
+
+  @Test
+  public void checkDirectLeafs() throws Exception {
+    int bytes = 128;
+    try (WritableHandle h = WritableMemory.allocateDirect(bytes)) {
+      WritableMemory wmem = h.getWritable(); //native mem
+      assertTrue(((BaseStateImpl)wmem).isDirectType());
+      assertFalse(wmem.isReadOnly());
+      checkCrossLeafTypeIds(wmem);
+      WritableMemory nnwmem = wmem.writableRegion(0, bytes, Util.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, Util.NON_NATIVE_BYTE_ORDER);
+      Buffer buf2 = mem2.asBuffer().region(0, bytes, Util.NON_NATIVE_BYTE_ORDER);
+      Buffer buf3 = buf2.duplicate();
+
+      assertTrue(((BaseStateImpl)mem).isRegionType());
+      assertTrue(((BaseStateImpl)mem2).isRegionType());
+      assertTrue(((BaseStateImpl)buf).isRegionType());
+      assertTrue(((BaseStateImpl)buf2).isRegionType());
+      assertTrue(((BaseStateImpl)buf3).isDuplicateType());
+    }
+  }
+
+  @Test
+  public void checkMapLeafs() throws Exception {
+    File file = new File("TestFile2.bin");
+    if (file.exists()) {
+      try {
+        java.nio.file.Files.delete(file.toPath());
+      } catch (IOException e) {
+        throw new RuntimeException(e);
+      }
+    }
+    assertTrue(file.createNewFile());
+    assertTrue(file.setWritable(true, false)); //writable=true, ownerOnly=false
+    assertTrue(file.isFile());
+    file.deleteOnExit();  //comment out if you want to examine the file.
+
+    final long bytes = 128;
+
+    try (WritableMapHandle h = WritableMemory.writableMap(file, 0L, bytes, ByteOrder.nativeOrder())) {
+      WritableMemory mem = h.getWritable(); //native mem
+      assertTrue(((BaseStateImpl)mem).isMapType());
+      assertFalse(mem.isReadOnly());
+      checkCrossLeafTypeIds(mem);
+      Memory nnreg = mem.region(0, bytes, Util.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, Util.NON_NATIVE_BYTE_ORDER);
+      Buffer buf2 = reg2.asBuffer().region(0, bytes, Util.NON_NATIVE_BYTE_ORDER);
+      Buffer buf3 = buf2.duplicate();
+
+      assertTrue(((BaseStateImpl)reg).isRegionType());
+      assertTrue(((BaseStateImpl)reg2).isRegionType());
+      assertTrue(((BaseStateImpl)buf).isRegionType());
+      assertTrue(((BaseStateImpl)buf2).isRegionType());
+      assertTrue(((BaseStateImpl)buf3).isDuplicateType());
+      assertTrue(((BaseStateImpl)buf4).isDuplicateType());
+    }
+  }
+
+  @Test
+  public void checkHeapLeafs() {
+    int bytes = 128;
+    Memory mem = Memory.wrap(new byte[bytes]);
+    assertTrue(((BaseStateImpl)mem).isHeapType());
+    assertTrue(((BaseStateImpl)mem).isReadOnlyType());
+    checkCrossLeafTypeIds(mem);
+    Memory nnreg = mem.region(0, bytes, Util.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, Util.NON_NATIVE_BYTE_ORDER);
+    Buffer buf2 = reg2.asBuffer().region(0, bytes, Util.NON_NATIVE_BYTE_ORDER);
+    Buffer buf3 = buf2.duplicate();
+
+    assertFalse(((BaseStateImpl)mem).isRegionType());
+    assertTrue(((BaseStateImpl)reg2).isRegionType());
+    assertTrue(((BaseStateImpl)buf).isRegionType());
+    assertTrue(((BaseStateImpl)buf2).isRegionType());
+    assertTrue(((BaseStateImpl)buf3).isDuplicateType());
+    assertTrue(((BaseStateImpl)buf4).isDuplicateType());
+  }
+
+  private static void checkCrossLeafTypeIds(Memory mem) {
+    Memory reg1 = mem.region(0, mem.getCapacity());
+    assertTrue(((BaseStateImpl)reg1).isRegionType());
+
+    Buffer buf1 = reg1.asBuffer();
+    assertTrue(((BaseStateImpl)buf1).isRegionType());
+    assertTrue(((BaseStateImpl)buf1).isBufferType());
+    assertTrue(buf1.isReadOnly());
+
+    Buffer buf2 = buf1.duplicate();
+    assertTrue(((BaseStateImpl)buf2).isRegionType());
+    assertTrue(((BaseStateImpl)buf2).isBufferType());
+    assertTrue(((BaseStateImpl)buf2).isDuplicateType());
+    assertTrue(buf2.isReadOnly());
+
+    Memory mem2 = buf1.asMemory(); //
+    assertTrue(((BaseStateImpl)mem2).isRegionType());
+    assertFalse(((BaseStateImpl)mem2).isBufferType());
+    assertFalse(((BaseStateImpl)mem2).isDuplicateType());
+    assertTrue(mem2.isReadOnly());
+
+    Buffer buf3 = buf1.duplicate(Util.NON_NATIVE_BYTE_ORDER);
+    assertTrue(((BaseStateImpl)buf3).isRegionType());
+    assertTrue(((BaseStateImpl)buf3).isBufferType());
+    assertTrue(((BaseStateImpl)buf3).isDuplicateType());
+    assertTrue(((BaseStateImpl)buf3).isNonNativeType());
+    assertTrue(buf3.isReadOnly());
+
+    Memory mem3 = buf3.asMemory();
+    assertTrue(((BaseStateImpl)mem3).isRegionType());
+    assertFalse(((BaseStateImpl)mem3).isBufferType());
+    assertTrue(((BaseStateImpl)mem3).isDuplicateType());
+    assertTrue(((BaseStateImpl)mem3).isNonNativeType());
+    assertTrue(mem3.isReadOnly());
+  }
+
+}
diff --git a/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/UnsafeUtilTest.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/UnsafeUtilTest.java
new file mode 100644
index 0000000..baaf90a
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/UnsafeUtilTest.java
@@ -0,0 +1,151 @@
+/*
+ * 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 static org.testng.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.testng.annotations.Test;
+
+
+/**
+ * @author Lee Rhodes
+ */
+public class UnsafeUtilTest {
+  long testField = 1; //Do not remove & cannot be static. Used in reflection check.
+
+
+  @Test
+  public void checkJdkString() {
+    String jdkVer;
+    int[] p = new int[2];
+    String[] good1_Strings = {"1.8.0_121", "8", "9", "10", "11", "12", "13"};
+    int len = good1_Strings.length;
+    for (int i = 0; i < len; i++) {
+      jdkVer = good1_Strings[i];
+      p = UnsafeUtil.parseJavaVersion(jdkVer);
+      UnsafeUtil.checkJavaVersion(jdkVer, p[0], p[1]);
+      int jdkMajor = (p[0] == 1) ? p[1] : p[0]; //model the actual JDK_MAJOR
+      if (p[0] == 1) { assertTrue(jdkMajor == p[1]); }
+      if (p[0] > 1 ) { assertTrue(jdkMajor == p[0]); }
+    }
+    try {
+      jdkVer = "14.0.4"; //ver 14 string
+      p = UnsafeUtil.parseJavaVersion(jdkVer);
+      UnsafeUtil.checkJavaVersion(jdkVer, p[0], p[1]);
+      fail();
+    } catch (IllegalArgumentException e) {
+      println("" + e);
+    }
+
+    try {
+      jdkVer = "1.7.0_80"; //1.7 string
+      p = UnsafeUtil.parseJavaVersion(jdkVer);
+      UnsafeUtil.checkJavaVersion(jdkVer, p[0], p[1]);
+      fail();
+    } catch (IllegalArgumentException e) {
+      println("" + e);
+    }
+    try {
+      jdkVer = "1.6.0_65"; //valid string but < 1.7
+      p = UnsafeUtil.parseJavaVersion(jdkVer);
+      UnsafeUtil.checkJavaVersion(jdkVer, p[0], p[1]); //throws
+      fail();
+    } catch (IllegalArgumentException e) {
+      println("" + e);
+    }
+    try {
+      jdkVer = "b"; //invalid string
+      p = UnsafeUtil.parseJavaVersion(jdkVer);
+      UnsafeUtil.checkJavaVersion(jdkVer, p[0], p[1]); //throws
+      fail();
+    } catch (IllegalArgumentException e) {
+      println("" + e);
+    }
+    try {
+      jdkVer = ""; //invalid string
+      p = UnsafeUtil.parseJavaVersion(jdkVer);
+      UnsafeUtil.checkJavaVersion(jdkVer, p[0], p[1]); //throws
+      fail();
+    } catch (IllegalArgumentException e) {
+      println("" + e);
+    }
+  }
+
+  @Test
+  public void checkFieldOffset() {
+    assertEquals(testField, 1);
+    long offset = UnsafeUtil.getFieldOffset(this.getClass(), "testField");
+    assertEquals(offset, 16);
+    try {
+      offset = UnsafeUtil.getFieldOffset(this.getClass(), "testField2");
+      fail();
+    } catch (IllegalStateException e) {
+      //OK
+    }
+  }
+
+  @Test(expectedExceptions = IllegalArgumentException.class)
+  public void checkInts() {
+    Ints.checkedCast(1L << 32);
+  }
+
+  @SuppressWarnings("restriction")
+  @Test
+  public void checkArrayBaseOffset()
+  {
+    final List<Class<?>> classes = new ArrayList<>();
+    classes.add(byte[].class);
+    classes.add(int[].class);
+    classes.add(long[].class);
+    classes.add(float[].class);
+    classes.add(double[].class);
+    classes.add(boolean[].class);
+    classes.add(short[].class);
+    classes.add(char[].class);
+    classes.add(Object[].class);
+    classes.add(byte[][].class); // An array type that is not cached
+
+    for (Class<?> clazz : classes) {
+      assertEquals(
+          UnsafeUtil.getArrayBaseOffset(clazz),
+          UnsafeUtil.unsafe.arrayBaseOffset(clazz),
+          clazz.getTypeName()
+      );
+    }
+  }
+
+  @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-java8/src/test/java/org/apache/datasketches/memory/internal/Utf8Test.java b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/Utf8Test.java
new file mode 100644
index 0000000..762efe3
--- /dev/null
+++ b/datasketches-memory-java8/src/test/java/org/apache/datasketches/memory/internal/Utf8Test.java
@@ -0,0 +1,516 @@
+/*
+ * 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
... 2380 lines suppressed ...


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