package ru.ifmo.nds.jmh.internal;

import java.util.Random;
import java.util.concurrent.TimeUnit;

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;

import ru.ifmo.nds.util.ArrayHelper;

@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Timeout(time = 10)
@Warmup(time = 1, iterations = 10)
@Measurement(time = 1, iterations = 3)
@Fork(value = 3)
public class MedianBenchmark {
    @Param(value = {
            "2", "5", "10",
            "20", "50", "100",
            "200", "500", "1000",
            "2000", "5000", "10000",
            "20000", "50000", "100000"})
    private int size;

    @Param(value = {"hypercube", "discrete"})
    private String type;

    private double[][] data;
    private double[] temp;

    @Setup
    public void initialize() {
        Random random = new Random(size * 723525217L);
        data = new double[10][size];
        switch (type) {
            case "hypercube":
                for (int i = 0; i < 10; ++i) {
                    for (int j = 0; j < size; ++j) {
                        data[i][j] = random.nextDouble();
                    }
                }
                break;
            case "discrete":
                for (int i = 0; i < 10; ++i) {
                    for (int j = 0; j < size; ++j) {
                        data[i][j] = random.nextInt(100);
                    }
                }
                break;
            default:
                throw new AssertionError("Unknown data type: '" + type + "'");
        }
        temp = new double[size];
    }

    @Benchmark
    public void baseline(Blackhole bh) {
        for (double[] test : data) {
            System.arraycopy(test, 0, temp, 0, test.length);
            bh.consume(temp);
        }
    }

    @Benchmark
    public void quickSelect(Blackhole bh) {
        for (double[] test : data) {
            System.arraycopy(test, 0, temp, 0, test.length);
            bh.consume(ArrayHelper.destructiveMedian(temp, 0, temp.length));
        }
    }
}

@@ -682,16 +682,31 @@
 alue = %7B
+%22whole-range%22, 
 %22hypercu
@@ -719,24 +719,24 @@
 discrete%22%7D)%0A
-
     private 
@@ -903,16 +903,49 @@
 5217L);%0A
+        temp = new double%5Bsize%5D;%0A
         
@@ -993,24 +993,431 @@
 ch (type) %7B%0A
+            case %22whole-range%22:%0A                for (int i = 0; i %3C 10; ++i) %7B%0A                    for (int j = 0; j %3C size; ++j) %7B%0A                        double v;%0A                        do %7B%0A                            v = Double.longBitsToDouble(random.nextLong());%0A                        %7D while (Double.isInfinite(v));%0A                        data%5Bi%5D%5Bj%5D = v;%0A                    %7D%0A                %7D%0A
             
@@ -2005,16 +2005,16 @@
 + %22'%22);%0A
+
         
@@ -2019,41 +2019,8 @@
   %7D%0A
-        temp = new double%5Bsize%5D;%0A
     

Add one more kind of test for medians.