/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.collection.arrays;

import java.io.IOException;
import java.util.Comparator;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import net.ranides.assira.collection.IntComparator;
import net.ranides.assira.collection.arrays.ArraySort;
import net.ranides.assira.collection.arrays.ArrayUtils;
import net.ranides.assira.collection.arrays.IntArraySort;
import static net.ranides.benchmark.app.BenchmarkRunner.run;
import net.ranides.benchmark.app.BenchmarkName;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.runner.RunnerException;

/**
 * Benchmark for IntArraySort. We want to compare it with generic "NativeArray".
 * Results:
 *      1. IntArray is 20-30% faster than NativeArray
 *      2. IntComparator is 2-3 times faster than Comparator
 *      3. Difference between IntArray and NativeArray is close to measurement errors.
 *         That's good, it means that difference in reality is quite negligible.
 * 
 * MergeSort:                   TIME   ERROR     RELATIVE     
 *      IntArray                 50     1.5     100%	3%
 *      IntArray (natural)       52     4.5     103%	9%
 *      NativeArray (natural) 	 61    14.6     120%	29%
 *      NativeArray (int)        69    13.2 	136%	26%
 *      NativeArray (Integer)	196    18.2     387%	36%
				
 * QuickSort                     TIME   ERROR     RELATIVE     
 *      IntArray                 63     1.2 	100%	2%
 *      NativeArray (int)        84     5.6 	134%	11%
 *      NativeArray (Integer)	155    18.2 	245%	36%
 * 
 */
public class IntArrayBenchmark {
    
    static final int[] ARRAY = new int[10000];
    
    static {
        Random rand = new Random(777);
        for(int i=0; i<ARRAY.length; i++) {
            ARRAY[i] = rand.nextInt();
        }
    }
    
    int[] array(int size) {
        return ArrayUtils.head(ARRAY, size);
    }
   
    @Benchmark
    public int Randomize() {
        int[] array = array(1000);
        return array[0] + array[999];
    }
    
    @Benchmark
    @BenchmarkName("QuickSort: IntArray")
    public int QuickSort_IntArray() {
        int[] array = array(1000);
        IntArraySort.quickSort(array, (int a,int b) -> Integer.compare(a, b));
        return array[0] + array[999];
    }
    
    @Benchmark
    @BenchmarkName("QuickSort: NativeArray (int)")
    public int QuickSort_NativeArray_int() {
        int[] array = array(1000);
        ArraySort.quickSort(array, (IntComparator)Integer::compare);
        return array[0] + array[999];
    }
    
    @Benchmark
    @BenchmarkName("QuickSort: NativeArray (Integer)")
    public int QuickSort_NativeArray_Integer() {
        int[] array = array(1000);
        ArraySort.quickSort(array, (Comparator<Integer>)(a,b) -> Integer.compare(a, b));
        return array[0] + array[999];
    }
    
    @Benchmark
    @BenchmarkName("MergeSort: IntArray")
    public int MergeSort_IntArray() {
        int[] array = array(1000);
        IntArraySort.mergeSort(array, (int a,int b) -> Integer.compare(a, b));
        return array[0] + array[999];
    }
    
    @Benchmark
    @BenchmarkName("MergeSort: IntArray (natural)")
    public int MergeSort_IntArray_Natural() {
        int[] array = array(1000);
        IntArraySort.mergeSort(array);
        return array[0] + array[999];
    }
    
    @Benchmark
    @BenchmarkName("MergeSort: NativeArray (int)")
    public int MergeSort_NativeArray_int() {
        int[] array = array(1000);
        ArraySort.mergeSort(array, (IntComparator)(a,b) -> Integer.compare(a, b));
        return array[0] + array[999];
    }
    
    @Benchmark
    @BenchmarkName("MergeSort: NativeArray (Integer)")
    public int MergeSort_NativeArray_Integer() {
        int[] array = array(1000);
        ArraySort.mergeSort(array, (Comparator<Integer>)(a,b) -> Integer.compare(a, b));
        return array[0] + array[999];
    }
    
    @Benchmark
    @BenchmarkName("MergeSort: NativeArray (natural)")
    public int MergeSort_NativeArray_Natural() {
        int[] array = array(1000);
        ArraySort.mergeSort(array);
        return array[0] + array[999];
    }
    
    public static void main(String[] args) throws RunnerException, IOException {
        run(IntArrayBenchmark.class);
    }
    
}
