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