// File TryDelegate4.java * Last update 2006-03-23

// The reflective call is 10 to 25 times slower than a virtual call,
// with Sun HotSpot Client VM 1.4.0 under Linux on Pentium 3.

import java.lang.reflect.*;                             // Method

public class TryDelegate4 {
  public static void main(String[] args) 
    throws NoSuchMethodException, IllegalAccessException, 
           InvocationTargetException {
    int count = Integer.parseInt(args[0]);
    Class ty = SomeClass.class;                         // Get SomeClass class
    SomeClass o = new SomeClass();
    Object[] margs = new Object[] { };
    // Get m0() method
    Method m0 = ty.getMethod("m0", new Class[] {});   
    { 
      Timer t = new Timer();
      for (int i=count; i>0; i--)
        m0.invoke(o, margs); 
      System.out.println("Reflective call to o.m0: " + t.Check());
      System.out.println(o.k);
    }
    {
      Timer t = new Timer();
      for (int i=count; i>0; i--)
        o.m0(); 
      System.out.println("Virtual call to o.m0: " + t.Check());
      System.out.println(o.k);
    }
    {
      SomeClassInterface oi = o;
      Timer t = new Timer();
      for (int i=count; i>0; i--)
        oi.m0(); 
      System.out.println("Interface call to oi.m0: " + t.Check());
      System.out.println(oi.getK());
    }
    {
      Void2Void dlg0 = (Void2Void)Delegate.createDelegate(Void2Void.class, 
                                                          m0, o);
      Timer t = new Timer();
      for (int i=count; i>0; i--)
        dlg0.call(); 
      System.out.println("Delegate call to m0(): " + t.Check());
      System.out.println(o.getK());
    }
    // Get m1(int) method
    Method m1 = ty.getMethod("m1", new Class[] { int.class }); 
    { 
      Timer t = new Timer();
      int res = 0;
      for (int i=count; i>0; i--) {
        Object obj = m1.invoke(o, new Object[] { new Integer(i) });
        res = ((Integer)obj).intValue();        
      }
      System.out.println("Reflective call to o.m1: " + t.Check());
      System.out.println(res);
      System.out.println(o.getK());
    }
    {
      Timer t = new Timer();
      int res = 0;
      for (int i=count; i>0; i--)
        res = o.m1(i); 
      System.out.println("Virtual call to o.m1: " + t.Check());
      System.out.println(res);
      System.out.println(o.k);
    }
    {
      SomeClassInterface oi = o;
      Timer t = new Timer();
      int res = 0;
      for (int i=count; i>0; i--)
        res = oi.m1(i); 
      System.out.println("Interface call to oi.m1: " + t.Check());
      System.out.println(res);
      System.out.println(oi.getK());
    }
    {
      Int2Int dlg1 = (Int2Int)Delegate.createDelegate(Int2Int.class, m1, o);
      Timer t = new Timer();
      int res = 0;
      for (int i=count; i>0; i--)
        res = dlg1.call(i); 
      System.out.println("Delegate call to m1(i): " + t.Check());
      System.out.println(res);
      System.out.println(o.getK());
    }
  }

  public interface Void2Void {
    void call();
  }

  public interface Int2Int {
    int call(int x);
  }
}

// Crude timing utility ----------------------------------------
   
class Timer {
  private long start;

  public Timer() {
    start = System.currentTimeMillis();
  }

  public double Check() {
    return (System.currentTimeMillis()-start)/1000.0;
  }
}

