Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* Copyright (C) 2007 The Trustees of Indiana University
- *
- * Use, modification and distribution is subject to the Boost Software
- * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
- * http://www.boost.org/LICENSE_1_0.txt)
- *
- * Authors: Douglas Gregor
- * Andrew Lumsdaine
- *
- * Url: http://www.osl.iu.edu/research/mpi.net/svn/
- *
- * This file provides the "Operations" class, which contains common
- * reduction operations such as addition and multiplication for any
- * type.
- *
- * This code was heavily influenced by Keith Farmer's
- * Operator Overloading with Generics
- * at http://www.codeproject.com/csharp/genericoperators.asp
- *
- * All MPI related code removed by John Alexiou. Code retains the dynamic
- * operator generators of
- */
- using System;
- using System.Reflection;
- using System.Reflection.Emit;
- using System.Runtime.InteropServices;
- using System.Collections.Generic;
- using System.Linq;
- namespace SO
- {
- /// <summary>
- /// The <c>Operation</c> class provides reduction operations for use with the
- /// reduction collectives.
- /// </summary>
- /// <remarks>
- /// The <c>Operation</c> class is used with the reduction collective communication operations
- /// For example, the <see cref="Add"/> property is a delegate that adds two data of type
- /// <typeparamref name="T"/>, while <see cref="Min"/> returns the minimum of the
- /// two data. The reduction operations provided by this class should be
- /// preferred to hand-written reduction operations (particularly for built-in types)
- /// because it enables additional optimizations in the MPI library.
- /// </remarks>
- /// <typeparam name="T">The type of data used in these operations.</typeparam>
- public class Operation<T>
- {
- #region Function Generators
- /// <summary>
- /// Synthesize a new UnaryFunction associated with a given operation.
- /// </summary>
- /// <param name="name">The name of the function to build, e.g., "add".</arg>
- /// <param name="opCode">The <c>OpCode</c> used for primitive types.</arg>
- /// <param name="methodName">The name of the overloaded function used for class types.</arg>
- /// <returns>Returns a new delegate implementing the given operation.</returns>
- public static Func<T, T> BuildUnaryFunction(string name, OpCode opCode, string methodName)
- {
- return BuildUnaryFunction<T, T>(name, opCode, methodName);
- }
- /// <summary>
- /// Synthesize a new UnaryFunction associated with a given operation.
- /// </summary>
- /// <param name="name">The name of the function to build, e.g., "add".</arg>
- /// <param name="opCode">The <c>OpCode</c> used for primitive types.</arg>
- /// <param name="methodName">The name of the overloaded function used for class types.</arg>
- /// <typeparam name="M">The argument type</typeparam>
- /// <typeparam name="R">The return type</typeparam>
- /// <returns>Returns a new delegate implementing the given operation.</returns>
- public static Func<M, R> BuildUnaryFunction<M, R>(string name, OpCode opCode, string methodName)
- {
- // Build the new mpiDelegateMethod
- DynamicMethod method=
- new DynamicMethod(
- name+":"+typeof(T).ToString(),
- typeof(R),
- new Type[] { typeof(M) },
- typeof(Operation<T>));
- ILGenerator generator=method.GetILGenerator();
- // Load the arguments onto the stack
- generator.Emit(OpCodes.Ldarg_0);
- if(typeof(T).IsPrimitive)
- {
- // Emit the op-code for primitive types, and we're done.
- generator.Emit(opCode);
- }
- else
- {
- // Find the overloaded operator and create a call to it
- MethodInfo opMethod=typeof(T).GetMethod(methodName, new Type[] { typeof(M) });
- if(opMethod!=null)
- {
- generator.EmitCall(OpCodes.Call, opMethod, null);
- }
- else
- {
- throw new MissingMemberException(
- string.Format("Method {0}({1}) Not Found.",
- methodName,
- typeof(T).Name));
- }
- }
- // Return the intermediate
- generator.Emit(OpCodes.Ret);
- // Return a delegate to call the mpiDelegateMethod
- return (Func<M, R>)method.CreateDelegate(typeof(Func<M, R>));
- }
- /// <summary>
- /// Synthesize a new UnaryFunction associated with a given operation.
- /// </summary>8
- /// <typeparam name="TArg">The argument type for the function</typeparam>
- /// <arg name="name">The name of the function to build, e.g., "add".</arg>
- /// <arg name="opCode">The <c>OpCode</c> used for primitive types.</arg>
- /// <arg name="methodName">The name of the overloaded function used for class types.</arg>
- /// <returns>Returns a new delegate implementing the given operation.</returns>
- public static Func<TArg, T> BuildConstructor<TArg>()
- {
- // Build the new mpiDelegateMethod
- DynamicMethod method=
- new DynamicMethod(
- "new:"+typeof(T).ToString(),
- typeof(T),
- new Type[] { typeof(TArg) },
- typeof(Operation<T>));
- ILGenerator generator=method.GetILGenerator();
- LocalBuilder local_var=generator.DeclareLocal(typeof(T));
- Label lbl=generator.DefineLabel();
- // Find the overloaded operator and create a call to it
- ConstructorInfo opMethod=typeof(T).GetConstructor(new Type[] { typeof(TArg) });
- if(opMethod!=null)
- {
- // Load the arguments onto the stack
- generator.Emit(OpCodes.Ldarg_0);
- generator.Emit(OpCodes.Newobj, opMethod);
- generator.Emit(OpCodes.Stloc_0);
- generator.Emit(OpCodes.Br_S, lbl);
- generator.MarkLabel(lbl);
- generator.Emit(OpCodes.Ldloc_0);
- }
- else
- {
- throw new MissingMemberException(
- string.Format("Constructor {0}({1}) Not Found.",
- typeof(T).Name,
- typeof(TArg).Name));
- }
- // Return the intermediate
- generator.Emit(OpCodes.Ret);
- // Return a delegate to call the mpiDelegateMethod
- return (Func<TArg, T>)method.CreateDelegate(typeof(Func<TArg, T>));
- }
- public static Func<TArg1, TArg2, T> BuildConstructor<TArg1, TArg2>()
- {
- // Build the new mpiDelegateMethod
- DynamicMethod method=
- new DynamicMethod(
- "new:"+typeof(T).ToString(),
- typeof(T),
- new Type[] { typeof(TArg1), typeof(TArg2) },
- typeof(Operation<T>));
- ILGenerator generator=method.GetILGenerator();
- LocalBuilder local_var=generator.DeclareLocal(typeof(T));
- Label lbl=generator.DefineLabel();
- // Find the overloaded operator and create a call to it
- ConstructorInfo opMethod=typeof(T).GetConstructor(new Type[] { typeof(TArg1), typeof(TArg2) });
- if(opMethod!=null)
- {
- // Load the arguments onto the stack
- generator.Emit(OpCodes.Ldarg_1);
- generator.Emit(OpCodes.Ldarg_0);
- generator.Emit(OpCodes.Newobj, opMethod);
- generator.Emit(OpCodes.Stloc_0);
- generator.Emit(OpCodes.Br_S, lbl);
- generator.MarkLabel(lbl);
- generator.Emit(OpCodes.Ldloc_0);
- }
- else
- {
- throw new MissingMemberException(
- string.Format("Constructor {0}({1},{2}) Not Found.",
- typeof(T).Name,
- typeof(TArg1).Name,
- typeof(TArg2).Name));
- }
- // Return the intermediate
- generator.Emit(OpCodes.Ret);
- // Return a delegate to call the mpiDelegateMethod
- return (Func<TArg1, TArg2, T>)method.CreateDelegate(typeof(Func<TArg1, TArg2, T>));
- }
- /// <summary>
- /// Synthesize a new BinaryFunction associated with a given operation.
- /// </summary>
- /// <arg name="name">The name of the function to build, e.g., "add".</arg>
- /// <arg name="opCode">The <c>OpCode</c> used for primitive types.</arg>
- /// <arg name="methodName">The name of the overloaded function used for class types.</arg>
- /// <returns>Returns a new delegate implementing the given operation.</returns>
- public static Func<T, T, T> BuildBinaryFunction(string name, OpCode opCode, string methodName)
- {
- // Build the new mpiDelegateMethod
- DynamicMethod method=
- new DynamicMethod(
- name+":"+typeof(T).ToString(),
- typeof(T),
- new Type[] { typeof(T), typeof(T) },
- typeof(Operation<T>));
- ILGenerator generator=method.GetILGenerator();
- // Load the arguments onto the stack
- generator.Emit(OpCodes.Ldarg_0);
- generator.Emit(OpCodes.Ldarg_1);
- if(typeof(T).IsPrimitive)
- {
- // Emit the op-code for primitive types, and we're done.
- generator.Emit(opCode);
- }
- else
- {
- // Find the overloaded operator and create a call to it
- MethodInfo opMethod=typeof(T).GetMethod(methodName, new Type[] { typeof(T), typeof(T) });
- if(opMethod!=null)
- {
- generator.EmitCall(OpCodes.Call, opMethod, null);
- }
- else
- {
- throw new MissingMemberException(
- string.Format("Method {0}({1},{2}) Not Found.",
- methodName,
- typeof(T).Name,
- typeof(T).Name));
- }
- }
- // Return the intermediate
- generator.Emit(OpCodes.Ret);
- // Return a delegate to call the mpiDelegateMethod
- return (Func<T, T, T>)method.CreateDelegate(typeof(Func<T, T, T>));
- }
- public static Func<T, T, R> BuildBinaryFunction<R>(string name, OpCode opCode, string methodName)
- {
- // Build the new mpiDelegateMethod
- DynamicMethod method=
- new DynamicMethod(
- name+":"+typeof(T).ToString(),
- typeof(R),
- new Type[] { typeof(T), typeof(T) },
- typeof(Operation<T>));
- ILGenerator generator=method.GetILGenerator();
- // Load the arguments onto the stack
- generator.Emit(OpCodes.Ldarg_0);
- generator.Emit(OpCodes.Ldarg_1);
- if(typeof(T).IsPrimitive)
- {
- // Emit the op-code for primitive types, and we're done.
- generator.Emit(opCode);
- }
- else
- {
- // Find the overloaded operator and create a call to it
- MethodInfo opMethod=typeof(T).GetMethod(methodName, new Type[] { typeof(T), typeof(T) });
- if(opMethod!=null)
- {
- generator.EmitCall(OpCodes.Call, opMethod, null);
- }
- else
- {
- throw new MissingMemberException(
- string.Format("Method {0}({1},{2}) Not Found.",
- methodName,
- typeof(T).Name,
- typeof(T).Name));
- }
- }
- // Return the intermediate
- generator.Emit(OpCodes.Ret);
- // Return a delegate to call the mpiDelegateMethod
- return (Func<T, T, R>)method.CreateDelegate(typeof(Func<T, T, R>));
- }
- /// <summary>
- /// Synthesize a new BinaryFunction associated with a given operation.
- /// </summary>
- /// <arg name="name">The name of the function to build, e.g., "add".</arg>
- /// <arg name="opCode">The <c>OpCode</c> used for primitive types.</arg>
- /// <arg name="methodName">The name of the overloaded function used for class types.</arg>
- /// <returns>Returns a new delegate implementing the given operation.</returns>
- public static Func<L, R, T> BuildBinaryFunction<L, R>(string name, OpCode opCode, string methodName)
- {
- // Build the new mpiDelegateMethod
- DynamicMethod method=
- new DynamicMethod(
- name+":"+typeof(T).ToString(),
- typeof(T),
- new Type[] { typeof(L), typeof(R) },
- typeof(Operation<T>));
- ILGenerator generator=method.GetILGenerator();
- // Load the arguments onto the stack
- generator.Emit(OpCodes.Ldarg_0);
- generator.Emit(OpCodes.Ldarg_1);
- if(typeof(T).IsPrimitive)
- {
- // Emit the op-code for primitive types, and we're done.
- generator.Emit(opCode);
- }
- else
- {
- // Find the overloaded operator and create a call to it
- MethodInfo opMethod=typeof(T).GetMethod(methodName, new Type[] { typeof(L), typeof(R) });
- if(opMethod!=null)
- {
- generator.EmitCall(OpCodes.Call, opMethod, null);
- }
- else
- {
- throw new MissingMemberException(
- string.Format("Method {0}({1},{2}) Not Found.",
- methodName,
- typeof(L).Name,
- typeof(R).Name));
- }
- }
- // Return the intermediate
- generator.Emit(OpCodes.Ret);
- // Return a delegate to call the mpiDelegateMethod
- return (Func<L, R, T>)method.CreateDelegate(typeof(Func<L, R, T>));
- }
- #endregion
- #region Minimum and maximum
- /// <summary>
- /// Cached intermediate of the reduction operation that computes the minimum of
- /// two data.
- /// </summary>
- private static Func<T, T, T> min=null;
- /// <summary>
- /// Reduction operation that computes the minimum of two data.
- /// </summary>
- public static Func<T, T, T> Min
- {
- get
- {
- if(min==null)
- {
- // Build the new mpiDelegateMethod
- DynamicMethod method=
- new DynamicMethod(
- "min:"+typeof(T).ToString(),
- typeof(T),
- new Type[] { typeof(T), typeof(T) },
- typeof(Operation<T>));
- ILGenerator generator=method.GetILGenerator();
- // Load the arguments onto the stack
- generator.Emit(OpCodes.Ldarg_0);
- generator.Emit(OpCodes.Ldarg_1);
- Label ifLess=generator.DefineLabel();
- if(typeof(T).IsPrimitive)
- // Compare the two operands with "<" and jump to ifLess if they are equal
- generator.Emit(OpCodes.Blt_S, ifLess);
- else
- {
- // Find the overloaded "<" operator
- MethodInfo opMethod=typeof(T).GetMethod("op_LessThan", new Type[] { typeof(T), typeof(T) });
- if(opMethod==null)
- throw new ArgumentException("Type "+typeof(T).Name+" does not have a < operator");
- // Create a call to the "<" operator
- generator.EmitCall(OpCodes.Call, opMethod, null);
- // If the intermediate was "1" (true), jump to ifLess
- generator.Emit(OpCodes.Brtrue_S, ifLess);
- }
- // We're in the fall-through case, where the first argument is not less than the second.
- // Load the second argument
- generator.Emit(OpCodes.Ldarg_1);
- // Return the intermediate
- generator.Emit(OpCodes.Ret);
- // Label the case where the first argument is less than the second
- generator.MarkLabel(ifLess);
- // Load the first argument
- generator.Emit(OpCodes.Ldarg_0);
- // Return the intermediate
- generator.Emit(OpCodes.Ret);
- // Create the delegate to call the mpiDelegateMethod
- min=(Func<T, T, T>)method.CreateDelegate(typeof(Func<T, T, T>));
- }
- return min;
- }
- }
- /// <summary>
- /// Cached intermediate of the reduction operation that computes the maximum of
- /// two data.
- /// </summary>
- private static Func<T, T, T> max=null;
- /// <summary>
- /// Reduction operation that computes the maximum of two data.
- /// </summary>
- public static Func<T, T, T> Max
- {
- get
- {
- if(max==null)
- {
- // Build the new mpiDelegateMethod
- DynamicMethod method=
- new DynamicMethod(
- "max:"+typeof(T).ToString(),
- typeof(T),
- new Type[] { typeof(T), typeof(T) },
- typeof(Operation<T>));
- ILGenerator generator=method.GetILGenerator();
- // Load the arguments onto the stack
- generator.Emit(OpCodes.Ldarg_0);
- generator.Emit(OpCodes.Ldarg_1);
- Label ifLess=generator.DefineLabel();
- if(typeof(T).IsPrimitive)
- // Compare the two operands with "<" and jump to ifLess if they are equal
- generator.Emit(OpCodes.Blt_S, ifLess);
- else
- {
- // Find the overloaded "<" operator
- MethodInfo opMethod=typeof(T).GetMethod("op_LessThan", new Type[] { typeof(T), typeof(T) });
- if(opMethod==null)
- throw new ArgumentException("Type "+typeof(T).Name+" does not have a < operator");
- // Create a call to the "<" operator
- generator.EmitCall(OpCodes.Call, opMethod, null);
- // If the intermediate was "1" (true), jump to ifLess
- generator.Emit(OpCodes.Brtrue_S, ifLess);
- }
- // We're in the fall-through case, where the first argument is not less than the second.
- // Load the first argument
- generator.Emit(OpCodes.Ldarg_0);
- // Return the intermediate
- generator.Emit(OpCodes.Ret);
- // Label the case where the first argument is less than the second
- generator.MarkLabel(ifLess);
- // Load the second argument
- generator.Emit(OpCodes.Ldarg_1);
- // Return the intermediate
- generator.Emit(OpCodes.Ret);
- // Create the delegate to call the mpiDelegateMethod
- max=(Func<T, T, T>)method.CreateDelegate(typeof(Func<T, T, T>));
- }
- return max;
- }
- }
- #endregion
- #region Arithmetics
- /// <summary>
- /// Cached intermediate of the reduction operation that adds two data.
- /// </summary>
- private static Func<T, T, T> add=null;
- /// <summary>
- /// Reduction operation that adds two data.
- /// </summary>
- public static Func<T, T, T> Add
- {
- get
- {
- if(add==null)
- {
- if(typeof(T)==typeof(string))
- add=BuildBinaryFunction("add", OpCodes.Add, "Concat");
- else
- add=BuildBinaryFunction("add", OpCodes.Add, "op_Addition");
- }
- return add;
- }
- }
- /// <summary>
- /// Cached intermediate of the reduction operation that subs two data.
- /// </summary>
- private static Func<T, T, T> sub=null;
- /// <summary>
- /// Reduction operation that subs two data.
- /// </summary>
- public static Func<T, T, T> Sub
- {
- get
- {
- if(sub==null)
- {
- sub=BuildBinaryFunction("sub", OpCodes.Sub, "op_Subtraction");
- }
- return sub;
- }
- }
- /// <summary>
- /// Cached intermediate of the reduction operation that negates a value.
- /// </summary>
- private static Func<T, T> neg=null;
- /// <summary>
- /// Reduction operation that negates a value.
- /// </summary>
- public static Func<T, T> Neg
- {
- get
- {
- if(neg==null)
- {
- neg=BuildUnaryFunction("neg", OpCodes.Neg, "op_Negate");
- }
- return neg;
- }
- }
- /// <summary>
- /// Cached intermediate of the reduction operation that multiplies two data.
- /// </summary>
- private static Func<T, T, T> multiply=null;
- /// <summary>
- /// Reduction operation that multiply two data.
- /// </summary>
- public static Func<T, T, T> Mul
- {
- get
- {
- if(multiply==null)
- multiply=BuildBinaryFunction("multiply", OpCodes.Mul, "op_Multiply");
- return multiply;
- }
- }
- private static Delegate multiply2=null;
- public static Func<L, R, T> BuildMultiply<L, R>()
- {
- if(multiply2==null)
- {
- multiply2=BuildBinaryFunction<L, R>("multiply", OpCodes.Mul, "op_Multiply");
- }
- return (Func<L, R, T>)multiply2;
- }
- /// <summary>
- /// Cached intermediate of the reduction operation that divides two data.
- /// </summary>
- private static Func<T, T, T> div=null;
- /// <summary>
- /// Reduction operation that divides two data.
- /// </summary>
- public static Func<T, T, T> Div
- {
- get
- {
- if(div==null)
- div=BuildBinaryFunction("div", OpCodes.Div, "op_Divide");
- return div;
- }
- }
- static Func<T, T, bool> gt=null, lt=null;
- public static Func<T, T, bool> Gt
- {
- get
- {
- if(gt==null)
- {
- gt=BuildBinaryFunction<bool>("gt", OpCodes.Cgt, "op_GreaterThan");
- }
- return gt;
- }
- }
- public static Func<T, T, bool> Lt
- {
- get
- {
- if(lt==null)
- {
- lt=BuildBinaryFunction<bool>("lt", OpCodes.Clt, "op_LessThan");
- }
- return lt;
- }
- }
- #endregion
- #region Datatype categorization
- /// <summary>
- /// The kind of MPI datatype. MPI classifies the predefined data types into
- /// several different categories. This classification is used primarily to determine
- /// which predefined reduction operations are supported by the low-level MPI
- /// implementation.
- /// </summary>
- internal enum DatatypeKind
- {
- /// <summary>
- /// C integer types, such as the predefined integral types in C# and .NET.
- /// </summary>
- CInteger,
- /// <summary>
- /// Fortran integer types. At present, there are no C# or .NET types that
- /// are classified this way.
- /// </summary>
- FortranInteger,
- /// <summary>
- /// Floating point types, such as the predefined <c>float</c> and <c>double</c> types.
- /// </summary>
- FloatingPoint,
- /// <summary>
- /// The MPI logical type. At present, there are no C# or .NET types that
- /// are classified this way.
- /// </summary>
- Logical,
- /// <summary>
- /// The MPI complex type. At present, there are no C# or .NET types that
- /// are classified this way.
- /// </summary>
- Complex,
- /// <summary>
- /// The MPI byte type, which corresponds to the <c>byte</c> type in C#.
- /// </summary>
- Byte,
- /// <summary>
- /// Any type that does not fit into one of the other MPI datatype classifications.
- /// </summary>
- Other
- }
- ///// <summary>
- ///// The MPI datatype classification of the type <typeparamref name="TEventArgs"/>.
- ///// </summary>
- //internal static DatatypeKind Kind=GetDatatypeKind();
- /// <summary>
- /// Retrieves the kind of datatype for the type <typeparamref name="TEventArgs"/>.
- /// Used only to initialize <see cref="Kind"/>.
- /// </summary>
- private static DatatypeKind GetDatatypeKind()
- {
- if(!typeof(T).IsPrimitive)
- // Non-primitive types don'editbox fit any of the MPI datatype categories
- return DatatypeKind.Other;
- // C Integer types
- if(typeof(T)==typeof(short)||typeof(T)==typeof(ushort)
- ||typeof(T)==typeof(int)||typeof(T)==typeof(uint)
- ||typeof(T)==typeof(long)||typeof(T)==typeof(ulong))
- return DatatypeKind.CInteger;
- // Floating point types
- if(typeof(T)==typeof(float)||typeof(T)==typeof(double))
- return DatatypeKind.FloatingPoint;
- // Deal with other kinds of types (future?)
- return DatatypeKind.Other;
- }
- #endregion
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement