fork download
  1. /*
  2.  * This file provides dynamic invocation of method, fields and properties
  3.  * based on IL code generation.
  4.  *
  5.  * This code was heavily influenced by
  6.  *
  7. 8 * a) Keith Farmer's Operator Overloading with Generics at
  8.  * http://w...content-available-to-author-only...t.com/csharp/genericoperators.asp
  9.  *
  10.  * b) Douglas Gregor and Andrew Lumsdaine Operator<T> class for use in MPI
  11.  * environments, licensed under http://w...content-available-to-author-only...t.org/LICENSE_1_0.txt
  12.  * http://w...content-available-to-author-only...u.edu/research/mpi.net/svn/
  13.  *
  14.  */
  15.  
  16. using System;
  17. using System.Collections.Generic;
  18. using System.Linq;
  19. using System.Text;
  20. using System.Reflection;
  21. using System.Reflection.Emit;
  22.  
  23. public enum UnaryOperator
  24. {
  25. /// <summary>
  26. /// The <c>-x</c> operator
  27. /// </summary>
  28. op_UnaryNegation,
  29. /// <summary>
  30. /// The <c>!x</c> operator
  31. /// </summary>
  32. op_LogicalNot,
  33. }
  34.  
  35. public enum BinaryOperator
  36. {
  37. /// <summary>
  38. /// The <c>x+y</c> operator
  39. /// </summary>
  40. op_Addition,
  41. /// <summary>
  42. /// The <c>x-y</c> operator
  43. /// </summary>
  44. op_Subtraction,
  45. /// <summary>
  46. /// The <c>x*y</c> operator
  47. /// </summary>
  48. op_Multiply,
  49. /// <summary>
  50. /// The <c>x/y</c> operator
  51. /// </summary>
  52. op_Division,
  53. /// <summary>
  54. /// The <c>x%y</c> operator
  55. /// </summary>
  56. op_Modulus,
  57. /// <summary>
  58. /// The <c>x|y</c> operator
  59. /// </summary>
  60. op_BitwiseOr,
  61. /// <summary>
  62. /// The <c>x&amp;y</c> operator
  63. /// </summary>
  64. op_BitwiseAnd,
  65. }
  66.  
  67. public enum ConditionalOperator
  68. {
  69. /// <summary>
  70. /// The <c>x==y</c> operator
  71. /// </summary>
  72. op_Equality,
  73. /// <summary>
  74. /// The <c>x&lt;y</c> operator
  75. /// </summary>
  76. op_LessThan,
  77. /// <summary>
  78. /// The <c>x&lt;=y</c> operator
  79. /// </summary>
  80. op_LessThanOrEqual,
  81. /// <summary>
  82. /// The <c>x&gt;y</c> operator
  83. /// </summary>
  84. op_GreaterThan,
  85. /// <summary>
  86. /// The <c>x&gt;=y</c> operator
  87. /// </summary>
  88. op_GreaterThanOrEqual,
  89. }
  90.  
  91. /// <summary>
  92. /// Class to provides dynamic invocation of static method, fields and properties based on IL code generation.
  93. /// </summary>
  94. /// <typeparam name="T">The type that contains the static methods to call</typeparam>
  95. public sealed class Static<T>
  96. {
  97. Delegate f;
  98.  
  99. #region Factory
  100. /// <summary>
  101. /// Initilialized the dynamic method and creates the delegate
  102. /// </summary>
  103. /// <param name="method">The method definifiton</param>
  104. /// <param name="call">The type of call this method makes</param>
  105. /// <param name="delegate_type">The type of delegate to generate</param>
  106. Static(DynamicMethod method, MethodCall call, Type delegate_type)
  107. {
  108. var generator=method.GetILGenerator();
  109. // Find the overloaded operator and create a call to it
  110. call.Emit(generator);
  111. // Return the intermediate
  112. generator.Emit(OpCodes.Ret);
  113.  
  114. // Return a delegate to call the mpiDelegateMethod
  115. this.f=method.CreateDelegate(delegate_type);
  116. }
  117. /// <summary>
  118. /// Implicitly convert method to nonary delegate of type <c><typeparamref name="T"/> f();</c>
  119. /// </summary>
  120. /// <param name="op">The emitted method</param>
  121. /// <returns>A delegate</returns>
  122. public static implicit operator Func<T>(Static<T> op)
  123. {
  124. return op.f as Func<T>;
  125. }
  126. /// <summary>
  127. /// Implicitly convert method to unary delegate of type <c><typeparamref name="T"/> f(<typeparamref name="T"/>);</c>
  128. /// </summary>
  129. /// <param name="op">The emitted method</param>
  130. /// <returns>A delegate</returns>
  131. public static implicit operator Func<T, T>(Static<T> op)
  132. {
  133. return op.f as Func<T, T>;
  134. }
  135. /// <summary>
  136. /// Implicitly convert method to binary delegate of type <c><typeparamref name="T"/> f(<typeparamref name="T"/>, <typeparamref name="T"/>);</c>
  137. /// </summary>
  138. /// <param name="op">The emitted method</param>
  139. /// <returns>A delegate</returns>
  140. public static implicit operator Func<T, T, T>(Static<T> op)
  141. {
  142. return op.f as Func<T, T, T>;
  143. }
  144. /// <summary>
  145. /// Implicitly convert method to a conditional delegate of type <c>bool f(<typeparamref name="T"/>, <typeparamref name="T"/>);</c>
  146. /// </summary>
  147. /// <param name="op">The emitted method</param>
  148. /// <returns>A delegate</returns>
  149. public static implicit operator Func<T, T, bool>(Static<T> op)
  150. {
  151. return op.f as Func<T, T, bool>;
  152. }
  153.  
  154. #endregion
  155.  
  156. #region Method Call Types
  157. /// <summary>
  158. /// Base class for emiting method calls.
  159. /// </summary>
  160. abstract class MethodCall
  161. {
  162. /// <summary>
  163. /// Overriding classes use this to emit the IL code to call the method
  164. /// </summary>
  165. /// <param name="generator">The IL generator to target</param>
  166. public abstract void Emit(ILGenerator generator);
  167. /// <summary>
  168. /// The name of the field, method or property being called
  169. /// </summary>
  170. public abstract string Name { get; }
  171.  
  172. #region Methods
  173. /// <summary>
  174. /// Returns the type and name of this method
  175. /// </summary>
  176. public override string ToString()
  177. {
  178. return string.Format("{0}({1})", GetType().Name, Name);
  179. }
  180. /// <summary>
  181. /// Helper function to create a string from a type list
  182. /// </summary>
  183. /// <param name="parameter_types"></param>
  184. /// <returns></returns>
  185. static string Signature(params Type[] parameter_types)
  186. {
  187. return string.Join(",", parameter_types.Select((t) => t.Name).ToArray());
  188. }
  189. #endregion
  190.  
  191. #region Op Code Emit
  192. /// <summary>
  193. /// Defines a call based on an IL op code such as <c>op_Multiply</c>
  194. /// </summary>
  195. /// <param name="description">The description of the sequence of op codes</param>
  196. /// <param name="parameter_counts">The number of paramers it used (to be pulled from the stack)</param>
  197. /// <param name="op_codes">The op codes to use</param>
  198. public static MethodCall Primitive(string description, int parameter_counts, params OpCode[] op_codes)
  199. {
  200. return new PrimitiveCall(description, parameter_counts, op_codes);
  201. }
  202. /// <summary>
  203. /// Class for primitive op calls
  204. /// </summary>
  205. class PrimitiveCall : MethodCall
  206. {
  207. string name;
  208. OpCode[] op_codes;
  209. int parameter_count;
  210. /// <summary>
  211. /// Defines a call based on an IL op code such as <c>op_Multiply</c>
  212. /// </summary>
  213. /// <param name="description">The description of the sequence of op codes</param>
  214. /// <param name="parameter_count">The number of arguments to be pulled of the stack</param>
  215. /// <param name="op_codes">The op codes to use</param>
  216. public PrimitiveCall(string description, int parameter_count, params OpCode[] op_codes)
  217. {
  218. this.name=description;
  219. this.parameter_count=parameter_count;
  220. this.op_codes=op_codes;
  221. }
  222. public override void Emit(ILGenerator generator)
  223. {
  224. for(int i=0; i<parameter_count; i++)
  225. {
  226. generator.Emit(OpCodes.Ldarg_S, i);
  227. }
  228. for(int i=0; i<op_codes.Length; i++)
  229. {
  230. generator.Emit(op_codes[i]);
  231. }
  232. }
  233. public override string Name
  234. {
  235. get { return name; }
  236. }
  237. }
  238. #endregion
  239.  
  240. #region Field Call
  241. /// <summary>
  242. /// Defines a call based on a reflected field.
  243. /// </summary>
  244. /// <param name="field_name">The field name</param>
  245. /// <returns>An overriden MethodCall instance</returns>
  246. public static MethodCall Field(string field_name)
  247. {
  248. return new FieldCall(field_name);
  249. }
  250. /// <summary>
  251. /// Class for reflected field calls
  252. /// </summary>
  253. class FieldCall : MethodCall
  254. {
  255. FieldInfo field;
  256. public FieldCall(string field_name)
  257. {
  258. this.field=type.GetField(field_name, BindingFlags.Public|BindingFlags.Static);
  259. if(field==null)
  260. {
  261. throw new MissingFieldException(name, field_name);
  262. }
  263. }
  264. public override void Emit(ILGenerator generator)
  265. {
  266. generator.Emit(OpCodes.Ldsfld, field);
  267. }
  268. public override string Name
  269. {
  270. get { return field.Name; }
  271. }
  272. }
  273.  
  274. #endregion
  275.  
  276. #region Method Call
  277. /// <summary>
  278. /// Defines a call based on a reflected method with one argument. Uses the specified types
  279. /// for overload resolution.
  280. /// </summary>
  281. /// <param name="method_name">The method name</param>
  282. /// <param name="argument_types">The list of argument types, or Type.EmptyTypes</param>
  283. /// <returns>An overriden MethodCall instance</returns>
  284. public static MethodCall Method(string method_name, params Type[] argument_types)
  285. {
  286. return new ReflectionCall(method_name, argument_types);
  287. }
  288.  
  289. /// <summary>
  290. /// Class for reflected method calls
  291. /// </summary>
  292. class ReflectionCall : MethodCall
  293. {
  294. MethodInfo method;
  295. Type[] argument_types;
  296. public ReflectionCall(string method_name, params Type[] argument_types)
  297. {
  298. this.argument_types=argument_types;
  299. this.method=type.GetMethod(method_name, argument_types);
  300. if(method==null)
  301. {
  302. throw new MissingMethodException(name, method_name);
  303. }
  304. }
  305. public override void Emit(ILGenerator generator)
  306. {
  307. if(argument_types.Length>=1) generator.Emit(OpCodes.Ldarg_0);
  308. if(argument_types.Length>=2) generator.Emit(OpCodes.Ldarg_1);
  309. generator.EmitCall(OpCodes.Call, method, null);
  310. }
  311. public override string Name
  312. {
  313. get { return string.Format("{0}({1})", method.Name, Signature(argument_types)); }
  314. }
  315. }
  316. #endregion
  317.  
  318. #region Constructor Call
  319.  
  320. public static MethodCall Constructor(params Type[] argument_types)
  321. {
  322. return new ConstructorCall(argument_types);
  323. }
  324.  
  325. class ConstructorCall : MethodCall
  326. {
  327. ConstructorInfo ctor;
  328. Type[] argument_types;
  329. public ConstructorCall(params Type[] argument_types)
  330. {
  331. this.argument_types=argument_types;
  332. this.ctor=type.GetConstructor(argument_types);
  333. if(ctor==null)
  334. {
  335. throw new MissingMethodException(name, name);
  336. }
  337. }
  338. public override void Emit(ILGenerator generator)
  339. {
  340. //LocalBuilder local_var=generator.DeclareLocal(type);
  341. Label lbl=generator.DefineLabel();
  342.  
  343. // Load the arguments onto the stack
  344. if(argument_types.Length>=1) generator.Emit(OpCodes.Ldarg_0);
  345. if(argument_types.Length>=2) generator.Emit(OpCodes.Ldarg_1);
  346. generator.Emit(OpCodes.Newobj, ctor);
  347. generator.Emit(OpCodes.Stloc_0);
  348. generator.Emit(OpCodes.Br_S, lbl);
  349. generator.MarkLabel(lbl);
  350. generator.Emit(OpCodes.Ldloc_0);
  351.  
  352. }
  353. public override string Name
  354. {
  355. get { return string.Format("{0}({1})", ctor.Name, Signature(argument_types)); }
  356. }
  357. }
  358. #endregion
  359. }
  360.  
  361. #endregion
  362.  
  363. #region Fields
  364.  
  365. static Static<T> BuildField<TReturn>(string field_name)
  366. {
  367. Type delegate_type=typeof(Func<TReturn>);
  368. var call=MethodCall.Field(field_name);
  369. var method=Declare<T>(call.Name);
  370. return new Static<T>(method, call, delegate_type);
  371. }
  372. /// <summary>
  373. /// Returns a field as a delegate. The prototype is <typeparamref name="T"/> f();
  374. /// </summary>
  375. /// <param name="field_name">The field name</param>
  376. /// <exception cref="MissingMethodException">if <paramref name="field_name"/> does not correspond to a field name in <typeparamref name="T"/></exception>
  377. /// <returns>A delegate</returns>
  378. public static Func<T> Field(string field_name)
  379. {
  380. string key=type.ToString()+"."+field_name;
  381. if(!nonary_cache.ContainsKey(key))
  382. {
  383. var op=BuildField<T>(field_name);
  384. nonary_cache.Add(key, op);
  385. return op;
  386. }
  387. return nonary_cache[key];
  388. }
  389. /// <summary>
  390. /// Returns a field as a delegate. The prototype is <typeparamref name="TReturn"/> f();
  391. /// </summary>
  392. /// <typeparam name="TField">The field type name</typeparam>
  393. /// <param name="field_name">The field name</param>
  394. /// <exception cref="MissingMethodException">if <paramref name="field_name"/> does not correspond to a field name in <typeparamref name="T"/></exception>
  395. /// <returns>A delegate</returns>
  396. public static Func<TField> Field<TField>(string field_name)
  397. {
  398. var op=BuildField<TField>(field_name);
  399. return op.f as Func<TField>;
  400. }
  401.  
  402. #endregion
  403.  
  404. #region Methods
  405.  
  406. static Static<T> BuildMethod<TReturn>(string method_name)
  407. {
  408. Type delegate_type=typeof(Func<TReturn>);
  409. var call=MethodCall.Method(method_name);
  410. var method=Declare<TReturn>(call.Name);
  411. return new Static<T>(method, call, delegate_type);
  412. }
  413. static Static<T> BuildMethod<TReturn>(string description, params OpCode[] opcodes)
  414. {
  415. Type delegate_type=typeof(Func<TReturn>);
  416. var call=MethodCall.Primitive(description, 0, opcodes);
  417. var method=Declare<TReturn>(call.Name);
  418. return new Static<T>(method, call, delegate_type);
  419. }
  420. static Static<T> BuildMethod<TArg, TReturn>(string method_name)
  421. {
  422. Type delegate_type=typeof(Func<TArg, TReturn>);
  423. var call=MethodCall.Method(method_name, typeof(TArg));
  424. var method=Declare<TArg, TReturn>(call.Name);
  425. return new Static<T>(method, call, delegate_type);
  426. }
  427. static Static<T> BuildMethod<TArg, TReturn>(string description, params OpCode[] opcodes)
  428. {
  429. Type delegate_type=typeof(Func<TArg, TReturn>);
  430. var call=MethodCall.Primitive(description, 1, opcodes);
  431. var method=Declare<TArg, TReturn>(call.Name);
  432. return new Static<T>(method, call, delegate_type);
  433. }
  434. static Static<T> BuildMethod<TArg1, TArg2, TReturn>(string method_name)
  435. {
  436. Type delegate_type=typeof(Func<TArg1, TArg2, TReturn>);
  437. var call=MethodCall.Method(method_name, typeof(TArg1), typeof(TArg2));
  438. var method=Declare<TArg1, TArg2, TReturn>(call.Name);
  439. return new Static<T>(method, call, delegate_type);
  440. }
  441. static Static<T> BuildMethod<TArg1, TArg2, TReturn>(string description, params OpCode[] opcodes)
  442. {
  443. Type delegate_type=typeof(Func<TArg1, TArg2, TReturn>);
  444. var call=MethodCall.Primitive(description, 2, opcodes);
  445. var method=Declare<TArg1, TArg2, TReturn>(call.Name);
  446. return new Static<T>(method, call, delegate_type);
  447. }
  448. /// <summary>
  449. /// Returns a method as a delegate. The prototype is <c><typeparamref name="TReturn"/> f();</c>
  450. /// </summary>
  451. /// <typeparam name="TReturn">The return type</typeparam>
  452. /// <param name="method_name">The method name</param>
  453. /// <exception cref="MissingMethodException">if <paramref name="method_name"/> does not correspond to a method name in <typeparamref name="T"/></exception>
  454. /// <returns>A delegate</returns>
  455. public static Func<TReturn> Method<TReturn>(string method_name)
  456. {
  457. var op=BuildMethod<TReturn>(method_name);
  458. return op.f as Func<TReturn>;
  459. }
  460. /// <summary>
  461. /// Returns a method as a delegate. The prototype is <c><typeparamref name="TReturn"/> f();</c>
  462. /// </summary>
  463. /// <typeparam name="TReturn">The return type</typeparam>
  464. /// <param name="description">The description for the opcodes</param>
  465. /// <param name="opcodes">The opcode sequence to use</param>
  466. /// <returns>A delegate</returns>
  467. public static Func<TReturn> Method<TReturn>(string description, params OpCode[] opcodes)
  468. {
  469. var op=BuildMethod<TReturn>(description, opcodes);
  470. return op.f as Func<TReturn>;
  471. }
  472.  
  473. /// <summary>
  474. /// Returns a method as a delegate. The prototype is <c><typeparamref name="TReturn"/> f(<typeparamref name="TArg"/>);</c>
  475. /// </summary>
  476. /// <typeparam name="TArg">The argument type</typeparam>
  477. /// <typeparam name="TReturn">The return type</typeparam>
  478. /// <param name="method_name">The method name</param>
  479. /// <exception cref="MissingMethodException">if <paramref name="method_name"/> does not correspond to a method name in <typeparamref name="T"/></exception>
  480. /// <returns>A delegate</returns>
  481. public static Func<TArg, TReturn> Method<TArg, TReturn>(string method_name)
  482. {
  483. var op=BuildMethod<TArg, TReturn>(method_name);
  484. return op.f as Func<TArg, TReturn>;
  485. }
  486. /// <summary>
  487. /// Returns a method as a delegate. The prototype is <c><typeparamref name="TReturn"/> f(<typeparamref name="TArg"/>);</c>
  488. /// </summary>
  489. /// <typeparam name="TArg">The argument type</typeparam>
  490. /// <typeparam name="TReturn">The return type</typeparam>
  491. /// <param name="description">The description for the opcodes</param>
  492. /// <param name="opcodes">The opcode sequence to use</param>
  493. /// <returns>A delegate</returns>
  494. public static Func<TArg, TReturn> Method<TArg, TReturn>(string description, params OpCode[] opcodes)
  495. {
  496. var op=BuildMethod<TArg, TReturn>(description, opcodes);
  497. return op.f as Func<TArg, TReturn>;
  498. }
  499. /// <summary>
  500. /// Returns a method as a delegate. The prototype is <c><typeparamref name="TReturn"/> f(<typeparamref name="TArg1"/>, <typeparamref name="TArg2"/>);</c>
  501. /// </summary>
  502. /// <typeparam name="TArg1">The first argument type</typeparam>
  503. /// <typeparam name="TArg2">The second argument type</typeparam>
  504. /// <typeparam name="TReturn">The return type</typeparam>
  505. /// <param name="method_name">The method name</param>
  506. /// <exception cref="MissingMethodException">if <paramref name="method_name"/> does not correspond to a method name in <typeparamref name="T"/></exception>
  507. /// <returns>A delegate</returns>
  508. public static Func<TArg1, TArg2, TReturn> Method<TArg1, TArg2, TReturn>(string method_name)
  509. {
  510. var op=BuildMethod<TArg1, TArg2, TReturn>(method_name);
  511. return op.f as Func<TArg1, TArg2, TReturn>;
  512. }
  513. /// <summary>
  514. /// Returns a method as a delegate. The prototype is <c><typeparamref name="TReturn"/> f(<typeparamref name="TArg1"/>, <typeparamref name="TArg2"/>);</c>
  515. /// </summary>
  516. /// <typeparam name="TArg1">The first argument type</typeparam>
  517. /// <typeparam name="TArg2">The second argument type</typeparam>
  518. /// <typeparam name="TReturn">The return type</typeparam>
  519. /// <param name="description">The description for the opcodes</param>
  520. /// <param name="opcodes">The opcode sequence to use</param>
  521. /// <returns>A delegate</returns>
  522. public static Func<TArg1, TArg2, TReturn> Method<TArg1, TArg2, TReturn>(string description, params OpCode[] opcodes)
  523. {
  524. var op=BuildMethod<TArg1, TArg2, TReturn>(description, opcodes);
  525. return op.f as Func<TArg1, TArg2, TReturn>;
  526. }
  527.  
  528. /// <summary>
  529. /// Returns a method as a delegate. The prototype is <c><typeparamref name="T"/> f();</c>
  530. /// </summary>
  531. /// <param name="method_name">The method name</param>
  532. /// <exception cref="MissingMethodException">if <paramref name="method_name"/> does not correspond to a method name in <typeparamref name="T"/></exception>
  533. /// <returns>A delegate</returns>
  534. public static Func<T> NonaryMethod(string method_name)
  535. {
  536. string key=type.ToString()+"."+method_name;
  537. if(!nonary_cache.ContainsKey(key))
  538. {
  539. var op=BuildMethod<T>(method_name);
  540. nonary_cache.Add(key, op);
  541. return op;
  542. }
  543. return nonary_cache[key];
  544. }
  545. /// <summary>
  546. /// Returns opcodes as a delegate. The prototype is <c><typeparamref name="T"/> f();</c>
  547. /// </summary>
  548. /// <param name="description">A description for the codes</param>
  549. /// <param name="opcodes">The op code sequence</param>
  550. /// <returns>A delegate</returns>
  551. public static Func<T> NonaryMethod(string description, params OpCode[] opcodes)
  552. {
  553. string key=type.ToString()+"."+description;
  554. if(!nonary_cache.ContainsKey(key))
  555. {
  556. var op=BuildMethod<T>(description, opcodes);
  557. nonary_cache.Add(key, op);
  558. return op;
  559. }
  560. return nonary_cache[key];
  561. }
  562.  
  563. /// <summary>
  564. /// Returns method as a delegate. The prototype is <c><typeparamref name="T"/> f(<typeparamref name="T"/>);</c>
  565. /// </summary>
  566. /// <param name="method_name">The method name</param>
  567. /// <exception cref="MissingMethodException">if <paramref name="method_name"/> does not correspond to a method name in <typeparamref name="T"/></exception>
  568. /// <returns>A delegate</returns>
  569. public static Func<T, T> UnaryMethod(string method_name)
  570. {
  571. string key=type.ToString()+"."+method_name;
  572. if(!unary_cache.ContainsKey(key))
  573. {
  574. var op=BuildMethod<T, T>(method_name);
  575. unary_cache.Add(key, op);
  576. return op;
  577. }
  578. return unary_cache[key];
  579. }
  580.  
  581. /// <summary>
  582. /// Returns opcodes as a delegate. The prototype is <c><typeparamref name="T"/> f(<typeparamref name="T"/>);</c>
  583. /// </summary>
  584. /// <param name="description">A description for the codes</param>
  585. /// <param name="opcodes">The op code sequence</param>
  586. /// <returns>A delegate</returns>
  587. public static Func<T, T> UnaryMethod(string description, params OpCode[] opcodes)
  588. {
  589. string key=type.ToString()+"."+description;
  590. if(!unary_cache.ContainsKey(key))
  591. {
  592. var op=BuildMethod<T, T>(description, opcodes);
  593. unary_cache.Add(key, op);
  594. return op;
  595. }
  596. return unary_cache[key];
  597. }
  598.  
  599. /// <summary>
  600. /// Returns method as a delegate. The prototype is <c><typeparamref name="T"/> f(<typeparamref name="T"/>, <typeparamref name="T"/>);</c>
  601. /// </summary>
  602. /// <param name="method_name">The method name</param>
  603. /// <exception cref="MissingMethodException">if <paramref name="method_name"/> does not correspond to a method name in <typeparamref name="T"/></exception>
  604. /// <returns>A delegate</returns>
  605. public static Func<T, T, T> BinaryMethod(string method_name)
  606. {
  607. string key=type.ToString()+"."+method_name;
  608. if(!binary_cache.ContainsKey(key))
  609. {
  610. var op=BuildMethod<T, T, T>(method_name);
  611. binary_cache.Add(key, op);
  612. return op;
  613. }
  614. return binary_cache[key];
  615. }
  616.  
  617. /// <summary>
  618. /// Returns opcodes as a delegate.
  619. /// The prototype is <c><typeparamref name="T"/> f(<typeparamref name="T"/>, <typeparamref name="T"/>);</c>
  620. /// </summary>
  621. /// <param name="description">A description for the codes</param>
  622. /// <param name="opcodes">The op code sequence</param>
  623. /// <returns>A delegate</returns>
  624. public static Func<T, T, T> BinaryMethod(string description, params OpCode[] opcodes)
  625. {
  626. string key=type.ToString()+"."+description;
  627. if(!binary_cache.ContainsKey(key))
  628. {
  629. var op=BuildMethod<T, T, T>(description, opcodes);
  630. binary_cache.Add(key, op);
  631. return op;
  632. }
  633. return binary_cache[key];
  634. }
  635. /// <summary>
  636. /// Generates a delegate for a homogeneous unary operation.
  637. /// The prototype is <c><typeparamref name="T"/> f(<typeparamref name="T"/>);</c>
  638. /// </summary>
  639. /// <remarks>Can cache the results</remarks>
  640. /// <param name="op">The operation</param>
  641. /// <returns>A delegate</returns>
  642. public static Func<T, T> Operator(UnaryOperator op)
  643. {
  644. string key=name+"."+op.ToString();
  645. if(!unary_cache.ContainsKey(key))
  646. {
  647. Func<T, T> f;
  648. if(is_primitive)
  649. {
  650. f=UnaryMethod(op.ToString(), unary_operators[op]);
  651. }
  652. else
  653. {
  654. f=UnaryMethod(op.ToString());
  655. }
  656. unary_cache.Add(key, f);
  657. return f;
  658. }
  659. return unary_cache[key];
  660. }
  661. /// <summary>
  662. /// Generates a delegate for an inhomogeneous unary operation.
  663. /// The prototype is <c><typeparamref name="TResult"/> f(<typeparamref name="T"/>);</c>
  664. /// </summary>
  665. /// <param name="op">The operation</param>
  666. /// <typeparam name="TResult">The delegate result type</typeparam>
  667. /// <returns>A delegate</returns>
  668. public static Func<T, TResult> Operator<TResult>(UnaryOperator op)
  669. {
  670. if(is_primitive)
  671. {
  672. return Method<T, TResult>(op.ToString(), unary_operators[op]);
  673. }
  674. return Method<T, TResult>(op.ToString());
  675. }
  676. /// <summary>
  677. /// Generates delegate for a homogeneous binary operation.
  678. /// The prototype is <c><typeparamref name="T"/> f(<typeparamref name="T"/>, <typeparamref name="T"/>);</c>
  679. /// </summary>
  680. /// <remarks>Can cache the results</remarks>
  681. /// <param name="op">The operation</param>
  682. /// <returns>A delegate</returns>
  683. public static Func<T, T, T> Operator(BinaryOperator op)
  684. {
  685. string key=name+"."+op.ToString();
  686. if(!binary_cache.ContainsKey(key))
  687. {
  688. Func<T, T, T> f;
  689. if(is_primitive)
  690. {
  691. f=BinaryMethod(op.ToString(), binary_operators[op]);
  692. }
  693. else
  694. {
  695. f=BinaryMethod(op.ToString());
  696. }
  697. binary_cache.Add(key, f);
  698. return f;
  699. }
  700. return binary_cache[key];
  701. }
  702. /// <summary>
  703. /// Generates delegate for an inhomogeneous binary operation.
  704. /// The prototype is <c><typeparamref name="TResult"/> f(<typeparamref name="T"/>, <typeparamref name="TArg"/>);</c>
  705. /// </summary>
  706. /// <typeparam name="TArg">The delegate argument type</typeparam>
  707. /// <typeparam name="TResult">The delegate return type</typeparam>
  708. /// <param name="op">The operation</param>
  709. /// <returns>A delegate</returns>
  710. public static Func<T, TArg, TResult> Operator<TArg, TResult>(BinaryOperator op)
  711. {
  712. if(is_primitive)
  713. {
  714. return Method<T, TArg, TResult>(op.ToString(), binary_operators[op]);
  715. }
  716. return Method<T, TArg, TResult>(op.ToString());
  717. }
  718. /// <summary>
  719. /// Generates delegate for a homogeneous conditional operaton.
  720. /// The prototype is <c>bool f(<typeparamref name="T"/>, <typeparamref name="T"/>);</c>
  721. /// </summary>
  722. /// <remarks>Can cache the results</remarks>
  723. /// <param name="op">The operation</param>
  724. /// <returns>A delegate</returns>
  725. public static Func<T, T, bool> Operator(ConditionalOperator op)
  726. {
  727. string key=name+"."+op.ToString();
  728. if(!conditional_cache.ContainsKey(key))
  729. {
  730. Func<T, T, bool> f;
  731. if(is_primitive)
  732. {
  733. f=Method<T, T, bool>(op.ToString(), conditional_operators[op]);
  734. }
  735. else
  736. {
  737. f=Method<T, T, bool>(op.ToString());
  738. }
  739. conditional_cache.Add(key, f);
  740. return f;
  741. }
  742. return conditional_cache[key];
  743. }
  744. /// <summary>
  745. /// Generates delegate for an inhomogeneous conditional operaton.
  746. /// The prototype is <c>bool f(<typeparamref name="T"/>, <typeparamref name="TArg"/>);</c>
  747. /// </summary>
  748. /// <typeparam name="TArg">The delegate argument type</typeparam>
  749. /// <param name="op">The operation</param>
  750. /// <returns>A delegate</returns>
  751. public static Func<T, TArg, bool> Operator<TArg>(ConditionalOperator op)
  752. {
  753. if(is_primitive)
  754. {
  755. return Method<T, TArg, bool>(op.ToString(), conditional_operators[op]);
  756. }
  757. return Method<T, TArg, bool>(op.ToString());
  758. }
  759.  
  760.  
  761. #endregion
  762.  
  763. #region Constructors
  764.  
  765. static Static<T> BuildConstructor()
  766. {
  767. Type delegate_type=typeof(Func<T>);
  768. var call=MethodCall.Constructor();
  769. var method=Declare<T>(call.Name);
  770. return new Static<T>(method, call, delegate_type);
  771. }
  772. static Static<T> BuildConstructor<TArg>()
  773. {
  774. Type delegate_type=typeof(Func<TArg, T>);
  775. var call=MethodCall.Constructor(typeof(TArg));
  776. var method=Declare<TArg, T>(call.Name);
  777. return new Static<T>(method, call, delegate_type);
  778. }
  779. static Static<T> BuildConstructor<TArg1, TArg2>()
  780. {
  781. Type delegate_type=typeof(Func<TArg1, TArg2, T>);
  782. var call=MethodCall.Constructor(typeof(TArg1), typeof(TArg2));
  783. var method=Declare<TArg1, TArg2, T>(call.Name);
  784. return new Static<T>(method, call, delegate_type);
  785. }
  786.  
  787. /// <summary>
  788. /// Returns a default constructor. The prototype is <c>new <typeparamref name="T"/>()</c>
  789. /// </summary>
  790. /// <remarks>Caches the results for future use</remarks>
  791. /// <exception cref="MissingMethodException">if default constructor does not exist for <typeparamref name="T"/></exception>
  792. /// <returns>A delegate</returns>
  793. public static Func<T> Factory()
  794. {
  795. string key=type.Name+".ctor";
  796. if(!nonary_cache.ContainsKey(key))
  797. {
  798. var op=BuildConstructor();
  799. nonary_cache.Add(key, op);
  800. return op;
  801. }
  802. return nonary_cache[key];
  803. }
  804.  
  805. /// <summary>
  806. /// Returns a copy constructor. The prototype is <c>new <typeparamref name="T"/>(<typeparamref name="T"/>)</c>
  807. /// </summary>
  808. /// <remarks>Caches the results for future use</remarks>
  809. /// <exception cref="MissingMethodException">if copy constructor does not exist for <typeparamref name="T"/></exception>
  810. /// <returns>A delegate</returns>
  811. public static Func<T, T> Copy()
  812. {
  813. string key=type.Name+".ctor";
  814. if(!unary_cache.ContainsKey(key))
  815. {
  816. var op=BuildConstructor<T>();
  817. unary_cache.Add(key, op);
  818. return op;
  819. }
  820. return unary_cache[key];
  821. }
  822. /// <summary>
  823. /// Returns a constructor. The prototype is <c>new <typeparamref name="T"/>(<typeparamref name="TArg"/>)</c>
  824. /// </summary>
  825. /// <typeparam name="TArg">The constructor agument type</typeparam>
  826. /// <exception cref="MissingMethodException">if constructor with parameter of type <typeparamref name="TArg"/> does not exist for <typeparamref name="T"/></exception>
  827. /// <returns>A delegate</returns>
  828. public static Func<TArg, T> Factory<TArg>()
  829. {
  830. var op=BuildConstructor<TArg>();
  831. return op.f as Func<TArg, T>;
  832. }
  833.  
  834. /// <summary>
  835. /// Returns a constructor. The prototype is <c>new <typeparamref name="T"/>(<typeparamref name="TArg1"/>, <typeparamref name="TArg2"/>)</c>
  836. /// </summary>
  837. /// <typeparam name="TArg1">The first constructor agument type</typeparam>
  838. /// <typeparam name="TArg2">The second constructor agument type</typeparam>
  839. /// <exception cref="MissingMethodException">if constructor with parameter of type <typeparamref name="TArg"/> does not exist for <typeparamref name="T"/></exception>
  840. /// <returns>A delegate</returns>
  841. public static Func<TArg1, TArg2, T> Factory<TArg1, TArg2>()
  842. {
  843. var op=BuildConstructor<TArg1, TArg2>();
  844. return op.f as Func<TArg1, TArg2, T>;
  845. }
  846.  
  847. /// <summary>
  848. /// Calls the default constructor for type <typeparamref name="T"/>.
  849. /// </summary>
  850. /// <returns>A new instance of type <typeparamref name="T"/></returns>
  851. public static T New()
  852. {
  853. return Factory()();
  854. }
  855. /// <summary>
  856. /// Calls the copy constructor for type <typeparamref name="T"/>.
  857. /// </summary>
  858. /// <param name="arg">The value to copy from</param>
  859. /// <returns>A new instance of type <typeparamref name="T"/></returns>
  860. public static T New(T arg)
  861. {
  862. return Copy()(arg);
  863. }
  864.  
  865. /// <summary>
  866. /// Calls the constructor for type <typeparamref name="T"/> with one argument.
  867. /// </summary>
  868. /// <typeparam name="TArg">The argument type</typeparam>
  869. /// <param name="arg">The argument value</param>
  870. /// <returns>A new instance of type <typeparamref name="T"/></returns>
  871. public static T New<TArg>(TArg arg)
  872. {
  873. var op=BuildConstructor<TArg>();
  874. var f=op.f as Func<TArg, T>;
  875. return f(arg);
  876. }
  877. /// <summary>
  878. /// Calls the constructor for type for type <typeparamref name="T"/> with two arguments.
  879. /// </summary>
  880. /// <typeparam name="TArg1">The first argument type</typeparam>
  881. /// <typeparam name="TArg2">The second argument type</typeparam>
  882. /// <param name="arg1">The first argument value</param>
  883. /// <param name="arg2">The second argumnet value</param>
  884. /// <returns>A new instance of type <typeparamref name="T"/></returns>
  885. public static T New<TArg1, TArg2>(TArg1 arg1, TArg2 arg2)
  886. {
  887. var op=BuildConstructor<TArg1, TArg2>();
  888. var f=op.f as Func<TArg1, TArg2, T>;
  889. return f(arg1, arg2);
  890. }
  891.  
  892. #endregion
  893.  
  894. #region Dynamic Method Factory
  895.  
  896. static DynamicMethod Declare<TReturn>(string name)
  897. {
  898. return new DynamicMethod(type.ToString()+"."+name,
  899. typeof(TReturn),
  900. Type.EmptyTypes,
  901. typeof(Static<T>));
  902. }
  903. static DynamicMethod Declare<TArg1, TReturn>(string name)
  904. {
  905. return new DynamicMethod(type.ToString()+"."+name,
  906. typeof(TReturn),
  907. new Type[] { typeof(TArg1) },
  908. typeof(Static<T>));
  909. }
  910. static DynamicMethod Declare<TArg1, TArg2, TReturn>(string name)
  911. {
  912. return new DynamicMethod(type.ToString()+"."+name,
  913. typeof(TReturn),
  914. new Type[] { typeof(TArg1), typeof(TArg2) },
  915. typeof(Static<T>));
  916. }
  917. #endregion
  918.  
  919. #region Arithmitic
  920. /// <summary>
  921. /// Return the negation operator for type <typeparamref name="T"/>
  922. /// </summary>
  923. public static Func<T, T> Neg { get { return Operator(UnaryOperator.op_UnaryNegation); } }
  924. /// <summary>
  925. /// Return the not operator for type <typeparamref name="T"/>
  926. /// </summary>
  927. public static Func<T, T> Not { get { return Operator(UnaryOperator.op_LogicalNot); } }
  928. /// <summary>
  929. /// Return the add operator for type <typeparamref name="T"/> and <typeparamref name="T"/>
  930. /// </summary>
  931. public static Func<T, T, T> Add { get { return Operator(BinaryOperator.op_Addition); } }
  932. /// <summary>
  933. /// Return the subtract operator for type <typeparamref name="T"/> and <typeparamref name="T"/>
  934. /// </summary>
  935. public static Func<T, T, T> Sub { get { return Operator(BinaryOperator.op_Subtraction); } }
  936. /// <summary>
  937. /// Return the multiply operator for type <typeparamref name="T"/> and <typeparamref name="T"/>
  938. /// </summary>
  939. public static Func<T, T, T> Mul { get { return Operator(BinaryOperator.op_Multiply); } }
  940. /// <summary>
  941. /// Return the scale operator for type <typeparamref name="T"/> and <c>double</c>
  942. /// </summary>
  943. public static Func<T, double, T> Scale { get { return Operator<double, T>(BinaryOperator.op_Multiply); } }
  944. /// <summary>
  945. /// Return the divide operator for type <typeparamref name="T"/> and <typeparamref name="T"/>
  946. /// </summary>
  947. public static Func<T, T, T> Div { get { return Operator(BinaryOperator.op_Division); } }
  948. /// <summary>
  949. /// Return the modulus operator for type <typeparamref name="T"/> and <typeparamref name="T"/>
  950. /// </summary>
  951. public static Func<T, T, T> Mod { get { return Operator(BinaryOperator.op_Modulus); } }
  952. /// <summary>
  953. /// Return the or operator for type <typeparamref name="T"/> and <typeparamref name="T"/>
  954. /// </summary>
  955. public static Func<T, T, T> Or { get { return Operator(BinaryOperator.op_BitwiseOr); } }
  956. /// <summary>
  957. /// Return the and operator for type <typeparamref name="T"/> and <typeparamref name="T"/>
  958. /// </summary>
  959. public static Func<T, T, T> And { get { return Operator(BinaryOperator.op_BitwiseAnd); } }
  960. /// <summary>
  961. /// Return the equals operator for type <typeparamref name="T"/> and <typeparamref name="T"/>
  962. /// </summary>
  963. public static Func<T, T, bool> Eq { get { return Operator(ConditionalOperator.op_Equality); } }
  964. /// <summary>
  965. /// Return the less than operator for type <typeparamref name="T"/> and <typeparamref name="T"/>
  966. /// </summary>
  967. public static Func<T, T, bool> Lt { get { return Operator(ConditionalOperator.op_LessThan); } }
  968. /// <summary>
  969. /// Return the greater than operator for type <typeparamref name="T"/> and <typeparamref name="T"/>
  970. /// </summary>
  971. public static Func<T, T, bool> Gt { get { return Operator(ConditionalOperator.op_GreaterThan); } }
  972. /// <summary>
  973. /// Return the less than or equals operator for type <typeparamref name="T"/> and <typeparamref name="T"/>
  974. /// </summary>
  975. public static Func<T, T, bool> Lte { get { return Operator(ConditionalOperator.op_LessThanOrEqual); } }
  976. /// <summary>
  977. /// Return the greater then or equals operator for type <typeparamref name="T"/> and <typeparamref name="T"/>
  978. /// </summary>
  979. public static Func<T, T, bool> Gte { get { return Operator(ConditionalOperator.op_GreaterThanOrEqual); } }
  980. #endregion
  981.  
  982. #region Static Fields and Cache
  983. static Type type=typeof(T);
  984. static string name=typeof(T).Name;
  985. static bool is_primitive=typeof(T).IsPrimitive;
  986. static Dictionary<string, Func<T>> nonary_cache=new Dictionary<string, Func<T>>();
  987. static Dictionary<string, Func<T, T>> unary_cache=new Dictionary<string, Func<T, T>>();
  988. static Dictionary<string, Func<T, T, T>> binary_cache=new Dictionary<string, Func<T, T, T>>();
  989. static Dictionary<string, Func<T, T, bool>> conditional_cache=new Dictionary<string, Func<T, T, bool>>();
  990.  
  991. static Dictionary<UnaryOperator, OpCode[]> unary_operators=new Dictionary<UnaryOperator, OpCode[]>
  992. {
  993. {UnaryOperator.op_UnaryNegation, new OpCode[] { OpCodes.Neg} },
  994. {UnaryOperator.op_LogicalNot, new OpCode[]{OpCodes.Not} },
  995. };
  996. static Dictionary<BinaryOperator, OpCode[]> binary_operators=new Dictionary<BinaryOperator, OpCode[]>
  997. {
  998. {BinaryOperator.op_Addition, new OpCode[] { OpCodes.Add} },
  999. {BinaryOperator.op_Subtraction, new OpCode[] { OpCodes.Sub} },
  1000. {BinaryOperator.op_Multiply, new OpCode[] { OpCodes.Mul} },
  1001. {BinaryOperator.op_Division, new OpCode[] { OpCodes.Div} },
  1002. {BinaryOperator.op_Modulus, new OpCode[] { OpCodes.Rem} },
  1003. {BinaryOperator.op_BitwiseOr, new OpCode[] { OpCodes.Or} },
  1004. {BinaryOperator.op_BitwiseAnd, new OpCode[] { OpCodes.Add} },
  1005. };
  1006. static Dictionary<ConditionalOperator, OpCode[]> conditional_operators=new Dictionary<ConditionalOperator, OpCode[]>
  1007. {
  1008. {ConditionalOperator.op_Equality, new OpCode[]{OpCodes.Ceq} },
  1009. {ConditionalOperator.op_GreaterThan, new OpCode[]{OpCodes.Cgt} },
  1010. {ConditionalOperator.op_GreaterThanOrEqual, new OpCode[] { OpCodes.Clt, OpCodes.Ldc_I4_0, OpCodes.Ceq}},
  1011. {ConditionalOperator.op_LessThan,new OpCode[] {OpCodes.Clt} },
  1012. {ConditionalOperator.op_LessThanOrEqual, new OpCode[] { OpCodes.Cgt, OpCodes.Ldc_I4_0, OpCodes.Ceq }},
  1013. };
  1014.  
  1015. #endregion
  1016.  
  1017. }
  1018.  
  1019. class Program
  1020. {
  1021. public struct MyStruct
  1022. {
  1023. public readonly int x;
  1024. public MyStruct(int x) { this.x=x; }
  1025. public static MyStruct operator+(MyStruct a, MyStruct b)
  1026. {
  1027. return new MyStruct(a.x+b.x);
  1028. }
  1029. }
  1030. static void Main(string[] args)
  1031. {
  1032. int a=Static<int>.Add(1, 2);
  1033. uint b=Static<uint>.Add(1u, 2u);
  1034. long c=Static<long>.Add(1U, 2U);
  1035. MyStruct d = new MyStruct(1);
  1036. MyStruct e = new MyStruct(2);
  1037. MyStruct f=Static<MyStruct>.Add(d, e);
  1038. }
  1039. }
  1040.  
  1041.  
Success #stdin #stdout 0.07s 35128KB
stdin
Standard input is empty
stdout
Standard output is empty