1 /*
  2  * Copyright (c) 2019, 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 /*
 26  * @test
 27  * @run testng TestSegmentCopy
 28  */
 29 
 30 import jdk.incubator.foreign.MemoryHandles;
 31 import jdk.incubator.foreign.MemorySegment;
 32 import jdk.incubator.foreign.ResourceScope;
 33 import jdk.incubator.foreign.ValueLayout;
 34 import org.testng.annotations.DataProvider;
 35 import org.testng.annotations.Test;
 36 
 37 import java.lang.invoke.VarHandle;
 38 import java.nio.ByteOrder;
 39 import java.util.ArrayList;
 40 import java.util.List;
 41 import java.util.function.IntFunction;
 42 
 43 import static org.testng.Assert.*;
 44 
 45 public class TestSegmentCopy {
 46 
 47     @Test(dataProvider = "slices")
 48     public void testByteCopy(SegmentSlice s1, SegmentSlice s2) {
 49         int size = Math.min(s1.byteSize(), s2.byteSize());
 50         //prepare source and target segments
 51         for (int i = 0 ; i < size ; i++) {
 52             Type.BYTE.set(s2, i, 0);
 53         }
 54         for (int i = 0 ; i < size ; i++) {
 55             Type.BYTE.set(s1, i, i);
 56         }
 57         //perform copy
 58         MemorySegment.copy(s1.segment, 0, s2.segment, 0, size);
 59         //check that copy actually worked
 60         for (int i = 0 ; i < size ; i++) {
 61             Type.BYTE.check(s2, i, i);
 62         }
 63     }
 64 
 65     @Test(dataProvider = "slices")
 66     public void testElementCopy(SegmentSlice s1, SegmentSlice s2) {
 67         if (s1.type.carrier != s2.type.carrier) return;
 68         int size = Math.min(s1.elementSize(), s2.elementSize());
 69         //prepare source and target segments
 70         for (int i = 0 ; i < size ; i++) {
 71             s2.set(i, 0);
 72         }
 73         for (int i = 0 ; i < size ; i++) {
 74             s1.set(i, i);
 75         }
 76         //perform copy
 77         MemorySegment.copy(s1.segment, s1.type.layout, 0, s2.segment, s2.type.layout, 0, size);
 78         //check that copy actually worked
 79         for (int i = 0; i < size; i++) {
 80             s2.check(i, i);
 81         }
 82     }
 83 
 84     interface Getter<X> {
 85         X get(MemorySegment segment, ValueLayout layout, long index);
 86     }
 87 
 88     interface Setter<X> {
 89         void set(MemorySegment segment, ValueLayout layout, long index, X val);
 90     }
 91 
 92     enum Type {
 93         // Byte
 94         BYTE(byte.class, ValueLayout.JAVA_BYTE, i -> (byte)i),
 95         //LE
 96         SHORT_LE(short.class, ValueLayout.JAVA_SHORT.withOrder(ByteOrder.LITTLE_ENDIAN), i -> (short)i),
 97         CHAR_LE(char.class, ValueLayout.JAVA_CHAR.withOrder(ByteOrder.LITTLE_ENDIAN), i -> (char)i),
 98         INT_LE(int.class, ValueLayout.JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN), i -> i),
 99         FLOAT_LE(float.class, ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.LITTLE_ENDIAN), i -> (float)i),
