root/trunk/arg_bind/bind.d

Revision 35, 6.4 kB (checked in by BCS, 7 years ago)

fixed bug in For!().Args!().Become!()
added With!().Args!().Becomes!() as a runtime curry form of the older code
this templates on a function type and the args to curry, the resulting function takes a function of the given type and the values of the curried args and returns a delegate for the curried function

Line 
1 template T(t...){alias t T;}
2
3 template For(alias fn)   // the function to replace the arges with
4 {
5             // make shure fn is a function and get it's args list
6     static if(
7         is(typeof(fn) arg == function) &&
8         is(typeof(fn) R   == return)
9         )
10     {
11         template Args(A...)       // the 0 based indices of the args to replace
12         {
13                 // generate an args list without the given args removed
14             alias Remove!(A).From!(arg) pArgs;
15
16                 // V is the value to replace the args with
17             R Become(V...)(pArgs p)
18             {
19                     // the new function
20
21                 static assert(A.length == V.length);
22                     // genate an index list of the args that remain
23                 static const uint vl = arg.length;
24                 alias Remove!(A).From!(range!(0,vl-1)) map;
25
26                 arg set;
27                     // set constant args
28                 foreach(uint i, uint v; A)
29                 {
30                     set[A[i]] = V[i];
31                 }
32
33                     // copy args from this function's args
34                 foreach(uint i, uint v; map)
35                 {
36                     set[map[i]] = p[i];
37                 }
38
39                     // call and return
40                 return fn(set);
41             }
42         }
43     }
44     else
45         static assert(false);
46 }
47
48 template With(T)   // the function to replace the arges with
49 {
50             // make shure fn is a function and get it's args list
51     static if(
52         is(T arg == function) &&
53         is(T R   == return)
54         )
55     {
56         template Args(A...)       // the 0 based indices of the args to replace
57         {
58                 // generate an args list without the given args removed
59             alias Select!(A).From!(arg) cArgs;
60             alias Remove!(A).From!(arg) rArgs;
61
62                 // V is the value to replace the args with
63             R delegate(rArgs) Become(T* fn, cArgs c)
64             {
65                 struct Ret
66                 {
67                     cArgs ca;
68                     T* fn;
69
70                     R ret(rArgs v)
71                     {
72                         arg set;
73
74                             // set constant args
75                         foreach(uint i, uint _; A)
76                         {
77                             set[A[i]] = ca[i];
78                         }
79
80                             // copy args from this function's args
81
82                             // genate an index list of the args that remain
83                         static const uint vl = arg.length;
84                         alias Remove!(A).From!(range!(0,vl-1)) map;
85                         foreach(uint i, uint _; map)
86                         {
87                             set[map[i]] = v[i];
88                         }
89
90                             // call and return
91                         return fn(set);
92                     }
93                 }
94                     // the new function
95                 Ret* ret = new Ret;
96                     // set constant args
97                 foreach(uint i, uint _; A)
98                 {
99                     ret.ca[i] = c[i];
100                 }
101                 ret.fn = fn;
102                 return &ret.ret;
103             }
104         }
105     }
106     else
107         static assert(false);
108 }
109
110 // return true if A[0] is in A[1..$], return false if A.length == 1 or otherwise
111 template isIn(A...)
112 {
113     static assert(A.length != 0);
114
115     static if(A.length == 1)
116         const bool isIn = false;
117     else
118     {
119         static if(A[0] == A[$-1])
120             const bool isIn = true;
121         else
122             const bool isIn = isIn!(A[0], A[1..$-1]);
123     }
124 }
125 static assert(!isIn!(1,2,3,4,5,6));
126 static assert(isIn!(2,2,3,4,5,6));
127 static assert(isIn!(4,2,3,4,5,6));
128 static assert(isIn!(6,2,3,4,5,6));
129 static assert(!isIn!(6));
130
131
132 template Remove(R...)      // 0 based indices of the Tuple parts to remove
133 {
134     template From(A...)    // the tuple to remove stuff from
135     {
136         static if(A.length != 0)
137         {
138             static if(isIn!(A.length-1, R))
139             {
140                 alias From!(A[0..$-1]) From;
141             }
142             else
143             {
144                 alias T!(From!(A[0..$-1]), A[$-1]) From;
145             }
146         }
147         else
148         {
149             alias T!() From;
150         }
151     }
152 }
153 alias Remove!(1,3,5).From!(ubyte,byte,ushort,short,uint,int) remove;
154 static assert(remove.length == 3, "lenght is: "~cast(char)('0' + remove.length));
155 static assert(is(remove[0] == ubyte));
156 static assert(is(remove[1] == ushort));
157 static assert(is(remove[2] == uint));
158
159 template Select(R...)      // 0 based indes the the Tuple parts to remove
160 {
161     template From(A...)    // the tuple to remove stuff from
162     {
163         static if(A.length != 0)
164         {
165             static if(isIn!(A.length-1, R))
166             {
167                 alias T!(From!(A[0..$-1]), A[$-1]) From;
168             }
169             else
170             {
171                 alias From!(A[0..$-1]) From;
172             }
173         }
174         else
175         {
176             alias T!() From;
177         }
178     }
179 }
180 alias Select!(1,3,5).From!(ubyte,byte,ushort,short,uint,int) select;
181 static assert(select.length == 3, "lenght is: "~cast(char)('0' + select.length));
182 static assert(is(select[0] == byte));
183 static assert(is(select[1] == short));
184 static assert(is(select[2] == int));
185
186 // return a tuple with ints from start to stop
187 template range(int start, int stop, A...)
188 {
189     static if(start >= stop)
190         alias T!(A,start) range;
191     else
192         alias range!(start+1, stop, A, start) range;
193 }
194 alias range!(0,5) r;
195 static assert(r.length == 6);
196 static assert(r[0] == 0);
197 static assert(r[$-1] == 5);
198
199
200 //void main(){}
201
202 private const bool output = false;
203 static if(output) { import std.stdio; }
204 unittest
205 {
206         // set up some locals
207     const float fc = 3.1415;
208     static int that_s = 2;
209     static char has_s = '\0';
210     static bool lots_s = false;
211     static int[] of_s = [9,8,7,6,5];
212     static float args_s = fc;
213
214         // this function sets the locals from the args
215     static int fnc(int that, char has, bool lots, int[] of, float args)
216     {
217         static if(output) writef("%s,\t%s,\t%s,\t%s,\t%s\n",that_s,has_s,lots_s,of_s,args_s);
218
219         that_s = that;
220         has_s = has;
221         lots_s = lots;
222         of_s = of;
223         args_s = args;
224
225         static if(output) writef("%s,\t%s,\t%s,\t%s,\t%s\n",that_s,has_s,lots_s,of_s,args_s);
226         return 0;
227     }
228
229         // bind some args
230     alias For!(fnc).
231           Args!  (0,2,   4).
232           Become!(1,true,1e7) fn2;
233
234         // test that stuff is what is expected
235     assert(that_s == 2,         "error");
236     assert(has_s == '\0',       "error");
237     assert(lots_s == false,     "error");
238     assert(of_s == [9,8,7,6,5], "error");
239     assert(args_s == fc,    "error");
240
241         // try the function
242     fn2('c', [1,2,3]);
243
244         // test that stuff is changed
245     assert(that_s == 1,       "error");
246     assert(has_s  == 'c',     "error");
247     assert(lots_s == true,    "error");
248     assert(of_s[] == [1,2,3], "error");
249     assert(args_s == 1e7,     "error");
250
251     that_s = 2;
252     has_s = '\0';
253     lots_s = false;
254     of_s = [9,8,7,6,5];
255     args_s = 3.1415;
256
257     auto rt = With!(typeof(fnc)).
258           Args!      (0,2,   4).
259           Become(&fnc,1,true,1e7);
260
261         // test that stuff is what is expected
262     assert(that_s == 2,         "error");
263     assert(has_s == '\0',       "error");
264     assert(lots_s == false,     "error");
265     assert(of_s == [9,8,7,6,5], "error");
266     assert(args_s == fc,    "error");
267
268         // try the function
269     rt('c', [1,2,3]);
270
271         // test that stuff is changed
272     assert(that_s == 1,       "error");
273     assert(has_s  == 'c',     "error");
274     assert(lots_s == true,    "error");
275     assert(of_s[] == [1,2,3], "error");
276     assert(args_s == 1e7,     "error");
277
278
279 }
Note: See TracBrowser for help on using the browser.