root/trunk/src/semitwist/util/functional.d

Revision 202, 6.2 kB (checked in by Abscissa, 1 year ago)

(NB) all: Fixed: In D2, compile-time constants use the 'enum' abomination, not 'const'.

  • Property svn:eol-style set to native
Line 
1 // SemiTwist Library
2 // Written in the D programming language.
3
4 module semitwist.util.functional;
5
6 /+version(Unittest)+/ import std.stdio;
7
8 import semitwist.util.all;
9
10
11 //TODO: Think about new naming scheme. Take a look at how tango does it.
12 template makeDg2To1(string str, T)
13 {
14     enum makeDg2To1 = "("~T.stringof~" a, "~T.stringof~" b){ return ("~str~"); }";
15     //pragma(msg, "makeDg2To1: "~makeDg2To1);
16 }
17 template makeDg2To1(string str, T1, T2)
18 {
19     enum makeDg2To1 = "("~T1.stringof~" a, "~T2.stringof~" b){ return ("~str~"); }";
20     //pragma(msg, "makeDg2To1: "~makeDg2To1);
21 }
22
23 template makeDg1To1(string str, T)
24 {
25     enum makeDg1To1 = "("~T.stringof~" a){ return ("~str~"); }";
26     //pragma(msg, "makeDg1To1: "~makeDg1To1);
27 }
28
29 T reduce(T)(T[] list, T delegate(T a, T b) dg)
30 {
31     return list.length==0? T.init  :
32            list.length==1? list[0] :
33                            list[1..$].reduce(list[0], dg);
34 }
35
36 T reduce(T)(T[] list, T init, T delegate(T a, T b) dg)
37 {
38     T result = init;
39     foreach(T elem; list)
40         result = dg(result, elem);
41    
42     return result;
43 }
44
45 TOut reduceTo(TOut, TIn)(TIn[] list, TOut delegate(TOut a, TIn b) dg)
46 {
47     return list.length==0? TOut.init :
48                            list.reduceTo(TOut.init, dg);
49 }
50
51 TOut reduceTo(TOut, TIn)(TIn[] list, TOut init, TOut delegate(TOut a, TIn b) dg)
52 {
53     TOut result = init;
54     foreach(TIn elem; list)
55         result = dg(result, elem);
56    
57     return result;
58 }
59
60 T reduce(string dgstr, T)(T[] list)
61 {
62     return reduce(list, mixin(makeDg2To1!(dgstr, T)));
63 }
64
65 T reduce(string dgstr, T)(T[] list, T init)
66 {
67     return reduce(list, init, mixin(makeDg2To1!(dgstr, T)));
68 }
69
70 TOut reduceTo(TOut, string dgstr, TIn)(TIn[] list)
71 {
72     return reduceTo(list, mixin(makeDg2To1!(dgstr, TOut, TIn)));
73 }
74
75 TOut reduceTo(TOut, string dgstr, TIn)(TIn[] list, TOut init)
76 {
77     return reduceTo(list, init, mixin(makeDg2To1!(dgstr, TOut, TIn)));
78 }
79
80 TOut[] map(TOut, TIn)(TIn[] list, TOut delegate(TIn a) dg)
81 {
82     TOut[] result;
83     result.length = list.length;
84     foreach(size_t i, TIn elem; list)
85         result[i] = dg(elem);
86    
87     return result;
88 }
89
90 TOut[TKey] map(TOut, TIn, TKey)(TIn[TKey] list, TOut delegate(TIn a, TKey b) dg)
91 {
92     TOut[TKey] result;
93     foreach(TKey key, TIn elem; list)
94         result[key] = dg(elem, key);
95    
96     return result;
97 }
98
99 T[] mapAAtoA(T, TKey)(T[TKey] list, T delegate(T a, TKey b) dg)
100 {
101     return mapAAtoATo(list, dg);
102 }
103
104 TOut[] mapAAtoATo(TOut, TIn, TKey)(TIn[TKey] list, TOut delegate(TIn a, TKey b) dg)
105 {
106     size_t i=0;
107     TOut[] result;
108     result.length = list.length;
109     foreach(TKey key, TIn elem; list)
110     {
111         result[i] = dg(elem, key);
112         i++;
113     }
114    
115     return result;
116 }
117
118 T[] map(string dgstr, T)(T[] list)
119 {
120     return map(list, mixin(makeDg1To1!(dgstr, T)));
121 }
122
123 T[TKey] map(string dgstr, T, TKey)(T[TKey] list)
124 {
125     return map(list, mixin(makeDg2To1!(dgstr, T, TKey)));
126 }
127
128 TOut[] mapTo(TOut, string dgstr, TIn)(TIn[] list)
129 {
130     return map(list, mixin(makeDg1To1!(dgstr, TIn)));
131 }
132
133 TOut[TKey] mapTo(TOut, string dgstr, TIn, TKey)(TIn[TKey] list)
134 {
135     return map(list, mixin(makeDg2To1!(dgstr, TIn, TKey)));
136 }
137
138 T[] mapAAtoA(string dgstr, T, TKey)(T[TKey] list)
139 {
140     return mapAAtoA(list, mixin(makeDg2To1!(dgstr, T, TKey)));
141 }
142
143 TOut[] mapAAtoATo(TOut, string dgstr, TIn, TKey)(TIn[TKey] list)
144 {
145     return mapAAtoATo(list, mixin(makeDg2To1!(dgstr, TIn, TKey)));
146 }
147
148 /+T[] filter(T)(T[] list, bool delegate(T a) dg)
149 {
150     T[] result = list.dup;
151     auto numRemaining = result.removeIf((T a){return !dg(a);});
152     return result[0..numRemaining];
153 }
154
155 T[] filter(string dgstr, T)(T[] list)
156 {
157     return filter(list, mixin(makeDg1To1!(dgstr, T)));
158 }+/
159
160 //TODO: Make foreachWhile
161 //TODO: Make variant that also provides an index to the delegate
162 //TODO: Make variant for AA
163 /// Like foreach, except the body has a return value,
164 /// and the loop bails whenever that value != whileVal
165 TRet foreachWhileVal(TRet, TElem)(TElem[] coll, TRet whileVal, TRet delegate(TElem) dg)
166 {
167     foreach(TElem elem; coll)
168     {
169         auto ret = dg(elem);
170         if(ret != whileVal)
171             return ret;
172     }
173     return whileVal;
174 }
175
176 mixin(unittestSemiTwistDLib(q{
177     int[string] aa = ["a":1, "b":2, "c":3];
178     int[string] expected;
179     int[string] result;
180
181     mixin(deferEnsure!(`aa.keys`,   `_ == ["a","b","c"]`));
182
183     // Map
184     int[] array = [1, 2, 3, 4, 5];
185     mixin(deferEnsure!(`map(array, (int a){return a*10;})`, `_ == [10,20,30,40,50]`));
186     mixin(deferEnsure!(`map!("a*10")(array)`, `_ == [10,20,30,40,50]`));
187
188     // Map assoc array using dg literal
189     result = map(aa, (int a, string b){return a*10;});
190     // Workaround for DMD Bug #1671
191     //mixin(deferEnsure!(`result`, `_ == ['a':10,'b':20,'c':30]`));
192     mixin(deferEnsure!(`result.length`, `_ == 3`));
193     mixin(deferEnsure!(`result.keys`,   `_ == ["a","b","c"]`));
194     //mixin(traceVal!("result.keys", "result.keys.length"));
195     //mixin(traceVal!("result.keys[0]", "result.keys[1]", `result.keys[2]~""`));
196     mixin(deferEnsure!(`result.values`, `_ == [10,20,30]`));
197
198     // Map assoc array using dg string
199     result = map!(`a*10`)(aa);
200     mixin(deferEnsure!(`result.length`, `_ == 3`));
201     mixin(deferEnsure!(`result.keys`,   `_ == ["a","b","c"]`));
202     mixin(deferEnsure!(`result.values`, `_ == [10,20,30]`));
203
204     // mapAAtoA
205     mixin(deferEnsure!(`mapAAtoA(aa, (int a, string b){return a*10;})`, `_ == [10,20,30]`));
206     mixin(deferEnsure!(`mapAAtoA!("a*10")(aa)`, `_ == [10,20,30]`));
207
208     // mapAAtoA To
209     mixin(deferEnsure!(`mapAAtoATo(aa, (int a, string b){return a*10+0.5;})`, `_ == [10.5,20.5,30.5]`));
210     mixin(deferEnsure!(`mapAAtoATo!(double, "a*10+0.5")(aa)`, `_ == [10.5,20.5,30.5]`));
211        
212     // Reduce
213     mixin(deferEnsure!(`reduce(array, (int a, int b){return a*b;})`, `_ == (1*2*3*4*5)`));
214     mixin(deferEnsure!(`reduce!("a*b")(array)`, `_ == (1*2*3*4*5)`));
215    
216     // Reduce To
217     mixin(deferEnsure!(`reduceTo(array, (int[] a, int b){return a~(b*10);})`, `_ == [10,20,30,40,50]`));
218     mixin(deferEnsure!(`reduceTo!(int[], "a~(b*10)")(array)`, `_ == [10,20,30,40,50]`));
219    
220     // Reduce using initial value
221     mixin(deferEnsure!(`reduce(array, 10, (int a, int b){return a*b;})`, `_ == (10*1*2*3*4*5)`));
222     mixin(deferEnsure!(`reduce!("a*b")(array, 10)`, `_ == (10*1*2*3*4*5)`));
223    
224     // Reduce empty array
225     mixin(deferEnsure!(`reduce(cast(int[])[], (int a, int b){return a*b;})`, `_ == 0`));
226     mixin(deferEnsure!(`reduce!("a*b")(cast(int[])[])`, `_ == 0`));
227
228     //TODO: Reduce assoc array
229    
230     // Filter
231 /+  mixin(deferEnsure!(`filter(array, (int a){return (a%2)==0;})`, `_ == [2,4]`));
232     mixin(deferEnsure!(`filter!("(a%2)==0")(array)`, `_ == [2,4]`));
233 +/
234     //TODO: Filter assoc array
235    
236 }));
Note: See TracBrowser for help on using the browser.