100         LONG_LE(long.class, ValueLayout.JAVA_LONG.withOrder(ByteOrder.LITTLE_ENDIAN), i -> (long)i),
101         DOUBLE_LE(double.class, ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.LITTLE_ENDIAN), i -> (double)i),
102         //BE
103         SHORT_BE(short.class, ValueLayout.JAVA_SHORT.withOrder(ByteOrder.BIG_ENDIAN), i -> (short)i),
104         CHAR_BE(char.class, ValueLayout.JAVA_CHAR.withOrder(ByteOrder.BIG_ENDIAN), i -> (char)i),
105         INT_BE(int.class, ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN), i -> i),
106         FLOAT_BE(float.class, ValueLayout.JAVA_FLOAT.withOrder(ByteOrder.BIG_ENDIAN), i -> (float)i),
107         LONG_BE(long.class, ValueLayout.JAVA_LONG.withOrder(ByteOrder.BIG_ENDIAN), i -> (long)i),
108         DOUBLE_BE(double.class, ValueLayout.JAVA_DOUBLE.withOrder(ByteOrder.BIG_ENDIAN), i -> (double)i);
109 
110         final ValueLayout layout;
111         final IntFunction<Object> valueConverter;
112         final Class<?> carrier;
113 
114         @SuppressWarnings("unchecked")
115         <Z> Type(Class<Z> carrier, ValueLayout layout, IntFunction<Z> valueConverter) {
116             this.carrier = carrier;
117             this.layout = layout;
118             this.valueConverter = (IntFunction<Object>)valueConverter;
119         }
120 
121         int size() {
122             return (int)layout.byteSize();
123         }
124 
125         VarHandle handle() {
126             return MemoryHandles.varHandle(layout);
127         }
128 
129         void set(SegmentSlice slice, int index, int val) {
130             handle().set(slice.segment, index * size(), valueConverter.apply(val));
131         }
132 
133         void check(SegmentSlice slice, int index, int val) {
134             assertEquals(handle().get(slice.segment, index * size()), valueConverter.apply(val));
135         }
136     }
137 
138     static class SegmentSlice {
139 
140         enum Kind {
141             NATIVE(i -> MemorySegment.allocateNative(i, ResourceScope.newImplicitScope())),
142             ARRAY(i -> MemorySegment.ofArray(new byte[i]));
143 
144             final IntFunction<MemorySegment> segmentFactory;
145 
146             Kind(IntFunction<MemorySegment> segmentFactory) {
147                 this.segmentFactory = segmentFactory;
148             }
149 
150             MemorySegment makeSegment(int elems) {
151                 return segmentFactory.apply(elems);
152             }
153         }
154 
155         final Kind kind;
156         final Type type;
157         final int first;
158         final int last;
159         final MemorySegment segment;
160 
161         public SegmentSlice(Kind kind, Type type, int first, int last, MemorySegment segment) {
162             this.kind = kind;
163             this.type = type;
164             this.first = first;
165             this.last = last;
166             this.segment = segment;
167         }
168 
169         void set(int index, int val) {
170             type.set(this, index, val);
171         }
172 
173         void check(int index, int val) {
174             type.check(this, index, val);
175         }
176 
177         int byteSize() {
178             return last - first + 1;
179         }
180 
181         int elementSize() {
182             return byteSize() / type.size();
183         }
184 
185         @Override
186         public String toString() {
187             return String.format("SegmentSlice{%s, %d, %d}", type, first, last);
188         }
189     }
190 
191     @DataProvider(name = "slices")
192     static Object[][] elementSlices() {
193         List<SegmentSlice> slices = new ArrayList<>();
194         for (SegmentSlice.Kind kind : SegmentSlice.Kind.values()) {
195             MemorySegment segment = kind.makeSegment(16);
196             //compute all slices
197             for (Type type : Type.values()) {
198                 for (int index = 0; index < 16; index += type.size()) {
199                     MemorySegment first = segment.asSlice(0, index);
200                     slices.add(new SegmentSlice(kind, type, 0, index - 1, first));
201                     MemorySegment second = segment.asSlice(index);
202                     slices.add(new SegmentSlice(kind, type, index, 15, second));
203                 }
204             }
205         }
206         Object[][] sliceArray = new Object[slices.size() * slices.size()][];
207         for (int i = 0 ; i < slices.size() ; i++) {
208             for (int j = 0 ; j < slices.size() ; j++) {
209                 sliceArray[i * slices.size() + j] = new Object[] { slices.get(i), slices.get(j) };
210             }
211         }
212         return sliceArray;
213     }
214 }