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