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

import com.google.caliper.SimpleBenchmark;
import java.util.Comparator;
import java.util.Random;
import net.ranides.assira.collection.IntComparator;
import net.ranides.assira.junit.BenchmarkRunner;

/**
 * Benchmark for IntArraySort. We want to compare it with generic "NativeArray".
 * Results:
 *      1. IntArray is ~75% faster than NativeArray
 *      2. IntComparator is 2 times faster than Comparator
 *      3. Real overhead is very small. Even change from (a-b) to Integer.compare(a,b) 
 *         changes results by ~50%. That's great.
 * 
 * 
 * IntComparator (a,b) -> a-b
 * QuickSort
 *      IntArray(int)            64 ns    75 %
 *      NativeArray(int)         86 ns   100 %
 *      NativeArray(Integer)    158 ns   183 %
 * 
 * MergeSort
 *      IntArray(int)            30 ns    81 %
 *      IntArray(natural)        63 ns   170 % Integer#cmp vs (a-b)
 *      NativeArray(int)         37 ns   100 %
 *      NativeArray(Integer)    134 ns   362 %
 *      NativeArray(natural)    110 ns   300 % Integer#cmp vs (a-b)
 * 
 * 
 * 
 * IntComparator (a,b) -> Integer::compare
 * QuickSort
 *      IntArray(int)            73 ns    77 %
 *      NativeArray(int)         94 ns   100 %
 *      NativeArray(Integer)    179 ns   190 %
 * 
 * MergeSort
 *      IntArray(int)            64 ns    94 %
 *      IntArray(natural)        62 ns    91 %
 *      NativeArray(int)         68 ns   100 %
 *      NativeArray(Integer)    208 ns   305 %
 *      NativeArray(natural)     74 ns   108 %
 * 
 */
public class IntArrayBenchmark extends SimpleBenchmark {
    
    int[] array(int size) {
        Random rand = new Random(777);
        int[] array = new int[size];
        for(int i=0; i<size; i++) {
            array[i] = rand.nextInt();
        }
        return array;
    }
   
    public int timeRandomize(int reps) {
        int ret = 0;
        for(int i=0; i<reps; i++) {
            int[] array = array(1000);
            ret += array[0] + array[999];
        }
        return ret;
    }
    
    public int timeQuickSort_IntArray(int reps) {
        int ret = 0;
        for(int i=0; i<reps; i++) {
            int[] array = array(1000);
            IntArraySort.quickSort(array, (int a,int b) -> Integer.compare(a, b));
            ret += array[0] + array[999];
        }
        return ret;
    }
    
    public int timeQuickSort_NativeArray_int(int reps) {
        int ret = 0;
        for(int i=0; i<reps; i++) {
            int[] array = array(1000);
            ArraySort.quickSort(array, (IntComparator)Integer::compare);
            ret += array[0] + array[999];
        }
        return ret;
    }
    
    public int timeQuickSort_NativeArray_Integer(int reps) {
        int ret = 0;
        for(int i=0; i<reps; i++) {
            int[] array = array(1000);
            ArraySort.quickSort(array, (Comparator<Integer>)(a,b) -> Integer.compare(a, b));
            ret += array[0] + array[999];
        }
        return ret;
    }
    
    public int timeMergeSort_IntArray(int reps) {
        int ret = 0;
        for(int i=0; i<reps; i++) {
            int[] array = array(1000);
            IntArraySort.mergeSort(array, (int a,int b) -> Integer.compare(a, b));
            ret += array[0] + array[999];
        }
        return ret;
    }
    
    public int timeMergeSort_IntArray_NC(int reps) {
        int ret = 0;
        for(int i=0; i<reps; i++) {
            int[] array = array(1000);
            IntArraySort.mergeSort(array);
            ret += array[0] + array[999];
        }
        return ret;
    }
    
    public int timeMergeSort_NativeArray_int(int reps) {
        int ret = 0;
        for(int i=0; i<reps; i++) {
            int[] array = array(1000);
            ArraySort.mergeSort(array, (IntComparator)(a,b) -> Integer.compare(a, b));
            ret += array[0] + array[999];
        }
        return ret;
    }
    
    public int timeMergeSort_NativeArray_Integer(int reps) {
        int ret = 0;
        for(int i=0; i<reps; i++) {
            int[] array = array(1000);
            ArraySort.mergeSort(array, (Comparator<Integer>)(a,b) -> Integer.compare(a, b));
            ret += array[0] + array[999];
        }
        return ret;
    }
    
    public int timeMergeSort_NativeArray_NC(int reps) {
        int ret = 0;
        for(int i=0; i<reps; i++) {
            int[] array = array(1000);
            ArraySort.mergeSort(array);
            ret += array[0] + array[999];
        }
        return ret;
    }
    
    public static void main(String[] args) {
        BenchmarkRunner.run(IntArrayBenchmark.class);
//        new IntArrayBenchmark().timeMergeSort_NativeArray_int(5000);
    }
    
}
