//this is a version of Power.java that has been modified to be used with Benchmark.java in order to perform timings

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

public class PowerVariableN {
    public static int power(int x, int n){
        if (n == 1)
            return x;
        else
            return x * power(x, n-1);
    }
    
    public static separable SafeCode<Integer> spower(SafeCode<Integer> x, int n){
        if (n == 1)
            return x;
        else
            return <| `x * `(spower(x, n-1)) |>;
    }
    
    public static interface ILambda_int_int {
        public int apply(int param);
    }
    
    public void run() {
        System.out.print("2^n. Enter n: ");
        java.io.BufferedReader br =
            new java.io.BufferedReader(new java.io.InputStreamReader(System.in));
        String line = null;
        try { line = br.readLine(); } catch(java.io.IOException ioe) {
            ioe.printStackTrace(System.out);
            System.exit(-1);
        }
        final int exponent = new Integer(line);
        System.out.println("power(2,"+exponent+")");
        
        System.out.println("unstaged: "+power(2, exponent));
        Code<? extends ILambda_int_int> primCodePowerOfN =
            <| new ILambda_int_int() {
            public int apply(int param) {
                // allowed to ` because in <| |>
                return `(spower(<|param|>,exponent));
                // return 1.0*param*param....;
            }
        } |>;
        ILambda_int_int primStagedPowerOfN = primCodePowerOfN.run(); 
        System.out.println("staged  : "+primStagedPowerOfN.apply(2));
        
        Benchmark.TimedTask[] results =
            Benchmark.benchmark(Benchmark.stagingTasks(new Benchmark.Task() {
            public void run() {
                //
                // call unstaged code here
                //
                power(2, exponent);
                //
                //
                //
            }
        }, new Benchmark.Thunk<Code<? extends Benchmark.Task>>() {
            public Code<? extends Benchmark.Task> value() {
                return <| new Benchmark.Task() {
                    public void run() {
                        //
                        // splice in staged code here
                        //
                        int i = `(spower(<| 2 |>, exponent));
                        //
                        //
                        //
                    }
                } |>;
            }
        }));
        
//        Benchmark.print(0, results); // relative to unstaged
//        System.out.println();
        Benchmark.print(results.length-1, results); // relative to staged
    }
    
    public interface ILambda<R,P> {
        public R apply(P param);
    }
    
    public static void main(String[] args) {
        new PowerVariableN().run();
    }
}

