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 <ae@cy.md>
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 /// ditto
88 auto trOnly(T...)(T values)
89 {
90 	static struct Result
91 	{
92 		T values; this(T values) { this.values = values; }
93 		
94 		bool opCall(Next)(Next next)
95 		{
96 			foreach (ref value; values)
97 				if (next(value))
98 					return true;
99 			return false;
100 		}
101 	}
102 	return Result(values);
103 }
104 
105 unittest
106 {
107 	static int fun()
108 	{
109 		int a = 2;
110 		int offset = 1;
111 		int x;
112 		trOnly(0, 1., 2f)
113 			.trMap!(n => n + offset)
114 			.trFilter!(n => n > a)
115 			.trEach!((n) { x = cast(int)n; } );
116 		return x;
117 	}
118 	static assert(fun() == 3);
119 }
120 
121 unittest
122 {
123 	static int fun()
124 	{
125 		int a = 2;
126 		int offset = 1;
127 		int result;
128 		int x = 0; double y = 1.; float z = 2f;
129 		trOnly(x, y, z)
130 			.trMap!(n => n + offset)
131 			.trFilter!(n => n > a)
132 			.trEach!((n) { result = cast(int)n; } );
133 		return result;
134 	}
135 	static assert(fun() == 3);
136 }
137 
138 unittest
139 {
140 	struct S
141 	{
142 		int a = 1;
143 		long b = 2;
144 		ubyte c = 3;
145 	}
146 	S s;
147 
148 	int[] results;
149 	s.tupleof
150 		.trOnly
151 		.trEach!((long n) { results ~= cast(int)n; });
152 	assert(results == [1, 2, 3]);
153 }
154 
155 /// Passes only values satisfying the given predicate to the next
156 /// layer.
157 auto trFilter(alias pred, R)(auto ref R r)
158 {
159 	struct Result
160 	{
161 		R r; this(R r) { this.r = r; }
162 
163 		bool opCall(Next)(Next next)
164 		{
165 			struct Handler
166 			{
167 				bool opCall(T)(auto ref T value)
168 				{
169 					if (!pred(value))
170 						return false; // keep going
171 					return next(value);
172 				}
173 			}
174 			Handler handler;
175 			return r(handler);
176 		}
177 	}
178 	return Result(r);
179 }
180 
181 ///
182 unittest
183 {
184 	int a = 2;
185 	int b = 3;
186 	int[] results;
187 	foreach (i; 0..10)
188 		(i)
189 			.trOnly
190 			.trFilter!(n => n % a == 0)
191 			.trFilter!(n => n % b == 0)
192 			.trEach!((int n) { results ~= n; });
193 	assert(results == [0, 6]);
194 }
195 
196 /// Like trFilter, but evaluates pred at compile-time with each
197 /// element's type.
198 auto trCTFilter(alias pred, R)(auto ref R r)
199 {
200 	struct Result
201 	{
202 		R r; this(R r) { this.r = r; }
203 
204 		bool opCall(Next)(Next next)
205 		{
206 			struct Handler
207 			{
208 				bool opCall(T)(auto ref T value)
209 				{
210 					static if (!pred!T)
211 						return false; // keep going
212 					else
213 						return next(value);
214 				}
215 			}
216 			Handler handler;
217 			return r(handler);
218 		}
219 	}
220 	return Result(r);
221 }
222 
223 ///
224 unittest
225 {
226 	enum isNumeric(T) = is(typeof(cast(int)T.init));
227 	int[] results;
228 	trOnly(1, 2., "3", '\x04')
229 		.trCTFilter!isNumeric
230 		.trEach!((n) { results ~= cast(int)n; });
231 	assert(results == [1, 2, 4]);
232 }
233 
234 /// Transforms values using the given predicate before passing them to
235 /// the next layer.
236 auto trMap(alias pred, R)(auto ref R r)
237 {
238 	struct Result
239 	{
240 		R r; this(R r) { this.r = r; }
241 
242 		bool opCall(Next)(Next next)
243 		{
244 			struct Handler
245 			{
246 				bool opCall(T)(auto ref T value)
247 				{
248 					return next(pred(value));
249 				}
250 			}
251 			Handler handler;
252 			return r(handler);
253 		}
254 	}
255 	return Result(r);
256 }
257 
258 ///
259 unittest
260 {
261 	int result;
262 	(2)
263 		.trOnly
264 		.trMap!(n => n+1)
265 		.trMap!(n => n * 2)
266 		.trEach!((int n) { result = n; });
267 	assert(result == 6);
268 }
269 
270 /// Sink, calls predicate over each value in r.
271 /// If predicate returns a boolean, use that to determine whether to
272 /// stop or keep going.
273 auto trEach(alias pred, R)(auto ref R r)
274 {
275 	struct Handler
276 	{
277 		bool opCall(T)(auto ref T value)
278 		{
279 			alias R = typeof(pred(value));
280 			static if (is(R == bool))
281 				return pred(value);
282 			else
283 			static if (is(R == void))
284 			{
285 				pred(value);
286 				return false; // keep going
287 			}
288 			else
289 				static assert(false);
290 		}
291 	}
292 	Handler handler;
293 	return r(handler);
294 }
295 
296 /// Calls predicate with only the first value in r.
297 auto trFront(alias pred, R)(auto ref R r)
298 {
299 	struct Handler
300 	{
301 		bool opCall(T)(auto ref T value)
302 		{
303 			pred(value);
304 			return true;
305 		}
306 	}
307 	Handler handler;
308 	return r(handler);
309 }
310 
311 /// r is a tuple range of tuple ranges.
312 /// Process it as one big range.
313 auto trJoiner(R)(auto ref R r)
314 {
315 	struct Result
316 	{
317 		R r; this(R r) { this.r = r; }
318 
319 		bool opCall(Next)(Next next)
320 		{
321 			struct Handler
322 			{
323 				bool opCall(T)(auto ref T value)
324 				{
325 					return value(next);
326 				}
327 			}
328 			Handler handler;
329 			return r(handler);
330 		}
331 	}
332 	return Result(r);
333 }
334 
335 unittest
336 {
337 	int[] values;
338 	trOnly(
339 		trOnly(1, 2f),
340 		trOnly(3.0, '\x04'),
341 	)
342 		.trJoiner
343 		.trEach!((n) { values ~= cast(int)n; });
344 	assert(values == [1, 2, 3, 4]);
345 }
346 
347 /// Convert a regular (homogeneous) range to a tuple range.
348 auto trIter(R)(auto ref R r)
349 {
350 	struct Result
351 	{
352 		R r; this(R r) { this.r = r; }
353 
354 		bool opCall(Next)(Next next)
355 		{
356 			foreach (ref e; r)
357 				if (next(e))
358 					return true;
359 			return false;
360 		}
361 	}
362 	return Result(r);
363 }
364 
365 unittest
366 {
367 	int[] values;
368 	trOnly(
369 		[1., 2.].trIter,
370 		['\x03', '\x04'].trIter,
371 	)
372 		.trJoiner
373 		.trEach!((n) { values ~= cast(int)n; });
374 	assert(values == [1, 2, 3, 4]);
375 	
376 }