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

import com.google.caliper.Param;
import com.google.caliper.SimpleBenchmark;
import net.ranides.assira.BenchmarkRunner;
import net.ranides.assira.collection.Grid;
import net.ranides.assira.math.Randomizer;

/**
 * Comparison between classic String constructor: String(char[]) and
 * unsafe array wrapper: Strings#wrap(char[]) which don't copy anything, but
 * from the other side, it uses reflection.
 * 
 * We want to be sure that reflection overhead wont neglect potential performance boost.
 * 
 * RESULTS:
 * 
 *      CharCopyS 26,04 ===========
 *      CharWrapS 24,32 ==========
 *      CharCopyM 24,00 ==========
 *      CharWrapM 11,50 ====
 *      CharCopyL 70,64 ==============================
 *      CharWrapL  2,87 =
 * 
 * SUMMARY:
 *      STRING SIZE | NORM RATIO     | PERCENT
 *      4-12        | 3.04 /  3.26  | = 93%
 *      16-64       | 2.88 /  6.00  | = 48%
 *      128-1024    | 2.87 / 70.64  | =  4%
 * 
 * CONCLUSION:
 *      wrapper is better even for smallest strings
 *      we can use it everywhere without fear of "sub-optimization"
 * 
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public class StringsBenchmark extends SimpleBenchmark {
    
    @Param
    private int param;
    
    private char[][] data;
    
    @BenchmarkRunner.ParamGrid({
        "CharCopy", 
        "CharWrap"
    })
    private static final Grid<Integer> GPARAMS = new Grid<>()
        .header("param", "count", "min", "max")
        .add(0, 100,     4,     4 )
        .add(1, 100,     8,     8 )
        .add(2, 100,     8,    16 )
        .add(3, 100,    16,    32 )
        .add(4, 100,    32,    64 )
        .add(5, 100,    64,   128 )
        .add(6, 100,   128,   256 )
        .add(7, 100,   512,  1024 )
        .add(8, 100,  1024,  1024 )
        .add(9, 100,  1024,  2048 )
    ;
    
    @Override
    public void setUp() {
        int count = GPARAMS.rows().get(param).get("count");
        int min   = GPARAMS.rows().get(param).get("min");
        int max   = GPARAMS.rows().get(param).get("max");
        data = new char[count][];
        for(int i=0; i<count; i++) {
            data[i] = Randomizer.text(Randomizer.number(min,max)).toCharArray();
        }
    }
    
    private static int itimeCharCopy(int reps, char[][] input) {
        int c = 0;
        for(int r=0; r<reps; r++) {
            for(char[] text : input) {
                c += new String(text).length();
            }
        }
        return c;
    }
    
    private static int itimeCharWrap(int reps, char[][] input) {
        int c = 0;
        for(int r=0; r<reps; r++) {
            for(char[] text : input) {
                c += Strings.wrap(text).length();
            }
        }
        return c;
    }
    
    public int timeCharCopy(int reps) {
        return itimeCharCopy(reps, data);
    }
    
    public int timeCharWrap(int reps) {
        return itimeCharWrap(reps, data);
    }

    public static void main(String[] args) throws Exception {
        BenchmarkRunner.run();
    }
    
}
