1 /*
  2  * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 /*
 25  * @test
 26  * @run testng TestArrayCopy
 27  */
 28 
 29 import java.lang.foreign.MemoryLayout;
 30 import java.lang.foreign.MemorySegment;
 31 import java.lang.foreign.ValueLayout;
 32 import java.lang.invoke.MethodHandle;
 33 import java.lang.invoke.MethodHandles;
 34 import java.lang.invoke.MethodType;
 35 import java.lang.invoke.VarHandle;
 36 import java.nio.ByteOrder;
 37 import java.util.ArrayList;
 38 import java.util.List;
 39 import org.testng.annotations.DataProvider;
 40 import org.testng.annotations.Test;
 41 
 42 import static java.lang.foreign.ValueLayout.JAVA_BYTE;
 43 import static java.lang.foreign.ValueLayout.JAVA_INT;
 44 import static org.testng.Assert.assertEquals;
 45 import static org.testng.Assert.fail;
 46 
 47 /**
 48  * These tests exercise the MemoryCopy copyFromArray(...) and copyToArray(...).
 49  * To make these tests more challenging the segment is a view of the given array,
 50  * which makes the copy operations overlapping self-copies.  Thus, this checks the claim:
 51  *
 52  * <p>If the source (destination) segment is actually a view of the destination (source) array,
 53  * and if the copy region of the source overlaps with the copy region of the destination,
 54  * the copy of the overlapping region is performed as if the data in the overlapping region
 55  * were first copied into a temporary segment before being copied to the destination.</p>
 56  */
 57 public class TestArrayCopy {
 58     private static final ByteOrder NATIVE_ORDER = ByteOrder.nativeOrder();
 59     private static final ByteOrder NON_NATIVE_ORDER = NATIVE_ORDER == ByteOrder.LITTLE_ENDIAN
 60             ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
 61 
 62     private static final int SEG_LENGTH_BYTES = 32;
 63     private static final int SEG_OFFSET_BYTES = 8;
 64 
 65     @Test(dataProvider = "copyModesAndHelpers")
 66     public void testSelfCopy(CopyMode mode, CopyHelper<Object, ValueLayout> helper, String helperDebugString) {
 67         int bytesPerElement = (int)helper.elementLayout.byteSize();
 68         int indexShifts = SEG_OFFSET_BYTES / bytesPerElement;
 69         MemorySegment base = srcSegment(SEG_LENGTH_BYTES);
 70         MemorySegment truth = truthSegment(base, helper, indexShifts, mode);
 71         ByteOrder bo = mode.swap ? NON_NATIVE_ORDER : NATIVE_ORDER;
 72         //CopyFrom
 73         Object srcArr = helper.toArray(base);
 74         int srcIndex = mode.direction ? 0 : indexShifts;
 75         int srcCopyLen = helper.length(srcArr) - indexShifts;
 76         MemorySegment dstSeg = helper.fromArray(srcArr);
 77         long dstOffsetBytes = mode.direction ? SEG_OFFSET_BYTES : 0;
 78         helper.copyFromArray(srcArr, srcIndex, srcCopyLen, dstSeg, dstOffsetBytes, bo);
 79         assertEquals(truth.mismatch(dstSeg), -1);
 80         //CopyTo
 81         long srcOffsetBytes = mode.direction ? 0 : SEG_OFFSET_BYTES;
 82         Object dstArr = helper.toArray(base);
 83         MemorySegment srcSeg = helper.fromArray(dstArr).asReadOnly();
 84         int dstIndex = mode.direction ? indexShifts : 0;
 85         int dstCopyLen = helper.length(dstArr) - indexShifts;
 86         helper.copyToArray(srcSeg, srcOffsetBytes, dstArr, dstIndex, dstCopyLen, bo);
 87         MemorySegment result = helper.fromArray(dstArr);
 88         assertEquals(truth.mismatch(result), -1);
 89     }
 90 
 91     @Test(dataProvider = "copyModesAndHelpers")
 92     public void testUnalignedCopy(CopyMode mode, CopyHelper<Object, ValueLayout> helper, String helperDebugString) {
 93         int bytesPerElement = (int)helper.elementLayout.byteSize();
 94         int indexShifts = SEG_OFFSET_BYTES / bytesPerElement;
 95         MemorySegment base = srcSegment(SEG_LENGTH_BYTES);
 96         ByteOrder bo = mode.swap ? NON_NATIVE_ORDER : NATIVE_ORDER;
 97         //CopyFrom
 98         Object srcArr = helper.toArray(base);
 99         int srcIndex = mode.direction ? 0 : indexShifts;
100         int srcCopyLen = helper.length(srcArr) - indexShifts;
101         MemorySegment dstSeg = helper.fromArray(srcArr);
102         long dstOffsetBytes = mode.direction ? (SEG_OFFSET_BYTES - 1) : 0;
103         helper.copyFromArray(srcArr, srcIndex, srcCopyLen, dstSeg, dstOffsetBytes, bo);
104         //CopyTo
105         long srcOffsetBytes = mode.direction ? 0 : (SEG_OFFSET_BYTES - 1);
106         Object dstArr = helper.toArray(base);
107         MemorySegment srcSeg = helper.fromArray(dstArr).asReadOnly();
108         int dstIndex = mode.direction ? indexShifts : 0;
109         int dstCopyLen = helper.length(dstArr) - indexShifts;
110         helper.copyToArray(srcSeg, srcOffsetBytes, dstArr, dstIndex, dstCopyLen, bo);
111     }
112 
113     @Test(dataProvider = "copyModesAndHelpers")
114     public void testCopyOobLength(CopyMode mode, CopyHelper<Object, ValueLayout> helper, String helperDebugString) {
115         int bytesPerElement = (int)helper.elementLayout.byteSize();
116         MemorySegment base = srcSegment(SEG_LENGTH_BYTES);
117         //CopyFrom
118         Object srcArr = helper.toArray(base);
119         MemorySegment dstSeg = helper.fromArray(srcArr);
120         try {
121             helper.copyFromArray(srcArr, 0, (SEG_LENGTH_BYTES / bytesPerElement) * 2, dstSeg, 0, ByteOrder.nativeOrder());
122             fail();
123         } catch (IndexOutOfBoundsException ex) {
124             //ok
125         }
126         //CopyTo
127         Object dstArr = helper.toArray(base);
128         MemorySegment srcSeg = helper.fromArray(dstArr).asReadOnly();
129         try {
130             helper.copyToArray(srcSeg, 0, dstArr, 0, (SEG_LENGTH_BYTES / bytesPerElement) * 2, ByteOrder.nativeOrder());
131             fail();
132         } catch (IndexOutOfBoundsException ex) {
133             //ok
134         }
135     }
136 
137     @Test(dataProvider = "copyModesAndHelpers")
138     public void testCopyNegativeIndices(CopyMode mode, CopyHelper<Object, ValueLayout> helper, String helperDebugString) {
139         int bytesPerElement = (int)helper.elementLayout.byteSize();
140         MemorySegment base = srcSegment(SEG_LENGTH_BYTES);
141         //CopyFrom
142         Object srcArr = helper.toArray(base);
143         MemorySegment dstSeg = helper.fromArray(srcArr);
144         try {
145             helper.copyFromArray(srcArr, -1, SEG_LENGTH_BYTES / bytesPerElement, dstSeg, 0, ByteOrder.nativeOrder());
146             fail();
147         } catch (IndexOutOfBoundsException ex) {
148             //ok
149         }
150         //CopyTo
151         Object dstArr = helper.toArray(base);
152         MemorySegment srcSeg = helper.fromArray(dstArr).asReadOnly();
153         try {
154             helper.copyToArray(srcSeg, 0, dstArr, -1, SEG_LENGTH_BYTES / bytesPerElement, ByteOrder.nativeOrder());
155             fail();
156         } catch (IndexOutOfBoundsException ex) {
157             //ok
158         }
159     }
160 
161     @Test(dataProvider = "copyModesAndHelpers")
162     public void testCopyNegativeOffsets(CopyMode mode, CopyHelper<Object, ValueLayout> helper, String helperDebugString) {
163         int bytesPerElement = (int)helper.elementLayout.byteSize();
164         MemorySegment base = srcSegment(SEG_LENGTH_BYTES);
165         //CopyFrom
166         Object srcArr = helper.toArray(base);
167         MemorySegment dstSeg = helper.fromArray(srcArr);
168         try {
169             helper.copyFromArray(srcArr, 0, SEG_LENGTH_BYTES / bytesPerElement, dstSeg, -1, ByteOrder.nativeOrder());
170             fail();
171         } catch (IndexOutOfBoundsException ex) {
172             //ok
173         }
174         //CopyTo
175         Object dstArr = helper.toArray(base);
176         MemorySegment srcSeg = helper.fromArray(dstArr).asReadOnly();
177         try {
178             helper.copyToArray(srcSeg, -1, dstArr, 0, SEG_LENGTH_BYTES / bytesPerElement, ByteOrder.nativeOrder());
179             fail();
180         } catch (IndexOutOfBoundsException ex) {
181             //ok
182         }
183     }
184 
185     @Test(dataProvider = "copyModesAndHelpers")
186     public void testCopyOobIndices(CopyMode mode, CopyHelper<Object, ValueLayout> helper, String helperDebugString) {
187         int bytesPerElement = (int)helper.elementLayout.byteSize();
188         MemorySegment base = srcSegment(SEG_LENGTH_BYTES);
189         //CopyFrom
190         Object srcArr = helper.toArray(base);
191         MemorySegment dstSeg = helper.fromArray(srcArr);
192         try {
193             helper.copyFromArray(srcArr, helper.length(srcArr) + 1, SEG_LENGTH_BYTES / bytesPerElement, dstSeg, 0, ByteOrder.nativeOrder());
194             fail();
195         } catch (IndexOutOfBoundsException ex) {
196             //ok
197         }
198         //CopyTo
199         Object dstArr = helper.toArray(base);
200         MemorySegment srcSeg = helper.fromArray(dstArr).asReadOnly();
201         try {
202             helper.copyToArray(srcSeg, 0, dstArr, helper.length(dstArr) + 1, SEG_LENGTH_BYTES / bytesPerElement, ByteOrder.nativeOrder());
203             fail();
204         } catch (IndexOutOfBoundsException ex) {
205             //ok
206         }
207     }
208 
209     @Test(dataProvider = "copyModesAndHelpers")
210     public void testCopyOobOffsets(CopyMode mode, CopyHelper<Object, ValueLayout> helper, String helperDebugString) {
211         int bytesPerElement = (int)helper.elementLayout.byteSize();
212         MemorySegment base = srcSegment(SEG_LENGTH_BYTES);
213         //CopyFrom
214         Object srcArr = helper.toArray(base);
215         MemorySegment dstSeg = helper.fromArray(srcArr);
216         try {
217             helper.copyFromArray(srcArr, 0, SEG_LENGTH_BYTES / bytesPerElement, dstSeg, SEG_LENGTH_BYTES + 1, ByteOrder.nativeOrder());
218             fail();
219         } catch (IndexOutOfBoundsException ex) {
220             //ok
221         }
222         //CopyTo
223         Object dstArr = helper.toArray(base);
224         MemorySegment srcSeg = helper.fromArray(dstArr).asReadOnly();
225         try {
226             helper.copyToArray(srcSeg, SEG_OFFSET_BYTES + 1, dstArr, 0, SEG_LENGTH_BYTES / bytesPerElement, ByteOrder.nativeOrder());
227             fail();
228         } catch (IndexOutOfBoundsException ex) {
229             //ok
230         }
231     }
232 
233     @Test(dataProvider = "copyModesAndHelpers")
234     public void testCopyReadOnlyDest(CopyMode mode, CopyHelper<Object, ValueLayout> helper, String helperDebugString) {
235         int bytesPerElement = (int)helper.elementLayout.byteSize();
236         MemorySegment base = srcSegment(SEG_LENGTH_BYTES);
237         //CopyFrom
238         Object srcArr = helper.toArray(base);
239         MemorySegment dstSeg = helper.fromArray(srcArr).asReadOnly();
240         try {
241             helper.copyFromArray(srcArr, 0, SEG_LENGTH_BYTES / bytesPerElement, dstSeg, 0, ByteOrder.nativeOrder());
242             fail();
243         } catch (UnsupportedOperationException ex) {
244             //ok
245         }
246     }
247 
248     @Test(expectedExceptions = IllegalArgumentException.class)
249     public void testNotAnArraySrc() {
250         MemorySegment segment = MemorySegment.ofArray(new int[] {1, 2, 3, 4});
251         MemorySegment.copy(segment, JAVA_BYTE, 0, new String[] { "hello" }, 0, 4);
252     }
253 
254     @Test(expectedExceptions = IllegalArgumentException.class)
255     public void testNotAnArrayDst() {
256         MemorySegment segment = MemorySegment.ofArray(new int[] {1, 2, 3, 4});
257         MemorySegment.copy(new String[] { "hello" }, 0, segment, JAVA_BYTE, 0, 4);
258     }
259 
260     @Test(expectedExceptions = IllegalArgumentException.class)
261     public void testCarrierMismatchSrc() {
262         MemorySegment segment = MemorySegment.ofArray(new int[] {1, 2, 3, 4});
263         MemorySegment.copy(segment, JAVA_INT, 0, new byte[] { 1, 2, 3, 4 }, 0, 4);
264     }
265 
266     @Test(expectedExceptions = IllegalArgumentException.class)
267     public void testCarrierMismatchDst() {
268         MemorySegment segment = MemorySegment.ofArray(new int[] {1, 2, 3, 4});
269         MemorySegment.copy(new byte[] { 1, 2, 3, 4 }, 0, segment, JAVA_INT, 0, 4);
270     }
271 
272     @Test(expectedExceptions = IllegalArgumentException.class)
273     public void testHyperAlignedSrc() {
274         MemorySegment segment = MemorySegment.ofArray(new byte[] {1, 2, 3, 4});
275         MemorySegment.copy(new byte[] { 1, 2, 3, 4 }, 0, segment, JAVA_BYTE.withByteAlignment(2), 0, 4);
276     }
277 
278     @Test(expectedExceptions = IllegalArgumentException.class)
279     public void testHyperAlignedDst() {
280         MemorySegment segment = MemorySegment.ofArray(new byte[] {1, 2, 3, 4});
281         MemorySegment.copy(segment, JAVA_BYTE.withByteAlignment(2), 0, new byte[] { 1, 2, 3, 4 }, 0, 4);
282     }
283 
284     /***** Utilities *****/
285 
286     public static MemorySegment srcSegment(int bytesLength) {
287         byte[] arr = new byte[bytesLength];
288         for (int i = 0; i < arr.length; i++) {
289             arr[i] = (byte)i;
290         }
291         return MemorySegment.ofArray(arr);
292     }
293 
294     private static VarHandle arrayVarHandle(ValueLayout layout) {
295         return MethodHandles.collectCoordinates(layout.varHandle(),
296                 1, MethodHandles.insertArguments(layout.scaleHandle(), 0, 0L));
297     }
298 
299     public static MemorySegment truthSegment(MemorySegment srcSeg, CopyHelper<?, ?> helper, int indexShifts, CopyMode mode) {
300         VarHandle indexedHandleNO = arrayVarHandle(helper.elementLayout.withOrder(NATIVE_ORDER));
301         VarHandle indexedHandleNNO = arrayVarHandle(helper.elementLayout.withOrder(NON_NATIVE_ORDER));
302         MemorySegment dstSeg = MemorySegment.ofArray(srcSeg.toArray(JAVA_BYTE));
303         int indexLength = (int) dstSeg.byteSize() / (int)helper.elementLayout.byteSize();
304         if (mode.direction) {
305             if (mode.swap) {
306                 for (int i = indexLength - 1; i >= indexShifts; i--) {
307                     Object v = indexedHandleNNO.get(dstSeg, i - indexShifts);
308                     indexedHandleNO.set(dstSeg, i, v);
309                 }
310             } else {
311                 for (int i = indexLength - 1; i >= indexShifts; i--) {
312                     Object v = indexedHandleNO.get(dstSeg, i - indexShifts);
313                     indexedHandleNO.set(dstSeg, i, v);
314                 }
315             }
316         } else { //down
317             if (mode.swap) {
318                 for (int i = indexShifts; i < indexLength; i++) {
319                     Object v = indexedHandleNNO.get(dstSeg, i);
320                     indexedHandleNO.set(dstSeg, i - indexShifts, v);
321                 }
322             } else {
323                 for (int i = indexShifts; i < indexLength; i++) {
324                     Object v = indexedHandleNO.get(dstSeg, i);
325                     indexedHandleNO.set(dstSeg, i - indexShifts, v);
326                 }
327             }
328         }
329         return dstSeg;
330     }
331 
332     enum CopyMode {
333         UP_NO_SWAP(true, false),
334         UP_SWAP(true, true),
335         DOWN_NO_SWAP(false, false),
336         DOWN_SWAP(false, true);
337 
338         final boolean direction;
339         final boolean swap;
340 
341         CopyMode(boolean direction, boolean swap) {
342             this.direction = direction;
343             this.swap = swap;
344         }
345     }
346 
347     abstract static class CopyHelper<X, L extends ValueLayout> {
348 
349         final L elementLayout;
350         final Class<?> carrier;
351 
352         @SuppressWarnings("unchecked")
353         public CopyHelper(L elementLayout, Class<X> carrier) {
354             this.elementLayout = (L)elementLayout.withByteAlignment(1);
355             this.carrier = carrier;
356         }
357 
358         abstract void copyFromArray(X srcArr, int srcIndex, int srcCopyLen, MemorySegment dstSeg, long dstOffsetBytes, ByteOrder bo);
359         abstract void copyToArray(MemorySegment srcSeg, long srcOffsetBytes, X dstArr, int dstIndex, int dstCopyLen, ByteOrder bo);
360         abstract X toArray(MemorySegment segment);
361         abstract MemorySegment fromArray(X array);
362         abstract int length(X arr);
363 
364         @Override
365         public String toString() {
366             return "CopyHelper{" +
367                     "elementLayout=" + elementLayout +
368                     ", carrier=" + carrier.getName() +
369                     '}';
370         }
371 
372         static final CopyHelper<byte[], ValueLayout.OfByte> BYTE = new CopyHelper<>(JAVA_BYTE, byte[].class) {
373             @Override
374             void copyFromArray(byte[] srcArr, int srcIndex, int srcCopyLen, MemorySegment dstSeg, long dstOffsetBytes, ByteOrder bo) {
375                 MemorySegment.copy(srcArr, srcIndex, dstSeg, elementLayout.withOrder(bo), dstOffsetBytes, srcCopyLen);
376             }
377 
378             @Override
379             void copyToArray(MemorySegment srcSeg, long srcOffsetBytes, byte[] dstArr, int dstIndex, int dstCopyLen, ByteOrder bo) {
380                 MemorySegment.copy(srcSeg, elementLayout.withOrder(bo), srcOffsetBytes, dstArr, dstIndex, dstCopyLen);
381             }
382 
383             @Override
384             byte[] toArray(MemorySegment segment) {
385                 return segment.toArray(elementLayout);
386             }
387 
388             @Override
389             MemorySegment fromArray(byte[] array) {
390                 return MemorySegment.ofArray(array);
391             }
392 
393             @Override
394             int length(byte[] arr) {
395                 return arr.length;
396             }
397         };
398 
399         static final CopyHelper<char[], ValueLayout.OfChar> CHAR = new CopyHelper<>(ValueLayout.JAVA_CHAR, char[].class) {
400             @Override
401             void copyFromArray(char[] srcArr, int srcIndex, int srcCopyLen, MemorySegment dstSeg, long dstOffsetBytes, ByteOrder bo) {
402                 MemorySegment.copy(srcArr, srcIndex, dstSeg, elementLayout.withOrder(bo), dstOffsetBytes, srcCopyLen);
403             }
404 
405             @Override
406             void copyToArray(MemorySegment srcSeg, long srcOffsetBytes, char[] dstArr, int dstIndex, int dstCopyLen, ByteOrder bo) {
407                 MemorySegment.copy(srcSeg, elementLayout.withOrder(bo), srcOffsetBytes, dstArr, dstIndex, dstCopyLen);
408             }
409 
410             @Override
411             char[] toArray(MemorySegment segment) {
412                 return segment.toArray(elementLayout);
413             }
414 
415             @Override
416             MemorySegment fromArray(char[] array) {
417                 return MemorySegment.ofArray(array);
418             }
419 
420             @Override
421             int length(char[] arr) {
422                 return arr.length;
423             }
424         };
425 
426         static final CopyHelper<short[], ValueLayout.OfShort> SHORT = new CopyHelper<>(ValueLayout.JAVA_SHORT, short[].class) {
427             @Override
428             void copyFromArray(short[] srcArr, int srcIndex, int srcCopyLen, MemorySegment dstSeg, long dstOffsetBytes, ByteOrder bo) {
429                 MemorySegment.copy(srcArr, srcIndex, dstSeg, elementLayout.withOrder(bo), dstOffsetBytes, srcCopyLen);
430             }
431 
432             @Override
433             void copyToArray(MemorySegment srcSeg, long srcOffsetBytes, short[] dstArr, int dstIndex, int dstCopyLen, ByteOrder bo) {
434                 MemorySegment.copy(srcSeg, elementLayout.withOrder(bo), srcOffsetBytes, dstArr, dstIndex, dstCopyLen);
435             }
436 
437             @Override
438             short[] toArray(MemorySegment segment) {
439                 return segment.toArray(elementLayout);
440             }
441 
442             @Override
443             MemorySegment fromArray(short[] array) {
444                 return MemorySegment.ofArray(array);
445             }
446 
447             @Override
448             int length(short[] arr) {
449                 return arr.length;
450             }
451         };
452 
453         static final CopyHelper<int[], ValueLayout.OfInt> INT = new CopyHelper<>(ValueLayout.JAVA_INT, int[].class) {
454             @Override
455             void copyFromArray(int[] srcArr, int srcIndex, int srcCopyLen, MemorySegment dstSeg, long dstOffsetBytes, ByteOrder bo) {
456                 MemorySegment.copy(srcArr, srcIndex, dstSeg, elementLayout.withOrder(bo), dstOffsetBytes, srcCopyLen);
457             }
458 
459             @Override
460             void copyToArray(MemorySegment srcSeg, long srcOffsetBytes, int[] dstArr, int dstIndex, int dstCopyLen, ByteOrder bo) {
461                 MemorySegment.copy(srcSeg, elementLayout.withOrder(bo), srcOffsetBytes, dstArr, dstIndex, dstCopyLen);
462             }
463 
464             @Override
465             int[] toArray(MemorySegment segment) {
466                 return segment.toArray(elementLayout);
467             }
468 
469             @Override
470             MemorySegment fromArray(int[] array) {
471                 return MemorySegment.ofArray(array);
472             }
473 
474             @Override
475             int length(int[] arr) {
476                 return arr.length;
477             }
478         };
479 
480         static final CopyHelper<float[], ValueLayout.OfFloat> FLOAT = new CopyHelper<>(ValueLayout.JAVA_FLOAT, float[].class) {
481             @Override
482             void copyFromArray(float[] srcArr, int srcIndex, int srcCopyLen, MemorySegment dstSeg, long dstOffsetBytes, ByteOrder bo) {
483                 MemorySegment.copy(srcArr, srcIndex, dstSeg, elementLayout.withOrder(bo), dstOffsetBytes, srcCopyLen);
484             }
485 
486             @Override
487             void copyToArray(MemorySegment srcSeg, long srcOffsetBytes, float[] dstArr, int dstIndex, int dstCopyLen, ByteOrder bo) {
488                 MemorySegment.copy(srcSeg, elementLayout.withOrder(bo), srcOffsetBytes, dstArr, dstIndex, dstCopyLen);
489             }
490 
491             @Override
492             float[] toArray(MemorySegment segment) {
493                 return segment.toArray(elementLayout);
494             }
495 
496             @Override
497             MemorySegment fromArray(float[] array) {
498                 return MemorySegment.ofArray(array);
499             }
500 
501             @Override
502             int length(float[] arr) {
503                 return arr.length;
504             }
505         };
506 
507         static final CopyHelper<long[], ValueLayout.OfLong> LONG = new CopyHelper<>(ValueLayout.JAVA_LONG, long[].class) {
508             @Override
509             void copyFromArray(long[] srcArr, int srcIndex, int srcCopyLen, MemorySegment dstSeg, long dstOffsetBytes, ByteOrder bo) {
510                 MemorySegment.copy(srcArr, srcIndex, dstSeg, elementLayout.withOrder(bo), dstOffsetBytes, srcCopyLen);
511             }
512 
513             @Override
514             void copyToArray(MemorySegment srcSeg, long srcOffsetBytes, long[] dstArr, int dstIndex, int dstCopyLen, ByteOrder bo) {
515                 MemorySegment.copy(srcSeg, elementLayout.withOrder(bo), srcOffsetBytes, dstArr, dstIndex, dstCopyLen);
516             }
517 
518             @Override
519             long[] toArray(MemorySegment segment) {
520                 return segment.toArray(elementLayout);
521             }
522 
523             @Override
524             MemorySegment fromArray(long[] array) {
525                 return MemorySegment.ofArray(array);
526             }
527 
528             @Override
529             int length(long[] arr) {
530                 return arr.length;
531             }
532         };
533 
534         static final CopyHelper<double[], ValueLayout.OfDouble> DOUBLE = new CopyHelper<>(ValueLayout.JAVA_DOUBLE, double[].class) {
535             @Override
536             void copyFromArray(double[] srcArr, int srcIndex, int srcCopyLen, MemorySegment dstSeg, long dstOffsetBytes, ByteOrder bo) {
537                 MemorySegment.copy(srcArr, srcIndex, dstSeg, elementLayout.withOrder(bo), dstOffsetBytes, srcCopyLen);
538             }
539 
540             @Override
541             void copyToArray(MemorySegment srcSeg, long srcOffsetBytes, double[] dstArr, int dstIndex, int dstCopyLen, ByteOrder bo) {
542                 MemorySegment.copy(srcSeg, elementLayout.withOrder(bo), srcOffsetBytes, dstArr, dstIndex, dstCopyLen);
543             }
544 
545             @Override
546             double[] toArray(MemorySegment segment) {
547                 return segment.toArray(elementLayout);
548             }
549 
550             @Override
551             MemorySegment fromArray(double[] array) {
552                 return MemorySegment.ofArray(array);
553             }
554 
555             @Override
556             int length(double[] arr) {
557                 return arr.length;
558             }
559         };
560     }
561 
562     @DataProvider
563     Object[][] copyModesAndHelpers() {
564         CopyHelper<?, ?>[] helpers = { CopyHelper.BYTE, CopyHelper.CHAR, CopyHelper.SHORT, CopyHelper.INT,
565                                     CopyHelper.FLOAT, CopyHelper.LONG, CopyHelper.DOUBLE };
566         List<Object[]> results = new ArrayList<>();
567         for (CopyHelper<?, ?> helper : helpers) {
568             for (CopyMode mode : CopyMode.values()) {
569                 results.add(new Object[] { mode, helper, helper.toString() });
570             }
571         }
572         return results.stream().toArray(Object[][]::new);
573     }
574 }