aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2023-06-16 00:43:11 +0200
committerSven Gothel <[email protected]>2023-06-16 00:43:11 +0200
commit03c548d96e5c81d0fc39503fe3042cf03e0a75e2 (patch)
tree604aa5b285e5f0476727f0d9b3d23aaf557833a3
parentffd0c48999daa2b321a00fb9ad7ba175734486e3 (diff)
GlueGen Struct [1]: Enhance com.jogamp.common.nio.* to serve a most native-free-code Struct-Code generation
Recfactored all NIO buffer utils to Buffers, i.e. buffer <-> address, memcpy, strnlen, etc Buffers: - Added copyNativeToDirectByteBuffer(..), allowing to copy a native memory slice into a direct buffer. - Added typeNameToBufferClass(String) and sizeOfBufferElem(Class<? extends Buffer>) - Completed slize2<Type>(..) buffer-mapping methods - Exposure of safe getDirectByteBuffer(..) w/ null-check (package private) Added NativeBuffer.storeDirectAddress(..), allowing to write the array address into a native buffer (struct, etc), allowing to referencing the ElementBuffer (linear array of elements) and PointerBuffer (array of pointer). Hint: This can be read via PointerBuffer.wrap(..).get(0) Added ElementBuffer (a NativeBuffer) mapping an array of elements, completing native abstraction next to PointerBuffer (array of pointer). ElementBuffer can dereference an existing element-array by native address via ElementBuffer.derefPointer(..). Views of its content can be directly accessed via ElementBuffer.slice(..). +++ These utilities and buffer abstractions will allow to reuse code and simplify the GlueGen struct get/set implementations and help to reduce native code injection.
-rw-r--r--src/java/com/jogamp/common/nio/AbstractBuffer.java49
-rw-r--r--src/java/com/jogamp/common/nio/Buffers.java668
-rw-r--r--src/java/com/jogamp/common/nio/ElementBuffer.java197
-rw-r--r--src/java/com/jogamp/common/nio/NativeBuffer.java36
-rw-r--r--src/java/com/jogamp/common/nio/PointerBuffer.java88
-rw-r--r--src/java/com/jogamp/common/nio/StructAccessor.java14
-rw-r--r--src/junit/com/jogamp/gluegen/test/junit/generation/BaseClass.java7
-rw-r--r--src/native/common/Buffers.c30
-rw-r--r--src/native/common/PointerBuffer.c14
9 files changed, 901 insertions, 202 deletions
diff --git a/src/java/com/jogamp/common/nio/AbstractBuffer.java b/src/java/com/jogamp/common/nio/AbstractBuffer.java
index a774c39..b31929b 100644
--- a/src/java/com/jogamp/common/nio/AbstractBuffer.java
+++ b/src/java/com/jogamp/common/nio/AbstractBuffer.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2010 JogAmp Community. All rights reserved.
+ * Copyright 2010-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -34,6 +34,9 @@ package com.jogamp.common.nio;
import com.jogamp.common.os.*;
import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import java.nio.LongBuffer;
/**
* @author Sven Gothel
@@ -41,6 +44,8 @@ import java.nio.Buffer;
*/
@SuppressWarnings("rawtypes")
public abstract class AbstractBuffer<B extends AbstractBuffer> implements NativeBuffer<B> {
+ /** Platform dependent pointer size in bytes, i.e. 32bit or 64bit wide, depending of the CPU pointer width. */
+ public static final int POINTER_SIZE;
protected final Buffer buffer;
protected final int elementSize;
@@ -49,6 +54,7 @@ public abstract class AbstractBuffer<B extends AbstractBuffer> implements Native
static {
Platform.initSingleton(); // loads native gluegen_rt library
+ POINTER_SIZE = Platform.is32Bit() ? Buffers.SIZEOF_INT : Buffers.SIZEOF_LONG ;
}
/**
@@ -118,11 +124,44 @@ public abstract class AbstractBuffer<B extends AbstractBuffer> implements Native
public final Buffer getBuffer() {
return buffer;
}
-
@Override
public final boolean isDirect() {
return buffer.isDirect();
}
+ @Override
+ public long getDirectBufferAddress() {
+ if( isDirect() ) {
+ return Buffers.getDirectBufferAddressImpl(buffer);
+ } else {
+ return 0;
+ }
+ }
+ @Override
+ public void storeDirectAddress(final ByteBuffer directDest) {
+ final long addr = getDirectBufferAddress();
+ switch(POINTER_SIZE) {
+ case 4:
+ directDest.putInt(0, (int) ( addr & 0x00000000FFFFFFFFL ) );
+ break;
+ case 8:
+ directDest.putLong(0, addr);
+ break;
+ }
+ directDest.position(directDest.position()+POINTER_SIZE);
+ }
+
+ @Override
+ public void storeDirectAddress(final ByteBuffer directDest, final int destBytePos) {
+ final long addr = getDirectBufferAddress();
+ switch(POINTER_SIZE) {
+ case 4:
+ directDest.putInt(destBytePos, (int) ( addr & 0x00000000FFFFFFFFL ) );
+ break;
+ case 8:
+ directDest.putLong(destBytePos, addr);
+ break;
+ }
+ }
@Override
public final boolean hasArray() {
@@ -143,9 +182,11 @@ public abstract class AbstractBuffer<B extends AbstractBuffer> implements Native
return buffer.array();
}
+ protected String toSubString() {
+ return "[direct["+isDirect()+", addr 0x"+Long.toHexString(getDirectBufferAddress())+"], hasArray "+hasArray()+", capacity "+capacity+", position "+position+", elementSize "+elementSize+", buffer[capacity "+buffer.capacity()+", lim "+buffer.limit()+", pos "+buffer.position()+"]]";
+ }
@Override
public String toString() {
- return "AbstractBuffer[direct "+isDirect()+", hasArray "+hasArray()+", capacity "+capacity+", position "+position+", elementSize "+elementSize+", buffer[capacity "+buffer.capacity()+", lim "+buffer.limit()+", pos "+buffer.position()+"]]";
+ return "AbstractBuffer"+toSubString();
}
-
}
diff --git a/src/java/com/jogamp/common/nio/Buffers.java b/src/java/com/jogamp/common/nio/Buffers.java
index f37eaa9..b22e41e 100644
--- a/src/java/com/jogamp/common/nio/Buffers.java
+++ b/src/java/com/jogamp/common/nio/Buffers.java
@@ -1,6 +1,6 @@
/*
+ * Copyright (c) 2010-2023 JogAmp Community. All rights reserved.
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
- * Copyright (c) 2010 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -39,7 +39,6 @@
*/
package com.jogamp.common.nio;
-import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.Buffer;
import java.nio.ByteBuffer;
@@ -233,146 +232,74 @@ public class Buffers {
}
/**
- * Calls slice on the specified buffer while maintaining the byteorder.
- * @see #slice(java.nio.Buffer, int, int)
+ * Helper routine to set a ByteBuffer to the native byte order, if
+ * that operation is supported by the underlying NIO
+ * implementation.
*/
- @SuppressWarnings("unchecked")
- public static <B extends Buffer> B slice(final B buffer) {
- if (buffer instanceof ByteBuffer) {
- final ByteBuffer bb = (ByteBuffer) buffer;
- return (B) bb.slice().order(bb.order()); // slice and duplicate may change byte order
- } else if (buffer instanceof IntBuffer) {
- return (B) ((IntBuffer) buffer).slice();
- } else if (buffer instanceof ShortBuffer) {
- return (B) ((ShortBuffer) buffer).slice();
- } else if (buffer instanceof FloatBuffer) {
- return (B) ((FloatBuffer) buffer).slice();
- } else if (buffer instanceof DoubleBuffer) {
- return (B) ((DoubleBuffer) buffer).slice();
- } else if (buffer instanceof LongBuffer) {
- return (B) ((LongBuffer) buffer).slice();
- } else if (buffer instanceof CharBuffer) {
- return (B) ((CharBuffer) buffer).slice();
- }
- throw new IllegalArgumentException("unexpected buffer type: " + buffer.getClass());
+ public static ByteBuffer nativeOrder(final ByteBuffer buf) {
+ return buf.order(ByteOrder.nativeOrder());
}
/**
- * Slices the specified buffer with offset as position and offset+size as limit
- * while maintaining the byteorder.
- * Concurrency warning: this method changes the buffers position and limit but
- * will restore it before return.
+ * Returns {@link Buffer} class matching the given lower case `typeName`
+ * @param typeName lower-case type name
+ * @return matching {@link Buffer} class or `null`
+ * @see #sizeOfBufferElem(Class)
*/
- public static <B extends Buffer> B slice(final B buffer, final int offset, final int size) {
- final int pos = buffer.position();
- final int limit = buffer.limit();
-
- B slice = null;
- try {
- buffer.position(offset).limit(offset+size);
- slice = slice(buffer);
- } finally {
- buffer.position(pos).limit(limit);
+ public static Class<? extends Buffer> typeNameToBufferClass(final String typeName) {
+ if (typeName == null) {
+ return null;
}
-
- return slice;
+ if( "byte".equals(typeName) ) {
+ return ByteBuffer.class;
+ } else if( "short".equals(typeName) ) {
+ return ShortBuffer.class;
+ } else if( "char".equals(typeName) ) {
+ return CharBuffer.class;
+ } else if( "int".equals(typeName) ) {
+ return IntBuffer.class;
+ } else if( "float".equals(typeName) ) {
+ return FloatBuffer.class;
+ } else if( "long".equals(typeName) ) {
+ return LongBuffer.class;
+ } else if( "double".equals(typeName) ) {
+ return DoubleBuffer.class;
+ }
+ return null;
}
/**
- * Slices a ByteBuffer <i>or</i> a FloatBuffer to a FloatBuffer
- * at the given position with the given size in float-space.
- * <p>
- * The returned sliced buffer's start position is always zero.
- * </p>
- * <p>
- * The returned sliced buffer is {@link FloatBuffer#mark() marked} at it's {@link FloatBuffer#position() start position}. Hence
- * {@link FloatBuffer#reset()} will rewind it to start after applying relative operations like {@link FloatBuffer#get()}.
- * </p>
- * <p>
- * Using a ByteBuffer as the source guarantees
- * keeping the source native order programmatically.
- * This works around <a href="http://code.google.com/p/android/issues/detail?id=16434">Honeycomb / Android 3.0 Issue 16434</a>.
- * This bug is resolved at least in Android 3.2.
- * </p>
- *
- * @param buf source Buffer, maybe ByteBuffer (recommended) or FloatBuffer.
- * Buffer's position is ignored and floatPos is being used.
- * @param floatStartPos {@link Buffers#SIZEOF_FLOAT} position
- * @param floatSize {@link Buffers#SIZEOF_FLOAT} size
- * @return FloatBuffer w/ native byte order as given ByteBuffer
+ * Returns the size of a single element of the given buffer class in bytes
+ * or <code>0</code> if the given buffer is <code>null</code>.
+ * @see #typeNameToBufferClass(String)
+ * @see #sizeOfBufferElem(Object)
*/
- public static final FloatBuffer slice2Float(final Buffer buf, final int floatStartPos, final int floatSize) {
- final int pos;
- final int limit;
- if(null != buf) {
- pos = buf.position();
- limit = buf.limit();
- } else {
- pos = 0;
- limit = 0;
+ public static int sizeOfBufferElem(final Class<? extends Buffer> bufferClz) {
+ if (bufferClz == null) {
+ return 0;
}
- final FloatBuffer res;
- try {
- if(buf instanceof ByteBuffer) {
- final ByteBuffer bb = (ByteBuffer) buf;
- bb.position( floatStartPos * Buffers.SIZEOF_FLOAT );
- bb.limit( (floatStartPos + floatSize) * Buffers.SIZEOF_FLOAT );
- res = bb.slice().order(bb.order()).asFloatBuffer(); // slice and duplicate may change byte order
- } else if(buf instanceof FloatBuffer) {
- final FloatBuffer fb = (FloatBuffer) buf;
- fb.position( floatStartPos );
- fb.limit( floatStartPos + floatSize );
- res = fb.slice(); // slice and duplicate may change byte order
- } else {
- throw new InternalError("Buffer not ByteBuffer, nor FloarBuffer, nor backing array given");
- }
- } finally {
- if(null != buf) {
- buf.position(pos).limit(limit);
- }
+ if (ByteBuffer.class.isAssignableFrom(bufferClz)) {
+ return SIZEOF_BYTE;
+ } else if (ShortBuffer.class.isAssignableFrom(bufferClz)) {
+ return SIZEOF_SHORT;
+ } else if (CharBuffer.class.isAssignableFrom(bufferClz)) {
+ return SIZEOF_CHAR;
+ } else if (IntBuffer.class.isAssignableFrom(bufferClz)) {
+ return SIZEOF_INT;
+ } else if (FloatBuffer.class.isAssignableFrom(bufferClz)) {
+ return SIZEOF_FLOAT;
+ } else if (LongBuffer.class.isAssignableFrom(bufferClz)) {
+ return SIZEOF_LONG;
+ } else if (DoubleBuffer.class.isAssignableFrom(bufferClz)) {
+ return SIZEOF_DOUBLE;
}
- res.mark();
- return res;
- }
-
- /**
- * Slices a primitive float backing array to a FloatBuffer at the given position with the given size
- * in float-space by {@link FloatBuffer#wrap(float[], int, int) wrapping} the backing array.
- * <p>
- * Due to {@link FloatBuffer#wrap(float[], int, int) wrapping} the backing array,
- * the returned sliced buffer's {@link FloatBuffer#position() start position} equals
- * the given <code>floatStartPos</code> within the given backing array
- * while it's {@link FloatBuffer#arrayOffset() array-offset} is zero.
- * This has the advantage of being able to dismiss the {@link FloatBuffer#arrayOffset() array-offset}
- * in user code, while only being required to consider it's {@link FloatBuffer#position() position}.
- * </p>
- * <p>
- * The returned sliced buffer is {@link FloatBuffer#mark() marked} at it's {@link FloatBuffer#position() start position}. Hence
- * {@link FloatBuffer#reset()} will rewind it to start after applying relative operations like {@link FloatBuffer#get()}.
- * </p>
- *
- * @param backing source float array
- * @param floatStartPos {@link Buffers#SIZEOF_FLOAT} position
- * @param floatSize {@link Buffers#SIZEOF_FLOAT} size
- * @return FloatBuffer w/ native byte order as given ByteBuffer
- */
- public static final FloatBuffer slice2Float(final float[] backing, final int floatStartPos, final int floatSize) {
- return (FloatBuffer) FloatBuffer.wrap(backing, floatStartPos, floatSize).mark();
- }
-
-
- /**
- * Helper routine to set a ByteBuffer to the native byte order, if
- * that operation is supported by the underlying NIO
- * implementation.
- */
- public static ByteBuffer nativeOrder(final ByteBuffer buf) {
- return buf.order(ByteOrder.nativeOrder());
+ throw new RuntimeException("Unexpected buffer type " + bufferClz.getName());
}
/**
* Returns the size of a single element of the given buffer in bytes
* or <code>0</code> if the given buffer is <code>null</code>.
+ * @see #sizeOfBufferElem(Class)
*/
public static int sizeOfBufferElem(final Object buffer) {
if (buffer == null) {
@@ -564,6 +491,429 @@ public class Buffers {
//----------------------------------------------------------------------
+ // Slice routines (mapping buffer to typed-buffer w/o copy)
+ //
+ /**
+ * Calls slice on the specified buffer while maintaining the byteorder.
+ * @see #slice(java.nio.Buffer, int, int)
+ */
+ @SuppressWarnings("unchecked")
+ public static <B extends Buffer> B slice(final B buffer) {
+ if (buffer instanceof ByteBuffer) {
+ final ByteBuffer bb = (ByteBuffer) buffer;
+ return (B) bb.slice().order(bb.order()); // slice and duplicate may change byte order
+ } else if (buffer instanceof IntBuffer) {
+ return (B) ((IntBuffer) buffer).slice();
+ } else if (buffer instanceof ShortBuffer) {
+ return (B) ((ShortBuffer) buffer).slice();
+ } else if (buffer instanceof FloatBuffer) {
+ return (B) ((FloatBuffer) buffer).slice();
+ } else if (buffer instanceof DoubleBuffer) {
+ return (B) ((DoubleBuffer) buffer).slice();
+ } else if (buffer instanceof LongBuffer) {
+ return (B) ((LongBuffer) buffer).slice();
+ } else if (buffer instanceof CharBuffer) {
+ return (B) ((CharBuffer) buffer).slice();
+ }
+ throw new IllegalArgumentException("unexpected buffer type: " + buffer.getClass());
+ }
+
+ /**
+ * Slices the specified buffer with offset as position and offset+size as limit
+ * while maintaining the byteorder.
+ * Concurrency warning: this method changes the buffers position and limit but
+ * will restore it before return.
+ */
+ public static <B extends Buffer> B slice(final B buffer, final int offset, final int size) {
+ final int pos = buffer.position();
+ final int limit = buffer.limit();
+
+ B slice = null;
+ try {
+ buffer.position(offset).limit(offset+size);
+ slice = slice(buffer);
+ } finally {
+ buffer.position(pos).limit(limit);
+ }
+
+ return slice;
+ }
+
+ /**
+ * Slices a ByteBuffer <i>or</i> a FloatBuffer to a FloatBuffer
+ * at the given `elementStartPos` with the given `elementCount` in float-space.
+ * <p>
+ * The returned sliced buffer's start position is zero.
+ * </p>
+ * <p>
+ * The returned sliced buffer is {@link FloatBuffer#mark() marked} at it's {@link FloatBuffer#position() start position}. Hence
+ * {@link FloatBuffer#reset()} will rewind it to start after applying relative operations like {@link FloatBuffer#get()}.
+ * </p>
+ * <p>
+ * Using a ByteBuffer as the source guarantees
+ * keeping the source native order programmatically.
+ * This works around <a href="http://code.google.com/p/android/issues/detail?id=16434">Honeycomb / Android 3.0 Issue 16434</a>.
+ * This bug is resolved at least in Android 3.2.
+ * </p>
+ *
+ * @param buf source Buffer, maybe ByteBuffer (recommended) or FloatBuffer.
+ * Buffer's position is ignored and `elementStartPos` is being used.
+ * @param elementStartPos element start position w/ element of size {@link Buffers#SIZEOF_FLOAT}
+ * @param elementCount element count for element of size {@link Buffers#SIZEOF_FLOAT}
+ * @return FloatBuffer w/ native byte order as given ByteBuffer
+ */
+ public static final FloatBuffer slice2Float(final Buffer buf, final int elementStartPos, final int elementCount) {
+ if( null == buf ) {
+ throw new IllegalArgumentException("Buffer is null");
+ }
+ final int pos = buf.position();
+ final int limit = buf.limit();
+ final FloatBuffer res;
+ try {
+ if(buf instanceof ByteBuffer) {
+ final ByteBuffer bb = (ByteBuffer) buf;
+ bb.position( elementStartPos * Buffers.SIZEOF_FLOAT );
+ bb.limit( (elementStartPos + elementCount) * Buffers.SIZEOF_FLOAT );
+ res = bb.slice().order(bb.order()).asFloatBuffer(); // slice and duplicate may change byte order
+ } else if(buf instanceof FloatBuffer) {
+ final FloatBuffer fb = (FloatBuffer) buf;
+ fb.position( elementStartPos );
+ fb.limit( elementStartPos + elementCount );
+ res = fb.slice(); // slice and duplicate may change byte order
+ } else {
+ throw new IllegalArgumentException("Buffer not ByteBuffer, nor FloarBuffer, nor backing array given");
+ }
+ } finally {
+ buf.position(pos).limit(limit);
+ }
+ res.mark();
+ return res;
+ }
+ /**
+ * Slices a primitive float backing array to a FloatBuffer at the given `elementStartPos` with the given `elementCount`
+ * in float-space by {@link FloatBuffer#wrap(float[], int, int) wrapping} the backing array.
+ * <p>
+ * Due to {@link FloatBuffer#wrap(float[], int, int) wrapping} the backing array,
+ * the returned sliced buffer's {@link FloatBuffer#position() start position} equals
+ * the given <code>floatStartPos</code> within the given backing array
+ * while it's {@link FloatBuffer#arrayOffset() array-offset} is zero.
+ * This has the advantage of being able to dismiss the {@link FloatBuffer#arrayOffset() array-offset}
+ * in user code, while only being required to consider it's {@link FloatBuffer#position() position}.
+ * </p>
+ * <p>
+ * The returned sliced buffer is {@link FloatBuffer#mark() marked} at it's {@link FloatBuffer#position() start position}. Hence
+ * {@link FloatBuffer#reset()} will rewind it to start after applying relative operations like {@link FloatBuffer#get()}.
+ * </p>
+ *
+ * @param backing source float array
+ * @param elementStartPos element start position w/ element of size {@link Buffers#SIZEOF_FLOAT}
+ * @param elementCount element count for element of size {@link Buffers#SIZEOF_FLOAT}
+ * @return FloatBuffer w/ native byte order as given ByteBuffer
+ */
+ public static final FloatBuffer slice2Float(final float[] backing, final int elementStartPos, final int elementCount) {
+ return (FloatBuffer) FloatBuffer.wrap(backing, elementStartPos, elementCount).mark();
+ }
+
+ /**
+ * Slices a ByteBuffer <i>or</i> a ShortBuffer to a ShortBuffer
+ * at the given `elementStartPos` with the given `elementCount` in short-space.
+ * <p>
+ * The returned sliced buffer's start position is zero.
+ * </p>
+ * <p>
+ * See {@link #slice2Float(Buffer, int, int)} for details.
+ * </p>
+ *
+ * @param buf source Buffer, maybe ByteBuffer (recommended) or ShortBuffer.
+ * Buffer's position is ignored and `elementStartPos` is being used.
+ * @param elementStartPos element start position w/ element of size {@link Buffers#SIZEOF_SHORT}
+ * @param elementCount element count for element of size {@link Buffers#SIZEOF_SHORT}
+ * @return ShortBuffer w/ native byte order as given ByteBuffer
+ * @see #slice2Float(Buffer, int, int)
+ */
+ public static final ShortBuffer slice2Short(final Buffer buf, final int elementStartPos, final int elementCount) {
+ if( null == buf ) {
+ throw new IllegalArgumentException("Buffer is null");
+ }
+ final int pos = buf.position();
+ final int limit = buf.limit();
+ final ShortBuffer res;
+ try {
+ if(buf instanceof ByteBuffer) {
+ final ByteBuffer bb = (ByteBuffer) buf;
+ bb.position( elementStartPos * Buffers.SIZEOF_SHORT );
+ bb.limit( (elementStartPos + elementCount) * Buffers.SIZEOF_SHORT );
+ res = bb.slice().order(bb.order()).asShortBuffer(); // slice and duplicate may change byte order
+ } else if(buf instanceof ShortBuffer) {
+ final ShortBuffer fb = (ShortBuffer) buf;
+ fb.position( elementStartPos );
+ fb.limit( elementStartPos + elementCount );
+ res = fb.slice(); // slice and duplicate may change byte order
+ } else {
+ throw new IllegalArgumentException("Buffer not ByteBuffer, nor ShortBuffer");
+ }
+ } finally {
+ buf.position(pos).limit(limit);
+ }
+ res.mark();
+ return res;
+ }
+ /**
+ * Slices a primitive float backing array to a ShortBuffer at the given `elementStartPos` with the given `elementCount`
+ * in short-space by {@link ShortBuffer#wrap(float[], int, int) wrapping} the backing array.
+ * <p>
+ * See {@link #slice2Float(float[], int, int)} for details.
+ * </p>
+ * @param backing source float array
+ * @param elementStartPos element start position w/ element of size {@link Buffers#SIZEOF_SHORT}
+ * @param elementCount element count for element of size {@link Buffers#SIZEOF_SHORT}
+ * @return ShortBuffer w/ native byte order as given ByteBuffer
+ * @see #slice2Float(float[], int, int)
+ */
+ public static final ShortBuffer slice2Short(final short[] backing, final int elementStartPos, final int elementCount) {
+ return (ShortBuffer) ShortBuffer.wrap(backing, elementStartPos, elementCount).mark();
+ }
+
+ /**
+ * Slices a ByteBuffer <i>or</i> a CharBuffer to a CharBuffer
+ * at the given `elementStartPos` with the given `elementCount` in short-space.
+ * <p>
+ * The returned sliced buffer's start position is zero.
+ * </p>
+ * <p>
+ * See {@link #slice2Float(Buffer, int, int)} for details.
+ * </p>
+ *
+ * @param buf source Buffer, maybe ByteBuffer (recommended) or CharBuffer.
+ * Buffer's position is ignored and `elementStartPos` is being used.
+ * @param elementStartPos element start position w/ element of size {@link Buffers#SIZEOF_CHAR}
+ * @param elementCount element count for element of size {@link Buffers#SIZEOF_CHAR}
+ * @return CharBuffer w/ native byte order as given ByteBuffer
+ * @see #slice2Float(Buffer, int, int)
+ */
+ public static final CharBuffer slice2Char(final Buffer buf, final int elementStartPos, final int elementCount) {
+ if( null == buf ) {
+ throw new IllegalArgumentException("Buffer is null");
+ }
+ final int pos = buf.position();
+ final int limit = buf.limit();
+ final CharBuffer res;
+ try {
+ if(buf instanceof ByteBuffer) {
+ final ByteBuffer bb = (ByteBuffer) buf;
+ bb.position( elementStartPos * Buffers.SIZEOF_CHAR );
+ bb.limit( (elementStartPos + elementCount) * Buffers.SIZEOF_CHAR );
+ res = bb.slice().order(bb.order()).asCharBuffer(); // slice and duplicate may change byte order
+ } else if(buf instanceof CharBuffer) {
+ final CharBuffer fb = (CharBuffer) buf;
+ fb.position( elementStartPos );
+ fb.limit( elementStartPos + elementCount );
+ res = fb.slice(); // slice and duplicate may change byte order
+ } else {
+ throw new IllegalArgumentException("Buffer not ByteBuffer, nor CharBuffer");
+ }
+ } finally {
+ buf.position(pos).limit(limit);
+ }
+ res.mark();
+ return res;
+ }
+ /**
+ * Slices a primitive float backing array to a CharBuffer at the given `elementStartPos` with the given `elementCount`
+ * in short-space by {@link CharBuffer#wrap(float[], int, int) wrapping} the backing array.
+ * <p>
+ * See {@link #slice2Float(float[], int, int)} for details.
+ * </p>
+ * @param backing source float array
+ * @param elementStartPos element start position w/ element of size {@link Buffers#SIZEOF_CHAR}
+ * @param elementCount element count for element of size {@link Buffers#SIZEOF_CHAR}
+ * @return CharBuffer w/ native byte order as given ByteBuffer
+ * @see #slice2Float(float[], int, int)
+ */
+ public static final CharBuffer slice2Char(final char[] backing, final int elementStartPos, final int elementCount) {
+ return (CharBuffer) CharBuffer.wrap(backing, elementStartPos, elementCount).mark();
+ }
+
+ /**
+ * Slices a ByteBuffer <i>or</i> a IntBuffer to a IntBuffer
+ * at the given `elementStartPos` with the given `elementCount` in int-space.
+ * <p>
+ * The returned sliced buffer's start position is zero.
+ * </p>
+ * <p>
+ * See {@link #slice2Float(Buffer, int, int)} for details.
+ * </p>
+ *
+ * @param buf source Buffer, maybe ByteBuffer (recommended) or IntBuffer.
+ * Buffer's position is ignored and `elementStartPos` is being used.
+ * @param elementStartPos element start position w/ element of size {@link Buffers#SIZEOF_INT}
+ * @param elementCount element count for element of size {@link Buffers#SIZEOF_INT}
+ * @return IntBuffer w/ native byte order as given ByteBuffer
+ * @see #slice2Float(Buffer, int, int)
+ */
+ public static final IntBuffer slice2Int(final Buffer buf, final int elementStartPos, final int elementCount) {
+ if( null == buf ) {
+ throw new IllegalArgumentException("Buffer is null");
+ }
+ final int pos = buf.position();
+ final int limit = buf.limit();
+ final IntBuffer res;
+ try {
+ if(buf instanceof ByteBuffer) {
+ final ByteBuffer bb = (ByteBuffer) buf;
+ bb.position( elementStartPos * Buffers.SIZEOF_INT );
+ bb.limit( (elementStartPos + elementCount) * Buffers.SIZEOF_INT );
+ res = bb.slice().order(bb.order()).asIntBuffer(); // slice and duplicate may change byte order
+ } else if(buf instanceof IntBuffer) {
+ final IntBuffer fb = (IntBuffer) buf;
+ fb.position( elementStartPos );
+ fb.limit( elementStartPos + elementCount );
+ res = fb.slice(); // slice and duplicate may change byte order
+ } else {
+ throw new IllegalArgumentException("Buffer not ByteBuffer, nor IntBuffer");
+ }
+ } finally {
+ buf.position(pos).limit(limit);
+ }
+ res.mark();
+ return res;
+ }
+ /**
+ * Slices a primitive float backing array to a IntBuffer at the given `elementStartPos` with the given `elementCount`
+ * in int-space by {@link IntBuffer#wrap(float[], int, int) wrapping} the backing array.
+ * <p>
+ * See {@link #slice2Float(float[], int, int)} for details.
+ * </p>
+ * @param backing source float array
+ * @param elementStartPos element start position w/ element of size {@link Buffers#SIZEOF_INT}
+ * @param elementCount element count for element of size {@link Buffers#SIZEOF_INT}
+ * @return IntBuffer w/ native byte order as given ByteBuffer
+ * @see #slice2Float(float[], int, int)
+ */
+ public static final IntBuffer slice2Int(final int[] backing, final int elementStartPos, final int elementCount) {
+ return (IntBuffer) IntBuffer.wrap(backing, elementStartPos, elementCount).mark();
+ }
+
+ /**
+ * Slices a ByteBuffer <i>or</i> a LongBuffer to a LongBuffer
+ * at the given `elementStartPos` with the given `elementCount` in long-space.
+ * <p>
+ * The returned sliced buffer's start position is zero.
+ * </p>
+ * <p>
+ * See {@link #slice2Float(Buffer, int, int)} for details.
+ * </p>
+ *
+ * @param buf source Buffer, maybe ByteBuffer (recommended) or LongBuffer.
+ * Buffer's position is ignored and `elementStartPos` is being used.
+ * @param elementStartPos element start position w/ element of size {@link Buffers#SIZEOF_LONG}
+ * @param elementCount element count for element of size {@link Buffers#SIZEOF_LONG}
+ * @return LongBuffer w/ native byte order as given ByteBuffer
+ * @see #slice2Float(Buffer, int, int)
+ */
+ public static final LongBuffer slice2Long(final Buffer buf, final int elementStartPos, final int elementCount) {
+ if( null == buf ) {
+ throw new IllegalArgumentException("Buffer is null");
+ }
+ final int pos = buf.position();
+ final int limit = buf.limit();
+ final LongBuffer res;
+ try {
+ if(buf instanceof ByteBuffer) {
+ final ByteBuffer bb = (ByteBuffer) buf;
+ bb.position( elementStartPos * Buffers.SIZEOF_LONG );
+ bb.limit( (elementStartPos + elementCount) * Buffers.SIZEOF_LONG );
+ res = bb.slice().order(bb.order()).asLongBuffer(); // slice and duplicate may change byte order
+ } else if(buf instanceof LongBuffer) {
+ final LongBuffer fb = (LongBuffer) buf;
+ fb.position( elementStartPos );
+ fb.limit( elementStartPos + elementCount );
+ res = fb.slice(); // slice and duplicate may change byte order
+ } else {
+ throw new IllegalArgumentException("Buffer not ByteBuffer, nor LongBuffer");
+ }
+ } finally {
+ buf.position(pos).limit(limit);
+ }
+ res.mark();
+ return res;
+ }
+ /**
+ * Slices a primitive float backing array to a LongBuffer at the given `elementStartPos` with the given `elementCount`
+ * in long-space by {@link LongBuffer#wrap(float[], int, int) wrapping} the backing array.
+ * <p>
+ * See {@link #slice2Float(float[], int, int)} for details.
+ * </p>
+ * @param backing source float array
+ * @param elementStartPos element start position w/ element of size {@link Buffers#SIZEOF_LONG}
+ * @param elementCount element count for element of size {@link Buffers#SIZEOF_LONG}
+ * @return LongBuffer w/ native byte order as given ByteBuffer
+ * @see #slice2Float(float[], int, int)
+ */
+ public static final LongBuffer slice2Long(final long[] backing, final int elementStartPos, final int elementCount) {
+ return (LongBuffer) LongBuffer.wrap(backing, elementStartPos, elementCount).mark();
+ }
+
+ /**
+ * Slices a ByteBuffer <i>or</i> a DoubleBuffer to a DoubleBuffer
+ * at the given `elementStartPos` with the given `elementCount` in double-space.
+ * <p>
+ * The returned sliced buffer's start position is zero.
+ * </p>
+ * <p>
+ * See {@link #slice2Float(Buffer, int, int)} for details.
+ * </p>
+ *
+ * @param buf source Buffer, maybe ByteBuffer (recommended) or DoubleBuffer.
+ * Buffer's position is ignored and `elementStartPos` is being used.
+ * @param elementStartPos element start position w/ element of size {@link Buffers#SIZEOF_DOUBLE}
+ * @param elementCount element count for element of size {@link Buffers#SIZEOF_DOUBLE}
+ * @return DoubleBuffer w/ native byte order as given ByteBuffer
+ * @see #slice2Float(Buffer, int, int)
+ */
+ public static final DoubleBuffer slice2Double(final Buffer buf, final int elementStartPos, final int elementCount) {
+ if( null == buf ) {
+ throw new IllegalArgumentException("Buffer is null");
+ }
+ final int pos = buf.position();
+ final int limit = buf.limit();
+ final DoubleBuffer res;
+ try {
+ if(buf instanceof ByteBuffer) {
+ final ByteBuffer bb = (ByteBuffer) buf;
+ bb.position( elementStartPos * Buffers.SIZEOF_DOUBLE );
+ bb.limit( (elementStartPos + elementCount) * Buffers.SIZEOF_DOUBLE );
+ res = bb.slice().order(bb.order()).asDoubleBuffer(); // slice and duplicate may change byte order
+ } else if(buf instanceof DoubleBuffer) {
+ final DoubleBuffer fb = (DoubleBuffer) buf;
+ fb.position( elementStartPos );
+ fb.limit( elementStartPos + elementCount );
+ res = fb.slice(); // slice and duplicate may change byte order
+ } else {
+ throw new IllegalArgumentException("Buffer not ByteBuffer, nor DoubleBuffer");
+ }
+ } finally {
+ buf.position(pos).limit(limit);
+ }
+ res.mark();
+ return res;
+ }
+ /**
+ * Slices a primitive float backing array to a DoubleBuffer at the given `elementStartPos` with the given `elementCount`
+ * in double-space by {@link DoubleBuffer#wrap(float[], int, int) wrapping} the backing array.
+ * <p>
+ * See {@link #slice2Float(float[], int, int)} for details.
+ * </p>
+ * @param backing source float array
+ * @param elementStartPos element start position w/ element of size {@link Buffers#SIZEOF_DOUBLE}
+ * @param elementCount element count for element of size {@link Buffers#SIZEOF_DOUBLE}
+ * @return DoubleBuffer w/ native byte order as given ByteBuffer
+ * @see #slice2Float(float[], int, int)
+ */
+ public static final DoubleBuffer slice2Double(final double[] backing, final int elementStartPos, final int elementCount) {
+ return (DoubleBuffer) DoubleBuffer.wrap(backing, elementStartPos, elementCount).mark();
+ }
+ //----------------------------------------------------------------------
// Copy routines (type-to-type)
//
/**
@@ -1710,4 +2060,72 @@ public class Buffers {
}
}
}
+
+ /**
+ * Copy `len` native bytes @ `source_address` into a newly created direct {@link ByteBuffer}.
+ * @param source_address memory address of bytes to copy from
+ * @param len number of bytes to copy
+ * @return newly created direct {@link ByteBuffer} holding the copied bytes
+ */
+ public static ByteBuffer copyNativeToDirectByteBuffer(final long source_address, final long len) {
+ final Method id;
+ if( Integer.MAX_VALUE < len ) {
+ throw new IllegalArgumentException("length "+len+" > MAX_INT");
+ }
+ final int lenI = (int)len;
+ final ByteBuffer bb = Buffers.newDirectByteBuffer(lenI);
+ if( null == bb ) {
+ throw new RuntimeException("New direct ByteBuffer is NULL");
+ }
+ if( 0 < lenI ) {
+ final long byteBufferPtr = getDirectBufferAddressImpl(bb);
+ memcpyImpl(byteBufferPtr, source_address, lenI);
+ }
+ return bb;
+ }
+
+ /* pp */ static ByteBuffer getDirectByteBuffer(final long aptr, final int byteCount) {
+ final ByteBuffer r = getDirectByteBufferImpl(aptr, byteCount);
+ return null != r ? nativeOrder( r ) : null;
+ }
+
+ /* pp */ static void storeDirectAddress(final long addr, final ByteBuffer dest, final int destBytePos, final int nativeSizeInBytes) {
+ switch(nativeSizeInBytes) {
+ case 4:
+ dest.putInt(destBytePos, (int) ( addr & 0x00000000FFFFFFFFL ) );
+ break;
+ case 8:
+ dest.putLong(destBytePos, addr);
+ break;
+ default:
+ throw new InternalError("invalid nativeSizeInBytes "+nativeSizeInBytes);
+ }
+ }
+
+ /**
+ * Returns <code>strnlen(cstrptr, maxlen)</code> according to POSIX.1-2008.
+ * <p>
+ * The `strnlen()` function returns the number of bytes in the string pointed to by `cstrptr`, excluding the terminating null byte ('\0'), but at most `maxlen`.
+ * In doing this, `strnlen()` looks only at the first `maxlen` characters in the string pointed to by `cstrptr` and never beyond `cstrptr[maxlen-1]`.
+ * </p>
+ */
+ public static int strnlen(final long cstrptr, final int maxlen) {
+ return strnlenImpl(cstrptr, maxlen);
+ }
+
+ /**
+ * Returns <code>memcpy(dest, src, len)</code> according to POSIX.1-2001, POSIX.1-2008.
+ * <p>
+ * The `memcpy()` function copies `len` bytes from memory area `src` to memory area `dest`. The memory areas must not overlap.<br/>
+ * The `memcpy()` function returns a pointer to `dest`.
+ * </p>
+ public static long memcpy(final long dest, final long src, final long len) {
+ return memcpyImpl(dest, src, len);
+ }
+ */
+
+ /* pp */ static native long getDirectBufferAddressImpl(Object directBuffer);
+ private static native ByteBuffer getDirectByteBufferImpl(long aptr, int byteCount);
+ private static native int strnlenImpl(long cstrptr, int maxlen);
+ private static native long memcpyImpl(long dest, long src, long len);
}
diff --git a/src/java/com/jogamp/common/nio/ElementBuffer.java b/src/java/com/jogamp/common/nio/ElementBuffer.java
new file mode 100644
index 0000000..f9909b8
--- /dev/null
+++ b/src/java/com/jogamp/common/nio/ElementBuffer.java
@@ -0,0 +1,197 @@
+/**
+ * Copyright 2010-2023 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.common.nio;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Hardware independent container holding an array of linearly aligned elements,
+ * while its {@link #getDirectBufferAddress()} is-a pointer-type value, i.e. the element-array address.
+ * <p>
+ * An instance maps an array of linearly aligned elements, represented as bytes.
+ * </p>
+ */
+public class ElementBuffer extends AbstractBuffer<ElementBuffer> {
+ /** supports backup array */
+ ElementBuffer(final int elementSize, final ByteBuffer b) {
+ super(b, elementSize, b.capacity()/elementSize);
+ }
+
+ /** Returns a non direct PointerBuffer in native order, having a backup array */
+ public static ElementBuffer allocate(final int elementSize, final int elementCount) {
+ return new ElementBuffer(elementSize, ByteBuffer.allocate(elementCount * elementSize));
+ }
+
+ /** Returns a direct PointerBuffer in native order, w/o backup array */
+ public static ElementBuffer allocateDirect(final int elementSize, final int elementCount) {
+ return new ElementBuffer(elementSize, Buffers.newDirectByteBuffer(elementCount * elementSize));
+ }
+
+ public static ElementBuffer wrap(final int elementSize, final ByteBuffer src) {
+ return new ElementBuffer(elementSize, src);
+ }
+ public static ElementBuffer wrap(final int elementSize, final int elementCount, final ByteBuffer src, final int srcByteOffset) {
+ final int oldPos = src.position();
+ final int oldLimit = src.limit();
+ src.position(srcByteOffset);
+ src.limit(srcByteOffset + ( elementSize * elementCount ));
+ final ElementBuffer r = new ElementBuffer(elementSize, src.slice().order(src.order())); // slice and duplicate may change byte order
+ src.position(oldPos);
+ src.limit(oldLimit);
+ return r;
+ }
+ public static ElementBuffer derefPointer(final int elementSize, final int elementCount, final long aptr) {
+ if( 0 == aptr ) {
+ throw new NullPointerException("aptr is null");
+ }
+ final ByteBuffer bb = Buffers.getDirectByteBuffer(aptr, elementCount * elementSize);
+ if( null == bb ) {
+ throw new InternalError("Couldn't dereference aptr 0x"+Long.toHexString(aptr)+", size "+elementCount+" * "+elementSize);
+ }
+ return new ElementBuffer(elementSize, bb);
+ }
+ public static ElementBuffer derefPointer(final int elementSize, final int elementCount, final ByteBuffer ptrSrc, final int ptrSrcByteOffset) {
+ return derefPointer(elementSize, elementCount, PointerBuffer.wrap(ptrSrc, ptrSrcByteOffset, 1).get(0));
+ }
+
+ @Override
+ public final ElementBuffer put(final ElementBuffer src) {
+ if (remaining() < src.remaining()) {
+ throw new IndexOutOfBoundsException("remaining[this "+remaining()+" < src "+src.remaining()+"], this "+this+", src "+src);
+ }
+ if( this.elementSize() != src.elementSize() ) {
+ throw new IllegalArgumentException("Element-Size mismatch source "+src+", dest "+this);
+ }
+ final ByteBuffer tmp = ByteBuffer.allocate(elementSize);
+ while (src.hasRemaining()) {
+ put( src.get(tmp) );
+ }
+ return this;
+ }
+
+ /** Returns the ByteBuffer, i.e. {@link #getBuffer()} w/o casting. */
+ public final ByteBuffer getByteBuffer() {
+ return (ByteBuffer) buffer;
+ }
+
+ /**
+ * Returns a slice of this instance's ByteBuffer `[offset..offset+length)`, i.e. referencing the underlying bytes.
+ * @param offset starting element-index within this buffer
+ * @param length element count
+ * @return slice of this instance's ByteBuffer
+ */
+ public final ByteBuffer slice(final int offset, final int length) {
+ if (0 > offset || offset + length > capacity) {
+ throw new IndexOutOfBoundsException("idx "+offset+" + elementCount "+length+" not within [0.."+capacity+"), "+this);
+ }
+ final ByteBuffer src = (ByteBuffer)buffer;
+ final int oldPos = src.position();
+ final int oldLimit = src.limit();
+ src.position(elementSize*offset);
+ src.limit(elementSize * (offset + length));
+ final ByteBuffer ref = src.slice().order(src.order()); // slice and duplicate may change byte order
+ src.position(oldPos);
+ src.limit(oldLimit);
+ return ref;
+ }
+
+ /** Absolute get method. Copy the element-bytes at the given index, storing them into `destElemBytes`. */
+ public final ByteBuffer get(final int idx, final ByteBuffer destElemBytes) {
+ if (0 > idx || idx >= capacity) {
+ throw new IndexOutOfBoundsException("idx "+idx+" not within [0.."+capacity+"), "+this);
+ }
+ final ByteBuffer bBuffer = (ByteBuffer)buffer;
+ for(int i=0; i<elementSize; ++i) {
+ destElemBytes.put(i, bBuffer.get(elementSize*idx+i));
+ }
+ return destElemBytes;
+ }
+ /** Relative get method. Copy the element-bytes at the current position and increment the position by one, storing the element-bytes into `destElemBytes`. */
+ public final ByteBuffer get(final ByteBuffer destElemBytes) {
+ final ByteBuffer r = get(position, destElemBytes);
+ position++;
+ return r;
+ }
+ /**
+ * Relative bulk get method. Copy the element-bytes <code> [ position .. position+length [</code>
+ * to the destination array <code> [ destElements[offset] .. destElements[offset+length] [ </code>
+ * and increment the position by <code>length</code>. */
+ public final ElementBuffer get(final ByteBuffer[] destElements, int offset, int length) {
+ if (destElements.length<offset+length) {
+ throw new IndexOutOfBoundsException("dest.length "+destElements.length+" < (offset "+offset+" + length "+length+")");
+ }
+ if (remaining() < length) {
+ throw new IndexOutOfBoundsException("remaining "+remaining()+" < length "+length+", this "+this);
+ }
+ while(length>0) {
+ get(position++, destElements[offset++]);
+ length--;
+ }
+ return this;
+ }
+
+ /** Absolute put method. Put the element-bytes at the given element-index */
+ public final ElementBuffer put(final int idx, final ByteBuffer srcElemBytes) {
+ if (0 > idx || idx >= capacity) {
+ throw new IndexOutOfBoundsException("idx "+idx+" not within [0.."+capacity+"), "+this);
+ }
+ final ByteBuffer bBuffer = (ByteBuffer)buffer;
+ for(int i=0; i<elementSize; ++i) {
+ bBuffer.put(elementSize*idx+i, srcElemBytes.get(i));
+ }
+ return this;
+ }
+ /** Relative put method. Put the element-bytes at the current position and increment the position by one. */
+ public final ElementBuffer put(final ByteBuffer srcElemBytes) {
+ put(position, srcElemBytes);
+ position++;
+ return this;
+ }
+ /**
+ * Relative bulk put method. Put the element-bytes <code> [ srcElements[offset] .. srcElements[offset+length] [</code>
+ * at the current position and increment the position by <code>length</code>. */
+ public final ElementBuffer put(final ByteBuffer[] srcElements, int offset, int length) {
+ if (srcElements.length<offset+length) {
+ throw new IndexOutOfBoundsException("src.length "+srcElements.length+" < (offset "+offset+" + length "+length+")");
+ }
+ if (remaining() < length) {
+ throw new IndexOutOfBoundsException("remaining "+remaining()+" < length "+length+", this "+this);
+ }
+ while(length>0) {
+ put(position++, srcElements[offset++]);
+ length--;
+ }
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return "ElementBuffer"+toSubString();
+ }
+}
diff --git a/src/java/com/jogamp/common/nio/NativeBuffer.java b/src/java/com/jogamp/common/nio/NativeBuffer.java
index d81da9d..5ee6af8 100644
--- a/src/java/com/jogamp/common/nio/NativeBuffer.java
+++ b/src/java/com/jogamp/common/nio/NativeBuffer.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2010 JogAmp Community. All rights reserved.
+ * Copyright 2010-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -32,6 +32,7 @@
package com.jogamp.common.nio;
import java.nio.Buffer;
+import java.nio.ByteBuffer;
/**
* Hardware independent container for various kinds of buffers.
@@ -76,19 +77,34 @@ public interface NativeBuffer<B extends NativeBuffer> {
*/
public Object array() throws UnsupportedOperationException ;
+ /** Returns the underlying buffer object. */
public Buffer getBuffer();
-
+ /** Return true if the underlying buffer is NIO direct, otherwise false. */
public boolean isDirect();
+ /** Returns the native address of the underlying buffer if {@link #isDirect()}, otherwise {@code 0}. */
+ public long getDirectBufferAddress();
+ /**
+ * Store the {@link #getDirectBufferAddress()} into the given {@link ByteBuffer} using relative put.
+ * <p>
+ * The native pointer value is stored either as a 32bit (int) or 64bit (long) wide value,
+ * depending of the CPU pointer width.
+ * </p>
+ */
+ public void storeDirectAddress(final ByteBuffer directDest);
+ /**
+ * Store the {@link #getDirectBufferAddress()} into the given {@link ByteBuffer} using absolute put.
+ * <p>
+ * The native pointer value is stored either as a 32bit (int) or 64bit (long) wide value,
+ * depending of the CPU pointer width.
+ * </p>
+ **/
+ public void storeDirectAddress(final ByteBuffer directDest, final int destOffset);
public B rewind();
- public B put(int index, long value);
-
- public B put(long value);
-
+ /**
+ * Relative bulk get method. Copy the source values <code> src[position .. capacity] [</code>
+ * to this buffer and increment the position by <code>capacity-position</code>.
+ */
public B put(B src);
-
- public long get();
-
- public long get(int idx);
}
diff --git a/src/java/com/jogamp/common/nio/PointerBuffer.java b/src/java/com/jogamp/common/nio/PointerBuffer.java
index 7498756..2a2cdd9 100644
--- a/src/java/com/jogamp/common/nio/PointerBuffer.java
+++ b/src/java/com/jogamp/common/nio/PointerBuffer.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2010 JogAmp Community. All rights reserved.
+ * Copyright 2010-2023 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
@@ -40,22 +40,21 @@ import com.jogamp.common.os.Platform;
import com.jogamp.common.util.LongObjectHashMap;
/**
- * Hardware independent container for native pointer arrays.
- *
+ * Hardware independent container holding an array of native pointer,
+ * while its {@link #getDirectBufferAddress()} is-a pointer-pointer type value.
+ * <p>
+ * An instance maps an array of pointers of referenced Buffer objects, represented as longs.
+ * </p>
+ * <p>
* The native values (NIO direct ByteBuffer) might be 32bit or 64bit wide,
- * depending of the CPU pointer width.
- *
+ * depending of the CPU pointer width, see {@link #POINTER_SIZE}.
+ * </p>
* @author Sven Gothel
* @author Michael Bien
*/
public class PointerBuffer extends AbstractBuffer<PointerBuffer> {
- public static final int ELEMENT_SIZE = Platform.is32Bit() ? Buffers.SIZEOF_INT : Buffers.SIZEOF_LONG ;
protected LongObjectHashMap dataMap = null;
- static {
- Platform.initSingleton(); // loads native gluegen_rt library
- }
-
/** no backup array, use for direct usage only */
static PointerBuffer create(final ByteBuffer bb) {
return Platform.is32Bit() ? new PointerBuffer( bb.asIntBuffer() ) : new PointerBuffer( bb.asLongBuffer() );
@@ -63,12 +62,12 @@ public class PointerBuffer extends AbstractBuffer<PointerBuffer> {
/** supports backup array */
PointerBuffer(final IntBuffer b) {
- super(b, ELEMENT_SIZE, b.capacity());
+ super(b, POINTER_SIZE, b.capacity());
}
/** supports backup array */
PointerBuffer(final LongBuffer b) {
- super(b, ELEMENT_SIZE, b.capacity());
+ super(b, POINTER_SIZE, b.capacity());
}
private final void validateDataMap() {
@@ -78,7 +77,7 @@ public class PointerBuffer extends AbstractBuffer<PointerBuffer> {
}
}
- /** Returns a non direct PointerBuffer in native order, having a backup array */
+ /** Returns a non direct PointerBuffer, having a backup array */
public static PointerBuffer allocate(final int size) {
if (Platform.is32Bit()) {
return new PointerBuffer(IntBuffer.wrap(new int[size]));
@@ -89,12 +88,30 @@ public class PointerBuffer extends AbstractBuffer<PointerBuffer> {
/** Returns a direct PointerBuffer in native order, w/o backup array */
public static PointerBuffer allocateDirect(final int size) {
- return create(Buffers.newDirectByteBuffer(ELEMENT_SIZE * size));
+ return create(Buffers.newDirectByteBuffer(POINTER_SIZE * size));
}
+ /** Wraps given {@link ByteBuffer} {@code src} up to it {@link ByteBuffer#capacity()}/{@link #POINTER_SIZE} pointers. */
public static PointerBuffer wrap(final ByteBuffer src) {
return create(src);
}
+ /**
+ * Wraps given {@link ByteBuffer} {@code src} @ {@code srcByteOffset} to contain {@code elementCount} pointers.
+ * @param src
+ * @param srcByteOffset
+ * @param elementCount
+ * @return
+ */
+ public static PointerBuffer wrap(final ByteBuffer src, final int srcByteOffset, final int elementCount) {
+ final int oldPos = src.position();
+ final int oldLimit = src.limit();
+ src.position(srcByteOffset);
+ src.limit(srcByteOffset + POINTER_SIZE*elementCount);
+ final ByteBuffer ref = src.slice().order(src.order()); // slice and duplicate may change byte order
+ src.position(oldPos);
+ src.limit(oldLimit);
+ return create(ref);
+ }
/**
* @return new PointerBuffer sharing the same buffer data of this instance (identity),
@@ -114,13 +131,10 @@ public class PointerBuffer extends AbstractBuffer<PointerBuffer> {
return npb;
}
- /**
- * Relative bulk get method. Copy the source values <code> src[position .. capacity] [</code>
- * to this buffer and increment the position by <code>capacity-position</code>. */
@Override
public final PointerBuffer put(final PointerBuffer src) {
if (remaining() < src.remaining()) {
- throw new IndexOutOfBoundsException();
+ throw new IndexOutOfBoundsException("remaining[this "+remaining()+" < src "+src.remaining()+"], this "+this+", src "+src);
}
if( null == src.dataMap && null == dataMap ) {
// fast path no dataMap usage on both
@@ -147,19 +161,10 @@ public class PointerBuffer extends AbstractBuffer<PointerBuffer> {
return this;
}
- /** Relative get method. Get the pointer value at the current position and increment the position by one. */
- @Override
- public final long get() {
- final long r = get(position);
- position++;
- return r;
- }
-
/** Absolute get method. Get the pointer value at the given index */
- @Override
public final long get(final int idx) {
if (0 > idx || idx >= capacity) {
- throw new IndexOutOfBoundsException();
+ throw new IndexOutOfBoundsException("idx "+idx+" not within [0.."+capacity+"), "+this);
}
if (Platform.is32Bit()) {
return ((IntBuffer) buffer).get(idx) & 0x00000000FFFFFFFFL;
@@ -167,17 +172,22 @@ public class PointerBuffer extends AbstractBuffer<PointerBuffer> {
return ((LongBuffer) buffer).get(idx);
}
}
-
+ /** Relative get method. Get the pointer value at the current position and increment the position by one. */
+ public final long get() {
+ final long r = get(position);
+ position++;
+ return r;
+ }
/**
* Relative bulk get method. Copy the pointer values <code> [ position .. position+length [</code>
* to the destination array <code> [ dest[offset] .. dest[offset+length] [ </code>
* and increment the position by <code>length</code>. */
public final PointerBuffer get(final long[] dest, int offset, int length) {
if (dest.length<offset+length) {
- throw new IndexOutOfBoundsException();
+ throw new IndexOutOfBoundsException("dest.length "+dest.length+" < (offset "+offset+" + length "+length+")");
}
if (remaining() < length) {
- throw new IndexOutOfBoundsException();
+ throw new IndexOutOfBoundsException("remaining "+remaining()+" < length "+length+", this "+this);
}
while(length>0) {
dest[offset++] = get(position++);
@@ -187,10 +197,9 @@ public class PointerBuffer extends AbstractBuffer<PointerBuffer> {
}
/** Absolute put method. Put the pointer value at the given index */
- @Override
public final PointerBuffer put(final int idx, final long v) {
if (0 > idx || idx >= capacity) {
- throw new IndexOutOfBoundsException();
+ throw new IndexOutOfBoundsException("idx "+idx+" not within [0.."+capacity+"), "+this);
}
if (Platform.is32Bit()) {
((IntBuffer) buffer).put(idx, (int) v);
@@ -199,24 +208,21 @@ public class PointerBuffer extends AbstractBuffer<PointerBuffer> {
}
return this;
}
-
/** Relative put method. Put the pointer value at the current position and increment the position by one. */
- @Override
public final PointerBuffer put(final long value) {
put(position, value);
position++;
return this;
}
-
/**
* Relative bulk put method. Put the pointer values <code> [ src[offset] .. src[offset+length] [</code>
* at the current position and increment the position by <code>length</code>. */
public final PointerBuffer put(final long[] src, int offset, int length) {
if (src.length<offset+length) {
- throw new IndexOutOfBoundsException();
+ throw new IndexOutOfBoundsException("src.length "+src.length+" < (offset "+offset+" + length "+length+")");
}
if (remaining() < length) {
- throw new IndexOutOfBoundsException();
+ throw new IndexOutOfBoundsException("remaining "+remaining()+" < length "+length+", this "+this);
}
while(length>0) {
put(position++, src[offset++]);
@@ -239,7 +245,7 @@ public class PointerBuffer extends AbstractBuffer<PointerBuffer> {
throw new IllegalArgumentException("Buffer is not direct");
}
final long mask = Platform.is32Bit() ? 0x00000000FFFFFFFFL : 0xFFFFFFFFFFFFFFFFL ;
- final long bbAddr = getDirectBufferAddressImpl(bb) & mask;
+ final long bbAddr = Buffers.getDirectBufferAddressImpl(bb) & mask;
if(0==bbAddr) {
throw new RuntimeException("Couldn't determine native address of given Buffer: "+bb);
}
@@ -272,10 +278,8 @@ public class PointerBuffer extends AbstractBuffer<PointerBuffer> {
return bb;
}
- private native long getDirectBufferAddressImpl(Object directBuffer);
-
@Override
public String toString() {
- return "PointerBuffer:"+super.toString();
+ return "PointerBuffer"+toSubString();
}
}
diff --git a/src/java/com/jogamp/common/nio/StructAccessor.java b/src/java/com/jogamp/common/nio/StructAccessor.java
index 8ae0c29..79e8a36 100644
--- a/src/java/com/jogamp/common/nio/StructAccessor.java
+++ b/src/java/com/jogamp/common/nio/StructAccessor.java
@@ -1,6 +1,6 @@
/*
+ * Copyright (c) 2010-2023 JogAmp Community. All rights reserved.
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
- * Copyright (c) 2010 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -42,22 +42,28 @@ package com.jogamp.common.nio;
import java.nio.*;
/**
- * @author Kenneth Russel, et al.
+ * @author Kenneth Russel, Sven Gothel, Michael Bien, et al.
*/
public class StructAccessor {
private final ByteBuffer bb;
+ /** Create a new instance. The {@link ByteBuffer} will be {@link ByteBuffer#rewind()} and native-order to be used with native code set. */
public StructAccessor(final ByteBuffer bb) {
- // Setting of byte order is concession to native code which needs
- // to instantiate these
this.bb = bb.order(ByteOrder.nativeOrder());
+ this.bb.rewind();
}
+ /** Return the underlying native direct ByteBuffer */
public final ByteBuffer getBuffer() {
return bb;
}
+ /** Returns the native address of the underlying native ByteBuffer. */
+ public final long getDirectBufferAddress() {
+ return Buffers.getDirectBufferAddressImpl(bb);
+ }
+
/**
* Returns a slice of the current ByteBuffer starting at the
* specified byte offset and extending the specified number of
diff --git a/src/junit/com/jogamp/gluegen/test/junit/generation/BaseClass.java b/src/junit/com/jogamp/gluegen/test/junit/generation/BaseClass.java
index db8c157..34cd925 100644
--- a/src/junit/com/jogamp/gluegen/test/junit/generation/BaseClass.java
+++ b/src/junit/com/jogamp/gluegen/test/junit/generation/BaseClass.java
@@ -28,6 +28,7 @@
package com.jogamp.gluegen.test.junit.generation;
+import com.jogamp.common.nio.AbstractBuffer;
import com.jogamp.common.nio.Buffers;
import com.jogamp.common.nio.PointerBuffer;
import com.jogamp.common.os.MachineDataInfo;
@@ -465,8 +466,8 @@ public class BaseClass extends SingletonJunitCase {
return pb;
}
PointerBuffer safeByteBuffer2PointerBuffer(final ByteBuffer bb, final int elements) {
- Assert.assertEquals("ByteBuffer capacity not PointerBuffer ELEMENT_SIZE * "+elements, elements * PointerBuffer.ELEMENT_SIZE, bb.capacity());
- Assert.assertEquals("ByteBuffer remaining not PointerBuffer ELEMENT_SIZE * "+elements, elements * PointerBuffer.ELEMENT_SIZE, bb.remaining());
+ Assert.assertEquals("ByteBuffer capacity not PointerBuffer POINTER_SIZE * "+elements, elements * AbstractBuffer.POINTER_SIZE, bb.capacity());
+ Assert.assertEquals("ByteBuffer remaining not PointerBuffer POINTER_SIZE * "+elements, elements * AbstractBuffer.POINTER_SIZE, bb.remaining());
return validatePointerBuffer(PointerBuffer.wrap(bb), elements);
}
@@ -849,7 +850,7 @@ public class BaseClass extends SingletonJunitCase {
Assert.assertEquals(l0, l1);
Assert.assertEquals(l0, l2);
- final ByteBuffer bb = Buffers.newDirectByteBuffer(PointerBuffer.ELEMENT_SIZE);
+ final ByteBuffer bb = Buffers.newDirectByteBuffer(AbstractBuffer.POINTER_SIZE);
for(int j=0; j<bb.limit(); j++) {
bb.put(j, (byte)(0xAA+j));
}
diff --git a/src/native/common/Buffers.c b/src/native/common/Buffers.c
new file mode 100644
index 0000000..0898e6b
--- /dev/null
+++ b/src/native/common/Buffers.c
@@ -0,0 +1,30 @@
+
+#include <jni.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <gluegen_stdint.h>
+
+#include "com_jogamp_common_nio_Buffers.h"
+
+JNIEXPORT jlong JNICALL
+Java_com_jogamp_common_nio_Buffers_getDirectBufferAddressImpl(JNIEnv *env, jclass _unused, jobject directBuffer) {
+ return ( NULL != directBuffer ) ? (jlong) (intptr_t) (*env)->GetDirectBufferAddress(env, directBuffer) : 0L ;
+}
+
+JNIEXPORT jobject JNICALL
+Java_com_jogamp_common_nio_Buffers_getDirectByteBufferImpl(JNIEnv *env, jclass _unused, jlong japtr, jint jbyteCount) {
+ return ( 0 != japtr && 0 < jbyteCount ) ? (*env)->NewDirectByteBuffer(env, (void *)(intptr_t)japtr, jbyteCount) : NULL;
+}
+
+JNIEXPORT jint JNICALL
+Java_com_jogamp_common_nio_Buffers_strnlenImpl(JNIEnv *env, jclass _unused, jlong jcstrptr, jint jmaxlen) {
+ return ( 0 != jcstrptr && 0 < jmaxlen ) ? strnlen((const char *)(void *)(intptr_t)jcstrptr, jmaxlen) : 0;
+}
+
+JNIEXPORT jlong JNICALL
+Java_com_jogamp_common_nio_Buffers_memcpyImpl(JNIEnv *env, jclass _unused, jlong jdest, jlong jsrc, jlong jlen) {
+ return ( 0 != jdest && 0 != jsrc && 0 < jlen ) ? memcpy((void *)(intptr_t)jdest, (void *)(intptr_t)jsrc, (size_t)jlen) : jdest;
+}
+
diff --git a/src/native/common/PointerBuffer.c b/src/native/common/PointerBuffer.c
deleted file mode 100644
index f3e25d3..0000000
--- a/src/native/common/PointerBuffer.c
+++ /dev/null
@@ -1,14 +0,0 @@
-
-#include <jni.h>
-
-#include <assert.h>
-
-#include <gluegen_stdint.h>
-
-#include "com_jogamp_common_nio_PointerBuffer.h"
-
-JNIEXPORT jlong JNICALL
-Java_com_jogamp_common_nio_PointerBuffer_getDirectBufferAddressImpl(JNIEnv *env, jclass _unused, jobject directBuffer) {
- return ( NULL != directBuffer ) ? (jlong) (intptr_t) (*env)->GetDirectBufferAddress(env, directBuffer) : 0L ;
-}
-