1 /** 2 Module contains UniversalDelegate, usefull to change complicated delegates to void delegate(void) 3 */ 4 module mutils.job_manager.universal_delegate; 5 import std.traits:ReturnType,Parameters,isFunctionPointer,isDelegate,ParameterStorageClassTuple,ParameterStorageClass,AliasSeq; 6 7 auto makeUniversalDelegate(T,Args...)(T del,Args args){ 8 alias pstc = ParameterStorageClassTuple!T; 9 foreach(arg;pstc){ 10 static assert(arg!=ParameterStorageClass.ref_,"Delegates with ref parameters can not passed without specifying exact delegate type.\n Change from makeUniversalDelegate(&del) to makeUniversalDelegate!(typeof(&del)(&del)."); 11 } 12 return UniversalDelegate!(T)(del,args); 13 } 14 auto makeUniversalDelegate(T)(T del,Parameters!(T) args){ 15 return UniversalDelegate!(T)(del,args); 16 } 17 /** 18 Struct which stores all parameters for given delegate. 19 Mainly used to store delegate with patameters for future call. 20 May be used to convert: AnyType deletage(SomeTypes..) to void delegate() 21 22 Ref parameters are stored as a pointers 23 */ 24 struct UniversalDelegate(Delegate) 25 { 26 static assert(is(Delegate == function) || isFunctionPointer!Delegate || isDelegate!Delegate,"Provided type has to be: delegate, function, function pointer" ); 27 enum hasReturn=!is(ReturnType!Delegate==void); 28 Delegate deleg; 29 getDelegateArgumentsSave!Delegate argumentsSave;//for ref variables pointer is saved 30 static if(hasReturn)ReturnType!Delegate result; 31 32 this(Delegate del,Parameters!Delegate args){ 33 static assert(Parameters!(Delegate).length==args.length,"Parameters have to match" ); 34 alias pstc=ParameterStorageClassTuple!Delegate; 35 deleg=del; 36 foreach(i,ref a;args){ 37 static if(pstc[i] == ParameterStorageClass.ref_){ 38 argumentsSave[i]=&a; 39 }else{ 40 argumentsSave[i]=a; 41 } 42 } 43 } 44 45 void* getFuncPtr(){ 46 static if(is(Delegate == delegate)){ 47 return deleg.funcptr; 48 49 }else{ 50 return deleg; 51 52 } 53 } 54 55 ReturnType!Delegate call(){ 56 // Load arguments to orginal form 57 Parameters!Delegate argumentsTmp; 58 alias pstc=ParameterStorageClassTuple!Delegate; 59 foreach(i,a;argumentsSave){ 60 static if(pstc[i] == ParameterStorageClass.ref_){ 61 argumentsTmp[i]=*a; 62 }else{ 63 argumentsTmp[i]=a; 64 } 65 } 66 // Call 67 static if(hasReturn){ 68 ReturnType!Delegate result=deleg(argumentsTmp); 69 }else{ 70 deleg(argumentsTmp); 71 } 72 // Assign ref values to theirs orginal location 73 foreach(i,a;argumentsSave){ 74 static if(pstc[i] == ParameterStorageClass.ref_){ 75 *a=argumentsTmp[i]; 76 } 77 } 78 static if(hasReturn)return result; 79 } 80 81 void callAndSaveReturn(){ 82 static if(hasReturn){ 83 result=call(); 84 }else{ 85 call(); 86 } 87 } 88 } 89 90 template getPointer(T){ 91 alias getPointer = T*; 92 } 93 94 ///Replaces ref variables with pointer 95 private template getDelegateArgumentsSave(Delegate){ 96 alias getDelegateArgumentsSave=getDelegateArgumentsSaveImpl!(ParameterStorageClassTuple!Delegate,Parameters!Delegate).result; 97 } 98 private template getDelegateArgumentsSaveImpl(args...) 99 if(args.length%2==0) 100 { 101 enum half=args.length/2; 102 alias pstc = args[0 .. half]; 103 alias tuple = args[half .. $]; 104 105 static if (tuple.length) 106 { 107 alias head = tuple[0]; 108 alias tail = tuple[1 .. $]; 109 alias next = getDelegateArgumentsSaveImpl!(AliasSeq!(pstc[1..$],tuple[1..$])).result; 110 static if (pstc[0] == ParameterStorageClass.ref_) 111 alias result = AliasSeq!(getPointer!head, next); 112 else 113 alias result = AliasSeq!(head, next); 114 } 115 else 116 { 117 alias result = AliasSeq!(); 118 } 119 } 120 121 @nogc nothrow: 122 /// Using Deleagte 123 unittest { 124 static struct TestTmp{ 125 @nogc nothrow int add(int a,int b,ref ulong result) { 126 result=a+b; 127 return a+b; 128 } 129 } 130 TestTmp test; 131 ulong returnByRef; 132 auto universalDelegate=makeUniversalDelegate!(typeof(&test.add))(&test.add,2,2,returnByRef); 133 auto result=universalDelegate.call(); 134 assert(result==4); 135 assert(returnByRef==4); 136 137 } 138 139 /// Using Function 140 unittest { 141 @nogc nothrow int add(int a,int b,ref ulong result) { 142 result=a+b; 143 return a+b; 144 } 145 ulong returnByRef; 146 auto universalDelegate=makeUniversalDelegate!(typeof(&add))(&add,2,2,returnByRef); 147 auto result=universalDelegate.call(); 148 assert(result==4); 149 assert(returnByRef==4); 150 } 151 // void with no parameters 152 unittest { 153 static int someNum; 154 static @nogc nothrow void add() { 155 someNum=200; 156 } 157 auto universalDelegate=makeUniversalDelegate!(typeof(&add))(&add); 158 universalDelegate.call(); 159 assert(someNum==200); 160 }