1 /**
2  * Tuple ranges
3  *
4  * Contains constructs for iterating and chaining together operations
5  * on range-like constructs which operate on heterogeneous types.
6  *
7  * To allow heterogeneous elements, iteration is internal rather than
8  * external.  The range elements are functors - calling a range with
9  * a function parameter "next" asks the range to iterate over its
10  * members and call "next" over each one.  "next" returns a bool
11  * (true if iteration should stop, false if it should continue),
12  * which is propagated by the range's opCall upwards.
13  *
14  * License:
15  *   This Source Code Form is subject to the terms of
16  *   the Mozilla Public License, v. 2.0. If a copy of
17  *   the MPL was not distributed with this file, You
18  *   can obtain one at http://mozilla.org/MPL/2.0/.
19  *
20  * Authors:
21  *   Vladimir Panteleev <vladimir@thecybershadow.net>
22  */
23 
24 module ae.utils.meta.tuplerange;
25 
26 ///
27 unittest
28 {
29 	int a = 2;
30 	int offset = 1;
31 	int x;
32 	trOnly(0, 1., 2f)
33 		.trMap!(n => n + offset)
34 		.trFilter!(n => n > a)
35 		.trEach!((n) { x = cast(int)n; } );
36 	assert(x == 3);
37 }
38 
39 import std.meta;
40 
41 import ae.utils.meta.caps;
42 
43 unittest
44 {
45 	static struct X
46 	{
47 		bool fun(int x)
48 		{
49 			return this.tupleof
50 				.trOnly
51 				.trEach!(n => n == x);
52 		}
53 
54 		long a;
55 		int b;
56 		ubyte c;
57 	}
58 
59 	X x;
60 	assert(!x.fun(5));
61 	x.c = 5;
62 	assert(x.fun(5));
63 }
64 
65 /// Source, iterates over the given values.
66 auto trOnly(T...)(ref return T values)
67 {
68 	alias PointerTo(T) = T*;
69 	alias P = staticMap!(PointerTo, T);
70 	struct Result
71 	{
72 		P values; this(P values) { this.values = values; }
73 		bool opCall(Next)(Next next)
74 		{
75 			foreach (ref value; values)
76 				if (next(*value))
77 					return true;
78 			return false;
79 		}
80 	}
81 	P pvalues;
82 	foreach (i, ref value; values)
83 		pvalues[i] = &value;
84 	return Result(pvalues);
85 }
86 
87 auto trOnly(T...)(T values) /// ditto
88 {
89 	static struct Result
90 	{
91 		T values; this(T values) { this.values = values; }
92 		
93 		bool opCall(Next)(Next next)
94 		{
95 			foreach (ref value; values)
96 				if (next(value))
97 					return true;
98 			return false;
99 		}
100 	}
101 	return Result(values);
102 }
103 
104 unittest
105 {
106 	static int fun()
107 	{
108 		int a = 2;
109 		int offset = 1;
110 		int x;
111 		trOnly(0, 1., 2f)
112 			.trMap!(n => n + offset)
113 			.trFilter!(n => n > a)
114 			.trEach!((n) { x = cast(int)n; } );
115 		return x;
116 	}
117 	static assert(fun() == 3);
118 }
119 
120 unittest
121 {
122 	static int fun()
123 	{
124 		int a = 2;
125 		int offset = 1;
126 		int result;
127 		int x = 0; double y = 1.; float z = 2f;
128 		trOnly(x, y, z)
129 			.trMap!(n => n + offset)
130 			.trFilter!(n => n > a)
131 			.trEach!((n) { result = cast(int)n; } );
132 		return result;
133 	}
134 	static assert(fun() == 3);
135 }
136 
137 unittest
138 {
139 	struct S
140 	{
141 		int a = 1;
142 		long b = 2;
143 		ubyte c = 3;
144 	}
145 	S s;
146 
147 	int[] results;
148 	s.tupleof
149 		.trOnly
150 		.trEach!((long n) { results ~= cast(int)n; });
151 	assert(results == [1, 2, 3]);
152 }
153 
154 /// Passes only values satisfying the given predicate to the next
155 /// layer.
156 auto trFilter(alias pred, R)(auto ref R r)
157 {
158 	struct Result
159 	{
160 		R r; this(R r) { this.r = r; }
161 
162 		bool opCall(Next)(Next next)
163 		{
164 			struct Handler
165 			{
166 				bool opCall(T)(auto ref T value)
167 				{
168 					if (!pred(value))
169 						return false; // keep going
170 					return next(value);
171 				}
172 			}
173 			Handler handler;
174 			return r(handler);
175 		}
176 	}
177 	return Result(r);
178 }
179 
180 ///
181 unittest
182 {
183 	int a = 2;
184 	int b = 3;
185 	int[] results;
186 	foreach (i; 0..10)
187 		(i)
188 			.trOnly
189 			.trFilter!(n => n % a == 0)
190 			.trFilter!(n => n % b == 0)
191 			.trEach!((int n) { results ~= n; });
192 	assert(results == [0, 6]);
193 }
194 
195 /// Like trFilter, but evaluates pred at compile-time with each
196 /// element's type.
197 auto trCTFilter(alias pred, R)(auto ref R r)
198 {
199 	struct Result
200 	{
201 		R r; this(R r) { this.r = r; }
202 
203 		bool opCall(Next)(Next next)
204 		{
205 			struct Handler
206 			{
207 				bool opCall(T)(auto ref T value)
208 				{
209 					static if (!pred!T)
210 						return false; // keep going
211 					else
212 						return next(value);
213 				}
214 			}
215 			Handler handler;
216 			return r(handler);
217 		}
218 	}
219 	return Result(r);
220 }
221 
222 ///
223 unittest
224 {
225 	enum isNumeric(T) = is(typeof(cast(int)T.init));
226 	int[] results;
227 	trOnly(1, 2., "3", '\x04')
228 		.trCTFilter!isNumeric
229 		.trEach!((n) { results ~= cast(int)n; });
230 	assert(results == [1, 2, 4]);
231 }
232 
233 /// Transforms values using the given predicate before passing them to
234 /// the next layer.
235 auto trMap(alias pred, R)(auto ref R r)
236 {
237 	struct Result
238 	{
239 		R r; this(R r) { this.r = r; }
240 
241 		bool opCall(Next)(Next next)
242 		{
243 			struct Handler
244 			{
245 				bool opCall(T)(auto ref T value)
246 				{
247 					return next(pred(value));
248 				}
249 			}
250 			Handler handler;
251 			return r(handler);
252 		}
253 	}
254 	return Result(r);
255 }
256 
257 ///
258 unittest
259 {
260 	int result;
261 	(2)
262 		.trOnly
263 		.trMap!(n => n+1)
264 		.trMap!(n => n * 2)
265 		.trEach!((int n) { result = n; });
266 	assert(result == 6);
267 }
268 
269 /// Sink, calls predicate over each value in r.
270 /// If predicate returns a boolean, use that to determine whether to
271 /// stop or keep going.
272 auto trEach(alias pred, R)(auto ref R r)
273 {
274 	struct Handler
275 	{
276 		bool opCall(T)(auto ref T value)
277 		{
278 			alias R = typeof(pred(value));
279 			static if (is(R == bool))
280 				return pred(value);
281 			else
282 			static if (is(R == void))
283 			{
284 				pred(value);
285 				return false; // keep going
286 			}
287 			else
288 				static assert(false);
289 		}
290 	}
291 	Handler handler;
292 	return r(handler);
293 }
294 
295 /// Calls predicate with only the first value in r.
296 auto trFront(alias pred, R)(auto ref R r)
297 {
298 	struct Handler
299 	{
300 		bool opCall(T)(auto ref T value)
301 		{
302 			pred(value);
303 			return true;
304 		}
305 	}
306 	Handler handler;
307 	return r(handler);
308 }
309 
310 /// r is a tuple range of tuple ranges.
311 /// Process it as one big range.
312 auto trJoiner(R)(auto ref R r)
313 {
314 	struct Result
315 	{
316 		R r; this(R r) { this.r = r; }
317 
318 		bool opCall(Next)(Next next)
319 		{
320 			struct Handler
321 			{
322 				bool opCall(T)(auto ref T value)
323 				{
324 					return value(next);
325 				}
326 			}
327 			Handler handler;
328 			return r(handler);
329 		}
330 	}
331 	return Result(r);
332 }
333 
334 unittest
335 {
336 	int[] values;
337 	trOnly(
338 		trOnly(1, 2f),
339 		trOnly(3.0, '\x04'),
340 	)
341 		.trJoiner
342 		.trEach!((n) { values ~= cast(int)n; });
343 	assert(values == [1, 2, 3, 4]);
344 }
345 
346 /// Convert a regular (homogeneous) range to a tuple range.
347 auto trIter(R)(auto ref R r)
348 {
349 	struct Result
350 	{
351 		R r; this(R r) { this.r = r; }
352 
353 		bool opCall(Next)(Next next)
354 		{
355 			foreach (ref e; r)
356 				if (next(e))
357 					return true;
358 			return false;
359 		}
360 	}
361 	return Result(r);
362 }
363 
364 unittest
365 {
366 	int[] values;
367 	trOnly(
368 		[1., 2.].trIter,
369 		['\x03', '\x04'].trIter,
370 	)
371 		.trJoiner
372 		.trEach!((n) { values ~= cast(int)n; });
373 	assert(values == [1, 2, 3, 4]);
374 	
375 }