1 /**
2 * ae.utils.meta.chain
3 *
4 * License:
5 * This Source Code Form is subject to the terms of
6 * the Mozilla Public License, v. 2.0. If a copy of
7 * the MPL was not distributed with this file, You
8 * can obtain one at http://mozilla.org/MPL/2.0/.
9 *
10 * Authors:
11 * Vladimir Panteleev <ae@cy.md>
12 */
13
14 /// Chains are a concept a bit like ranges,
15 /// but which operate on heterogeneous types
16 /// (e.g. a tuple of values).
17
18 /// Composition is done by a chain of functors.
19 /// To allow state, each functor can be represented
20 /// as a struct.
21
22 /// Functors return a bool (true if iteration should
23 /// stop, false if it should continue).
24
25 deprecated("Use ae.utils.meta.tuplerange")
26 module ae.utils.meta.chain;
27
28 import ae.utils.meta.caps;
29
30 ///
31 static if (haveAliasStructBinding)
32 debug(ae_unittest) unittest
33 {
34 int a = 2;
35 int x;
36 chainIterator(chainFilter!(n => n > a)((int n) { x = n; return true; } ))(1, 2, 3);
37 assert(x == 3);
38 }
39
40 static if (haveAliasStructBinding)
41 debug(ae_unittest) unittest
42 {
43 static struct X
44 {
45 bool fun(int x)
46 {
47 return chainIterator(chainFunctor!(n => n == x))(this.tupleof);
48 }
49
50 long a;
51 int b;
52 ubyte c;
53 }
54
55 X x;
56 assert(!x.fun(5));
57 x.c = 5;
58 assert(x.fun(5));
59 }
60
61 /// Starts the chain by iterating over a tuple.
62 struct ChainIterator(Next)
63 {
64 Next next; ///
65
66 this(ref Next next)
67 {
68 this.next = next;
69 } ///
70
71 bool opCall(Args...)(auto ref Args args)
72 {
73 foreach (ref arg; args)
74 if (next(arg))
75 return true;
76 return false;
77 } ///
78 }
79 auto chainIterator(Next)(Next next)
80 {
81 return ChainIterator!Next(next);
82 } /// ditto
83
84 debug(ae_unittest) unittest
85 {
86 struct S
87 {
88 int a = 1;
89 long b = 2;
90 ubyte c = 3;
91 }
92 S s;
93
94 int[] results;
95 chainIterator((long n) { results ~= cast(int)n; return false; })(s.tupleof);
96 assert(results == [1, 2, 3]);
97 }
98
99 /// Wraps a function template into a concrete value type functor.
100 struct ChainFunctor(alias fun)
101 {
102 auto opCall(Arg)(auto ref Arg arg)
103 {
104 return fun(arg);
105 } ///
106 }
107 auto chainFunctor(alias fun)()
108 {
109 ChainFunctor!fun s;
110 return s;
111 } /// ditto
112
113 ///
114 static if (haveAliasStructBinding)
115 debug(ae_unittest) unittest
116 {
117 int[] results;
118 auto fn = chainFunctor!(n => results ~= cast(int)n);
119 fn(1);
120 fn(long(2));
121 fn(ubyte(3));
122 assert(results == [1, 2, 3]);
123 }
124
125 /// Calls next only if pred(value) is true.
126 struct ChainFilter(alias pred, Next)
127 {
128 Next next; ///
129
130 this(Next next) { this.next = next; } ///
131
132 bool opCall(T)(auto ref T v)
133 {
134 if (pred(v))
135 return next(v);
136 return false;
137 } ///
138 }
139 template chainFilter(alias pred)
140 {
141 auto chainFilter(Next)(Next next)
142 {
143 return ChainFilter!(pred, Next)(next);
144 }
145 } /// ditto
146
147 /// Iteration control.
148 struct ChainControl(bool result, Next)
149 {
150 Next next; ///
151
152 this(Next next) { this.next = next; } ///
153
154 bool opCall(T)(auto ref T v)
155 {
156 cast(void)next(v);
157 return result;
158 } ///
159 }
160 template chainControl(bool result)
161 {
162 auto chainControl(Next)(Next next)
163 {
164 return ChainControl!(result, Next)(next);
165 }
166 } ///
167 alias chainAll = chainControl!false; /// Always continue iteration
168 alias chainFirst = chainControl!true; /// Stop iteration after this element
169
170 ///
171 static if (haveAliasStructBinding)
172 debug(ae_unittest) unittest
173 {
174 int a = 2;
175 int b = 3;
176 int[] results;
177 foreach (i; 0..10)
178 chainFilter!(n => n % a == 0)(
179 chainFilter!(n => n % b == 0)(
180 (int n) { results ~= n; return false; }))(i);
181 assert(results == [0, 6]);
182 }
183
184 /// Calls next with pred(value).
185 struct ChainMap(alias pred, Next)
186 {
187 Next next; ///
188
189 this(Next next) { this.next = next; } ///
190
191 bool opCall(T)(auto ref T v)
192 {
193 return next(pred(v));
194 } ///
195 }
196 template chainMap(alias pred)
197 {
198 auto chainMap(Next)(Next next)
199 {
200 return ChainMap!(pred, Next)(next);
201 }
202 } /// ditto
203
204 ///
205 debug(ae_unittest) unittest
206 {
207 int result;
208 chainMap!(n => n+1)(chainMap!(n => n * 2)((int n) { result = n; return false; }))(2);
209 assert(result == 6);
210 }