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