import edu.rice.cs.mint.runtime.Code;
import edu.rice.cs.mint.runtime.SafeCode;
import edu.rice.cs.mint.util.Benchmark;

// demonstrate how expensive boxed types are
// compares power function
// - unstaged
// - staged using ILambda<Double,Double> (boxed)
// - staged using ILambda_double_double (primitive)
public class BoxingUnboxingExpense {
    public static interface ILambda_double_double {
        public double apply(double param);
    }
    
    public static double power(double x, int n){
        if (n == 1)
            return x;
        else
            return x * power(x, n-1);
    }
    
    public static separable Code<Double> spower(final Code<Double> x, int n){
        if (n == 1)
            return x;
        else
            return <| `x * `(spower(x, n-1)) |>;
    }
    
    public static final int NUM_REPS = 200000000;
    
    public static void main(String[] args) {
        System.out.println("power(2, 17)                    = "+power(2,17));
        long start = System.nanoTime();
        for(int x = 0; x <  NUM_REPS; x++)
            power(2, 17);
        long unstaged = System.nanoTime() - start;
        System.out.println("\t"+unstaged);
        
        Code<? extends ILambda<Double,Double>> codePowerOf17 =
            <| new ILambda<Double,Double>() {
            public Double apply(Double param) {
                // allowed to ` because in <| |>
                return `(spower(<|param|>,17));
                // return 1.0*param*param....;
            }
        } |>;
        ILambda<Double,Double> stagedPowerOf17 = codePowerOf17.run();
        System.out.println("stagedPowerOf17.apply(2.0)      = "+stagedPowerOf17.apply(2.0));
        start = System.nanoTime();
        for(int x = 0; x < NUM_REPS; x++)
            stagedPowerOf17.apply(2.0);
        long staged = System.nanoTime() - start;
        System.out.println("\t"+staged);
        
        Code<? extends ILambda_double_double> primCodePowerOf17 =
            <| new ILambda_double_double() {
            public double apply(double param) {
                // allowed to ` because in <| |>
                return `(spower(<|param|>,17));
                // return 1.0*param*param....;
            }
        } |>;
        ILambda_double_double primStagedPowerOf17 = primCodePowerOf17.run();
        System.out.println("primStagedPowerOf17.apply(2.0)  = "+primStagedPowerOf17.apply(2.0));
        start = System.nanoTime();
        for(int x = 0; x < NUM_REPS; x++)
            primStagedPowerOf17.apply(2.0);
        long primStaged = System.nanoTime() - start;
        System.out.println("\t"+primStaged);
    }
}
