1 /*
  2  * Copyright (c) 2021, 2023, 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  * @enablePreview
 27  * @run testng/othervm TestSegmentOverlap
 28  */
 29 
 30 import java.io.File;
 31 import java.io.IOException;
 32 import java.lang.foreign.Arena;
 33 import java.nio.channels.FileChannel;
 34 import java.nio.file.Files;
 35 import java.nio.file.Path;
 36 import java.nio.file.StandardOpenOption;
 37 import java.util.List;
 38 import java.util.function.Supplier;
 39 import java.lang.foreign.MemorySegment;
 40 
 41 import org.testng.annotations.Test;
 42 import org.testng.annotations.DataProvider;
 43 import static java.lang.System.out;
 44 import static org.testng.Assert.*;
 45 
 46 public class TestSegmentOverlap {
 47 
 48     static Path tempPath;
 49 
 50     static {
 51         try {
 52             File file = File.createTempFile("buffer", "txt");
 53             file.deleteOnExit();
 54             tempPath = file.toPath();
 55             Files.write(file.toPath(), new byte[16], StandardOpenOption.WRITE);
 56 
 57         } catch (IOException ex) {
 58             throw new ExceptionInInitializerError(ex);
 59         }
 60     }
 61 
 62     @DataProvider(name = "segmentFactories")
 63     public Object[][] segmentFactories() {
 64         List<Supplier<MemorySegment>> l = List.of(
 65                 () -> Arena.ofAuto().allocate(16, 1),
 66                 () -> {
 67                     try (FileChannel fileChannel = FileChannel.open(tempPath, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
 68                         return fileChannel.map(FileChannel.MapMode.READ_WRITE, 0L, 16L, Arena.ofAuto());
 69                     } catch (IOException e) {
 70                         throw new RuntimeException(e);
 71                     }
 72                 },
 73                 () -> MemorySegment.ofArray(new byte[] { 0x00, 0x01, 0x02, 0x03 } ),
 74                 () -> MemorySegment.ofArray(new char[] {'a', 'b', 'c', 'd' } ),
 75                 () -> MemorySegment.ofArray(new double[] { 1d, 2d, 3d, 4d} ),
 76                 () -> MemorySegment.ofArray(new float[] { 1.0f, 2.0f, 3.0f, 4.0f } ),
 77                 () -> MemorySegment.ofArray(new int[] { 1, 2, 3, 4 }),
 78                 () -> MemorySegment.ofArray(new long[] { 1L, 2L, 3L, 4L } ),
 79                 () -> MemorySegment.ofArray(new short[] { 1, 2, 3, 4 } )
 80         );
 81         return l.stream().map(s -> new Object[] { s }).toArray(Object[][]::new);
 82     }
 83 
 84     @Test(dataProvider="segmentFactories")
 85     public void testBasic(Supplier<MemorySegment> segmentSupplier) {
 86         var s1 = segmentSupplier.get();
 87         var s2 = segmentSupplier.get();
 88         var sOther = s1.isNative() ? OtherSegmentFactory.HEAP.factory.get()
 89                 : OtherSegmentFactory.NATIVE.factory.get();
 90         out.format("testBasic s1:%s, s2:%s, sOther:%s\n", s1, s2, sOther);
 91         assertTrue(s1.asOverlappingSlice(s2).isEmpty());
 92         assertTrue(s2.asOverlappingSlice(s1).isEmpty());
 93         assertTrue(s1.asOverlappingSlice(sOther).isEmpty());
 94     }
 95 
 96     @Test(dataProvider="segmentFactories")
 97     public void testIdentical(Supplier<MemorySegment> segmentSupplier) {
 98         var s1 = segmentSupplier.get();
 99         var s2 = s1.asReadOnly();
100         out.format("testIdentical s1:%s, s2:%s\n", s1, s2);
101         assertEquals(s1.asOverlappingSlice(s2).get().byteSize(), s1.byteSize());
102         assertEquals(s1.asOverlappingSlice(s2).get().scope(), s1.scope());
103 
104         assertEquals(s2.asOverlappingSlice(s1).get().byteSize(), s2.byteSize());
105         assertEquals(s2.asOverlappingSlice(s1).get().scope(), s2.scope());
106 
107         if (s1.isNative()) {
108             assertEquals(s1.asOverlappingSlice(s2).get().address(), s1.address());
109             assertEquals(s2.asOverlappingSlice(s1).get().address(), s2.address());
110         }
111     }
112 
113     @Test(dataProvider="segmentFactories")
114     public void testSlices(Supplier<MemorySegment> segmentSupplier) {
115         MemorySegment s1 = segmentSupplier.get();
116         MemorySegment s2 = segmentSupplier.get();
117         for (int offset = 0 ; offset < 4 ; offset++) {
118             MemorySegment slice = s1.asSlice(offset);
119             out.format("testSlices s1:%s, s2:%s, slice:%s, offset:%d\n", s1, s2, slice, offset);
120             assertEquals(s1.asOverlappingSlice(slice).get().byteSize(), s1.byteSize() - offset);
121             assertEquals(s1.asOverlappingSlice(slice).get().scope(), s1.scope());
122 
123             assertEquals(slice.asOverlappingSlice(s1).get().byteSize(), slice.byteSize());
124             assertEquals(slice.asOverlappingSlice(s1).get().scope(), slice.scope());
125 
126             if (s1.isNative()) {
127                 assertEquals(s1.asOverlappingSlice(slice).get().address(), s1.address() + offset);
128                 assertEquals(slice.asOverlappingSlice(s1).get().address(), slice.address());
129             }
130             assertTrue(s2.asOverlappingSlice(slice).isEmpty());
131         }
132     }
133 
134     enum OtherSegmentFactory {
135         NATIVE(() -> Arena.ofAuto().allocate(16, 1)),
136         HEAP(() -> MemorySegment.ofArray(new byte[]{16}));
137 
138         final Supplier<MemorySegment> factory;
139 
140         OtherSegmentFactory(Supplier<MemorySegment> segmentFactory) {
141             this.factory = segmentFactory;
142         }
143     }
144 }