/*
* This file provides dynamic invocation of method, fields and properties
* based on IL code generation.
*
* This code was heavily influenced by
*
8 * a) Keith Farmer's Operator Overloading with Generics at
* http://w...content-available-to-author-only...t.com/csharp/genericoperators.asp
*
* b) Douglas Gregor and Andrew Lumsdaine Operator<T> class for use in MPI
* environments, licensed under http://w...content-available-to-author-only...t.org/LICENSE_1_0.txt
* http://w...content-available-to-author-only...u.edu/research/mpi.net/svn/
*
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
public enum UnaryOperator
{
/// <summary>
/// The <c>-x</c> operator
/// </summary>
op_UnaryNegation,
/// <summary>
/// The <c>!x</c> operator
/// </summary>
op_LogicalNot,
}
public enum BinaryOperator
{
/// <summary>
/// The <c>x+y</c> operator
/// </summary>
op_Addition,
/// <summary>
/// The <c>x-y</c> operator
/// </summary>
op_Subtraction,
/// <summary>
/// The <c>x*y</c> operator
/// </summary>
op_Multiply,
/// <summary>
/// The <c>x/y</c> operator
/// </summary>
op_Division,
/// <summary>
/// The <c>x%y</c> operator
/// </summary>
op_Modulus,
/// <summary>
/// The <c>x|y</c> operator
/// </summary>
op_BitwiseOr,
/// <summary>
/// The <c>x&y</c> operator
/// </summary>
op_BitwiseAnd,
}
public enum ConditionalOperator
{
/// <summary>
/// The <c>x==y</c> operator
/// </summary>
op_Equality,
/// <summary>
/// The <c>x<y</c> operator
/// </summary>
op_LessThan,
/// <summary>
/// The <c>x<=y</c> operator
/// </summary>
op_LessThanOrEqual,
/// <summary>
/// The <c>x>y</c> operator
/// </summary>
op_GreaterThan,
/// <summary>
/// The <c>x>=y</c> operator
/// </summary>
op_GreaterThanOrEqual,
}
/// <summary>
/// Class to provides dynamic invocation of static method, fields and properties based on IL code generation.
/// </summary>
/// <typeparam name="T">The type that contains the static methods to call</typeparam>
public sealed class Static<T>
{
Delegate f;
#region Factory
/// <summary>
/// Initilialized the dynamic method and creates the delegate
/// </summary>
/// <param name="method">The method definifiton</param>
/// <param name="call">The type of call this method makes</param>
/// <param name="delegate_type">The type of delegate to generate</param>
Static(DynamicMethod method, MethodCall call, Type delegate_type)
{
var generator=method.GetILGenerator();
// Find the overloaded operator and create a call to it
call.Emit(generator);
// Return the intermediate
generator.Emit(OpCodes.Ret);
// Return a delegate to call the mpiDelegateMethod
this.f=method.CreateDelegate(delegate_type);
}
/// <summary>
/// Implicitly convert method to nonary delegate of type <c><typeparamref name="T"/> f();</c>
/// </summary>
/// <param name="op">The emitted method</param>
/// <returns>A delegate</returns>
public static implicit operator Func<T>(Static<T> op)
{
return op.f as Func<T>;
}
/// <summary>
/// Implicitly convert method to unary delegate of type <c><typeparamref name="T"/> f(<typeparamref name="T"/>);</c>
/// </summary>
/// <param name="op">The emitted method</param>
/// <returns>A delegate</returns>
public static implicit operator Func<T, T>(Static<T> op)
{
return op.f as Func<T, T>;
}
/// <summary>
/// Implicitly convert method to binary delegate of type <c><typeparamref name="T"/> f(<typeparamref name="T"/>, <typeparamref name="T"/>);</c>
/// </summary>
/// <param name="op">The emitted method</param>
/// <returns>A delegate</returns>
public static implicit operator Func<T, T, T>(Static<T> op)
{
return op.f as Func<T, T, T>;
}
/// <summary>
/// Implicitly convert method to a conditional delegate of type <c>bool f(<typeparamref name="T"/>, <typeparamref name="T"/>);</c>
/// </summary>
/// <param name="op">The emitted method</param>
/// <returns>A delegate</returns>
public static implicit operator Func<T, T, bool>(Static<T> op)
{
return op.f as Func<T, T, bool>;
}
#endregion
#region Method Call Types
/// <summary>
/// Base class for emiting method calls.
/// </summary>
abstract class MethodCall
{
/// <summary>
/// Overriding classes use this to emit the IL code to call the method
/// </summary>
/// <param name="generator">The IL generator to target</param>
public abstract void Emit(ILGenerator generator);
/// <summary>
/// The name of the field, method or property being called
/// </summary>
public abstract string Name { get; }
#region Methods
/// <summary>
/// Returns the type and name of this method
/// </summary>
public override string ToString()
{
return string.Format("{0}({1})", GetType().Name, Name);
}
/// <summary>
/// Helper function to create a string from a type list
/// </summary>
/// <param name="parameter_types"></param>
/// <returns></returns>
static string Signature(params Type[] parameter_types)
{
return string.Join(",", parameter_types.Select((t) => t.Name).ToArray());
}
#endregion
#region Op Code Emit
/// <summary>
/// Defines a call based on an IL op code such as <c>op_Multiply</c>
/// </summary>
/// <param name="description">The description of the sequence of op codes</param>
/// <param name="parameter_counts">The number of paramers it used (to be pulled from the stack)</param>
/// <param name="op_codes">The op codes to use</param>
public static MethodCall Primitive(string description, int parameter_counts, params OpCode[] op_codes)
{
return new PrimitiveCall(description, parameter_counts, op_codes);
}
/// <summary>
/// Class for primitive op calls
/// </summary>
class PrimitiveCall : MethodCall
{
string name;
OpCode[] op_codes;
int parameter_count;
/// <summary>
/// Defines a call based on an IL op code such as <c>op_Multiply</c>
/// </summary>
/// <param name="description">The description of the sequence of op codes</param>
/// <param name="parameter_count">The number of arguments to be pulled of the stack</param>
/// <param name="op_codes">The op codes to use</param>
public PrimitiveCall(string description, int parameter_count, params OpCode[] op_codes)
{
this.name=description;
this.parameter_count=parameter_count;
this.op_codes=op_codes;
}
public override void Emit(ILGenerator generator)
{
for(int i=0; i<parameter_count; i++)
{
generator.Emit(OpCodes.Ldarg_S, i);
}
for(int i=0; i<op_codes.Length; i++)
{
generator.Emit(op_codes[i]);
}
}
public override string Name
{
get { return name; }
}
}
#endregion
#region Field Call
/// <summary>
/// Defines a call based on a reflected field.
/// </summary>
/// <param name="field_name">The field name</param>
/// <returns>An overriden MethodCall instance</returns>
public static MethodCall Field(string field_name)
{
return new FieldCall(field_name);
}
/// <summary>
/// Class for reflected field calls
/// </summary>
class FieldCall : MethodCall
{
FieldInfo field;
public FieldCall(string field_name)
{
this.field=type.GetField(field_name, BindingFlags.Public|BindingFlags.Static);
if(field==null)
{
throw new MissingFieldException(name, field_name);
}
}
public override void Emit(ILGenerator generator)
{
generator.Emit(OpCodes.Ldsfld, field);
}
public override string Name
{
get { return field.Name; }
}
}
#endregion
#region Method Call
/// <summary>
/// Defines a call based on a reflected method with one argument. Uses the specified types
/// for overload resolution.
/// </summary>
/// <param name="method_name">The method name</param>
/// <param name="argument_types">The list of argument types, or Type.EmptyTypes</param>
/// <returns>An overriden MethodCall instance</returns>
public static MethodCall Method(string method_name, params Type[] argument_types)
{
return new ReflectionCall(method_name, argument_types);
}
/// <summary>
/// Class for reflected method calls
/// </summary>
class ReflectionCall : MethodCall
{
MethodInfo method;
Type[] argument_types;
public ReflectionCall(string method_name, params Type[] argument_types)
{
this.argument_types=argument_types;
this.method=type.GetMethod(method_name, argument_types);
if(method==null)
{
throw new MissingMethodException(name, method_name);
}
}
public override void Emit(ILGenerator generator)
{
if(argument_types.Length>=1) generator.Emit(OpCodes.Ldarg_0);
if(argument_types.Length>=2) generator.Emit(OpCodes.Ldarg_1);
generator.EmitCall(OpCodes.Call, method, null);
}
public override string Name
{
get { return string.Format("{0}({1})", method.Name, Signature(argument_types)); }
}
}
#endregion
#region Constructor Call
public static MethodCall Constructor(params Type[] argument_types)
{
return new ConstructorCall(argument_types);
}
class ConstructorCall : MethodCall
{
ConstructorInfo ctor;
Type[] argument_types;
public ConstructorCall(params Type[] argument_types)
{
this.argument_types=argument_types;
this.ctor=type.GetConstructor(argument_types);
if(ctor==null)
{
throw new MissingMethodException(name, name);
}
}
public override void Emit(ILGenerator generator)
{
//LocalBuilder local_var=generator.DeclareLocal(type);
Label lbl=generator.DefineLabel();
// Load the arguments onto the stack
if(argument_types.Length>=1) generator.Emit(OpCodes.Ldarg_0);
if(argument_types.Length>=2) generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Newobj, ctor);
generator.Emit(OpCodes.Stloc_0);
generator.Emit(OpCodes.Br_S, lbl);
generator.MarkLabel(lbl);
generator.Emit(OpCodes.Ldloc_0);
}
public override string Name
{
get { return string.Format("{0}({1})", ctor.Name, Signature(argument_types)); }
}
}
#endregion
}
#endregion
#region Fields
static Static<T> BuildField<TReturn>(string field_name)
{
Type delegate_type=typeof(Func<TReturn>);
var call=MethodCall.Field(field_name);
var method=Declare<T>(call.Name);
return new Static<T>(method, call, delegate_type);
}
/// <summary>
/// Returns a field as a delegate. The prototype is <typeparamref name="T"/> f();
/// </summary>
/// <param name="field_name">The field name</param>
/// <exception cref="MissingMethodException">if <paramref name="field_name"/> does not correspond to a field name in <typeparamref name="T"/></exception>
/// <returns>A delegate</returns>
public static Func<T> Field(string field_name)
{
string key=type.ToString()+"."+field_name;
if(!nonary_cache.ContainsKey(key))
{
var op=BuildField<T>(field_name);
nonary_cache.Add(key, op);
return op;
}
return nonary_cache[key];
}
/// <summary>
/// Returns a field as a delegate. The prototype is <typeparamref name="TReturn"/> f();
/// </summary>
/// <typeparam name="TField">The field type name</typeparam>
/// <param name="field_name">The field name</param>
/// <exception cref="MissingMethodException">if <paramref name="field_name"/> does not correspond to a field name in <typeparamref name="T"/></exception>
/// <returns>A delegate</returns>
public static Func<TField> Field<TField>(string field_name)
{
var op=BuildField<TField>(field_name);
return op.f as Func<TField>;
}
#endregion
#region Methods
static Static<T> BuildMethod<TReturn>(string method_name)
{
Type delegate_type=typeof(Func<TReturn>);
var call=MethodCall.Method(method_name);
var method=Declare<TReturn>(call.Name);
return new Static<T>(method, call, delegate_type);
}
static Static<T> BuildMethod<TReturn>(string description, params OpCode[] opcodes)
{
Type delegate_type=typeof(Func<TReturn>);
var call=MethodCall.Primitive(description, 0, opcodes);
var method=Declare<TReturn>(call.Name);
return new Static<T>(method, call, delegate_type);
}
static Static<T> BuildMethod<TArg, TReturn>(string method_name)
{
Type delegate_type=typeof(Func<TArg, TReturn>);
var call=MethodCall.Method(method_name, typeof(TArg));
var method=Declare<TArg, TReturn>(call.Name);
return new Static<T>(method, call, delegate_type);
}
static Static<T> BuildMethod<TArg, TReturn>(string description, params OpCode[] opcodes)
{
Type delegate_type=typeof(Func<TArg, TReturn>);
var call=MethodCall.Primitive(description, 1, opcodes);
var method=Declare<TArg, TReturn>(call.Name);
return new Static<T>(method, call, delegate_type);
}
static Static<T> BuildMethod<TArg1, TArg2, TReturn>(string method_name)
{
Type delegate_type=typeof(Func<TArg1, TArg2, TReturn>);
var call=MethodCall.Method(method_name, typeof(TArg1), typeof(TArg2));
var method=Declare<TArg1, TArg2, TReturn>(call.Name);
return new Static<T>(method, call, delegate_type);
}
static Static<T> BuildMethod<TArg1, TArg2, TReturn>(string description, params OpCode[] opcodes)
{
Type delegate_type=typeof(Func<TArg1, TArg2, TReturn>);
var call=MethodCall.Primitive(description, 2, opcodes);
var method=Declare<TArg1, TArg2, TReturn>(call.Name);
return new Static<T>(method, call, delegate_type);
}
/// <summary>
/// Returns a method as a delegate. The prototype is <c><typeparamref name="TReturn"/> f();</c>
/// </summary>
/// <typeparam name="TReturn">The return type</typeparam>
/// <param name="method_name">The method name</param>
/// <exception cref="MissingMethodException">if <paramref name="method_name"/> does not correspond to a method name in <typeparamref name="T"/></exception>
/// <returns>A delegate</returns>
public static Func<TReturn> Method<TReturn>(string method_name)
{
var op=BuildMethod<TReturn>(method_name);
return op.f as Func<TReturn>;
}
/// <summary>
/// Returns a method as a delegate. The prototype is <c><typeparamref name="TReturn"/> f();</c>
/// </summary>
/// <typeparam name="TReturn">The return type</typeparam>
/// <param name="description">The description for the opcodes</param>
/// <param name="opcodes">The opcode sequence to use</param>
/// <returns>A delegate</returns>
public static Func<TReturn> Method<TReturn>(string description, params OpCode[] opcodes)
{
var op=BuildMethod<TReturn>(description, opcodes);
return op.f as Func<TReturn>;
}
/// <summary>
/// Returns a method as a delegate. The prototype is <c><typeparamref name="TReturn"/> f(<typeparamref name="TArg"/>);</c>
/// </summary>
/// <typeparam name="TArg">The argument type</typeparam>
/// <typeparam name="TReturn">The return type</typeparam>
/// <param name="method_name">The method name</param>
/// <exception cref="MissingMethodException">if <paramref name="method_name"/> does not correspond to a method name in <typeparamref name="T"/></exception>
/// <returns>A delegate</returns>
public static Func<TArg, TReturn> Method<TArg, TReturn>(string method_name)
{
var op=BuildMethod<TArg, TReturn>(method_name);
return op.f as Func<TArg, TReturn>;
}
/// <summary>
/// Returns a method as a delegate. The prototype is <c><typeparamref name="TReturn"/> f(<typeparamref name="TArg"/>);</c>
/// </summary>
/// <typeparam name="TArg">The argument type</typeparam>
/// <typeparam name="TReturn">The return type</typeparam>
/// <param name="description">The description for the opcodes</param>
/// <param name="opcodes">The opcode sequence to use</param>
/// <returns>A delegate</returns>
public static Func<TArg, TReturn> Method<TArg, TReturn>(string description, params OpCode[] opcodes)
{
var op=BuildMethod<TArg, TReturn>(description, opcodes);
return op.f as Func<TArg, TReturn>;
}
/// <summary>
/// Returns a method as a delegate. The prototype is <c><typeparamref name="TReturn"/> f(<typeparamref name="TArg1"/>, <typeparamref name="TArg2"/>);</c>
/// </summary>
/// <typeparam name="TArg1">The first argument type</typeparam>
/// <typeparam name="TArg2">The second argument type</typeparam>
/// <typeparam name="TReturn">The return type</typeparam>
/// <param name="method_name">The method name</param>
/// <exception cref="MissingMethodException">if <paramref name="method_name"/> does not correspond to a method name in <typeparamref name="T"/></exception>
/// <returns>A delegate</returns>
public static Func<TArg1, TArg2, TReturn> Method<TArg1, TArg2, TReturn>(string method_name)
{
var op=BuildMethod<TArg1, TArg2, TReturn>(method_name);
return op.f as Func<TArg1, TArg2, TReturn>;
}
/// <summary>
/// Returns a method as a delegate. The prototype is <c><typeparamref name="TReturn"/> f(<typeparamref name="TArg1"/>, <typeparamref name="TArg2"/>);</c>
/// </summary>
/// <typeparam name="TArg1">The first argument type</typeparam>
/// <typeparam name="TArg2">The second argument type</typeparam>
/// <typeparam name="TReturn">The return type</typeparam>
/// <param name="description">The description for the opcodes</param>
/// <param name="opcodes">The opcode sequence to use</param>
/// <returns>A delegate</returns>
public static Func<TArg1, TArg2, TReturn> Method<TArg1, TArg2, TReturn>(string description, params OpCode[] opcodes)
{
var op=BuildMethod<TArg1, TArg2, TReturn>(description, opcodes);
return op.f as Func<TArg1, TArg2, TReturn>;
}
/// <summary>
/// Returns a method as a delegate. The prototype is <c><typeparamref name="T"/> f();</c>
/// </summary>
/// <param name="method_name">The method name</param>
/// <exception cref="MissingMethodException">if <paramref name="method_name"/> does not correspond to a method name in <typeparamref name="T"/></exception>
/// <returns>A delegate</returns>
public static Func<T> NonaryMethod(string method_name)
{
string key=type.ToString()+"."+method_name;
if(!nonary_cache.ContainsKey(key))
{
var op=BuildMethod<T>(method_name);
nonary_cache.Add(key, op);
return op;
}
return nonary_cache[key];
}
/// <summary>
/// Returns opcodes as a delegate. The prototype is <c><typeparamref name="T"/> f();</c>
/// </summary>
/// <param name="description">A description for the codes</param>
/// <param name="opcodes">The op code sequence</param>
/// <returns>A delegate</returns>
public static Func<T> NonaryMethod(string description, params OpCode[] opcodes)
{
string key=type.ToString()+"."+description;
if(!nonary_cache.ContainsKey(key))
{
var op=BuildMethod<T>(description, opcodes);
nonary_cache.Add(key, op);
return op;
}
return nonary_cache[key];
}
/// <summary>
/// Returns method as a delegate. The prototype is <c><typeparamref name="T"/> f(<typeparamref name="T"/>);</c>
/// </summary>
/// <param name="method_name">The method name</param>
/// <exception cref="MissingMethodException">if <paramref name="method_name"/> does not correspond to a method name in <typeparamref name="T"/></exception>
/// <returns>A delegate</returns>
public static Func<T, T> UnaryMethod(string method_name)
{
string key=type.ToString()+"."+method_name;
if(!unary_cache.ContainsKey(key))
{
var op=BuildMethod<T, T>(method_name);
unary_cache.Add(key, op);
return op;
}
return unary_cache[key];
}
/// <summary>
/// Returns opcodes as a delegate. The prototype is <c><typeparamref name="T"/> f(<typeparamref name="T"/>);</c>
/// </summary>
/// <param name="description">A description for the codes</param>
/// <param name="opcodes">The op code sequence</param>
/// <returns>A delegate</returns>
public static Func<T, T> UnaryMethod(string description, params OpCode[] opcodes)
{
string key=type.ToString()+"."+description;
if(!unary_cache.ContainsKey(key))
{
var op=BuildMethod<T, T>(description, opcodes);
unary_cache.Add(key, op);
return op;
}
return unary_cache[key];
}
/// <summary>
/// Returns method as a delegate. The prototype is <c><typeparamref name="T"/> f(<typeparamref name="T"/>, <typeparamref name="T"/>);</c>
/// </summary>
/// <param name="method_name">The method name</param>
/// <exception cref="MissingMethodException">if <paramref name="method_name"/> does not correspond to a method name in <typeparamref name="T"/></exception>
/// <returns>A delegate</returns>
public static Func<T, T, T> BinaryMethod(string method_name)
{
string key=type.ToString()+"."+method_name;
if(!binary_cache.ContainsKey(key))
{
var op=BuildMethod<T, T, T>(method_name);
binary_cache.Add(key, op);
return op;
}
return binary_cache[key];
}
/// <summary>
/// Returns opcodes as a delegate.
/// The prototype is <c><typeparamref name="T"/> f(<typeparamref name="T"/>, <typeparamref name="T"/>);</c>
/// </summary>
/// <param name="description">A description for the codes</param>
/// <param name="opcodes">The op code sequence</param>
/// <returns>A delegate</returns>
public static Func<T, T, T> BinaryMethod(string description, params OpCode[] opcodes)
{
string key=type.ToString()+"."+description;
if(!binary_cache.ContainsKey(key))
{
var op=BuildMethod<T, T, T>(description, opcodes);
binary_cache.Add(key, op);
return op;
}
return binary_cache[key];
}
/// <summary>
/// Generates a delegate for a homogeneous unary operation.
/// The prototype is <c><typeparamref name="T"/> f(<typeparamref name="T"/>);</c>
/// </summary>
/// <remarks>Can cache the results</remarks>
/// <param name="op">The operation</param>
/// <returns>A delegate</returns>
public static Func<T, T> Operator(UnaryOperator op)
{
string key=name+"."+op.ToString();
if(!unary_cache.ContainsKey(key))
{
Func<T, T> f;
if(is_primitive)
{
f=UnaryMethod(op.ToString(), unary_operators[op]);
}
else
{
f=UnaryMethod(op.ToString());
}
unary_cache.Add(key, f);
return f;
}
return unary_cache[key];
}
/// <summary>
/// Generates a delegate for an inhomogeneous unary operation.
/// The prototype is <c><typeparamref name="TResult"/> f(<typeparamref name="T"/>);</c>
/// </summary>
/// <param name="op">The operation</param>
/// <typeparam name="TResult">The delegate result type</typeparam>
/// <returns>A delegate</returns>
public static Func<T, TResult> Operator<TResult>(UnaryOperator op)
{
if(is_primitive)
{
return Method<T, TResult>(op.ToString(), unary_operators[op]);
}
return Method<T, TResult>(op.ToString());
}
/// <summary>
/// Generates delegate for a homogeneous binary operation.
/// The prototype is <c><typeparamref name="T"/> f(<typeparamref name="T"/>, <typeparamref name="T"/>);</c>
/// </summary>
/// <remarks>Can cache the results</remarks>
/// <param name="op">The operation</param>
/// <returns>A delegate</returns>
public static Func<T, T, T> Operator(BinaryOperator op)
{
string key=name+"."+op.ToString();
if(!binary_cache.ContainsKey(key))
{
Func<T, T, T> f;
if(is_primitive)
{
f=BinaryMethod(op.ToString(), binary_operators[op]);
}
else
{
f=BinaryMethod(op.ToString());
}
binary_cache.Add(key, f);
return f;
}
return binary_cache[key];
}
/// <summary>
/// Generates delegate for an inhomogeneous binary operation.
/// The prototype is <c><typeparamref name="TResult"/> f(<typeparamref name="T"/>, <typeparamref name="TArg"/>);</c>
/// </summary>
/// <typeparam name="TArg">The delegate argument type</typeparam>
/// <typeparam name="TResult">The delegate return type</typeparam>
/// <param name="op">The operation</param>
/// <returns>A delegate</returns>
public static Func<T, TArg, TResult> Operator<TArg, TResult>(BinaryOperator op)
{
if(is_primitive)
{
return Method<T, TArg, TResult>(op.ToString(), binary_operators[op]);
}
return Method<T, TArg, TResult>(op.ToString());
}
/// <summary>
/// Generates delegate for a homogeneous conditional operaton.
/// The prototype is <c>bool f(<typeparamref name="T"/>, <typeparamref name="T"/>);</c>
/// </summary>
/// <remarks>Can cache the results</remarks>
/// <param name="op">The operation</param>
/// <returns>A delegate</returns>
public static Func<T, T, bool> Operator(ConditionalOperator op)
{
string key=name+"."+op.ToString();
if(!conditional_cache.ContainsKey(key))
{
Func<T, T, bool> f;
if(is_primitive)
{
f=Method<T, T, bool>(op.ToString(), conditional_operators[op]);
}
else
{
f=Method<T, T, bool>(op.ToString());
}
conditional_cache.Add(key, f);
return f;
}
return conditional_cache[key];
}
/// <summary>
/// Generates delegate for an inhomogeneous conditional operaton.
/// The prototype is <c>bool f(<typeparamref name="T"/>, <typeparamref name="TArg"/>);</c>
/// </summary>
/// <typeparam name="TArg">The delegate argument type</typeparam>
/// <param name="op">The operation</param>
/// <returns>A delegate</returns>
public static Func<T, TArg, bool> Operator<TArg>(ConditionalOperator op)
{
if(is_primitive)
{
return Method<T, TArg, bool>(op.ToString(), conditional_operators[op]);
}
return Method<T, TArg, bool>(op.ToString());
}
#endregion
#region Constructors
static Static<T> BuildConstructor()
{
Type delegate_type=typeof(Func<T>);
var call=MethodCall.Constructor();
var method=Declare<T>(call.Name);
return new Static<T>(method, call, delegate_type);
}
static Static<T> BuildConstructor<TArg>()
{
Type delegate_type=typeof(Func<TArg, T>);
var call=MethodCall.Constructor(typeof(TArg));
var method=Declare<TArg, T>(call.Name);
return new Static<T>(method, call, delegate_type);
}
static Static<T> BuildConstructor<TArg1, TArg2>()
{
Type delegate_type=typeof(Func<TArg1, TArg2, T>);
var call=MethodCall.Constructor(typeof(TArg1), typeof(TArg2));
var method=Declare<TArg1, TArg2, T>(call.Name);
return new Static<T>(method, call, delegate_type);
}
/// <summary>
/// Returns a default constructor. The prototype is <c>new <typeparamref name="T"/>()</c>
/// </summary>
/// <remarks>Caches the results for future use</remarks>
/// <exception cref="MissingMethodException">if default constructor does not exist for <typeparamref name="T"/></exception>
/// <returns>A delegate</returns>
public static Func<T> Factory()
{
string key=type.Name+".ctor";
if(!nonary_cache.ContainsKey(key))
{
var op=BuildConstructor();
nonary_cache.Add(key, op);
return op;
}
return nonary_cache[key];
}
/// <summary>
/// Returns a copy constructor. The prototype is <c>new <typeparamref name="T"/>(<typeparamref name="T"/>)</c>
/// </summary>
/// <remarks>Caches the results for future use</remarks>
/// <exception cref="MissingMethodException">if copy constructor does not exist for <typeparamref name="T"/></exception>
/// <returns>A delegate</returns>
public static Func<T, T> Copy()
{
string key=type.Name+".ctor";
if(!unary_cache.ContainsKey(key))
{
var op=BuildConstructor<T>();
unary_cache.Add(key, op);
return op;
}
return unary_cache[key];
}
/// <summary>
/// Returns a constructor. The prototype is <c>new <typeparamref name="T"/>(<typeparamref name="TArg"/>)</c>
/// </summary>
/// <typeparam name="TArg">The constructor agument type</typeparam>
/// <exception cref="MissingMethodException">if constructor with parameter of type <typeparamref name="TArg"/> does not exist for <typeparamref name="T"/></exception>
/// <returns>A delegate</returns>
public static Func<TArg, T> Factory<TArg>()
{
var op=BuildConstructor<TArg>();
return op.f as Func<TArg, T>;
}
/// <summary>
/// Returns a constructor. The prototype is <c>new <typeparamref name="T"/>(<typeparamref name="TArg1"/>, <typeparamref name="TArg2"/>)</c>
/// </summary>
/// <typeparam name="TArg1">The first constructor agument type</typeparam>
/// <typeparam name="TArg2">The second constructor agument type</typeparam>
/// <exception cref="MissingMethodException">if constructor with parameter of type <typeparamref name="TArg"/> does not exist for <typeparamref name="T"/></exception>
/// <returns>A delegate</returns>
public static Func<TArg1, TArg2, T> Factory<TArg1, TArg2>()
{
var op=BuildConstructor<TArg1, TArg2>();
return op.f as Func<TArg1, TArg2, T>;
}
/// <summary>
/// Calls the default constructor for type <typeparamref name="T"/>.
/// </summary>
/// <returns>A new instance of type <typeparamref name="T"/></returns>
public static T New()
{
return Factory()();
}
/// <summary>
/// Calls the copy constructor for type <typeparamref name="T"/>.
/// </summary>
/// <param name="arg">The value to copy from</param>
/// <returns>A new instance of type <typeparamref name="T"/></returns>
public static T New(T arg)
{
return Copy()(arg);
}
/// <summary>
/// Calls the constructor for type <typeparamref name="T"/> with one argument.
/// </summary>
/// <typeparam name="TArg">The argument type</typeparam>
/// <param name="arg">The argument value</param>
/// <returns>A new instance of type <typeparamref name="T"/></returns>
public static T New<TArg>(TArg arg)
{
var op=BuildConstructor<TArg>();
var f=op.f as Func<TArg, T>;
return f(arg);
}
/// <summary>
/// Calls the constructor for type for type <typeparamref name="T"/> with two arguments.
/// </summary>
/// <typeparam name="TArg1">The first argument type</typeparam>
/// <typeparam name="TArg2">The second argument type</typeparam>
/// <param name="arg1">The first argument value</param>
/// <param name="arg2">The second argumnet value</param>
/// <returns>A new instance of type <typeparamref name="T"/></returns>
public static T New<TArg1, TArg2>(TArg1 arg1, TArg2 arg2)
{
var op=BuildConstructor<TArg1, TArg2>();
var f=op.f as Func<TArg1, TArg2, T>;
return f(arg1, arg2);
}
#endregion
#region Dynamic Method Factory
static DynamicMethod Declare<TReturn>(string name)
{
return new DynamicMethod(type.ToString()+"."+name,
typeof(TReturn),
Type.EmptyTypes,
typeof(Static<T>));
}
static DynamicMethod Declare<TArg1, TReturn>(string name)
{
return new DynamicMethod(type.ToString()+"."+name,
typeof(TReturn),
new Type[] { typeof(TArg1) },
typeof(Static<T>));
}
static DynamicMethod Declare<TArg1, TArg2, TReturn>(string name)
{
return new DynamicMethod(type.ToString()+"."+name,
typeof(TReturn),
new Type[] { typeof(TArg1), typeof(TArg2) },
typeof(Static<T>));
}
#endregion
#region Arithmitic
/// <summary>
/// Return the negation operator for type <typeparamref name="T"/>
/// </summary>
public static Func<T, T> Neg { get { return Operator(UnaryOperator.op_UnaryNegation); } }
/// <summary>
/// Return the not operator for type <typeparamref name="T"/>
/// </summary>
public static Func<T, T> Not { get { return Operator(UnaryOperator.op_LogicalNot); } }
/// <summary>
/// Return the add operator for type <typeparamref name="T"/> and <typeparamref name="T"/>
/// </summary>
public static Func<T, T, T> Add { get { return Operator(BinaryOperator.op_Addition); } }
/// <summary>
/// Return the subtract operator for type <typeparamref name="T"/> and <typeparamref name="T"/>
/// </summary>
public static Func<T, T, T> Sub { get { return Operator(BinaryOperator.op_Subtraction); } }
/// <summary>
/// Return the multiply operator for type <typeparamref name="T"/> and <typeparamref name="T"/>
/// </summary>
public static Func<T, T, T> Mul { get { return Operator(BinaryOperator.op_Multiply); } }
/// <summary>
/// Return the scale operator for type <typeparamref name="T"/> and <c>double</c>
/// </summary>
public static Func<T, double, T> Scale { get { return Operator<double, T>(BinaryOperator.op_Multiply); } }
/// <summary>
/// Return the divide operator for type <typeparamref name="T"/> and <typeparamref name="T"/>
/// </summary>
public static Func<T, T, T> Div { get { return Operator(BinaryOperator.op_Division); } }
/// <summary>
/// Return the modulus operator for type <typeparamref name="T"/> and <typeparamref name="T"/>
/// </summary>
public static Func<T, T, T> Mod { get { return Operator(BinaryOperator.op_Modulus); } }
/// <summary>
/// Return the or operator for type <typeparamref name="T"/> and <typeparamref name="T"/>
/// </summary>
public static Func<T, T, T> Or { get { return Operator(BinaryOperator.op_BitwiseOr); } }
/// <summary>
/// Return the and operator for type <typeparamref name="T"/> and <typeparamref name="T"/>
/// </summary>
public static Func<T, T, T> And { get { return Operator(BinaryOperator.op_BitwiseAnd); } }
/// <summary>
/// Return the equals operator for type <typeparamref name="T"/> and <typeparamref name="T"/>
/// </summary>
public static Func<T, T, bool> Eq { get { return Operator(ConditionalOperator.op_Equality); } }
/// <summary>
/// Return the less than operator for type <typeparamref name="T"/> and <typeparamref name="T"/>
/// </summary>
public static Func<T, T, bool> Lt { get { return Operator(ConditionalOperator.op_LessThan); } }
/// <summary>
/// Return the greater than operator for type <typeparamref name="T"/> and <typeparamref name="T"/>
/// </summary>
public static Func<T, T, bool> Gt { get { return Operator(ConditionalOperator.op_GreaterThan); } }
/// <summary>
/// Return the less than or equals operator for type <typeparamref name="T"/> and <typeparamref name="T"/>
/// </summary>
public static Func<T, T, bool> Lte { get { return Operator(ConditionalOperator.op_LessThanOrEqual); } }
/// <summary>
/// Return the greater then or equals operator for type <typeparamref name="T"/> and <typeparamref name="T"/>
/// </summary>
public static Func<T, T, bool> Gte { get { return Operator(ConditionalOperator.op_GreaterThanOrEqual); } }
#endregion
#region Static Fields and Cache
static Type type=typeof(T);
static string name=typeof(T).Name;
static bool is_primitive=typeof(T).IsPrimitive;
static Dictionary<string, Func<T>> nonary_cache=new Dictionary<string, Func<T>>();
static Dictionary<string, Func<T, T>> unary_cache=new Dictionary<string, Func<T, T>>();
static Dictionary<string, Func<T, T, T>> binary_cache=new Dictionary<string, Func<T, T, T>>();
static Dictionary<string, Func<T, T, bool>> conditional_cache=new Dictionary<string, Func<T, T, bool>>();
static Dictionary<UnaryOperator, OpCode[]> unary_operators=new Dictionary<UnaryOperator, OpCode[]>
{
{UnaryOperator.op_UnaryNegation, new OpCode[] { OpCodes.Neg} },
{UnaryOperator.op_LogicalNot, new OpCode[]{OpCodes.Not} },
};
static Dictionary<BinaryOperator, OpCode[]> binary_operators=new Dictionary<BinaryOperator, OpCode[]>
{
{BinaryOperator.op_Addition, new OpCode[] { OpCodes.Add} },
{BinaryOperator.op_Subtraction, new OpCode[] { OpCodes.Sub} },
{BinaryOperator.op_Multiply, new OpCode[] { OpCodes.Mul} },
{BinaryOperator.op_Division, new OpCode[] { OpCodes.Div} },
{BinaryOperator.op_Modulus, new OpCode[] { OpCodes.Rem} },
{BinaryOperator.op_BitwiseOr, new OpCode[] { OpCodes.Or} },
{BinaryOperator.op_BitwiseAnd, new OpCode[] { OpCodes.Add} },
};
static Dictionary<ConditionalOperator, OpCode[]> conditional_operators=new Dictionary<ConditionalOperator, OpCode[]>
{
{ConditionalOperator.op_Equality, new OpCode[]{OpCodes.Ceq} },
{ConditionalOperator.op_GreaterThan, new OpCode[]{OpCodes.Cgt} },
{ConditionalOperator.op_GreaterThanOrEqual, new OpCode[] { OpCodes.Clt, OpCodes.Ldc_I4_0, OpCodes.Ceq}},
{ConditionalOperator.op_LessThan,new OpCode[] {OpCodes.Clt} },
{ConditionalOperator.op_LessThanOrEqual, new OpCode[] { OpCodes.Cgt, OpCodes.Ldc_I4_0, OpCodes.Ceq }},
};
#endregion
}
class Program
{
public struct MyStruct
{
public readonly int x;
public MyStruct(int x) { this.x=x; }
public static MyStruct operator+(MyStruct a, MyStruct b)
{
return new MyStruct(a.x+b.x);
}
}
static void Main(string[] args)
{
int a=Static<int>.Add(1, 2);
uint b=Static<uint>.Add(1u, 2u);
long c=Static<long>.Add(1U, 2U);
MyStruct d = new MyStruct(1);
MyStruct e = new MyStruct(2);
MyStruct f=Static<MyStruct>.Add(d, e);
}
}