diff options
author | Sven Gothel <[email protected]> | 2023-06-16 00:43:11 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2023-06-16 00:43:11 +0200 |
commit | 03c548d96e5c81d0fc39503fe3042cf03e0a75e2 (patch) | |
tree | 604aa5b285e5f0476727f0d9b3d23aaf557833a3 | |
parent | ffd0c48999daa2b321a00fb9ad7ba175734486e3 (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.java | 49 | ||||
-rw-r--r-- | src/java/com/jogamp/common/nio/Buffers.java | 668 | ||||
-rw-r--r-- | src/java/com/jogamp/common/nio/ElementBuffer.java | 197 | ||||
-rw-r--r-- | src/java/com/jogamp/common/nio/NativeBuffer.java | 36 | ||||
-rw-r--r-- | src/java/com/jogamp/common/nio/PointerBuffer.java | 88 | ||||
-rw-r--r-- | src/java/com/jogamp/common/nio/StructAccessor.java | 14 | ||||
-rw-r--r-- | src/junit/com/jogamp/gluegen/test/junit/generation/BaseClass.java | 7 | ||||
-rw-r--r-- | src/native/common/Buffers.c | 30 | ||||
-rw-r--r-- | src/native/common/PointerBuffer.c | 14 |
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 ; -} - |