diff --git a/jre_lwjgl3glfw/src/main/java/org/lwjgl/system/MemoryUtil.java b/jre_lwjgl3glfw/src/main/java/org/lwjgl/system/MemoryUtil.java deleted file mode 100644 index 0bec229e1..000000000 --- a/jre_lwjgl3glfw/src/main/java/org/lwjgl/system/MemoryUtil.java +++ /dev/null @@ -1,3033 +0,0 @@ -/* - * Copyright LWJGL. All rights reserved. - * License terms: https://www.lwjgl.org/license - */ -package org.lwjgl.system; - -import org.lwjgl.*; -import org.lwjgl.system.MemoryManage.*; -import org.lwjgl.system.MemoryUtil.MemoryAllocationReport.*; -import org.lwjgl.system.jni.*; - -import javax.annotation.*; -import java.nio.*; -import java.nio.charset.*; -import java.util.*; - -import static java.lang.Character.*; -import static java.lang.Math.*; -import static org.lwjgl.system.APIUtil.*; -import static org.lwjgl.system.Checks.*; -import static org.lwjgl.system.MathUtil.*; -import static org.lwjgl.system.MemoryUtil.LazyInit.*; -import static org.lwjgl.system.Pointer.*; -import static org.lwjgl.system.jni.JNINativeInterface.*; -import static org.lwjgl.system.libc.LibCString.*; - -/** - * This class provides functionality for managing native memory. - * - *
All methods in this class will make use of {@link sun.misc.Unsafe} if it's available, for performance. If Unsafe is not available, the fallback - * implementations make use of reflection and, in the worst-case, JNI.
- * - *Method names in this class are prefixed with {@code mem} to avoid ambiguities when used with static imports.
- * - *Methods in bindings that accept/return {@code CharSequence}/{@code String} also support {@code ByteBuffer}, so custom codecs can be used if necessary.
- * - * @see Configuration#MEMORY_ALLOCATOR - * @see Configuration#DEBUG_MEMORY_ALLOCATOR - */ -public final class MemoryUtil { - - /** Alias for the null pointer address. */ - public static final long NULL = 0L; - - /** The memory page size, in bytes. This value is always a power-of-two. */ - public static final int PAGE_SIZE; - - /** The cache-line size, in bytes. This value is always a power-of-two. */ - public static final int CACHE_LINE_SIZE; - - static final int ARRAY_TLC_SIZE = Configuration.ARRAY_TLC_SIZE.get(8192); - - static final ThreadLocalAllocations made through the returned instance will not be tracked for memory leaks, even if {@link Configuration#DEBUG_MEMORY_ALLOCATOR} is enabled. - * This can be useful for {@code static final} allocations that live throughout the application's lifetime and will never be freed until the process is - * terminated. Normally such allocations would be reported as memory leaks by the debug allocator.
- * - *The expectation is that this method will rarely be used, so it does not have the {@code mem} prefix to avoid pollution of auto-complete lists.
- * - * @return the {@link MemoryAllocator} instance - */ - public static MemoryAllocator getAllocator() { - return getAllocator(false); - } - - /** - * Returns the {@link MemoryAllocator} instance used internally by the explicit memory management API ({@link #memAlloc}, {@link #memFree}, etc). - * - * @param tracked whether allocations will be tracked for memory leaks, if {@link Configuration#DEBUG_MEMORY_ALLOCATOR} is enabled. - * - * @return the {@link MemoryAllocator} instance - */ - public static MemoryAllocator getAllocator(boolean tracked) { - return tracked - ? ALLOCATOR - : ALLOCATOR_IMPL; - } - - // --- [ memAlloc ] --- - - /** Unsafe version of {@link #memAlloc}. May return {@link #NULL} if {@code size} is zero or the allocation failed. */ - public static long nmemAlloc(long size) { - return ALLOCATOR.malloc(size); - } - - /** - * Unsafe version of {@link #memAlloc} that checks the returned pointer. - * - * @return a pointer to the memory block allocated by the function on success. This pointer will never be {@link #NULL}, even if {@code size} is zero. - * - * @throws OutOfMemoryError if the function failed to allocate the requested block of memory - */ - public static long nmemAllocChecked(long size) { - long address = nmemAlloc(size != 0 ? size : 1L); - if (CHECKS && address == NULL) { - throw new OutOfMemoryError(); - } - return address; - } - - private static long getAllocationSize(int elements, int elementShift) { - return apiCheckAllocation(elements, Integer.toUnsignedLong(elements) << elementShift, BITS64 ? Long.MAX_VALUE : 0xFFFF_FFFFL); - } - - /** - * The standard C malloc function. - * - *Allocates a block of {@code size} bytes of memory, returning a pointer to the beginning of the block. The content of the newly allocated block of - * memory is not initialized, remaining with indeterminate values.
- * - *Memory allocated with this method must be freed with {@link #memFree}.
- * - * @param size the size of the memory block to allocate, in bytes. If {@code size} is zero, the returned pointer shall not be dereferenced. - * - * @return on success, a pointer to the memory block allocated by the function - * - * @throws OutOfMemoryError if the function failed to allocate the requested block of memory - */ - public static ByteBuffer memAlloc(int size) { - return wrap(BUFFER_BYTE, nmemAllocChecked(size), size).order(NATIVE_ORDER); - } - - /** - * ShortBuffer version of {@link #memAlloc}. - * - * @param size the number of short values to allocate. - */ - public static ShortBuffer memAllocShort(int size) { - return wrap(BUFFER_SHORT, nmemAllocChecked(getAllocationSize(size, 1)), size); - } - - /** - * IntBuffer version of {@link #memAlloc}. - * - * @param size the number of int values to allocate. - */ - public static IntBuffer memAllocInt(int size) { - return wrap(BUFFER_INT, nmemAllocChecked(getAllocationSize(size, 2)), size); - } - - /** - * FloatBuffer version of {@link #memAlloc}. - * - * @param size the number of float values to allocate. - */ - public static FloatBuffer memAllocFloat(int size) { - return wrap(BUFFER_FLOAT, nmemAllocChecked(getAllocationSize(size, 2)), size); - } - - /** - * LongBuffer version of {@link #memAlloc}. - * - * @param size the number of long values to allocate. - */ - public static LongBuffer memAllocLong(int size) { - return wrap(BUFFER_LONG, nmemAllocChecked(getAllocationSize(size, 3)), size); - } - - /** - * {@code CLongBuffer} version of {@link #memAlloc}. - * - * @param size the number of C long values to allocate. - */ - public static CLongBuffer memAllocCLong(int size) { - return Pointer.Default.wrap(CLongBuffer.class, nmemAllocChecked(getAllocationSize(size, CLONG_SHIFT)), size); - } - - /** - * DoubleBuffer version of {@link #memAlloc}. - * - * @param size the number of double values to allocate. - */ - public static DoubleBuffer memAllocDouble(int size) { - return wrap(BUFFER_DOUBLE, nmemAllocChecked(getAllocationSize(size, 3)), size); - } - - /** - * PointerBuffer version of {@link #memAlloc}. - * - * @param size the number of pointer values to allocate. - */ - public static PointerBuffer memAllocPointer(int size) { - return Pointer.Default.wrap(PointerBuffer.class, nmemAllocChecked(getAllocationSize(size, POINTER_SHIFT)), size); - } - - /** Unsafe version of {@link #memFree}. */ - public static void nmemFree(long ptr) { - ALLOCATOR.free(ptr); - } - - /** - * The standard C free function. - * - *A block of memory previously allocated by a call to {@link #memAlloc}, {@link #memCalloc} or {@link #memRealloc} is deallocated, making it available - * again for further allocations.
- * - * @param ptr pointer to a memory block previously allocated with {@link #memAlloc}, {@link #memCalloc} or {@link #memRealloc}. If {@code ptr} does not - * point to a block of memory allocated with the above functions, it causes undefined behavior. If {@code ptr} is a {@link #NULL} pointer, the - * function does nothing. - */ - public static void memFree(@Nullable Buffer ptr) { - if (ptr != null) { - nmemFree(UNSAFE.getLong(ptr, ADDRESS)); - } - } - - /** {@code CustomBuffer} version of {@link #memFree}. */ - public static void memFree(@Nullable CustomBuffer ptr) { - if (ptr != null) { - nmemFree(ptr.address); - } - } - - // from LWJGL 3.2.2 - /** {@code PointerBuffer} version of {@link #memFree}. */ - public static void memFree(@Nullable PointerBuffer ptr) { - if (ptr != null) { - nmemFree(ptr.address); - } - } - - // --- [ memCalloc ] --- - - /** Unsafe version of {@link #memCalloc}. May return {@link #NULL} if {@code num} or {@code size} are zero or the allocation failed. */ - public static long nmemCalloc(long num, long size) { - return ALLOCATOR.calloc(num, size); - } - - /** - * Unsafe version of {@link #memCalloc} that checks the returned pointer. - * - * @return a pointer to the memory block allocated by the function on success. This pointer will never be {@link #NULL}, even if {@code num} or - * {@code size} are zero. - * - * @throws OutOfMemoryError if the function failed to allocate the requested block of memory - */ - public static long nmemCallocChecked(long num, long size) { - if (num == 0L || size == 0L) { - num = 1L; - size = 1L; - } - - long address = nmemCalloc(num, size); - if (CHECKS && address == NULL) { - throw new OutOfMemoryError(); - } - return address; - } - - /** - * The standard C calloc function. - * - *Allocates a block of memory for an array of {@code num} elements, each of them {@code size} bytes long, and initializes all its bits to zero. The - * effective result is the allocation of a zero-initialized memory block of {@code (num*size)} bytes.
- * - *Memory allocated with this method must be freed with {@link #memFree}.
- * - * @param num the number of elements to allocate. - * @param size the size of each element. If {@code size} is zero, the return value depends on the particular library implementation (it may or may not be - * a null pointer), but the returned pointer shall not be dereferenced. - * - * @return on success, a pointer to the memory block allocated by the function - * - * @throws OutOfMemoryError if the function failed to allocate the requested block of memory - */ - public static ByteBuffer memCalloc(int num, int size) { - return wrap(BUFFER_BYTE, nmemCallocChecked(num, size), num * size).order(NATIVE_ORDER); - } - - /** - * Alternative version of {@link #memCalloc}. - * - * @param num the number of bytes to allocate. - */ - public static ByteBuffer memCalloc(int num) { - return wrap(BUFFER_BYTE, nmemCallocChecked(num, 1), num).order(NATIVE_ORDER); - } - - /** - * ShortBuffer version of {@link #memCalloc}. - * - * @param num the number of short values to allocate. - */ - public static ShortBuffer memCallocShort(int num) { - return wrap(BUFFER_SHORT, nmemCallocChecked(num, 2), num); - } - - /** - * IntBuffer version of {@link #memCalloc}. - * - * @param num the number of int values to allocate. - */ - public static IntBuffer memCallocInt(int num) { - return wrap(BUFFER_INT, nmemCallocChecked(num, 4), num); - } - - /** - * FloatBuffer version of {@link #memCalloc}. - * - * @param num the number of float values to allocate. - */ - public static FloatBuffer memCallocFloat(int num) { - return wrap(BUFFER_FLOAT, nmemCallocChecked(num, 4), num); - } - - /** - * LongBuffer version of {@link #memCalloc}. - * - * @param num the number of long values to allocate. - */ - public static LongBuffer memCallocLong(int num) { - return wrap(BUFFER_LONG, nmemCallocChecked(num, 8), num); - } - - /** - * {@code CLongBuffer} version of {@link #memCalloc}. - * - * @param num the number of C long values to allocate. - */ - public static CLongBuffer memCallocCLong(int num) { - return Pointer.Default.wrap(CLongBuffer.class, nmemCallocChecked(num, CLONG_SIZE), num); - } - - /** - * DoubleBuffer version of {@link #memCalloc}. - * - * @param num the number of double values to allocate. - */ - public static DoubleBuffer memCallocDouble(int num) { - return wrap(BUFFER_DOUBLE, nmemCallocChecked(num, 8), num); - } - - /** - * PointerBuffer version of {@link #memCalloc}. - * - * @param num the number of pointer values to allocate. - */ - public static PointerBuffer memCallocPointer(int num) { - return Pointer.Default.wrap(PointerBuffer.class, nmemCallocChecked(num, POINTER_SIZE), num); - } - - // --- [ memRealloc] --- - - /** Unsafe version of {@link #memRealloc}. May return {@link #NULL} if {@code size} is zero or the allocation failed. */ - public static long nmemRealloc(long ptr, long size) { - return ALLOCATOR.realloc(ptr, size); - } - - /** - * Unsafe version of {@link #memRealloc} that checks the returned pointer. - * - * @return a pointer to the memory block reallocated by the function on success. This pointer will never be {@link #NULL}, even if {@code size} is zero. - * - * @throws OutOfMemoryError if the function failed to allocate the requested block of memory - */ - public static long nmemReallocChecked(long ptr, long size) { - long address = nmemRealloc(ptr, size != 0 ? size : 1L); - if (CHECKS && address == NULL) { - throw new OutOfMemoryError(); - } - return address; - } - - private staticChanges the size of the memory block pointed to by {@code ptr}. The function may move the memory block to a new location (whose address is returned - * by the function). The content of the memory block is preserved up to the lesser of the new and old sizes, even if the block is moved to a new location. - * If the new size is larger, the value of the newly allocated portion is indeterminate.
- * - *The memory address used is always the address at the start of {@code ptr}, so the current position of {@code ptr} does not need to be set to 0 for - * this function to work. The current position is preserved, even if the memory block is moved to a new location, unless {@code size} is less than the - * current position in which case position will be equal to capacity. The limit is set to the capacity, and the mark is discarded.
- * - * @param ptr a pointer to a memory block previously allocated with {@link #memAlloc}, {@link #memCalloc} or {@link #memRealloc}. Alternatively, this can - * be a {@link #NULL} pointer, in which case a new block is allocated (as if {@link #memAlloc} was called). - * @param size the new size for the memory block, in bytes. - * - * @return a pointer to the reallocated memory block, which may be either the same as {@code ptr} or a new location - * - * @throws OutOfMemoryError if the function failed to allocate the requested block of memory. The memory block pointed to by argument {@code ptr} is not - * deallocated (it is still valid, and with its contents unchanged). - */ - public static ByteBuffer memRealloc(@Nullable ByteBuffer ptr, int size) { - return realloc(ptr, memByteBuffer(nmemReallocChecked(ptr == null ? NULL : UNSAFE.getLong(ptr, ADDRESS), size), size), size); - } - - /** - * ShortBuffer version of {@link #memRealloc}. - * - * @param size the number of short values to allocate. - */ - public static ShortBuffer memRealloc(@Nullable ShortBuffer ptr, int size) { - return realloc(ptr, memShortBuffer(nmemReallocChecked(ptr == null ? NULL : UNSAFE.getLong(ptr, ADDRESS), getAllocationSize(size, 1)), size), size); - } - - /** - * IntBuffer version of {@link #memRealloc}. - * - * @param size the number of int values to allocate. - */ - public static IntBuffer memRealloc(@Nullable IntBuffer ptr, int size) { - return realloc(ptr, memIntBuffer(nmemReallocChecked(ptr == null ? NULL : UNSAFE.getLong(ptr, ADDRESS), getAllocationSize(size, 2)), size), size); - } - - /** - * LongBuffer version of {@link #memRealloc}. - * - * @param size the number of long values to allocate. - */ - public static LongBuffer memRealloc(@Nullable LongBuffer ptr, int size) { - return realloc(ptr, memLongBuffer(nmemReallocChecked(ptr == null ? NULL : UNSAFE.getLong(ptr, ADDRESS), getAllocationSize(size, 3)), size), size); - } - - /** - * {@code CLongBuffer} version of {@link #memRealloc}. - * - * @param size the number of C long values to allocate. - */ - public static CLongBuffer memRealloc(@Nullable CLongBuffer ptr, int size) { - CLongBuffer buffer = memCLongBuffer(nmemReallocChecked(ptr == null ? NULL : ptr.address, getAllocationSize(size, CLONG_SIZE)), size); - if (ptr != null) { - buffer.position(min(ptr.position(), size)); - } - return buffer; - } - - /** - * FloatBuffer version of {@link #memRealloc}. - * - * @param size the number of float values to allocate. - */ - public static FloatBuffer memRealloc(@Nullable FloatBuffer ptr, int size) { - return realloc(ptr, memFloatBuffer(nmemReallocChecked(ptr == null ? NULL : UNSAFE.getLong(ptr, ADDRESS), getAllocationSize(size, 2)), size), size); - } - - /** - * DoubleBuffer version of {@link #memRealloc}. - * - * @param size the number of double values to allocate. - */ - public static DoubleBuffer memRealloc(@Nullable DoubleBuffer ptr, int size) { - return realloc(ptr, memDoubleBuffer(nmemReallocChecked(ptr == null ? NULL : UNSAFE.getLong(ptr, ADDRESS), getAllocationSize(size, 3)), size), size); - } - - /** - * PointerBuffer version of {@link #memRealloc}. - * - * @param size the number of pointer values to allocate. - */ - public static PointerBuffer memRealloc(@Nullable PointerBuffer ptr, int size) { - PointerBuffer buffer = memPointerBuffer(nmemReallocChecked(ptr == null ? NULL : ptr.address, getAllocationSize(size, POINTER_SHIFT)), size); - if (ptr != null) { - buffer.position(min(ptr.position(), size)); - } - return buffer; - } - - // --- [ memAlignedAlloc ] --- - - /** Unsafe version of {@link #memAlignedAlloc}. May return {@link #NULL} if {@code size} is zero or the allocation failed. */ - public static long nmemAlignedAlloc(long alignment, long size) { - return ALLOCATOR.aligned_alloc(alignment, size); - } - - /** - * Unsafe version of {@link #memAlignedAlloc} that checks the returned pointer. - * - * @return a pointer to the memory block allocated by the function on success. This pointer will never be {@link #NULL}, even if {@code size} is zero. - * - * @throws OutOfMemoryError if the function failed to allocate the requested block of memory - */ - public static long nmemAlignedAllocChecked(long alignment, long size) { - long address = nmemAlignedAlloc(alignment, size != 0 ? size : 1L); - if (CHECKS && address == NULL) { - throw new OutOfMemoryError(); - } - return address; - } - - /** - * The standard C aligned_alloc function. - * - *Allocate {@code size} bytes of uninitialized storage whose alignment is specified by {@code alignment}. The size parameter must be an integral - * multiple of alignment. Memory allocated with memAlignedAlloc() must be freed with {@link #memAlignedFree}.
- * - * @param alignment the alignment. Must be a power of two value and a multiple of {@code sizeof(void *)}. - * @param size the number of bytes to allocate. Must be a multiple of {@code alignment}. - */ - public static ByteBuffer memAlignedAlloc(int alignment, int size) { - return wrap(BUFFER_BYTE, nmemAlignedAllocChecked(alignment, size), size).order(NATIVE_ORDER); - } - - // --- [ memAlignedFree ] --- - - /** Unsafe version of {@link #memAlignedFree}. */ - public static void nmemAlignedFree(long ptr) { - ALLOCATOR.aligned_free(ptr); - } - - /** - * Frees a block of memory that was allocated with {@link #memAlignedAlloc}. If ptr is {@code NULL}, no operation is performed. - * - * @param ptr the aligned block of memory to free - */ - public static void memAlignedFree(@Nullable ByteBuffer ptr) { - if (ptr != null) { - nmemAlignedFree(UNSAFE.getLong(ptr, ADDRESS)); - } - } - - // --- [ DebugAllocator ] --- - - /** The memory allocation report callback. */ - public interface MemoryAllocationReport { - - /** - * Reports allocated memory. - * - * @param address the address of the memory allocated. May be {@link #NULL}. - * @param memory the amount of memory allocated, in bytes - * @param threadId id of the thread that allocated the memory. May be {@link #NULL}. - * @param threadName name of the thread that allocated the memory. May be {@code null}. - * @param stacktrace the allocation stacktrace. May be {@code null}. - */ - void invoke(long address, long memory, long threadId, @Nullable String threadName, @Nullable StackTraceElement... stacktrace); - - /** Specifies how to aggregate the reported allocations. */ - enum Aggregate { - /** Allocations are aggregated over the whole process or thread. */ - ALL, - /** - * Allocations are aggregated based on the first stack trace element. This will return an allocation aggregate per method/line number, regardless - * of how many different code paths lead to that specific method and line number. - */ - GROUP_BY_METHOD, - /** The allocations are aggregated based on the full stack trace chain. */ - GROUP_BY_STACKTRACE - } - } - - /** - * Reports all live allocations. - * - *This method can only be used if the {@link Configuration#DEBUG_MEMORY_ALLOCATOR} option has been set to true.
- * - * @param report the report callback - */ - public static void memReport(MemoryAllocationReport report) { - DebugAllocator.report(report); - } - - /** - * Reports aggregates for the live allocations. - * - *This method can only be used if the {@link Configuration#DEBUG_MEMORY_ALLOCATOR} option has been set to true.
- * - * @param report the report callback - * @param groupByStackTrace how to aggregate the reported allocations - * @param groupByThread if the reported allocations should be grouped by thread - */ - public static void memReport(MemoryAllocationReport report, Aggregate groupByStackTrace, boolean groupByThread) { - DebugAllocator.report(report, groupByStackTrace, groupByThread); - } - - /* ------------------------------------- - ------------------------------------- - BUFFER MANAGEMENT API - ------------------------------------- - ------------------------------------- */ - - // --- [ memAddress0 ] --- - - /** - * Returns the memory address of the specified buffer. [INTERNAL USE ONLY] - * - * @param buffer the buffer - * - * @return the memory address - */ - public static long memAddress0(Buffer buffer) { return UNSAFE.getLong(buffer, ADDRESS); } - - // --- [ Buffer address ] --- - - /** - * Returns the memory address at the current position of the specified buffer. This is effectively a pointer value that can be used in native function - * calls. - * - * @param buffer the buffer - * - * @return the memory address - */ - public static long memAddress(ByteBuffer buffer) { return buffer.position() + memAddress0(buffer); } - - /** - * Returns the memory address at the specified position of the specified buffer. - * - * @param buffer the buffer - * @param position the buffer position - * - * @return the memory address - * - * @see #memAddress(ByteBuffer) - */ - public static long memAddress(ByteBuffer buffer, int position) { - Objects.requireNonNull(buffer); - return memAddress0(buffer) + Integer.toUnsignedLong(position); - } - - private static long address(int position, int elementShift, long address) { - return address + ((position & 0xFFFF_FFFFL) << elementShift); - } - - /** ShortBuffer version of {@link #memAddress(ByteBuffer)}. */ - public static long memAddress(ShortBuffer buffer) { return address(buffer.position(), 1, memAddress0(buffer)); } - /** ShortBuffer version of {@link #memAddress(ByteBuffer, int)}. */ - public static long memAddress(ShortBuffer buffer, int position) { - Objects.requireNonNull(buffer); - return address(position, 1, memAddress0(buffer)); - } - - /** CharBuffer version of {@link #memAddress(ByteBuffer)}. */ - public static long memAddress(CharBuffer buffer) { return address(buffer.position(), 1, memAddress0(buffer)); } - /** CharBuffer version of {@link #memAddress(ByteBuffer, int)}. */ - public static long memAddress(CharBuffer buffer, int position) { - Objects.requireNonNull(buffer); - return address(position, 1, memAddress0(buffer)); - } - - /** IntBuffer version of {@link #memAddress(ByteBuffer)}. */ - public static long memAddress(IntBuffer buffer) { return address(buffer.position(), 2, memAddress0(buffer)); } - /** IntBuffer version of {@link #memAddress(ByteBuffer, int)}. */ - public static long memAddress(IntBuffer buffer, int position) { - Objects.requireNonNull(buffer); - return address(position, 2, memAddress0(buffer)); - } - - /** FloatBuffer version of {@link #memAddress(ByteBuffer)}. */ - public static long memAddress(FloatBuffer buffer) { return address(buffer.position(), 2, memAddress0(buffer)); } - /** FloatBuffer version of {@link #memAddress(ByteBuffer, int)}. */ - public static long memAddress(FloatBuffer buffer, int position) { - Objects.requireNonNull(buffer); - return address(position, 2, memAddress0(buffer)); - } - - /** LongBuffer version of {@link #memAddress(ByteBuffer)}. */ - public static long memAddress(LongBuffer buffer) { return address(buffer.position(), 3, memAddress0(buffer)); } - /** LongBuffer version of {@link #memAddress(ByteBuffer, int)}. */ - public static long memAddress(LongBuffer buffer, int position) { - Objects.requireNonNull(buffer); - return address(position, 3, memAddress0(buffer)); - } - - /** DoubleBuffer version of {@link #memAddress(ByteBuffer)}. */ - public static long memAddress(DoubleBuffer buffer) { return address(buffer.position(), 3, memAddress0(buffer)); } - /** DoubleBuffer version of {@link #memAddress(ByteBuffer, int)}. */ - public static long memAddress(DoubleBuffer buffer, int position) { - Objects.requireNonNull(buffer); - return address(position, 3, memAddress0(buffer)); - } - - /** Polymorphic version of {@link #memAddress(ByteBuffer)}. */ - public static long memAddress(Buffer buffer) { - int elementShift; - if (buffer instanceof ByteBuffer) { - elementShift = 0; - } else if (buffer instanceof ShortBuffer || buffer instanceof CharBuffer) { - elementShift = 1; - } else if (buffer instanceof IntBuffer || buffer instanceof FloatBuffer) { - elementShift = 2; - } else { - elementShift = 3; - } - return address(buffer.position(), elementShift, memAddress0(buffer)); - } - - /** CustomBuffer version of {@link #memAddress(ByteBuffer)}. */ - public static long memAddress(CustomBuffer> buffer) { return buffer.address(); } - /** CustomBuffer version of {@link #memAddress(ByteBuffer, int)}. */ - public static long memAddress(CustomBuffer> buffer, int position) { return buffer.address(position); } - - // --- [ Buffer address - Safe ] --- - - /** Null-safe version of {@link #memAddress(ByteBuffer)}. Returns {@link #NULL} if the specified buffer is null. */ - public static long memAddressSafe(@Nullable ByteBuffer buffer) { return buffer == null ? NULL : memAddress0(buffer) + buffer.position(); } - - /** ShortBuffer version of {@link #memAddressSafe(ByteBuffer)}. */ - public static long memAddressSafe(@Nullable ShortBuffer buffer) { return buffer == null ? NULL : address(buffer.position(), 1, memAddress0(buffer)); } - - /** CharBuffer version of {@link #memAddressSafe(ByteBuffer)}. */ - public static long memAddressSafe(@Nullable CharBuffer buffer) { return buffer == null ? NULL : address(buffer.position(), 1, memAddress0(buffer)); } - - /** IntBuffer version of {@link #memAddressSafe(ByteBuffer)}. */ - public static long memAddressSafe(@Nullable IntBuffer buffer) { return buffer == null ? NULL : address(buffer.position(), 2, memAddress0(buffer)); } - - /** FloatBuffer version of {@link #memAddressSafe(ByteBuffer)}. */ - public static long memAddressSafe(@Nullable FloatBuffer buffer) { return buffer == null ? NULL : address(buffer.position(), 2, memAddress0(buffer)); } - - /** LongBuffer version of {@link #memAddressSafe(ByteBuffer)}. */ - public static long memAddressSafe(@Nullable LongBuffer buffer) { return buffer == null ? NULL : address(buffer.position(), 3, memAddress0(buffer)); } - - /** DoubleBuffer version of {@link #memAddressSafe(ByteBuffer)}. */ - public static long memAddressSafe(@Nullable DoubleBuffer buffer) { return buffer == null ? NULL : address(buffer.position(), 3, memAddress0(buffer)); } - - /** Pointer version of {@link #memAddressSafe(ByteBuffer)}. */ - public static long memAddressSafe(@Nullable Pointer pointer) { return pointer == null ? NULL : pointer.address(); } - - // --- [ Buffer allocation ] --- - - /** - * Creates a new direct ByteBuffer that starts at the specified memory address and has the specified capacity. The returned ByteBuffer instance will be set - * to the native {@link ByteOrder}. - * - * @param address the starting memory address - * @param capacity the buffer capacity - * - * @return the new ByteBuffer - */ - public static ByteBuffer memByteBuffer(long address, int capacity) { - if (CHECKS) { - check(address); - } - return wrap(BUFFER_BYTE, address, capacity).order(NATIVE_ORDER); - } - - /** Like {@link #memByteBuffer}, but returns {@code null} if {@code address} is {@link #NULL}. */ - @Nullable - public static ByteBuffer memByteBufferSafe(long address, int capacity) { - return address == NULL ? null : wrap(BUFFER_BYTE, address, capacity).order(NATIVE_ORDER); - } - - /** - * Creates a {@link ByteBuffer} instance as a view of the specified {@link ShortBuffer} between its current position and limit. - * - *This operation is the inverse of {@link ByteBuffer#asShortBuffer()}. The returned {@code ByteBuffer} instance will be set to the native - * {@link ByteOrder}.
- * - * @param buffer the source buffer - * - * @return the {@code ByteBuffer} view - */ - public static ByteBuffer memByteBuffer(ShortBuffer buffer) { - if (CHECKS && (Integer.MAX_VALUE >> 1) < buffer.remaining()) { - throw new IllegalArgumentException("The source buffer range is too wide"); - } - return wrap(BUFFER_BYTE, memAddress(buffer), buffer.remaining() << 1).order(NATIVE_ORDER); - } - - /** - * Creates a {@link ByteBuffer} instance as a view of the specified {@link CharBuffer} between its current position and limit. - * - *This operation is the inverse of {@link ByteBuffer#asCharBuffer()}. The returned {@code ByteBuffer} instance will be set to the native - * {@link ByteOrder}.
- * - * @param buffer the source buffer - * - * @return the {@code ByteBuffer} view - */ - public static ByteBuffer memByteBuffer(CharBuffer buffer) { - if (CHECKS && (Integer.MAX_VALUE >> 1) < buffer.remaining()) { - throw new IllegalArgumentException("The source buffer range is too wide"); - } - return wrap(BUFFER_BYTE, memAddress(buffer), buffer.remaining() << 1).order(NATIVE_ORDER); - } - - /** - * Creates a {@link ByteBuffer} instance as a view of the specified {@link IntBuffer} between its current position and limit. - * - *This operation is the inverse of {@link ByteBuffer#asIntBuffer()}. The returned {@code ByteBuffer} instance will be set to the native - * {@link ByteOrder}.
- * - * @param buffer the source buffer - * - * @return the {@code ByteBuffer} view - */ - public static ByteBuffer memByteBuffer(IntBuffer buffer) { - if (CHECKS && (Integer.MAX_VALUE >> 2) < buffer.remaining()) { - throw new IllegalArgumentException("The source buffer range is too wide"); - } - return wrap(BUFFER_BYTE, memAddress(buffer), buffer.remaining() << 2).order(NATIVE_ORDER); - } - - /** - * Creates a {@link ByteBuffer} instance as a view of the specified {@link LongBuffer} between its current position and limit. - * - *This operation is the inverse of {@link ByteBuffer#asLongBuffer()}. The returned {@code ByteBuffer} instance will be set to the native - * {@link ByteOrder}.
- * - * @param buffer the source buffer - * - * @return the {@code ByteBuffer} view - */ - public static ByteBuffer memByteBuffer(LongBuffer buffer) { - if (CHECKS && (Integer.MAX_VALUE >> 3) < buffer.remaining()) { - throw new IllegalArgumentException("The source buffer range is too wide"); - } - return wrap(BUFFER_BYTE, memAddress(buffer), buffer.remaining() << 3).order(NATIVE_ORDER); - } - - /** - * Creates a {@link ByteBuffer} instance as a view of the specified {@link FloatBuffer} between its current position and limit. - * - *This operation is the inverse of {@link ByteBuffer#asFloatBuffer()}. The returned {@code ByteBuffer} instance will be set to the native - * {@link ByteOrder}.
- * - * @param buffer the source buffer - * - * @return the {@code ByteBuffer} view - */ - public static ByteBuffer memByteBuffer(FloatBuffer buffer) { - if (CHECKS && (Integer.MAX_VALUE >> 2) < buffer.remaining()) { - throw new IllegalArgumentException("The source buffer range is too wide"); - } - return wrap(BUFFER_BYTE, memAddress(buffer), buffer.remaining() << 2).order(NATIVE_ORDER); - } - - /** - * Creates a {@link ByteBuffer} instance as a view of the specified {@link DoubleBuffer} between its current position and limit. - * - *This operation is the inverse of {@link ByteBuffer#asDoubleBuffer()}. The returned {@code ByteBuffer} instance will be set to the native - * {@link ByteOrder}.
- * - * @param buffer the source buffer - * - * @return the {@code ByteBuffer} view - */ - public static ByteBuffer memByteBuffer(DoubleBuffer buffer) { - if (CHECKS && (Integer.MAX_VALUE >> 3) < buffer.remaining()) { - throw new IllegalArgumentException("The source buffer range is too wide"); - } - return wrap(BUFFER_BYTE, memAddress(buffer), buffer.remaining() << 3).order(NATIVE_ORDER); - } - - /** - * Creates a {@link ByteBuffer} instance as a view of the specified {@link CustomBuffer} between its current position and limit. - * - *The returned {@code ByteBuffer} instance will be set to the native {@link ByteOrder}.
- * - * @param buffer the source buffer - * - * @return the {@code ByteBuffer} view - */ - public static ByteBuffer memByteBuffer(CustomBuffer> buffer) { - if (CHECKS && (Integer.MAX_VALUE / buffer.sizeof()) < buffer.remaining()) { - throw new IllegalArgumentException("The source buffer range is too wide"); - } - return wrap(BUFFER_BYTE, memAddress(buffer), buffer.remaining() * buffer.sizeof()).order(NATIVE_ORDER); - } - - /** - * Creates a new direct ShortBuffer that starts at the specified memory address and has the specified capacity. - * - *The {@code address} specified must be aligned to 2 bytes. If not, use {@code memByteBuffer(address, capacity * 2).asShortBuffer()}.
- * - * @param address the starting memory address - * @param capacity the buffer capacity - * - * @return the new ShortBuffer - */ - public static ShortBuffer memShortBuffer(long address, int capacity) { - if (CHECKS) { - check(address); - } - return wrap(BUFFER_SHORT, address, capacity); - } - - /** Like {@link #memShortBuffer}, but returns {@code null} if {@code address} is {@link #NULL}. */ - @Nullable - public static ShortBuffer memShortBufferSafe(long address, int capacity) { - return address == NULL ? null : wrap(BUFFER_SHORT, address, capacity); - } - - /** - * Creates a new direct CharBuffer that starts at the specified memory address and has the specified capacity. - * - *The {@code address} specified must be aligned to 2 bytes. If not, use {@code memByteBuffer(address, capacity * 2).asCharBuffer()}.
- * - * @param address the starting memory address - * @param capacity the buffer capacity - * - * @return the new CharBuffer - */ - public static CharBuffer memCharBuffer(long address, int capacity) { - if (CHECKS) { - check(address); - } - return wrap(BUFFER_CHAR, address, capacity); - } - - /** Like {@link #memCharBuffer}, but returns {@code null} if {@code address} is {@link #NULL}. */ - @Nullable - public static CharBuffer memCharBufferSafe(long address, int capacity) { - return address == NULL ? null : wrap(BUFFER_CHAR, address, capacity); - } - - /** - * Creates a new direct IntBuffer that starts at the specified memory address and has the specified capacity. - * - *The {@code address} specified must be aligned to 4 bytes. If not, use {@code memByteBuffer(address, capacity * 4).asIntBuffer()}.
- * - * @param address the starting memory address - * @param capacity the buffer capacity - * - * @return the new IntBuffer - */ - public static IntBuffer memIntBuffer(long address, int capacity) { - if (CHECKS) { - check(address); - } - return wrap(BUFFER_INT, address, capacity); - } - - /** Like {@link #memIntBuffer}, but returns {@code null} if {@code address} is {@link #NULL}. */ - @Nullable - public static IntBuffer memIntBufferSafe(long address, int capacity) { - return address == NULL ? null : wrap(BUFFER_INT, address, capacity); - } - - /** - * Creates a new direct LongBuffer that starts at the specified memory address and has the specified capacity. - * - *The {@code address} specified must be aligned to 8 bytes. If not, use {@code memByteBuffer(address, capacity * 8).asLongBuffer()}.
- * - * @param address the starting memory address - * @param capacity the buffer capacity - * - * @return the new LongBuffer - */ - public static LongBuffer memLongBuffer(long address, int capacity) { - if (CHECKS) { - check(address); - } - return wrap(BUFFER_LONG, address, capacity); - } - - /** Like {@link #memLongBuffer}, but returns {@code null} if {@code address} is {@link #NULL}. */ - @Nullable - public static LongBuffer memLongBufferSafe(long address, int capacity) { - return address == NULL ? null : wrap(BUFFER_LONG, address, capacity); - } - - /** - * Creates a new direct {@code CLongBuffer} that starts at the specified memory address and has the specified capacity. - * - *The {@code address} specified must be aligned to 8 bytes. If not, use {@code memByteBuffer(address, capacity * 8).asLongBuffer()}.
- * - * @param address the starting memory address - * @param capacity the buffer capacity - * - * @return the new {@code CLongBuffer} - */ - public static CLongBuffer memCLongBuffer(long address, int capacity) { - if (CHECKS) { - check(address); - } - return Pointer.Default.wrap(CLongBuffer.class, address, capacity); - } - - /** Like {@link #memCLongBuffer}, but returns {@code null} if {@code address} is {@link #NULL}. */ - @Nullable - public static CLongBuffer memCLongBufferSafe(long address, int capacity) { - return address == NULL ? null : Pointer.Default.wrap(CLongBuffer.class, address, capacity); - } - - /** - * Creates a new direct FloatBuffer that starts at the specified memory address and has the specified capacity. - * - *The {@code address} specified must be aligned to 4 bytes. If not, use {@code memByteBuffer(address, capacity * 4).asFloatBuffer()}.
- * - * @param address the starting memory address - * @param capacity the buffer capacity - * - * @return the new FloatBuffer - */ - public static FloatBuffer memFloatBuffer(long address, int capacity) { - if (CHECKS) { - check(address); - } - return wrap(BUFFER_FLOAT, address, capacity); - } - - /** Like {@link #memFloatBuffer}, but returns {@code null} if {@code address} is {@link #NULL}. */ - @Nullable - public static FloatBuffer memFloatBufferSafe(long address, int capacity) { - return address == NULL ? null : wrap(BUFFER_FLOAT, address, capacity); - } - - /** - * Creates a new direct DoubleBuffer that starts at the specified memory address and has the specified capacity. - * - *The {@code address} specified must be aligned to 8 bytes. If not, use {@code memByteBuffer(address, capacity * 8).asDoubleBuffer()}.
- * - * @param address the starting memory address - * @param capacity the buffer capacity - * - * @return the new DoubleBuffer - */ - public static DoubleBuffer memDoubleBuffer(long address, int capacity) { - if (CHECKS) { - check(address); - } - return wrap(BUFFER_DOUBLE, address, capacity); - } - - /** Like {@link #memDoubleBuffer}, but returns {@code null} if {@code address} is {@link #NULL}. */ - @Nullable - public static DoubleBuffer memDoubleBufferSafe(long address, int capacity) { - return address == NULL ? null : wrap(BUFFER_DOUBLE, address, capacity); - } - - /** - * Creates a new PointerBuffer that starts at the specified memory address and has the specified capacity. - * - *The {@code address} specified must be aligned to the pointer size. If not, use {@code PointerBuffer.create(memByteBuffer(address, capacity * - * POINTER_SIZE))}.
- * - * @param address the starting memory address - * @param capacity the buffer capacity - * - * @return the new PointerBuffer - */ - public static PointerBuffer memPointerBuffer(long address, int capacity) { - if (CHECKS) { - check(address); - } - return Pointer.Default.wrap(PointerBuffer.class, address, capacity); - } - - /** Like {@link #memPointerBuffer}, but returns {@code null} if {@code address} is {@link #NULL}. */ - @Nullable - public static PointerBuffer memPointerBufferSafe(long address, int capacity) { - return address == NULL ? null : Pointer.Default.wrap(PointerBuffer.class, address, capacity); - } - - // --- [ Buffer duplication ] --- - - /** - * Duplicates the specified buffer. The returned buffer will have the same {@link ByteOrder} as the source buffer. - * - *This method should be preferred over {@link ByteBuffer#duplicate} because it has a much shorter call chain. Long call chains may fail to inline due - * to JVM limits, disabling important optimizations (e.g. scalar replacement via Escape Analysis).
- * - * @param buffer the buffer to duplicate - * - * @return the duplicated buffer - */ - public static ByteBuffer memDuplicate(ByteBuffer buffer) { - ByteBuffer target; - try { - target = (ByteBuffer)UNSAFE.allocateInstance(BUFFER_BYTE); - } catch (InstantiationException e) { - throw new UnsupportedOperationException(e); - } - - UNSAFE.putLong(target, ADDRESS, UNSAFE.getLong(buffer, ADDRESS)); - UNSAFE.putInt(target, MARK, UNSAFE.getInt(buffer, MARK)); - UNSAFE.putInt(target, POSITION, UNSAFE.getInt(buffer, POSITION)); - UNSAFE.putInt(target, LIMIT, UNSAFE.getInt(buffer, LIMIT)); - UNSAFE.putInt(target, CAPACITY, UNSAFE.getInt(buffer, CAPACITY)); - - Object attachment = UNSAFE.getObject(buffer, PARENT_BYTE); - UNSAFE.putObject(target, PARENT_BYTE, attachment == null ? buffer : attachment); - - return target.order(buffer.order()); - } - - /** - * Duplicates the specified buffer. - * - *This method should be preferred over {@link ShortBuffer#duplicate} because it has a much shorter call chain. Long call chains may fail to inline due - * to JVM limits, disabling important optimizations (e.g. scalar replacement via Escape Analysis).
- * - * @param buffer the buffer to duplicate - * - * @return the duplicated buffer - */ - public static ShortBuffer memDuplicate(ShortBuffer buffer) { return duplicate(BUFFER_SHORT, buffer, PARENT_SHORT); } - - /** - * Duplicates the specified buffer. - * - *This method should be preferred over {@link CharBuffer#duplicate} because it has a much shorter call chain. Long call chains may fail to inline due - * to JVM limits, disabling important optimizations (e.g. scalar replacement via Escape Analysis).
- * - * @param buffer the buffer to duplicate - * - * @return the duplicated buffer - */ - public static CharBuffer memDuplicate(CharBuffer buffer) { return duplicate(BUFFER_CHAR, buffer, PARENT_CHAR); } - - /** - * Duplicates the specified buffer. - * - *This method should be preferred over {@link IntBuffer#duplicate} because it has a much shorter call chain. Long call chains may fail to inline due - * to JVM limits, disabling important optimizations (e.g. scalar replacement via Escape Analysis).
- * - * @param buffer the buffer to duplicate - * - * @return the duplicated buffer - */ - public static IntBuffer memDuplicate(IntBuffer buffer) { return duplicate(BUFFER_INT, buffer, PARENT_INT); } - - /** - * Duplicates the specified buffer. - * - *This method should be preferred over {@link LongBuffer#duplicate} because it has a much shorter call chain. Long call chains may fail to inline due - * to JVM limits, disabling important optimizations (e.g. scalar replacement via Escape Analysis).
- * - * @param buffer the buffer to duplicate - * - * @return the duplicated buffer - */ - public static LongBuffer memDuplicate(LongBuffer buffer) { return duplicate(BUFFER_LONG, buffer, PARENT_LONG); } - - /** - * Duplicates the specified buffer. - * - *This method should be preferred over {@link FloatBuffer#duplicate} because it has a much shorter call chain. Long call chains may fail to inline due - * to JVM limits, disabling important optimizations (e.g. scalar replacement via Escape Analysis).
- * - * @param buffer the buffer to duplicate - * - * @return the duplicated buffer - */ - public static FloatBuffer memDuplicate(FloatBuffer buffer) { return duplicate(BUFFER_FLOAT, buffer, PARENT_FLOAT); } - - /** - * Duplicates the specified buffer. - * - *This method should be preferred over {@link DoubleBuffer#duplicate} because it has a much shorter call chain. Long call chains may fail to inline due - * to JVM limits, disabling important optimizations (e.g. scalar replacement via Escape Analysis).
- * - * @param buffer the buffer to duplicate - * - * @return the duplicated buffer - */ - public static DoubleBuffer memDuplicate(DoubleBuffer buffer) { return duplicate(BUFFER_DOUBLE, buffer, PARENT_DOUBLE); } - - // --- [ Buffer slicing ] --- - - /** - * Slices the specified buffer. The returned buffer will have the same {@link ByteOrder} as the source buffer. - * - *This method should be preferred over {@link ByteBuffer#slice} because it has a much shorter call chain. Long call chains may fail to inline due to - * JVM limits, disabling important optimizations (e.g. scalar replacement via Escape Analysis).
- * - * @param buffer the buffer to slice - * - * @return the sliced buffer - */ - public static ByteBuffer memSlice(ByteBuffer buffer) { - return slice(buffer, memAddress0(buffer) + buffer.position(), buffer.remaining()); - } - - /** - * Slices the specified buffer. - * - *This method should be preferred over {@link ShortBuffer#slice} because it has a much shorter call chain. Long call chains may fail to inline due to - * JVM limits, disabling important optimizations (e.g. scalar replacement via Escape Analysis).
- * - * @param buffer the buffer to slice - * - * @return the sliced buffer - */ - public static ShortBuffer memSlice(ShortBuffer buffer) { - return slice(BUFFER_SHORT, buffer, address(buffer.position(), 1, memAddress0(buffer)), buffer.remaining(), PARENT_SHORT); - } - - /** - * Slices the specified buffer. - * - *This method should be preferred over {@link CharBuffer#slice} because it has a much shorter call chain. Long call chains may fail to inline due to - * JVM limits, disabling important optimizations (e.g. scalar replacement via Escape Analysis).
- * - * @param buffer the buffer to slice - * - * @return the sliced buffer - */ - public static CharBuffer memSlice(CharBuffer buffer) { - return slice(BUFFER_CHAR, buffer, address(buffer.position(), 1, memAddress0(buffer)), buffer.remaining(), PARENT_CHAR); - } - - /** - * Slices the specified buffer. - * - *This method should be preferred over {@link IntBuffer#slice} because it has a much shorter call chain. Long call chains may fail to inline due to - * JVM limits, disabling important optimizations (e.g. scalar replacement via Escape Analysis).
- * - * @param buffer the buffer to slice - * - * @return the sliced buffer - */ - public static IntBuffer memSlice(IntBuffer buffer) { - return slice(BUFFER_INT, buffer, address(buffer.position(), 2, memAddress0(buffer)), buffer.remaining(), PARENT_INT); - } - - /** - * Slices the specified buffer. - * - *This method should be preferred over {@link LongBuffer#slice} because it has a much shorter call chain. Long call chains may fail to inline due to - * JVM limits, disabling important optimizations (e.g. scalar replacement via Escape Analysis).
- * - * @param buffer the buffer to slice - * - * @return the sliced buffer - */ - public static LongBuffer memSlice(LongBuffer buffer) { - return slice(BUFFER_LONG, buffer, address(buffer.position(), 3, memAddress0(buffer)), buffer.remaining(), PARENT_LONG); - } - - /** - * Slices the specified buffer. - * - *This method should be preferred over {@link FloatBuffer#slice} because it has a much shorter call chain. Long call chains may fail to inline due to - * JVM limits, disabling important optimizations (e.g. scalar replacement via Escape Analysis).
- * - * @param buffer the buffer to slice - * - * @return the sliced buffer - */ - public static FloatBuffer memSlice(FloatBuffer buffer) { - return slice(BUFFER_FLOAT, buffer, address(buffer.position(), 2, memAddress0(buffer)), buffer.remaining(), PARENT_FLOAT); - } - - /** - * Slices the specified buffer. - * - *This method should be preferred over {@link DoubleBuffer#slice} because it has a much shorter call chain. Long call chains may fail to inline due to - * JVM limits, disabling important optimizations (e.g. scalar replacement via Escape Analysis).
- * - * @param buffer the buffer to slice - * - * @return the sliced buffer - */ - public static DoubleBuffer memSlice(DoubleBuffer buffer) { - return slice(BUFFER_DOUBLE, buffer, address(buffer.position(), 3, memAddress0(buffer)), buffer.remaining(), PARENT_DOUBLE); - } - /** - * Returns a slice of the specified buffer between {@code (buffer.position() + offset)} and {@code (buffer.position() + offset + capacity)}. The returned - * buffer will have the same {@link ByteOrder} as the original buffer. - * - *The position and limit of the original buffer are preserved after a call to this method.
- * - * @param buffer the buffer to slice - * @param offset the slice offset, it must be ≤ {@code buffer.remaining()} - * @param capacity the slice length, it must be ≤ {@code buffer.capacity() - (buffer.position() + offset)} - * - * @return the sliced buffer - */ - public static ByteBuffer memSlice(ByteBuffer buffer, int offset, int capacity) { - int position = buffer.position() + offset; - if (offset < 0 || buffer.limit() < position) { - throw new IllegalArgumentException(); - } - if (capacity < 0 || buffer.capacity() - position < capacity) { - throw new IllegalArgumentException(); - } - return slice(buffer, memAddress0(buffer) + position, capacity); - } - - /** - * Returns a slice of the specified buffer between {@code (buffer.position() + offset)} and {@code (buffer.position() + offset + capacity)}. - * - *The position and limit of the original buffer are preserved after a call to this method.
- * - * @param buffer the buffer to slice - * @param offset the slice offset, it must be ≤ {@code buffer.remaining()} - * @param capacity the slice length, it must be ≤ {@code buffer.capacity() - (buffer.position() + offset)} - * - * @return the sliced buffer - */ - public static ShortBuffer memSlice(ShortBuffer buffer, int offset, int capacity) { - int position = buffer.position() + offset; - if (offset < 0 || buffer.limit() < position) { - throw new IllegalArgumentException(); - } - if (capacity < 0 || buffer.capacity() - position < capacity) { - throw new IllegalArgumentException(); - } - return slice(BUFFER_SHORT, buffer, address(position, 1, memAddress0(buffer)), capacity, PARENT_SHORT); - } - - /** - * Returns a slice of the specified buffer between {@code (buffer.position() + offset)} and {@code (buffer.position() + offset + capacity)}. - * - *The position and limit of the original buffer are preserved after a call to this method.
- * - * @param buffer the buffer to slice - * @param offset the slice offset, it must be ≤ {@code buffer.remaining()} - * @param capacity the slice length, it must be ≤ {@code buffer.capacity() - (buffer.position() + offset)} - * - * @return the sliced buffer - */ - public static CharBuffer memSlice(CharBuffer buffer, int offset, int capacity) { - int position = buffer.position() + offset; - if (offset < 0 || buffer.limit() < position) { - throw new IllegalArgumentException(); - } - if (capacity < 0 || buffer.capacity() - position < capacity) { - throw new IllegalArgumentException(); - } - return slice(BUFFER_CHAR, buffer, address(position, 1, memAddress0(buffer)), capacity, PARENT_CHAR); - } - - /** - * Returns a slice of the specified buffer between {@code (buffer.position() + offset)} and {@code (buffer.position() + offset + capacity)}. - * - *The position and limit of the original buffer are preserved after a call to this method.
- * - * @param buffer the buffer to slice - * @param offset the slice offset, it must be ≤ {@code buffer.remaining()} - * @param capacity the slice length, it must be ≤ {@code buffer.capacity() - (buffer.position() + offset)} - * - * @return the sliced buffer - */ - public static IntBuffer memSlice(IntBuffer buffer, int offset, int capacity) { - int position = buffer.position() + offset; - if (offset < 0 || buffer.limit() < position) { - throw new IllegalArgumentException(); - } - if (capacity < 0 || buffer.capacity() - position < capacity) { - throw new IllegalArgumentException(); - } - return slice(BUFFER_INT, buffer, address(position, 2, memAddress0(buffer)), capacity, PARENT_INT); - } - - /** - * Returns a slice of the specified buffer between {@code (buffer.position() + offset)} and {@code (buffer.position() + offset + capacity)}. - * - *The position and limit of the original buffer are preserved after a call to this method.
- * - * @param buffer the buffer to slice - * @param offset the slice offset, it must be ≤ {@code buffer.remaining()} - * @param capacity the slice length, it must be ≤ {@code buffer.capacity() - (buffer.position() + offset)} - * - * @return the sliced buffer - */ - public static LongBuffer memSlice(LongBuffer buffer, int offset, int capacity) { - int position = buffer.position() + offset; - if (offset < 0 || buffer.limit() < position) { - throw new IllegalArgumentException(); - } - if (capacity < 0 || buffer.capacity() - position < capacity) { - throw new IllegalArgumentException(); - } - return slice(BUFFER_LONG, buffer, address(position, 3, memAddress0(buffer)), capacity, PARENT_LONG); - } - - /** - * Returns a slice of the specified buffer between {@code (buffer.position() + offset)} and {@code (buffer.position() + offset + capacity)}. - * - *The position and limit of the original buffer are preserved after a call to this method.
- * - * @param buffer the buffer to slice - * @param offset the slice offset, it must be ≤ {@code buffer.remaining()} - * @param capacity the slice length, it must be ≤ {@code buffer.capacity() - (buffer.position() + offset)} - * - * @return the sliced buffer - */ - public static FloatBuffer memSlice(FloatBuffer buffer, int offset, int capacity) { - int position = buffer.position() + offset; - if (offset < 0 || buffer.limit() < position) { - throw new IllegalArgumentException(); - } - if (capacity < 0 || buffer.capacity() - position < capacity) { - throw new IllegalArgumentException(); - } - return slice(BUFFER_FLOAT, buffer, address(position, 2, memAddress0(buffer)), capacity, PARENT_FLOAT); - } - - /** - * Returns a slice of the specified buffer between {@code (buffer.position() + offset)} and {@code (buffer.position() + offset + capacity)}. - * - *The position and limit of the original buffer are preserved after a call to this method.
- * - * @param buffer the buffer to slice - * @param offset the slice offset, it must be ≤ {@code buffer.remaining()} - * @param capacity the slice length, it must be ≤ {@code buffer.capacity() - (buffer.position() + offset)} - * - * @return the sliced buffer - */ - public static DoubleBuffer memSlice(DoubleBuffer buffer, int offset, int capacity) { - int position = buffer.position() + offset; - if (offset < 0 || buffer.limit() < position) { - throw new IllegalArgumentException(); - } - if (capacity < 0 || buffer.capacity() - position < capacity) { - throw new IllegalArgumentException(); - } - return slice(BUFFER_DOUBLE, buffer, address(position, 3, memAddress0(buffer)), capacity, PARENT_DOUBLE); - } - - /** - * Returns a slice of the specified buffer between {@code (buffer.position() + offset)} and {@code (buffer.position() + offset + capacity)}. - * - *The position and limit of the original buffer are preserved after a call to this method.
- * - * @param buffer the buffer to slice - * @param offset the slice offset, it must be ≤ {@code buffer.remaining()} - * @param capacity the slice length, it must be ≤ {@code buffer.capacity() - (buffer.position() + offset)} - * - * @return the sliced buffer - */ - public staticThis method is useful for reading ASCII and UTF8 encoded text.
- * - * @param buffer the buffer containing the null-terminated string - * - * @return the string length, in bytes - */ - public static int memLengthNT1(ByteBuffer buffer) { - return memLengthNT1(memAddress(buffer), buffer.remaining()); - } - - private static int memLengthNT2(long address, int maxLength) { - if (CHECKS) { - check(address); - } - return BITS64 - ? strlen64NT2(address, maxLength) - : strlen32NT2(address, maxLength); - } - - private static int strlen64NT2(long address, int maxLength) { - int i = 0; - - if (8 <= maxLength) { - int misalignment = (int)address & 7; - if (misalignment != 0) { - // Align to 8 bytes - for (int len = 8 - misalignment; i < len; i += 2) { - if (UNSAFE.getShort(null, address + i) == 0) { - return i; - } - } - } - - // Aligned longs for performance - while (i <= maxLength - 8) { - if (mathHasZeroShort(UNSAFE.getLong(null, address + i))) { - break; - } - i += 8; - } - } - - // Tail - for (; i < maxLength; i += 2) { - if (UNSAFE.getShort(null, address + i) == 0) { - break; - } - } - - return i; - } - - private static int strlen32NT2(long address, int maxLength) { - int i = 0; - - if (4 <= maxLength) { - int misalignment = (int)address & 3; - if (misalignment != 0) { - // Align to 4 bytes - for (int len = 4 - misalignment; i < len; i += 2) { - if (UNSAFE.getShort(null, address + i) == 0) { - return i; - } - } - } - - // Aligned longs for performance - while (i <= maxLength - 4) { - if (mathHasZeroShort(UNSAFE.getInt(null, address + i))) { - break; - } - i += 4; - } - } - - // Tail - for (; i < maxLength; i += 2) { - if (UNSAFE.getShort(null, address + i) == 0) { - break; - } - } - - return i; - } - - /** - * Calculates the length, in bytes, of the null-terminated string that starts at the current position of the specified buffer. Two \0 characters will - * terminate the string. The returned buffer will NOT include the \0 bytes. - * - *This method is useful for reading UTF16 encoded text.
- * - * @param buffer the buffer containing the null-terminated string - * - * @return the string length, in bytes - */ - public static int memLengthNT2(ByteBuffer buffer) { - return memLengthNT2(memAddress(buffer), buffer.remaining()); - } - - /** - * Creates a new direct ByteBuffer that starts at the specified memory address and has capacity equal to the null-terminated string starting at that - * address. A single \0 character will terminate the string. The returned buffer will NOT include the \0 byte. - * - *This method is useful for reading ASCII and UTF8 encoded text.
- * - * @param address the starting memory address - * - * @return the new ByteBuffer - */ - public static ByteBuffer memByteBufferNT1(long address) { - return memByteBuffer(address, memLengthNT1(address, Integer.MAX_VALUE)); - } - - /** - * Creates a new direct ByteBuffer that starts at the specified memory address and has capacity equal to the null-terminated string starting at that - * address, up to a maximum of {@code maxLength} bytes. A single \0 character will terminate the string. The returned buffer will NOT include the \0 byte. - * - *This method is useful for reading ASCII and UTF8 encoded text.
- * - * @param address the starting memory address - * @param maxLength the maximum string length, in bytes - * - * @return the new ByteBuffer - */ - public static ByteBuffer memByteBufferNT1(long address, int maxLength) { - return memByteBuffer(address, memLengthNT1(address, maxLength)); - } - - /** Like {@link #memByteBufferNT1(long) memByteBufferNT1}, but returns {@code null} if {@code address} is {@link #NULL}. */ - @Nullable - public static ByteBuffer memByteBufferNT1Safe(long address) { - return address == NULL ? null : memByteBuffer(address, memLengthNT1(address, Integer.MAX_VALUE)); - } - - /** Like {@link #memByteBufferNT1(long, int) memByteBufferNT1}, but returns {@code null} if {@code address} is {@link #NULL}. */ - @Nullable - public static ByteBuffer memByteBufferNT1Safe(long address, int maxLength) { - return address == NULL ? null : memByteBuffer(address, memLengthNT1(address, maxLength)); - } - - /** - * Creates a new direct ByteBuffer that starts at the specified memory address and has capacity equal to the null-terminated string starting at that - * address. Two \0 characters will terminate the string. The returned buffer will NOT include the \0 bytes. - * - *This method is useful for reading UTF16 encoded text.
- * - * @param address the starting memory address - * - * @return the new ByteBuffer - */ - public static ByteBuffer memByteBufferNT2(long address) { - return memByteBufferNT2(address, Integer.MAX_VALUE - 1); - } - - /** - * Creates a new direct ByteBuffer that starts at the specified memory address and has capacity equal to the null-terminated string starting at that - * address, up to a maximum of {@code maxLength} bytes. Two \0 characters will terminate the string. The returned buffer will NOT include the \0 bytes. - * - *This method is useful for reading UTF16 encoded text.
- * - * @param address the starting memory address - * - * @return the new ByteBuffer - */ - public static ByteBuffer memByteBufferNT2(long address, int maxLength) { - if (DEBUG) { - if ((maxLength & 1) != 0) { - throw new IllegalArgumentException("The maximum length must be an even number."); - } - } - return memByteBuffer(address, memLengthNT2(address, maxLength)); - } - - /** Like {@link #memByteBufferNT2(long) memByteBufferNT2}, but returns {@code null} if {@code address} is {@link #NULL}. */ - @Nullable - public static ByteBuffer memByteBufferNT2Safe(long address) { - return address == NULL ? null : memByteBufferNT2(address, Integer.MAX_VALUE - 1); - } - - /** Like {@link #memByteBufferNT2(long, int) memByteBufferNT2}, but returns {@code null} if {@code address} is {@link #NULL}. */ - @Nullable - public static ByteBuffer memByteBufferNT2Safe(long address, int maxLength) { - return address == NULL ? null : memByteBufferNT2(address, maxLength); - } - - /** - * Converts the null-terminated ASCII encoded string at the specified memory address to a {@link String}. - * - * @param address the string memory address - * - * @return the decoded {@link String} - */ - public static String memASCII(long address) { - return memASCII(address, memLengthNT1(address, Integer.MAX_VALUE)); - } - - /** - * Converts the ASCII encoded string at the specified memory address to a {@link String}. - * - * @param address the string memory address - * @param length the number of bytes to decode - * - * @return the decoded {@link String} - */ - @SuppressWarnings("deprecation") - public static String memASCII(long address, int length) { - if (length <= 0) { - return ""; - } - - byte[] ascii = length <= ARRAY_TLC_SIZE ? ARRAY_TLC_BYTE.get() : new byte[length]; - memByteBuffer(address, length).get(ascii, 0, length); - return new String(ascii, 0, 0, length); - } - - /** - * Decodes the bytes with index {@code [position(), position()+remaining()}) in {@code buffer}, as an ASCII string. - * - *The current {@code position} and {@code limit} of the specified {@code buffer} are not affected by this operation.
- * - * @param buffer the {@link ByteBuffer} to decode - * - * @return the decoded {@link String} - */ - public static String memASCII(ByteBuffer buffer) { - return memASCII(memAddress(buffer), buffer.remaining()); - } - - /** Like {@link #memASCII(long) memASCII}, but returns {@code null} if {@code address} is {@link #NULL}. */ - @Nullable - public static String memASCIISafe(long address) { - return address == NULL ? null : memASCII(address, memLengthNT1(address, Integer.MAX_VALUE)); - } - - /** Like {@link #memASCII(long, int) memASCII}, but returns {@code null} if {@code address} is {@link #NULL}. */ - @Nullable - public static String memASCIISafe(long address, int length) { - return address == NULL ? null : memASCII(address, length); - } - - /** Like {@link #memASCII(ByteBuffer) memASCII}, but returns {@code null} if {@code buffer} is {@code null}. */ - @Nullable - public static String memASCIISafe(@Nullable ByteBuffer buffer) { - return buffer == null ? null : memASCII(memAddress(buffer), buffer.remaining()); - } - - /** - * Decodes the bytes with index {@code [position(), position()+length}) in {@code buffer}, as an ASCII string. - * - *The current {@code position} and {@code limit} of the specified {@code buffer} are not affected by this operation.
- * - * @param buffer the {@link ByteBuffer} to decode - * @param length the number of bytes to decode - * - * @return the decoded {@link String} - */ - public static String memASCII(ByteBuffer buffer, int length) { - return memASCII(memAddress(buffer), length); - } - - /** - * Decodes the bytes with index {@code [offset, offset+length}) in {@code buffer}, as an ASCII string. - * - *The current {@code position} and {@code limit} of the specified {@code buffer} are not affected by this operation.
- * - * @param buffer the {@link ByteBuffer} to decode - * @param length the number of bytes to decode - * @param offset the offset at which to start decoding. - * - * @return the decoded {@link String} - */ - public static String memASCII(ByteBuffer buffer, int length, int offset) { - return memASCII(memAddress(buffer, offset), length); - } - - /** - * Converts the null-terminated UTF-8 encoded string at the specified memory address to a {@link String}. - * - * @param address the string memory address - * - * @return the decoded {@link String} - */ - public static String memUTF8(long address) { - return MultiReleaseTextDecoding.decodeUTF8(address, memLengthNT1(address, Integer.MAX_VALUE)); - } - - /** - * Converts the UTF-8 encoded string at the specified memory address to a {@link String}. - * - * @param address the string memory address - * @param length the number of bytes to decode - * - * @return the decoded {@link String} - */ - public static String memUTF8(long address, int length) { - return MultiReleaseTextDecoding.decodeUTF8(address, length); - } - - /** - * Decodes the bytes with index {@code [position(), position()+remaining()}) in {@code buffer}, as a UTF-8 string. - * - *The current {@code position} and {@code limit} of the specified {@code buffer} are not affected by this operation.
- * - * @param buffer the {@link ByteBuffer} to decode - * - * @return the decoded {@link String} - */ - public static String memUTF8(ByteBuffer buffer) { - return MultiReleaseTextDecoding.decodeUTF8(memAddress(buffer), buffer.remaining()); - } - - /** Like {@link #memUTF8(long) memUTF8}, but returns {@code null} if {@code address} is {@link #NULL}. */ - @Nullable - public static String memUTF8Safe(long address) { - return address == NULL ? null : MultiReleaseTextDecoding.decodeUTF8(address, memLengthNT1(address, Integer.MAX_VALUE)); - } - - /** Like {@link #memUTF8(long, int) memUTF8}, but returns {@code null} if {@code address} is {@link #NULL}. */ - @Nullable - public static String memUTF8Safe(long address, int length) { - return address == NULL ? null : MultiReleaseTextDecoding.decodeUTF8(address, length); - } - - /** Like {@link #memUTF8(ByteBuffer) memUTF8}, but returns {@code null} if {@code buffer} is {@code null}. */ - @Nullable - public static String memUTF8Safe(@Nullable ByteBuffer buffer) { - return buffer == null ? null : MultiReleaseTextDecoding.decodeUTF8(memAddress(buffer), buffer.remaining()); - } - - /** - * Decodes the bytes with index {@code [position(), position()+length}) in {@code buffer}, as a UTF-8 string. - * - *The current {@code position} and {@code limit} of the specified {@code buffer} are not affected by this operation.
- * - * @param buffer the {@link ByteBuffer} to decode - * @param length the number of bytes to decode - * - * @return the decoded {@link String} - */ - public static String memUTF8(ByteBuffer buffer, int length) { - return MultiReleaseTextDecoding.decodeUTF8(memAddress(buffer), length); - } - - /** - * Decodes the bytes with index {@code [offset, offset+length}) in {@code buffer}, as a UTF-8 string. - * - *The current {@code position} and {@code limit} of the specified {@code buffer} are not affected by this operation.
- * - * @param buffer the {@link ByteBuffer} to decode - * @param length the number of bytes to decode - * @param offset the offset at which to start decoding. - * - * @return the decoded {@link String} - */ - public static String memUTF8(ByteBuffer buffer, int length, int offset) { - return MultiReleaseTextDecoding.decodeUTF8(memAddress(buffer, offset), length); - } - - /** - * Converts the null-terminated UTF-16 encoded string at the specified memory address to a {@link String}. - * - * @param address the string memory address - * - * @return the decoded {@link String} - */ - public static String memUTF16(long address) { - return memUTF16(address, memLengthNT2(address, Integer.MAX_VALUE - 1) >> 1); - } - - /** - * Converts the UTF-16 encoded string at the specified memory address to a {@link String}. - * - * @param address the string memory address - * @param length the number of characters to decode - * - * @return the decoded {@link String} - */ - public static String memUTF16(long address, int length) { - if (length <= 0) { - return ""; - } - - if (DEBUG) { - // The implementation below does no codepoint validation. - int len = length << 1; - byte[] bytes = len <= ARRAY_TLC_SIZE ? ARRAY_TLC_BYTE.get() : new byte[len]; - memByteBuffer(address, len).get(bytes, 0, len); - return new String(bytes, 0, len, UTF16); - } - - char[] chars = length <= ARRAY_TLC_SIZE ? ARRAY_TLC_CHAR.get() : new char[length]; - memCharBuffer(address, length).get(chars, 0, length); - return new String(chars, 0, length); - } - - /** - * Decodes the bytes with index {@code [position(), position()+remaining()}) in {@code buffer}, as a UTF-16 string. - * - *The current {@code position} and {@code limit} of the specified {@code buffer} are not affected by this operation.
- * - * @param buffer the {@link ByteBuffer} to decode - * - * @return the decoded {@link String} - */ - public static String memUTF16(ByteBuffer buffer) { - return memUTF16(memAddress(buffer), buffer.remaining() >> 1); - } - - /** Like {@link #memUTF16(long) memUTF16}, but returns {@code null} if {@code address} is {@link #NULL}. */ - @Nullable - public static String memUTF16Safe(long address) { - return address == NULL ? null : memUTF16(address, memLengthNT2(address, Integer.MAX_VALUE - 1) >> 1); - } - - /** Like {@link #memUTF16(long, int) memUTF16}, but returns {@code null} if {@code address} is {@link #NULL}. */ - @Nullable - public static String memUTF16Safe(long address, int length) { - return address == NULL ? null : memUTF16(address, length); - } - - /** Like {@link #memUTF16(ByteBuffer) memUTF16}, but returns {@code null} if {@code buffer} is {@code null}. */ - @Nullable - public static String memUTF16Safe(@Nullable ByteBuffer buffer) { - return buffer == null ? null : memUTF16(memAddress(buffer), buffer.remaining() >> 1); - } - - /** - * Decodes the bytes with index {@code [position(), position()+(length*2)}) in {@code buffer}, as a UTF-16 string. - * - *The current {@code position} and {@code limit} of the specified {@code buffer} are not affected by this operation.
- * - * @param buffer the {@link ByteBuffer} to decode - * @param length the number of characters to decode - * - * @return the decoded {@link String} - */ - public static String memUTF16(ByteBuffer buffer, int length) { - return memUTF16(memAddress(buffer), length); - } - - /** - * Decodes the bytes with index {@code [offset, offset+(length*2)}) in {@code buffer}, as a UTF-16 string. - * - *The current {@code position} and {@code limit} of the specified {@code buffer} are not affected by this operation.
- * - * @param buffer the {@link ByteBuffer} to decode - * @param length the number of characters to decode - * @param offset the offset at which to start decoding, in bytes. - * - * @return the decoded {@link String} - */ - public static String memUTF16(ByteBuffer buffer, int length, int offset) { - return memUTF16(memAddress(buffer, offset), length); - } - - // ------------------------------------------------- - // ------------------------------------------------- - // ------------------------------------------------- - - private static sun.misc.Unsafe getUnsafeInstance() { - java.lang.reflect.Field[] fields = sun.misc.Unsafe.class.getDeclaredFields(); - - /* - Different runtimes use different names for the Unsafe singleton, - so we cannot use .getDeclaredField and we scan instead. For example: - - Oracle: theUnsafe - PERC : m_unsafe_instance - Android: THE_ONE - */ - for (java.lang.reflect.Field field : fields) { - if (!field.getType().equals(sun.misc.Unsafe.class)) { - continue; - } - - int modifiers = field.getModifiers(); - if (!(java.lang.reflect.Modifier.isStatic(modifiers) && java.lang.reflect.Modifier.isFinal(modifiers))) { - continue; - } - - try { - field.setAccessible(true); - return (sun.misc.Unsafe)field.get(null); - } catch (Exception ignored) { - } - break; - } - - throw new UnsupportedOperationException("LWJGL requires sun.misc.Unsafe to be available."); - } - - private static long getAddressOffset() { - long MAGIC_ADDRESS = 0xDEADBEEF8BADF00DL; - if (BITS32) { - MAGIC_ADDRESS &= 0xFFFFFFFFL; - } - - ByteBuffer bb = Objects.requireNonNull(NewDirectByteBuffer(MAGIC_ADDRESS, 0)); - - long offset = 8L; // 8 byte aligned, cannot be at 0 - while (true) { - if (UNSAFE.getLong(bb, offset) == MAGIC_ADDRESS) { - return offset; - } - offset += 8L; - } - } - - private static final int MAGIC_CAPACITY = 0x0D15EA5E; - private static final int MAGIC_POSITION = 0x00FACADE; - - private static long getIntFieldOffset(ByteBuffer bb, int magicValue) { - long offset = 4L; // 4 byte aligned, cannot be at 0 - while (true) { - if (UNSAFE.getInt(bb, offset) == magicValue) { - return offset; - } - offset += 4L; - } - } - - private static long getMarkOffset() { - ByteBuffer bb = Objects.requireNonNull(NewDirectByteBuffer(1L, 0)); - return getIntFieldOffset(bb, -1); - } - - private static long getPositionOffset() { - ByteBuffer bb = Objects.requireNonNull(NewDirectByteBuffer(-1L, MAGIC_CAPACITY)); - bb.position(MAGIC_POSITION); - return getIntFieldOffset(bb, MAGIC_POSITION); - } - - private static long getLimitOffset() { - ByteBuffer bb = Objects.requireNonNull(NewDirectByteBuffer(-1L, MAGIC_CAPACITY)); - bb.limit(MAGIC_POSITION); - return getIntFieldOffset(bb, MAGIC_POSITION); - } - - private static long getCapacityOffset() { - ByteBuffer bb = Objects.requireNonNull(NewDirectByteBuffer(-1L, MAGIC_CAPACITY)); - bb.limit(0); - return getIntFieldOffset(bb, MAGIC_CAPACITY); - } - - private static