import java.nio.ByteBuffer;
 
import java.io.BufferedReader;
import java.io.InputStreamReader;
 
import java.lang.foreign.*;
import jdk.incubator.vector.*;
import java.nio.ByteOrder;

public class Test3 {
 
    public static void runInSeparateVM() throws Throwable {
        String separator = System.getProperty("file.separator");
        String path = System.getProperty("java.home") + separator + "bin" + separator + "java";
  
        // Javac compile
        String javaFile = Test3.class.getProtectionDomain().getCodeSource().getLocation().getPath();
        ProcessBuilder processBuilder = new ProcessBuilder(path + "c", "--add-modules=jdk.incubator.vector", javaFile);
        Process process = processBuilder.inheritIO().start();
        processBuilder.redirectErrorStream(true);
        process.waitFor();
  
        // Run
        String classpath = javaFile.replace("Test3.java", "");
        processBuilder = new ProcessBuilder(path, "-cp", classpath, "--add-modules=jdk.incubator.vector", "-Xbatch", "-XX:+PrintCompilation", "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,Test3::testB", "-XX:+PrintIdeal", Test3.class.getCanonicalName(), "run");
        process = processBuilder.start();
        processBuilder.redirectErrorStream(true);
 
        BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        StringBuilder builder = new StringBuilder();
        String line = null;
        while ( (line = reader.readLine()) != null) {
           builder.append(line);
           builder.append(System.getProperty("line.separator"));
        }
        String result = builder.toString();
 
        process.waitFor();
        System.out.println(result);
        if (!result.contains("LoadVector")) throw new RuntimeException("Test failed: not contains LoadVector.");
        if (process.exitValue() != 0) throw new RuntimeException("Test failed: non-zero exit code.");
        System.out.println("Passed: found LoadVector in PrintIdeal output.");
    }
 
    public static final int SIZE = 1000;
    public static final VectorSpecies<Integer> SPECIES = IntVector.SPECIES_64;

    public static MemorySegment msI1 = MemorySegment.ofArray(new int[SIZE]);
    public static MemorySegment msI2 = MemorySegment.ofArray(new int[SIZE]);

    public static MemorySegment msB1 = MemorySegment.ofArray(new byte[SIZE]);
    public static MemorySegment msB2 = MemorySegment.ofArray(new byte[SIZE]);

    public static MemorySegment msN1 = Arena.ofAuto().allocate(SIZE, 64);
    public static MemorySegment msN2 = Arena.ofAuto().allocate(SIZE, 64);

    public static void testI() {
        var v = IntVector.fromMemorySegment(SPECIES, msI1, 0, ByteOrder.nativeOrder());
        v.intoMemorySegment(msI2, 0, ByteOrder.nativeOrder());
    }

    public static void testB() {
        var v = IntVector.fromMemorySegment(SPECIES, msB1, 0, ByteOrder.nativeOrder());
        v.intoMemorySegment(msB2, 0, ByteOrder.nativeOrder());
    }

    public static void testN() {
        var v = IntVector.fromMemorySegment(SPECIES, msN1, 0, ByteOrder.nativeOrder());
        v.intoMemorySegment(msN2, 0, ByteOrder.nativeOrder());
    }

    public static void main(String[] args) throws Throwable {
        if (args.length != 0) {
            for (int i = 0; i < 10_000; i++) {
	        testI();
	        testB();
	        testN();
	    }
            return;
        } 
        runInSeparateVM();
    }
}
