| /* | |
| * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| * | |
| */ | |
| /* | |
| * @test | |
| * @modules java.base/jdk.internal.foreign | |
| * @run testng/othervm TestSegmentAllocators | |
| */ | |
| import java.lang.foreign.*; | |
| import org.testng.annotations.*; | |
| import java.lang.foreign.Arena; | |
| import java.lang.invoke.VarHandle; | |
| import java.nio.ByteBuffer; | |
| import java.nio.ByteOrder; | |
| import java.nio.CharBuffer; | |
| import java.nio.DoubleBuffer; | |
| import java.nio.FloatBuffer; | |
| import java.nio.IntBuffer; | |
| import java.nio.LongBuffer; | |
| import java.nio.ShortBuffer; | |
| import java.util.ArrayList; | |
| import java.util.List; | |
| import java.util.concurrent.CompletableFuture; | |
| import java.util.concurrent.ExecutionException; | |
| import java.util.concurrent.atomic.AtomicInteger; | |
| import java.util.function.BiFunction; | |
| import java.util.function.Function; | |
| import static org.testng.Assert.*; | |
| public class TestSegmentAllocators { | |
| final static int ELEMS = 128; | |
| @Test(dataProvider = "scalarAllocations") | |
| @SuppressWarnings("unchecked") | |
| public <Z, L extends ValueLayout> void testAllocation(Z value, AllocationFactory allocationFactory, L layout, AllocationFunction<Z, L> allocationFunction, Function<MemoryLayout, VarHandle> handleFactory) { | |
| layout = (L)layout.withByteAlignment(layout.byteSize()); | |
| L[] layouts = (L[])new ValueLayout[] { | |
| layout, | |
| layout.withByteAlignment(layout.byteAlignment() * 2), | |
| layout.withByteAlignment(layout.byteAlignment() * 4), | |
| layout.withByteAlignment(layout.byteAlignment() * 8) | |
| }; | |
| for (L alignedLayout : layouts) { | |
| List<MemorySegment> addressList = new ArrayList<>(); | |
| int elems = ELEMS / ((int)alignedLayout.byteAlignment() / (int)layout.byteAlignment()); | |
| Arena[] arenas = { | |
| Arena.ofConfined(), | |
| Arena.ofShared() | |
| }; | |
| for (Arena arena : arenas) { | |
| try (arena) { | |
| SegmentAllocator allocator = allocationFactory.allocator(alignedLayout.byteSize() * ELEMS, arena); | |
| for (int i = 0; i < elems; i++) { | |
| MemorySegment address = allocationFunction.allocate(allocator, alignedLayout, value); | |
| assertEquals(address.byteSize(), alignedLayout.byteSize()); | |
| addressList.add(address); | |
| VarHandle handle = handleFactory.apply(alignedLayout); | |
| assertEquals(value, handle.get(address, 0L)); | |
| } | |
| boolean isBound = allocationFactory.isBound(); | |
| try { | |
| allocationFunction.allocate(allocator, alignedLayout, value); | |
| assertFalse(isBound); | |
| } catch (IndexOutOfBoundsException ex) { | |
| //failure is expected if bound | |
| assertTrue(isBound); | |
| } | |
| } | |
| // addresses should be invalid now | |
| for (MemorySegment address : addressList) { | |
| assertFalse(address.scope().isAlive()); | |
| } | |
| } | |
| } | |
| } | |
| static final int SIZE_256M = 1024 * 1024 * 256; | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| public void testReadOnlySlicingAllocator() { | |
| SegmentAllocator.slicingAllocator(MemorySegment.ofArray(new int[0]).asReadOnly()); | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class) | |
| public void testReadOnlyPrefixAllocator() { | |
| SegmentAllocator.prefixAllocator(MemorySegment.ofArray(new int[0]).asReadOnly()); | |
| } | |
| @Test | |
| public void testBigAllocationInUnboundedSession() { | |
| try (Arena arena = Arena.ofConfined()) { | |
| for (int i = 8 ; i < SIZE_256M ; i *= 8) { | |
| SegmentAllocator allocator = SegmentAllocator.slicingAllocator(arena.allocate(i * 2 + 1)); | |
| MemorySegment address = allocator.allocate(i, i); | |
| //check size | |
| assertEquals(address.byteSize(), i); | |
| //check alignment | |
| assertEquals(address.address() % i, 0); | |
| } | |
| } | |
| } | |
| @Test | |
| public void testTooBigForBoundedArena() { | |
| try (Arena arena = Arena.ofConfined()) { | |
| SegmentAllocator allocator = SegmentAllocator.slicingAllocator(arena.allocate(10)); | |
| assertThrows(IndexOutOfBoundsException.class, () -> allocator.allocate(12)); | |
| allocator.allocate(5); | |
| } | |
| } | |
| @Test(dataProvider = "allocators", expectedExceptions = IllegalArgumentException.class) | |
| public void testBadAllocationSize(SegmentAllocator allocator) { | |
| allocator.allocate(-1); | |
| } | |
| @Test(dataProvider = "allocators", expectedExceptions = IllegalArgumentException.class) | |
| public void testBadAllocationAlignZero(SegmentAllocator allocator) { | |
| allocator.allocate(1, 0); | |
| } | |
| @Test(dataProvider = "allocators", expectedExceptions = IllegalArgumentException.class) | |
| public void testBadAllocationAlignNeg(SegmentAllocator allocator) { | |
| allocator.allocate(1, -1); | |
| } | |
| @Test(dataProvider = "allocators", expectedExceptions = IllegalArgumentException.class) | |
| public void testBadAllocationAlignNotPowerTwo(SegmentAllocator allocator) { | |
| allocator.allocate(1, 3); | |
| } | |
| @Test(dataProvider = "allocators", expectedExceptions = IllegalArgumentException.class) | |
| public void testBadAllocationArrayNegSize(SegmentAllocator allocator) { | |
| allocator.allocate(ValueLayout.JAVA_BYTE, -1); | |
| } | |
| @Test(dataProvider = "allocators", expectedExceptions = IllegalArgumentException.class) | |
| public void testBadAllocationArrayOverflow(SegmentAllocator allocator) { | |
| allocator.allocate(ValueLayout.JAVA_LONG, Long.MAX_VALUE); | |
| } | |
| @Test(expectedExceptions = OutOfMemoryError.class) | |
| public void testBadArenaNullReturn() { | |
| try (Arena arena = Arena.ofConfined()) { | |
| arena.allocate(Long.MAX_VALUE, 2); | |
| } | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class, | |
| expectedExceptionsMessageRegExp = ".*Heap segment not allowed.*") | |
| public void testArenaAllocateFromHeapSegment() { | |
| try (Arena arena = Arena.ofConfined()) { | |
| var heapSegment = MemorySegment.ofArray(new int[]{1}); | |
| arena.allocateFrom(ValueLayout.ADDRESS, heapSegment); | |
| } | |
| } | |
| @Test(expectedExceptions = IllegalArgumentException.class, | |
| expectedExceptionsMessageRegExp = ".*Heap segment not allowed.*") | |
| public void testAllocatorAllocateFromHeapSegment() { | |
| try (Arena arena = Arena.ofConfined()) { | |
| SegmentAllocator allocator = SegmentAllocator.prefixAllocator(arena.allocate(16)); | |
| var heapSegment = MemorySegment.ofArray(new int[]{1}); | |
| allocator.allocateFrom(ValueLayout.ADDRESS, heapSegment); | |
| } | |
| } | |
| // Invariant checking tests for the SegmentAllocator method: | |
| // MemorySegment allocateFrom(ValueLayout elementLayout, | |
| // MemorySegment source, | |
| // ValueLayout sourceElementLayout, | |
| // long sourceOffset, | |
| // long elementCount) { | |
| @Test | |
| public void testAllocatorAllocateFromArguments() { | |
| try (Arena arena = Arena.ofConfined()) { | |
| var sourceElements = 2; | |
| var source = arena.allocate(ValueLayout.JAVA_LONG, sourceElements); | |
| var elementLayout = ValueLayout.JAVA_INT; | |
| var sourceElementLayout = ValueLayout.JAVA_INT; | |
| // IllegalArgumentException if {@code elementLayout.byteSize() != sourceElementLayout.byteSize()} | |
| assertThrows(IllegalArgumentException.class, () -> | |
| arena.allocateFrom(elementLayout, source, ValueLayout.JAVA_BYTE, 0, 1) | |
| ); | |
| // IllegalArgumentException if source segment/offset | |
| // are <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> | |
| // in the source element layout | |
| assertThrows(IllegalArgumentException.class, () -> | |
| arena.allocateFrom(elementLayout, source.asSlice(1), sourceElementLayout, 0, 1) | |
| ); | |
| assertThrows(IllegalArgumentException.class, () -> | |
| arena.allocateFrom(elementLayout, source, sourceElementLayout, 1, 1) | |
| ); | |
| // IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()} | |
| assertThrows(IllegalArgumentException.class, () -> | |
| arena.allocateFrom(elementLayout.withByteAlignment(elementLayout.byteAlignment() * 2), source, sourceElementLayout, 1, 1) | |
| ); | |
| // IllegalStateException if the {@linkplain MemorySegment#scope() scope} associated | |
| // with {@code source} is not {@linkplain MemorySegment.Scope#isAlive() alive} | |
| // This is tested in TestScopedOperations | |
| // WrongThreadException if this method is called from a thread {@code T}, | |
| // such that {@code source.isAccessibleBy(T) == false} | |
| CompletableFuture<Arena> future = CompletableFuture.supplyAsync(Arena::ofConfined); | |
| try { | |
| Arena otherThreadArena = future.get(); | |
| assertThrows(WrongThreadException.class, () -> | |
| otherThreadArena.allocateFrom(elementLayout, source, sourceElementLayout, 0, 1) | |
| ); | |
| } catch (ExecutionException | InterruptedException e) { | |
| fail("Unable to create arena", e); | |
| } | |
| // IllegalArgumentException if {@code elementCount * sourceElementLayout.byteSize()} overflows | |
| assertThrows(IllegalArgumentException.class, () -> | |
| arena.allocateFrom(elementLayout, source, sourceElementLayout, 0, Long.MAX_VALUE) | |
| ); | |
| // IndexOutOfBoundsException if {@code sourceOffset > source.byteSize() - (elementCount * sourceElementLayout.byteSize())} | |
| assertThrows(IndexOutOfBoundsException.class, () -> | |
| arena.allocateFrom(elementLayout, source, sourceElementLayout, source.byteSize() - (1 * sourceElementLayout.byteAlignment()) + elementLayout.byteSize(), 1) | |
| ); | |
| // IndexOutOfBoundsException if {@code sourceOffset < 0} | |
| assertThrows(IndexOutOfBoundsException.class, () -> | |
| arena.allocateFrom(elementLayout, source, sourceElementLayout, -elementLayout.byteSize(), 1) | |
| ); | |
| // IllegalArgumentException if {@code elementCount < 0} | |
| assertThrows(IllegalArgumentException.class, () -> | |
| arena.allocateFrom(elementLayout, source, sourceElementLayout, 0, -1) | |
| ); | |
| } | |
| } | |
| @Test | |
| public void testArrayAllocateDelegation() { | |
| AtomicInteger calls = new AtomicInteger(); | |
| SegmentAllocator allocator = new SegmentAllocator() { | |
| @Override | |
| public MemorySegment allocate(long bytesSize, long byteAlignment) { | |
| return MemorySegment.NULL; | |
| } | |
| @Override | |
| public MemorySegment allocateFrom(ValueLayout elementLayout, MemorySegment source, ValueLayout sourceElementLayout, long sourceOffset, long elementCount) { | |
| calls.incrementAndGet(); | |
| return MemorySegment.NULL; | |
| } | |
| }; | |
| allocator.allocateFrom(ValueLayout.JAVA_BYTE); | |
| allocator.allocateFrom(ValueLayout.JAVA_SHORT); | |
| allocator.allocateFrom(ValueLayout.JAVA_CHAR); | |
| allocator.allocateFrom(ValueLayout.JAVA_INT); | |
| allocator.allocateFrom(ValueLayout.JAVA_FLOAT); | |
| allocator.allocateFrom(ValueLayout.JAVA_LONG); | |
| allocator.allocateFrom(ValueLayout.JAVA_DOUBLE); | |
| assertEquals(calls.get(), 7); | |
| } | |
| @Test | |
| public void testStringAllocateDelegation() { | |
| AtomicInteger calls = new AtomicInteger(); | |
| SegmentAllocator allocator = new SegmentAllocator() { | |
| @Override | |
| public MemorySegment allocate(long byteSize, long byteAlignment) { | |
| return Arena.ofAuto().allocate(byteSize, byteAlignment); | |
| } | |
| @Override | |
| public MemorySegment allocate(long size) { | |
| calls.incrementAndGet(); | |
| return allocate(size, 1); | |
| }; | |
| }; | |
| allocator.allocateFrom("Hello"); | |
| assertEquals(calls.get(), 1); | |
| } | |
| @Test(dataProvider = "arrayAllocations") | |
| public <Z> void testArray(AllocationFactory allocationFactory, ValueLayout layout, AllocationFunction<Object, ValueLayout> allocationFunction, ToArrayHelper<Z> arrayHelper) { | |
| Z arr = arrayHelper.array(); | |
| Arena[] arenas = { | |
| Arena.ofConfined(), | |
| Arena.ofShared() | |
| }; | |
| for (Arena arena : arenas) { | |
| try (arena) { | |
| SegmentAllocator allocator = allocationFactory.allocator(100, arena); | |
| MemorySegment address = allocationFunction.allocate(allocator, layout, arr); | |
| Z found = arrayHelper.toArray(address, layout); | |
| assertEquals(found, arr); | |
| } | |
| } | |
| } | |
| @Test(dataProvider = "arrayAllocations") | |
| public <Z> void testPredicatesAndCommands(AllocationFactory allocationFactory, ValueLayout layout, AllocationFunction<Object, ValueLayout> allocationFunction, ToArrayHelper<Z> arrayHelper) { | |
| Z arr = arrayHelper.array(); | |
| Arena[] arenas = { | |
| Arena.ofConfined(), | |
| Arena.ofShared() | |
| }; | |
| for (Arena arena : arenas) { | |
| try (arena) { | |
| SegmentAllocator allocator = allocationFactory.allocator(100, arena); | |
| MemorySegment segment = allocationFunction.allocate(allocator, layout, arr); | |
| assertThrows(UnsupportedOperationException.class, segment::load); | |
| assertThrows(UnsupportedOperationException.class, segment::unload); | |
| assertThrows(UnsupportedOperationException.class, segment::isLoaded); | |
| assertThrows(UnsupportedOperationException.class, segment::force); | |
| assertFalse(segment.isMapped()); | |
| assertTrue(segment.isNative()); | |
| } | |
| } | |
| } | |
| @DataProvider(name = "scalarAllocations") | |
| static Object[][] scalarAllocations() { | |
| List<Object[]> scalarAllocations = new ArrayList<>(); | |
| for (AllocationFactory factory : AllocationFactory.values()) { | |
| scalarAllocations.add(new Object[] { (byte)42, factory, ValueLayout.JAVA_BYTE, | |
| (AllocationFunction.OfByte) SegmentAllocator::allocateFrom, | |
| (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); | |
| scalarAllocations.add(new Object[] { (short)42, factory, ValueLayout.JAVA_SHORT.withOrder(ByteOrder.BIG_ENDIAN), | |
| (AllocationFunction.OfShort) SegmentAllocator::allocateFrom, | |
| (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); | |
| scalarAllocations.add(new Object[] { (char)42, factory, ValueLayout.JAVA_CHAR.withOrder(ByteOrder.BIG_ENDIAN), | |
| (AllocationFunction.OfChar) SegmentAllocator::allocateFrom, | |
| (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); | |
| scalarAllocations.add(new Object[] { 42, factory, | |
| ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN), | |
| (AllocationFunction.OfInt) SegmentAllocator::allocateFrom, | |
| (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); | |
| scalarAllocations.add(new Object[] { 42f, factory, ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.BIG_ENDIAN), | |
| (AllocationFunction.OfFloat) SegmentAllocator::allocateFrom, | |
| (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); | |
| scalarAllocations.add(new Object[] { 42L, factory, ValueLayout.JAVA_LONG.withOrder(ByteOrder.BIG_ENDIAN), | |
| (AllocationFunction.OfLong) SegmentAllocator::allocateFrom, | |
| (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); | |
| scalarAllocations.add(new Object[] { 42d, factory, ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.BIG_ENDIAN), | |
| (AllocationFunction.OfDouble) SegmentAllocator::allocateFrom, | |
| (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); | |
| scalarAllocations.add(new Object[] { MemorySegment.ofAddress(42), factory, ValueLayout.ADDRESS.withOrder(ByteOrder.BIG_ENDIAN), | |
| (AllocationFunction.OfAddress) SegmentAllocator::allocateFrom, | |
| (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); | |
| scalarAllocations.add(new Object[] { (short)42, factory, ValueLayout.JAVA_SHORT.withOrder(ByteOrder.LITTLE_ENDIAN), | |
| (AllocationFunction.OfShort) SegmentAllocator::allocateFrom, | |
| (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); | |
| scalarAllocations.add(new Object[] { (char)42, factory, ValueLayout.JAVA_CHAR.withOrder(ByteOrder.LITTLE_ENDIAN), | |
| (AllocationFunction.OfChar) SegmentAllocator::allocateFrom, | |
| (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); | |
| scalarAllocations.add(new Object[] { 42, factory, | |
| ValueLayout.JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN), | |
| (AllocationFunction.OfInt) SegmentAllocator::allocateFrom, | |
| (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); | |
| scalarAllocations.add(new Object[] { 42f, factory, ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.LITTLE_ENDIAN), | |
| (AllocationFunction.OfFloat) SegmentAllocator::allocateFrom, | |
| (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); | |
| scalarAllocations.add(new Object[] { 42L, factory, ValueLayout.JAVA_LONG.withOrder(ByteOrder.LITTLE_ENDIAN), | |
| (AllocationFunction.OfLong) SegmentAllocator::allocateFrom, | |
| (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); | |
| scalarAllocations.add(new Object[] { 42d, factory, ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.LITTLE_ENDIAN), | |
| (AllocationFunction.OfDouble) SegmentAllocator::allocateFrom, | |
| (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); | |
| scalarAllocations.add(new Object[] { MemorySegment.ofAddress(42), factory, ValueLayout.ADDRESS.withOrder(ByteOrder.BIG_ENDIAN), | |
| (AllocationFunction.OfAddress) SegmentAllocator::allocateFrom, | |
| (Function<MemoryLayout, VarHandle>)l -> l.varHandle() }); | |
| } | |
| return scalarAllocations.toArray(Object[][]::new); | |
| } | |
| @DataProvider(name = "arrayAllocations") | |
| static Object[][] arrayAllocations() { | |
| List<Object[]> arrayAllocations = new ArrayList<>(); | |
| for (AllocationFactory factory : AllocationFactory.values()) { | |
| arrayAllocations.add(new Object[] { factory, ValueLayout.JAVA_BYTE, | |
| (AllocationFunction.OfByteArray) SegmentAllocator::allocateFrom, | |
| ToArrayHelper.toByteArray }); | |
| arrayAllocations.add(new Object[] { factory, ValueLayout.JAVA_CHAR.withOrder(ByteOrder.LITTLE_ENDIAN), | |
| (AllocationFunction.OfCharArray) SegmentAllocator::allocateFrom, | |
| ToArrayHelper.toCharArray }); | |
| arrayAllocations.add(new Object[] { factory, ValueLayout.JAVA_SHORT.withOrder(ByteOrder.LITTLE_ENDIAN), | |
| (AllocationFunction.OfShortArray) SegmentAllocator::allocateFrom, | |
| ToArrayHelper.toShortArray }); | |
| arrayAllocations.add(new Object[] { factory, | |
| ValueLayout.JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN), | |
| (AllocationFunction.OfIntArray) SegmentAllocator::allocateFrom, | |
| ToArrayHelper.toIntArray }); | |
| arrayAllocations.add(new Object[] { factory, ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.LITTLE_ENDIAN), | |
| (AllocationFunction.OfFloatArray) SegmentAllocator::allocateFrom, | |
| ToArrayHelper.toFloatArray }); | |
| arrayAllocations.add(new Object[] { factory, ValueLayout.JAVA_LONG.withOrder(ByteOrder.LITTLE_ENDIAN), | |
| (AllocationFunction.OfLongArray) SegmentAllocator::allocateFrom, | |
| ToArrayHelper.toLongArray }); | |
| arrayAllocations.add(new Object[] { factory, ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.LITTLE_ENDIAN), | |
| (AllocationFunction.OfDoubleArray) SegmentAllocator::allocateFrom, | |
| ToArrayHelper.toDoubleArray }); | |
| arrayAllocations.add(new Object[] { factory, ValueLayout.JAVA_CHAR.withOrder(ByteOrder.BIG_ENDIAN), | |
| (AllocationFunction.OfCharArray) SegmentAllocator::allocateFrom, | |
| ToArrayHelper.toCharArray }); | |
| arrayAllocations.add(new Object[] { factory, ValueLayout.JAVA_SHORT.withOrder(ByteOrder.BIG_ENDIAN), | |
| (AllocationFunction.OfShortArray) SegmentAllocator::allocateFrom, | |
| ToArrayHelper.toShortArray }); | |
| arrayAllocations.add(new Object[] { factory, | |
| ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN), | |
| (AllocationFunction.OfIntArray) SegmentAllocator::allocateFrom, | |
| ToArrayHelper.toIntArray }); | |
| arrayAllocations.add(new Object[] { factory, ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.BIG_ENDIAN), | |
| (AllocationFunction.OfFloatArray) SegmentAllocator::allocateFrom, | |
| ToArrayHelper.toFloatArray }); | |
| arrayAllocations.add(new Object[] { factory, ValueLayout.JAVA_LONG.withOrder(ByteOrder.BIG_ENDIAN), | |
| (AllocationFunction.OfLongArray) SegmentAllocator::allocateFrom, | |
| ToArrayHelper.toLongArray }); | |
| arrayAllocations.add(new Object[] { factory, ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.BIG_ENDIAN), | |
| (AllocationFunction.OfDoubleArray) SegmentAllocator::allocateFrom, | |
| ToArrayHelper.toDoubleArray }); | |
| }; | |
| return arrayAllocations.toArray(Object[][]::new); | |
| } | |
| interface AllocationFunction<X, L extends ValueLayout> { | |
| MemorySegment allocate(SegmentAllocator allocator, L layout, X value); | |
| interface OfByte extends AllocationFunction<Byte, ValueLayout.OfByte> { } | |
| interface OfBoolean extends AllocationFunction<Boolean, ValueLayout.OfBoolean> { } | |
| interface OfChar extends AllocationFunction<Character, ValueLayout.OfChar> { } | |
| interface OfShort extends AllocationFunction<Short, ValueLayout.OfShort> { } | |
| interface OfInt extends AllocationFunction<Integer, ValueLayout.OfInt> { } | |
| interface OfFloat extends AllocationFunction<Float, ValueLayout.OfFloat> { } | |
| interface OfLong extends AllocationFunction<Long, ValueLayout.OfLong> { } | |
| interface OfDouble extends AllocationFunction<Double, ValueLayout.OfDouble> { } | |
| interface OfAddress extends AllocationFunction<MemorySegment, AddressLayout> { } | |
| interface OfByteArray extends AllocationFunction<byte[], ValueLayout.OfByte> { } | |
| interface OfCharArray extends AllocationFunction<char[], ValueLayout.OfChar> { } | |
| interface OfShortArray extends AllocationFunction<short[], ValueLayout.OfShort> { } | |
| interface OfIntArray extends AllocationFunction<int[], ValueLayout.OfInt> { } | |
| interface OfFloatArray extends AllocationFunction<float[], ValueLayout.OfFloat> { } | |
| interface OfLongArray extends AllocationFunction<long[], ValueLayout.OfLong> { } | |
| interface OfDoubleArray extends AllocationFunction<double[], ValueLayout.OfDouble> { } | |
| } | |
| enum AllocationFactory { | |
| SLICING(true, (size, arena) -> { | |
| return SegmentAllocator.slicingAllocator(arena.allocate(size, 1)); | |
| }); | |
| private final boolean isBound; | |
| private final BiFunction<Long, Arena, SegmentAllocator> factory; | |
| AllocationFactory(boolean isBound, BiFunction<Long, Arena, SegmentAllocator> factory) { | |
| this.isBound = isBound; | |
| this.factory = factory; | |
| } | |
| SegmentAllocator allocator(long size, Arena arena) { | |
| return factory.apply(size, arena); | |
| } | |
| public boolean isBound() { | |
| return isBound; | |
| } | |
| } | |
| interface ToArrayHelper<T> { | |
| T array(); | |
| T toArray(MemorySegment segment, ValueLayout layout); | |
| ToArrayHelper<byte[]> toByteArray = new ToArrayHelper<>() { | |
| @Override | |
| public byte[] array() { | |
| return new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; | |
| } | |
| @Override | |
| public byte[] toArray(MemorySegment segment, ValueLayout layout) { | |
| ByteBuffer buffer = segment.asByteBuffer().order(layout.order()); | |
| byte[] found = new byte[buffer.limit()]; | |
| buffer.get(found); | |
| return found; | |
| } | |
| }; | |
| ToArrayHelper<char[]> toCharArray = new ToArrayHelper<>() { | |
| @Override | |
| public char[] array() { | |
| return new char[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; | |
| } | |
| @Override | |
| public char[] toArray(MemorySegment segment, ValueLayout layout) { | |
| CharBuffer buffer = segment.asByteBuffer().order(layout.order()).asCharBuffer(); | |
| char[] found = new char[buffer.limit()]; | |
| buffer.get(found); | |
| return found; | |
| } | |
| }; | |
| ToArrayHelper<short[]> toShortArray = new ToArrayHelper<>() { | |
| @Override | |
| public short[] array() { | |
| return new short[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; | |
| } | |
| @Override | |
| public short[] toArray(MemorySegment segment, ValueLayout layout) { | |
| ShortBuffer buffer = segment.asByteBuffer().order(layout.order()).asShortBuffer(); | |
| short[] found = new short[buffer.limit()]; | |
| buffer.get(found); | |
| return found; | |
| } | |
| }; | |
| ToArrayHelper<int[]> toIntArray = new ToArrayHelper<>() { | |
| @Override | |
| public int[] array() { | |
| return new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; | |
| } | |
| @Override | |
| public int[] toArray(MemorySegment segment, ValueLayout layout) { | |
| IntBuffer buffer = segment.asByteBuffer().order(layout.order()).asIntBuffer(); | |
| int[] found = new int[buffer.limit()]; | |
| buffer.get(found); | |
| return found; | |
| } | |
| }; | |
| ToArrayHelper<float[]> toFloatArray = new ToArrayHelper<>() { | |
| @Override | |
| public float[] array() { | |
| return new float[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; | |
| } | |
| @Override | |
| public float[] toArray(MemorySegment segment, ValueLayout layout) { | |
| FloatBuffer buffer = segment.asByteBuffer().order(layout.order()).asFloatBuffer(); | |
| float[] found = new float[buffer.limit()]; | |
| buffer.get(found); | |
| return found; | |
| } | |
| }; | |
| ToArrayHelper<long[]> toLongArray = new ToArrayHelper<>() { | |
| @Override | |
| public long[] array() { | |
| return new long[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; | |
| } | |
| @Override | |
| public long[] toArray(MemorySegment segment, ValueLayout layout) { | |
| LongBuffer buffer = segment.asByteBuffer().order(layout.order()).asLongBuffer(); | |
| long[] found = new long[buffer.limit()]; | |
| buffer.get(found); | |
| return found; | |
| } | |
| }; | |
| ToArrayHelper<double[]> toDoubleArray = new ToArrayHelper<>() { | |
| @Override | |
| public double[] array() { | |
| return new double[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; | |
| } | |
| @Override | |
| public double[] toArray(MemorySegment segment, ValueLayout layout) { | |
| DoubleBuffer buffer = segment.asByteBuffer().order(layout.order()).asDoubleBuffer(); | |
| double[] found = new double[buffer.limit()]; | |
| buffer.get(found); | |
| return found; | |
| } | |
| }; | |
| } | |
| @DataProvider(name = "allocators") | |
| static Object[][] allocators() { | |
| return new Object[][] { | |
| { SegmentAllocator.prefixAllocator(Arena.global().allocate(10, 1)) }, | |
| }; | |
| } | |
| } |