1 /** Various stuff for working with generic tuples.
2 
3 A replacement for $(STDMODULE typetuple).
4 
5 The following symbols from $(D std.typetuple) are publicly imported:
6 $(UL
7 	$(LI $(STDREF typetuple, staticIndexOf))
8 	$(LI $(STDREF typetuple, NoDuplicates))
9 	$(LI $(STDREF typetuple, MostDerived))
10 	$(LI $(STDREF typetuple, DerivedToFront))
11 )
12 The following symbols from $(D std.typetuple) are superseded:
13 $(UL
14 	$(LI $(STDREF typetuple, Reverse), use $(MREF RetroTuple) instead)
15 	$(LI $(STDREF typetuple, EraseAll), use $(MREF FilterTuple) instead)
16 	$(LI $(STDREF typetuple, ReplaceAll), use $(MREF MapTuple) instead)
17 	$(LI $(STDREF typetuple, staticMap), use $(MREF MapTuple) instead)
18 	$(LI $(STDREF typetuple, anySatisfy), use $(MREF anyTuple) instead)
19 	$(LI $(STDREF typetuple, allSatisfy), use $(MREF allTuple) instead)
20 )
21 The following symbols from $(D std.typetuple) are considered useless:
22 $(UL
23 	$(LI $(STDREF typetuple, Erase))
24 	$(LI $(STDREF typetuple, Replace))
25 )
26 $(BOOKTABLE Generic tuple manipulation functions,
27 	$(TR $(TH Category) $(TH Functions))
28 	$(TR $(TD Searching)
29 		$(TD
30 			$(BTREF anyTuple)
31 			$(BTREF allTuple)
32 		)
33 	)
34 	$(TR $(TD Creation)
35 		$(TD
36 			$(BTREF RetroTuple)
37 			$(BTREF StrideTuple)
38 			$(BTREF ChainTuple)
39 			$(BTREF RoundRobinTuple)
40 			$(BTREF RadialTuple)
41 			$(BTREF RepeatTuple)
42 			$(BTREF ZipTuple)
43 			$(BTREF iotaTuple)
44 			$(BTREF IndexedTuple)
45 			$(BTREF ChunksTuple)
46 		)
47 	)
48 	$(TR $(TD Comparison)
49 		$(TD
50 			$(BTREF cmpTuple)
51 			$(BTREF equalTuple)
52 		)
53 	)
54 	$(TR $(TD Iteration)
55 		$(TD
56 			$(BTREF FilterTuple)
57 			$(BTREF groupTuple)
58 			$(BTREF JoinTuple)
59 			$(BTREF MapTuple)
60 			$(BTREF ReduceTuple)
61 			$(BTREF UniqTuple)
62 		)
63 	)
64 )
65 
66 Macros:
67 BTREF = $(MREF $0)  
68 
69 Copyright: Denis Shelomovskij 2011-2012
70 
71 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
72 
73 Authors: Denis Shelomovskij
74 */
75 module unstd.generictuple;
76 
77 
78 public import std.typetuple:
79 	staticIndexOf,
80 	NoDuplicates,
81 	MostDerived, DerivedToFront;
82 
83 import std.ascii: isDigit;
84 import std.algorithm: min, max;
85 import std.range: StoppingPolicy;
86 import unstd.traits;
87 import unstd.templates;
88 
89 
90 // Note: unittests often can't be used as examples in this module as
91 // there is no way to place such examples before "Analog..." comment.
92 
93 /**
94 Creates a generic tuple out of a sequence of zero or more types, expressions, or aliases.
95 */
96 alias GenericTuple(Args...) = Args;
97 
98 ///
99 unittest
100 {
101 	alias MyTemplate(T) = T[];
102 
103 	alias MyTuple = GenericTuple!(int, 5, "a string", MyTemplate);
104 
105 	MyTuple[0] myVar = MyTuple[1]; // same as `int myVar = 5;`
106 	auto str = MyTuple[2]; // same as `auto str = "a string";`
107 
108 	alias Template = MyTuple[3];
109 	static assert(is(Template!int == int[]));
110 }
111 
112 /**
113 Creates a packed generic tuple out of a sequence of zero or more types, expressions, or aliases.
114 
115 Packed version doesn't alias itself to its content, i.e. it doesn't auto-unpack.
116 */
117 template PackedGenericTuple(Args...)
118 {
119 	/// Use this member of to access its content as a generic tuple.
120 	alias Tuple = Args;
121 
122 	version(D_Ddoc)
123 	{
124 		/**
125 		Use this member of to access its content as a typetuple.
126 		Defined if $(D Args) is a typetuple.
127 		*/
128 		alias Types = Args;
129 
130 		/**
131 		Use this member of to access its content as an expression tuple.
132 		Defined if $(D Args) is an expression tuple.
133 		*/
134 		alias expressions = Args;
135 	}
136 	else
137 	{
138 		static if(isTypeTuple!Args)
139 			alias Types = Args;
140 		else static if(isExpressionTuple!Args)
141 			alias expressions = Args;
142 	}
143 
144 	/// Its content length.
145 	enum length = Tuple.length;
146 
147 	/// Detect whether it's empty.
148 	enum empty = !length;
149 
150 	/// Convenient equality check template. Same as $(MREF equalTuple).
151 	enum equals(A...) = equalTuple!(PackedGenericTuple!Args, PackedGenericTuple!A);
152 
153 	/// Convenient comparison template. Same as $(MREF cmpTuple).
154 	enum cmp(A...) = cmpTuple!(PackedGenericTuple!Args, PackedGenericTuple!A);
155 }
156 
157 ///
158 unittest
159 {
160 	alias MyPackedTuple = PackedGenericTuple!(long, 3);
161 
162 	MyPackedTuple.Tuple[0] myVar = MyPackedTuple.Tuple[1]; // same as `long myVar = 3;`
163 
164 	alias MyTemplate(alias packed) = packed.Tuple[0][];
165 
166 	// It is passed as a single template alias parameter:
167 	static assert(is(MyTemplate!MyPackedTuple == long[]));
168 }
169 
170 unittest
171 {
172 	static assert(isPackedTuple!(PackedGenericTuple!()));
173 
174 	static assert(is(PackedGenericTuple!int.Types == TypeTuple!int));
175 	static assert(PackedGenericTuple!3.expressions[0] == 3);
176 }
177 
178 
179 /**
180 Creates a typetuple out of a sequence of zero or more types.
181 Same as $(D GenericTuple), except it contains only types.
182 */
183 template TypeTuple(Types...) if(isTypeTuple!Types)
184 {
185 	alias TypeTuple = Types;
186 }
187 
188 ///
189 unittest
190 {
191 	alias IntDouble = TypeTuple!(int, double);
192 
193 	int foo(IntDouble args)  // same as `int foo(int, double)`
194 	{
195 		return args[0] + cast(int) args[1];
196 	}
197 
198 	alias IntDoubleChar = TypeTuple!(int, double, char);
199 	static assert(is(TypeTuple!(IntDouble, char) == IntDoubleChar));
200 	static assert(is(IntDoubleChar[0 .. 2] == IntDouble));
201 
202 
203 	version(none)
204 	alias BadTypeTuple = TypeTuple!(int, 5); // error: not a type tuple
205 }
206 
207 unittest
208 {
209 	static assert(TypeTuple!().length == 0);
210 	static assert(!__traits(compiles, TypeTuple!(int, 5)));
211 
212 	static assert(is(TypeTuple!(int, TypeTuple!()) == TypeTuple!int));
213 	static assert(is(TypeTuple!(int, TypeTuple!char) == TypeTuple!(int, char)));
214 	static assert(is(TypeTuple!(int, TypeTuple!(char, bool)) == TypeTuple!(int, char, bool)));
215 }
216 
217 
218 /**
219 Creates a packed typetuple out of a sequence of zero or more types.
220 Same as $(D PackedGenericTuple), except it contains only types.
221 */
222 template PackedTypeTuple(T...) if(isTypeTuple!T)
223 {
224 	alias PackedTypeTuple = PackedGenericTuple!T;
225 }
226 
227 unittest
228 {
229 	static assert(isPackedTuple!(PackedTypeTuple!()));
230 	static assert(is(PackedTypeTuple!int.Types == TypeTuple!int));
231 }
232 
233 
234 /**
235 Creates an expression tuple out of a sequence of zero or more expressions.
236 Same as $(D GenericTuple), except it contains only expressions.
237 */
238 template expressionTuple(expressions...) if(isExpressionTuple!expressions)
239 {
240 	alias expressionTuple = expressions;
241 }
242 
243 ///
244 unittest
245 {
246 	alias expressions = expressionTuple!(5, 'c', "str");
247 
248 	typeof(expressions[0]) myVar = expressions[1]; // same as `int myVar = 5;`
249 	auto str = expressions[2]; // same as `auto str = "a string";`
250 
251 	void foo(out typeof(expressions[0 .. 2]) args)  // same as `int foo(out int, out char)`
252 	{
253 		args[0] = expressions[0] * 2; // same as `5 * 2`
254 		args[1] = expressions[1] + 1; // same as `'c' + 1`
255 	}
256 
257 	void main()
258 	{
259 		int i;
260 		char c;
261 		foo(i, c);
262 		assert(i == 10 && c == 'd');
263 	}
264 
265 	version(none)
266 	alias badExpressionTuple = expressionTuple!(int, 5); // error: not an expression tuple
267 }
268 
269 unittest
270 {
271 	static assert(expressionTuple!().length == 0);
272 	static assert(expressionTuple!(5, 'c', "str") == expressionTuple!(5, 'c', "str"));
273 	static assert(!__traits(compiles, expressionTuple!(int, 5)));
274 	static assert(!__traits(compiles, expressionTuple!void));
275 }
276 
277 
278 /**
279 Creates a packed expression tuple out of a sequence of zero or more expressions.
280 Same as $(D PackedGenericTuple), except it contains only expressions.
281 */
282 template packedExpressionTuple(expr...) if(isExpressionTuple!expr)
283 {
284 	alias packedExpressionTuple = PackedGenericTuple!expr;
285 }
286 
287 unittest
288 {
289 	static assert(isPackedTuple!(packedExpressionTuple!()));
290 	static assert(packedExpressionTuple!3.expressions[0] == 3);
291 }
292 
293 
294 /**
295 Creates a generic tuple comprised of elemetns of $(D A) in reverse order.
296 
297 Applying RetroTuple twice to the same generic tuple equals to
298 the original generic tuple.
299 
300 Example:
301 ---
302 static assert(is(RetroTuple!(int, bool, long) == TypeTuple!(long, bool, int)));
303 static assert(PackedGenericTuple!(RetroTuple!(1, bool, "x")).equals!("x", bool, 1));
304 ---
305 
306 Analog of $(STDREF range, retro) for generic tuples.
307 */
308 template RetroTuple(A...)
309 {
310 	static if (A.length == 0)
311 		alias RetroTuple = GenericTuple!();
312 	else
313 		alias RetroTuple = GenericTuple!(.RetroTuple!(A[1 .. $]), A[0]);
314 }
315 
316 unittest
317 {
318 	static assert(is(RetroTuple!() == GenericTuple!()));
319 	static assert(is(RetroTuple!int == TypeTuple!int));
320 	static assert(is(RetroTuple!(int, bool, long) == TypeTuple!(long, bool, int)));
321 	static assert(PackedGenericTuple!(RetroTuple!(1, bool, "x")).equals!("x", bool, 1));
322 }
323 
324 
325 /**
326 Creates a generic tuple comprised of elemetns of $(D A) taken with stride $(D n).
327 
328 Applying StrideTuple twice to the same generic tuple equals to applying
329 StrideTuple with a step that is the product of the two applications.
330 
331 Example:
332 ---
333 static assert(is(StrideTuple!(2, ubyte, byte, uint, int, ulong, long) == TypeTuple!(ubyte, uint, ulong)));
334 static assert(StrideTuple!(3, iota) == expressionTuple!(1, 4, 7, 10));
335 ---
336 
337 Analog of $(STDREF range, stride) for generic tuples
338 except $(D n) is the first argument.
339 */
340 template StrideTuple(size_t n, A...)
341 	if(n > 0)
342 {
343 	static if(A.length)
344 		alias StrideTuple = GenericTuple!(A[0], StrideTuple!(n, A[min(n, $) .. $]));
345 	else
346 		alias StrideTuple = GenericTuple!();
347 }
348 
349 unittest
350 {
351 	static assert(is(StrideTuple!1 == GenericTuple!()));
352 	static assert(is(StrideTuple!(2, ubyte, byte, uint, int, ulong, long) == TypeTuple!(ubyte, uint, ulong)));
353 	alias iota = iotaTuple!(1, 11);
354 	static assert(StrideTuple!(1, iota) == iota);
355 	static assert(StrideTuple!(2, iota) == expressionTuple!(1, 3, 5, 7, 9));
356 	static assert(StrideTuple!(3, iota) == expressionTuple!(1, 4, 7, 10));
357 	static assert(StrideTuple!(4, iota) == expressionTuple!(1, 5, 9));
358 }
359 
360 
361 /**
362 Creates a generic tuple comprised of all elemetns of packed generic tuples
363 $(D packedTuples) in sequence.
364 
365 Example:
366 ---
367 alias chain = ChainTuple!(packedExpressionTuple!(1, 2, 3), packedExpressionTuple!(4, 5));
368 static assert(chain == expressionTuple!(1, 2, 3, 4, 5));
369 ---
370 
371 Analog of $(STDREF range, chain) for generic tuples.
372 */
373 template ChainTuple(packedTuples...)
374 	if(packedTuples.length && allTuple!(isPackedTuple, packedTuples))
375 {
376 	// Can't use UnaryTemplate!`A.Tuple` because of Issue 9017
377 	alias Func(alias packedTuple) = packedTuple.Tuple;
378 	alias ChainTuple = MapTuple!(Func, packedTuples);
379 }
380 
381 unittest
382 {
383 	alias chain = ChainTuple!(packedExpressionTuple!(1, 2, 3, 4), packedExpressionTuple!(5, 6), packedExpressionTuple!(), packedExpressionTuple!7);
384 	static assert(chain == expressionTuple!(1, 2, 3, 4, 5, 6, 7));
385 }
386 
387 
388 /**
389 Creates a generic tuple comprised of all elemetns of packed generic tuples
390 $(D packedTuples) in an order by analogy with
391 $(HTTP en.wikipedia.org/wiki/Round-robin_scheduling, Round-robin scheduling).
392 
393 Example:
394 ---
395 alias roundRobin = RoundRobinTuple!(packedExpressionTuple!(1, 2, 3), packedExpressionTuple!(10, 20, 30, 40));
396 static assert(roundRobin == expressionTuple!(1, 10, 2, 20, 3, 30, 40));
397 ---
398 
399 Analog of $(STDREF range, roundRobin) for generic tuples.
400 */
401 template RoundRobinTuple(packedTuples...)
402 	if(packedTuples.length && allTuple!(isPackedTuple, packedTuples))
403 {
404 	struct _Empty;
405 	enum pred(alias A) = !is(A == _Empty);
406 	alias RoundRobinTuple = FilterTuple!(pred, ChainTuple!(ZipTuple!(StoppingPolicy.longest, GenericTuple!_Empty, packedTuples)));
407 }
408 
409 unittest
410 {
411 	alias roundRobin = RoundRobinTuple!(packedExpressionTuple!(1, 2, 3), packedExpressionTuple!(10, 20, 30, 40));
412 	static assert(roundRobin == expressionTuple!(1, 10, 2, 20, 3, 30, 40));
413 }
414 
415 
416 /**
417 Creates a generic tuple comprised of all elemetns of $(D A) which are teken
418 starting from a given point and progressively extending left and right
419 from that point. If $(D RadialTupleMiddle) is used or $(D startingIndex)
420 is $(D -1) it is assumed that no initial point is given and iteration
421 starts from the middle of $(D A).
422 
423 Example:
424 ---
425 static assert(RadialTuple!(-1, 1, 2, 3, 4, 5) == expressionTuple!(3, 4, 2, 5, 1));
426 static assert(RadialTuple!( 1, 1, 2, 3, 4, 5) == expressionTuple!(2, 3, 1, 4, 5));
427 ---
428 
429 Analog of $(STDREF range, radial) for generic tuples
430 except $(D startingIndex) is the first argument and
431 there is no overload without it.
432 */
433 template RadialTuple(size_t startingIndex, A...)
434 {
435 	enum i = (startingIndex == -1 ? (A.length - !!A.length) / 2 : startingIndex) + !!A.length;
436 	alias RadialTuple = RoundRobinTuple!(PackedGenericTuple!(RetroTuple!(A[0 .. i])), PackedGenericTuple!(A[i .. $]));
437 }
438 
439 /// ditto
440 alias RadialTupleMiddle(A...) = RadialTuple!(-1, A);
441 
442 unittest
443 {
444 	static assert(RadialTupleMiddle!(1) == expressionTuple!1);
445 	static assert(RadialTupleMiddle!(1, 2) == expressionTuple!(1, 2));
446 	static assert(RadialTupleMiddle!(1, 2, 3) == expressionTuple!(2, 3, 1));
447 	static assert(RadialTupleMiddle!(1, 2, 3, 4) == expressionTuple!(2, 3, 1, 4));
448 	static assert(RadialTupleMiddle!(1, 2, 3, 4, 5) == expressionTuple!(3, 4, 2, 5, 1));
449 	static assert(RadialTupleMiddle!(1, 2, 3, 4, 5, 6) == expressionTuple!(3, 4, 2, 5, 1, 6));
450 	static assert(RadialTuple!(1, 1, 2, 3, 4, 5) == expressionTuple!(2, 3, 1, 4, 5));
451 }
452 
453 
454 /**
455 Repeats $(D A) $(D n) times.
456 
457 Example:
458 ---
459 static assert(is(RepeatTuple!(2, int) == TypeTuple!(int, int)));
460 static assert(RepeatTuple!(4, 5) == expressionTuple!(5, 5, 5, 5));
461 ---
462 
463 Analog of $(STDREF array, replicate) and $(STDREF range, repeat) for generic tuples
464 except $(D n) is the first argument and there is no overload
465 without it as tuples can't be infinite.
466 Also it repeats a generic tuple, not only one value.
467 */
468 template RepeatTuple(size_t n, A...)
469 {
470 	static if(n)
471 		alias RepeatTuple = GenericTuple!(A, RepeatTuple!(n - 1, A));
472 	else
473 		alias RepeatTuple = GenericTuple!();
474 }
475 
476 unittest
477 {
478 	static assert(is(RepeatTuple!(2, int) == TypeTuple!(int, int)));
479 	static assert(RepeatTuple!(4, 5) == expressionTuple!(5, 5, 5, 5));
480 }
481 
482 
483 /**
484 Creates a generic tuple comprised of packed generic tuples comprised of
485 elemetns of packed generic tuples $(D packedTuples) taken in lockstep.
486 
487 If $(D stoppingPolicy) is $(D StoppingPolicy.longest) and a tuple is finished
488 in a lockstep iteration then $(D empty) will be taken.
489 
490 Example:
491 ---
492 alias packed1 = packedExpressionTuple!(1, 2, 3);
493 alias packed2 = PackedTypeTuple!(short, int, long);
494 alias zip = ZipTuple!(packed1, packed2);
495 
496 static assert(zip[0].equals!(1, short));
497 static assert(zip[1].equals!(2, int));
498 static assert(zip[2].equals!(3, long))
499 ---
500 
501 Analog of $(STDREF range, zip) for generic tuples
502 except $(D empty) value must be explicitly specified
503 for $(D StoppingPolicy.longest).
504 */
505 template ZipTuple(StoppingPolicy stoppingPolicy : StoppingPolicy.longest, alias empty, packedTuples...)
506 {
507 	alias ZipTuple = ZipTupleImpl!(stoppingPolicy, PackedGenericTuple!empty, packedTuples);
508 }
509 
510 /// ditto
511 template ZipTuple(StoppingPolicy stoppingPolicy : StoppingPolicy.longest, empty, packedTuples...)
512 {
513 	alias ZipTuple = ZipTupleImpl!(stoppingPolicy, PackedGenericTuple!empty, packedTuples);
514 }
515 
516 /// ditto
517 template ZipTuple(StoppingPolicy stoppingPolicy, packedTuples...)
518 	if(stoppingPolicy != StoppingPolicy.longest) // probably a compiler @@@BUG@@@ workaround
519 {
520 	alias ZipTuple = ZipTupleImpl!(stoppingPolicy, PackedGenericTuple!void, packedTuples);
521 }
522 
523 /// ditto
524 template ZipTuple(packedTuples...)
525 	if(packedTuples.length && allTuple!(isPackedTuple, packedTuples)) // probably a compiler @@@BUG@@@ workaround
526 {
527 	alias ZipTuple = ZipTuple!(StoppingPolicy.shortest, packedTuples);
528 }
529 
530 private template ZipTupleImpl(StoppingPolicy stoppingPolicy, alias default_, packedTuples...)
531 	if(packedTuples.length && allTuple!(isPackedTuple, default_, packedTuples) && default_.length == 1)
532 {
533 	alias lengths = MapTuple!(`A.length`, packedTuples);
534 
535 	static if(stoppingPolicy == StoppingPolicy.requireSameLength)
536 		static assert(allTuple!(BindTemplate!(isSame, lengths[0], arg!0), lengths),
537 			"Inequal-length packed tuples passed to ZipTuple(StoppingPolicy.requireSameLength, ...)");
538 
539 	template Impl(size_t n, packedTuples...)
540 	{
541 		static if(n)
542 		{
543 			template tupleFrontOrDefault(alias packedTuple)
544 			{
545 				static if(!packedTuple.empty)
546 					alias tupleFrontOrDefault = packedTuple.Tuple[0 .. 1];
547 				else
548 					alias tupleFrontOrDefault = default_.Tuple;
549 			}
550 			alias Impl = GenericTuple!(PackedGenericTuple!(MapTuple!(tupleFrontOrDefault, packedTuples)),
551 				Impl!(n - 1, MapTuple!(`PackedGenericTuple!(A.Tuple[!A.empty .. $])`, packedTuples)));
552 		}
553 		else
554 			alias Impl = GenericTuple!();
555 	}
556 	static if(packedTuples.length == 1 || stoppingPolicy == StoppingPolicy.requireSameLength)
557 		enum length = lengths[0];
558 	else
559 		enum length = GenericTuple!(min, max)
560 			[stoppingPolicy == StoppingPolicy.longest](lengths);
561 
562 	alias ZipTupleImpl = Impl!(length, packedTuples);
563 }
564 
565 unittest
566 {
567 	alias packed1 = packedExpressionTuple!(1, 2, 3);
568 	alias packed2 = PackedTypeTuple!(short, int, long);
569 	alias zip = ZipTuple!(packed1, packed2);
570 
571 	static assert(zip[0].equals!(1, short));
572 	static assert(zip[1].equals!(2, int));
573 	static assert(zip[2].equals!(3, long));
574 }
575 
576 unittest
577 {
578 	alias packedIota5 = packedExpressionTuple!(iotaTuple!5);
579 	alias packedIota16 = packedExpressionTuple!(iotaTuple!(1, 6));
580 	alias packedIota14 = packedExpressionTuple!(iotaTuple!(1, 4));
581 	alias packedIota18 = packedExpressionTuple!(iotaTuple!(1, 8));
582 
583 	void test(size_t length, size_t filledLength, size_t longerIdx, zip...)()
584 	{
585 		static assert(zip.length == length);
586 		foreach (i, e; zip)
587 			static assert(e.Tuple[0] == (i < filledLength || longerIdx == 0 ? i : -2) &&
588 				e.Tuple[1] == (i < filledLength || longerIdx == 1 ? i + 1 : -3));
589 	}
590 
591 	with(StoppingPolicy) foreach(stoppingPolicy; expressionTuple!(shortest, longest, requireSameLength))
592 	{
593 		static if(stoppingPolicy == longest)
594 			alias def = void;
595 		else
596 			alias def = expressionTuple!();
597 
598 		alias zip = ZipTuple!(stoppingPolicy, def, packedIota5, packedIota16);
599 		test!(5, 5, -1, zip)();
600 	}
601 
602 	static assert(!__traits(compiles, ZipTuple!(StoppingPolicy.requireSameLength, packedIota5, packedIota14)));
603 	static assert(!__traits(compiles, ZipTuple!(StoppingPolicy.requireSameLength, packedIota5, packedIota18)));
604 
605 	test!(3, 3, -1, ZipTuple!(packedIota5, packedIota14))();
606 	test!(5, 5, -1, ZipTuple!(packedIota5, packedIota18))();
607 
608 	test!(5, 3, 0, ZipTuple!(StoppingPolicy.longest, -3, packedIota5, packedIota14))();
609 	test!(7, 5, 1, ZipTuple!(StoppingPolicy.longest, -2, packedIota5, packedIota18))();
610 }
611 
612 
613 /**
614 Returns expression tuple with elements going through the numbers $(D begin), $(D begin +
615 step), $(D begin + 2 * step), $(D ...), up to and excluding $(D end).
616 The two-arguments version has $(D step = 1).
617 The one-argument version also has $(D begin = 0).
618 If $(D begin < end && step < 0) or $(D begin > end && step > 0) or $(D begin == end),
619 then an empty tuple is returned.
620 
621 Example:
622 ---
623 int res;
624 foreach(i; iotaTuple!5) // same as res += foo!1(); res += foo!3();
625 	static if(i & 1)
626 		res += foo!i();
627 ---
628 
629 Tip:
630 This is a convenient way to create a CT analog of
631 $(HTTP dlang.org/statement.html#ForeachRangeStatement, Foreach Range Statement).
632 
633 Analog of $(STDREF range, iota) for generic tuples.
634 */
635 alias iotaTuple(alias begin, alias end, alias step) =
636 	iotaTupleImpl!(CommonType!(typeof(begin), typeof(end), typeof(step)), begin, end, step);
637 
638 /// ditto
639 alias iotaTuple(alias begin, alias end) =
640 	iotaTupleImpl!(CommonType!(typeof(begin), typeof(end)), begin, end, 1);
641 
642 /// ditto
643 alias iotaTuple(alias end) =
644 	iotaTupleImpl!(typeof(end), 0, end, 1);
645 
646 private template iotaTupleImpl(T, T begin, T end, T step)
647 	if(isIntegral!T || isFloatingPoint!T && step)
648 {
649 	static if(begin < end && step < 0 || begin > end && step > 0 || begin == end)
650 		alias iotaTupleImpl = expressionTuple!();
651 	else static if(step)
652 		alias iotaTupleImpl = expressionTuple!(begin, iotaTupleImpl!(T, begin + step, end, step));
653 	else
654 		static assert(0, "iotaTuple: `step` can't be zero for nonequal `begin` and `end`");
655 }
656 
657 unittest
658 {
659 	static assert(iotaTuple!0.length == 0);
660 	static assert(iotaTuple!(10, 1).length == 0);
661 	static assert(iotaTuple!(1, 10, -1).length == 0);
662 	static assert(iotaTuple!(2, 2, 0).length == 0);
663 	static assert(!__traits(compiles, iotaTuple!(1, 2, 0)));
664 
665 	static assert(iotaTuple!1 == expressionTuple!0);
666 	static assert(iotaTuple!3 == expressionTuple!(0, 1, 2));
667 	static assert(iotaTuple!(1.0, 3) == expressionTuple!(1.0, 2.0));
668 	static assert(iotaTuple!(1, 3.1f) == expressionTuple!(1.0, 2.0, 3.0));
669 	static assert(iotaTuple!(3, 0, -1) == expressionTuple!(3, 2, 1));
670 	static assert(iotaTuple!(3, 2, -.5) == expressionTuple!(3.0, 2.5));
671 }
672 
673 
674 /**
675 Creates a generic tuple comprised of elemetns of packed generic tuple
676 $(D packedSourceTuple) reordered according to packed expression tuple
677 $(D packedIndicesTuple). $(D packedIndicesTuple) may include only a subset
678 of the elements of $(D packedSourceTuple) and may also repeat elements.
679 
680 Example:
681 ---
682 alias indexed = IndexedTuple!(PackedTypeTuple!(short, int, long, double),
683                               packedExpressionTuple!(1, 0, 2, 2));
684 static assert(is(indexed == TypeTuple!(int, short, long, long)));
685 ---
686 
687 Analog of $(STDREF range, indexed) for generic tuples.
688 */
689 template IndexedTuple(alias packedSourceTuple, alias packedIndicesTuple)
690 	if(isPackedTuple!packedSourceTuple && isPackedTuple!packedIndicesTuple)
691 {
692 	template Func(A...) if(A.length == 1)
693 	{ alias Func = packedSourceTuple.Tuple[A[0] .. A[0] + 1]; }
694 	alias IndexedTuple = MapTuple!(Func, packedIndicesTuple.Tuple);
695 }
696 
697 unittest
698 {
699 	alias indexed = IndexedTuple!(PackedTypeTuple!(short, int, long, double), packedExpressionTuple!(1, 0, 2, 2));
700 	static assert(is(indexed == TypeTuple!(int, short, long, long)));
701 
702 	alias indexed2 = IndexedTuple!(packedExpressionTuple!(1, 2, 3, 4, 5), packedExpressionTuple!(4, 3, 1, 2, 0, 4));
703 	static assert(indexed2 == expressionTuple!(5, 4, 2, 3, 1, 5));
704 }
705 
706 
707 /**
708 Creates a generic tuple comprised of packed generic tuples comprised of
709 fixed-sized chunks of size $(D chunkSize) of $(D A).
710 
711 If $(D A.length) is not evenly divisible by $(D chunkSize), the last
712 packed generic tuple will contain fewer than $(D chunkSize) elements.
713 
714 Example:
715 ---
716 alias chunks = ChunksTuple!(4,  1, 2, 3, 4, 5, 6, byte, short, int, long);
717 static assert(chunks[0].equals!(1, 2, 3, 4));
718 static assert(chunks[1].equals!(5, 6, byte, short));
719 static assert(chunks[2].equals!(int, long));
720 ---
721 
722 Analog of $(STDREF range, chunks) for generic tuples
723 except $(D chunkSize) is the first argument.
724 */
725 template ChunksTuple(size_t chunkSize, A...)
726 {
727 	static if(A.length > chunkSize)
728 		alias ChunksTuple = GenericTuple!(PackedGenericTuple!(A[0 .. chunkSize]),
729 			ChunksTuple!(chunkSize, A[chunkSize .. $]));
730 	else
731 		alias ChunksTuple = GenericTuple!(PackedGenericTuple!A);
732 }
733 
734 unittest
735 {
736 	alias chunks = ChunksTuple!(4,  1, 2, 3, 4, 5, 6, byte, short, int, long);
737 	static assert(chunks[0].equals!(1, 2, 3, 4));
738 	static assert(chunks[1].equals!(5, 6, byte, short));
739 	static assert(chunks[2].equals!(int, long));
740 }
741 
742 
743 /**
744 Performs $(HTTP en.wikipedia.org/wiki/Three-way_comparison, three-way
745 lexicographical comparison) on two packed generic tuples
746 according to predicate $(D pred).
747 
748 Iterating $(D packedTuple1) and $(D packedTuple2) in lockstep, cmpTuple
749 compares each element $(D A1) of $(D packedTuple1) with the corresponding
750 element $(D A2) in $(D packedTuple2).
751 If $(D Inst!(binaryPred!pred, A1, A2)), $(D cmp) returns a negative value.
752 If $(D Inst!(binaryPred!pred, A2, A1)), $(D cmp) returns a positive value.
753 If one of the tuples has been finished, $(D cmp) returns a negative value
754 if $(D packedTuple1) has fewer elements than $(D packedTuple2), a positive
755 value if $(D packedTuple1) has more elements than $(D packedTuple2), and
756 $(D 0) if the tuples have the same number of elements.
757 
758 Example:
759 ---
760 static assert(cmpTuple!(packedExpressionTuple!0, packedExpressionTuple!0) == 0);
761 static assert(cmpTuple!(packedExpressionTuple!"a", packedExpressionTuple!"ab") < 0);
762 static assert(cmpTuple!(`T.sizeof < U.sizeof`, PackedTypeTuple!int, PackedTypeTuple!long) < 0);
763 ---
764 
765 Analog of $(STDREF algorithm, cmp) for generic tuples.
766 */
767 template cmpTuple(alias pred, alias packedTuple1, alias packedTuple2)
768 	if(isPackedTuple!packedTuple1 && isPackedTuple!packedTuple2)
769 {
770 	alias predTemplate = binaryPred!pred;
771 
772 	static if (packedTuple1.empty)
773 		enum cmpTuple = -cast(int) !packedTuple2.empty;
774 	else static if (packedTuple2.empty)
775 		enum cmpTuple = cast(int) !packedTuple1.empty;
776 	else static if (predTemplate!(packedTuple1.Tuple[0], packedTuple2.Tuple[0]))
777 		enum cmpTuple = -1;
778 	else static if (predTemplate!(packedTuple2.Tuple[0], packedTuple1.Tuple[0]))
779 		enum cmpTuple = 1;
780 	else
781 		enum cmpTuple = cmpTuple!(predTemplate, PackedGenericTuple!(packedTuple1.Tuple[1 .. $]), PackedGenericTuple!(packedTuple2.Tuple[1 .. $]));
782 }
783 
784 /// ditto
785 enum cmpTuple(alias packedTuple1, alias packedTuple2) =
786 	cmpTuple!(`a < b`, packedTuple1, packedTuple2);
787 
788 unittest
789 {
790 	static assert(cmpTuple!(PackedGenericTuple!(), PackedGenericTuple!()) == 0);
791 	static assert(cmpTuple!(packedExpressionTuple!0, packedExpressionTuple!0) == 0);
792 	static assert(cmpTuple!(packedExpressionTuple!0, packedExpressionTuple!1) < 0);
793 	static assert(cmpTuple!(packedExpressionTuple!0, packedExpressionTuple!(0, 0)) < 0);
794 	static assert(cmpTuple!(packedExpressionTuple!(0, 0), packedExpressionTuple!0) > 0);
795 	static assert(cmpTuple!(packedExpressionTuple!1, packedExpressionTuple!(0, 0)) > 0);
796 
797 	static assert(cmpTuple!(packedExpressionTuple!"a", packedExpressionTuple!"a") == 0);
798 	static assert(cmpTuple!(packedExpressionTuple!"a", packedExpressionTuple!"ab") < 0);
799 	static assert(cmpTuple!(packedExpressionTuple!"b", packedExpressionTuple!"ab") > 0);
800 
801 	static assert(cmpTuple!(`T.sizeof < U.sizeof`, PackedTypeTuple!int, PackedTypeTuple!long) < 0);
802 }
803 
804 
805 /**
806 Detect whether two packed generic tuples $(D packedTuple1) and $(D packedTuple2)
807 elements are equal according to binary predicate $(D pred).
808 
809 $(D isSame) is used if no predicacte specified.
810 
811 Example:
812 ---
813 static assert( equalTuple!(packedExpressionTuple!(0, 1), packedExpressionTuple!(iotaTuple!2)));
814 static assert( equalTuple!(PackedGenericTuple!(int, "a"), PackedGenericTuple!(int, "a")));
815 
816 static assert( equalTuple!(`true`, packedExpressionTuple!1, PackedTypeTuple!int));
817 static assert(!equalTuple!(`true`, packedExpressionTuple!1, packedExpressionTuple!()));
818 ---
819 
820 Analog of $(STDREF algorithm, equal) for generic tuples.
821 */
822 template equalTuple(alias pred, alias packedTuple1, alias packedTuple2)
823 	if(isPackedTuple!packedTuple1 && isPackedTuple!packedTuple2)
824 {
825 	alias predTemplate = binaryPred!pred;
826 
827 	template instForPackedTuple(alias packedTuple)
828 		if(isPackedTuple!packedTuple && packedTuple.length == 2)
829 	{
830 		enum instForPackedTuple = predTemplate!(packedTuple.Tuple);
831 	}
832 
833 	static if(packedTuple1.length == packedTuple2.length)
834 		enum equalTuple = allTuple!(instForPackedTuple, ZipTuple!(packedTuple1, packedTuple2));
835 	else
836 		enum equalTuple = false;
837 }
838 
839 /// ditto
840 enum equalTuple(alias packedTuple1, alias packedTuple2) =
841 	equalTuple!(isSame, packedTuple1, packedTuple2);
842 
843 unittest
844 {
845 	static assert( equalTuple!(PackedGenericTuple!(), PackedGenericTuple!()));
846 	static assert( equalTuple!(packedExpressionTuple!0, packedExpressionTuple!0));
847 	static assert(!equalTuple!(packedExpressionTuple!0, PackedTypeTuple!int));
848 	static assert(!equalTuple!(packedExpressionTuple!0, packedExpressionTuple!(0, 1)));
849 	static assert( equalTuple!(packedExpressionTuple!(0, 1), packedExpressionTuple!(iotaTuple!2)));
850 	static assert( equalTuple!(PackedGenericTuple!(int, "a"), PackedGenericTuple!(int, "a")));
851 
852 	static assert(!equalTuple!(`true`, packedExpressionTuple!1, packedExpressionTuple!()));
853 	static assert( equalTuple!(`true`, packedExpressionTuple!1, PackedTypeTuple!int));
854 }
855 
856 
857 /**
858 Creates a generic tuple comprised of elemetns of $(D A) for which a unary
859 predicate $(D pred) is $(D true).
860 
861 Example:
862 ----
863 import std.traits;
864 
865 static assert(is(FilterTuple!(isNumeric, int, void, immutable short, char) ==
866               TypeTuple!(int, immutable short)));
867 
868 static assert(is(FilterTuple!(`__traits(isUnsigned, T)`, int, size_t, void, ushort, char) ==
869               TypeTuple!(size_t, ushort, char)));
870 ----
871 
872 Analog of $(STDREF algorithm, filter) for generic tuples.
873 */
874 template FilterTuple(alias pred, A...)
875 {
876 	alias PredTemplate = UnaryTemplate!pred;
877 
878 	template func(A...) if(A.length == 1)
879 	{ alias func = A[0 .. PredTemplate!(A[0])]; }
880 
881 	alias FilterTuple = MapTuple!(func, A);
882 }
883 
884 unittest
885 {
886 	import std.traits;
887 
888 	static assert(is(FilterTuple!(isNumeric, int, size_t, void, immutable short, char) ==
889 		TypeTuple!(int, size_t, immutable short)));
890 
891 	static assert(is(FilterTuple!(`__traits(isUnsigned, T)`, int, size_t, void, immutable ushort, char) ==
892 		TypeTuple!(size_t, immutable ushort, char)));
893 }
894 
895 
896 /**
897 Similarly to $(MREF UniqTuple), creates a generic tuple comprised of packed generic tuples comprised of unique
898 consecutive elemetns of $(D A) and counts of equivalent elements seen.
899 
900 Equivalence of elements is assessed by using a binary predicate $(D pred).
901 
902 Example:
903 ----
904 alias tuple = GenericTuple!(1, 2, 2, 2, "x", "x", int, 1, 1);
905 
906 alias group = groupTuple!(isSame, tuple);
907 static assert(group.length == 5);
908 static assert(group[0].equals!(1, 1));
909 static assert(group[1].equals!(2, 3));
910 static assert(group[2].equals!("x", 2));
911 static assert(group[3].equals!(int, 1));
912 static assert(group[4].equals!(1, 2));
913 
914 alias group2 = groupTuple!(notTemplate!isSame, tuple);
915 static assert(group2.length == 3);
916 static assert(group2[0].equals!(1, 7));
917 static assert(group2[1].equals!(1, 1));
918 static assert(group2[2].equals!(1, 1));
919 ----
920 
921 Analog of $(STDREF algorithm, group) for generic tuples
922 except $(D pred) must be explicitly specified.
923 */
924 template groupTuple(alias pred, A...)
925 {
926 	alias predTemplate = binaryPred!pred;
927 
928 	template impl(size_t count, A...) if(A.length >= 1)
929 	{
930 		static if(A.length == 1 || !predTemplate!(A[0], A[1]))
931 		{
932 			alias curr = PackedGenericTuple!(A[0], count);
933 
934 			static if(A.length == 1)
935 				alias impl = GenericTuple!(curr);
936 			else
937 				alias impl = GenericTuple!(curr, impl!(1, A[1], A[2 .. $]));
938 		}
939 		else
940 			alias impl = impl!(count + 1, A[0], A[2 .. $]);
941 	}
942 
943 	static if(A.length)
944 		alias groupTuple = impl!(1, A);
945 	else
946 		alias groupTuple = GenericTuple!();
947 }
948 
949 unittest
950 {
951 	static assert(groupTuple!isSame.length == 0);
952 
953 	alias tuple = GenericTuple!(1, 2, 2, 2, "x", "x", int, 1, 1);
954 
955 	alias group = groupTuple!(isSame, tuple);
956 	static assert(group.length == 5);
957 	static assert(group[0].equals!(1, 1));
958 	static assert(group[1].equals!(2, 3));
959 	static assert(group[2].equals!("x", 2));
960 	static assert(group[3].equals!(int, 1));
961 	static assert(group[4].equals!(1, 2));
962 
963 	alias group2 = groupTuple!(notTemplate!isSame, tuple);
964 	static assert(group2.length == 3);
965 	static assert(group2[0].equals!(1, 7));
966 	static assert(group2[1].equals!(1, 1));
967 	static assert(group2[2].equals!(1, 1));
968 }
969 
970 
971 /**
972 Creates a generic tuple comprised of packed generic tuples $(D packedTuples)
973 generic tuples joined together using packed generic tuple $(D packedSeparatorTuple)
974 as a separator.
975 
976 Example:
977 ----
978 alias sep = packedExpressionTuple!"+";
979 alias part1 = PackedTypeTuple!(void, int);
980 alias part2 = packedExpressionTuple!0;
981 static assert(PackedGenericTuple!(JoinTuple!(sep, part1, part2)).equals!(void, int, "+", 0));
982 ----
983 
984 Analog of $(STDREF array, join) and $(STDREF algorithm, joiner) for generic tuples.
985 */
986 template JoinTuple(alias packedSeparatorTuple, packedTuples...)
987 	if(allTuple!(isPackedTuple, packedSeparatorTuple, packedTuples))
988 {
989 	alias Prefix(alias packedTuple) = ChainTuple!(packedSeparatorTuple, packedTuple);
990 
991 	static if(packedTuples.length)
992 		alias JoinTuple = GenericTuple!(packedTuples[0].Tuple, MapTuple!(Prefix, packedTuples[1 .. $]));
993 	else
994 		alias JoinTuple = GenericTuple!();
995 }
996 
997 unittest
998 {
999 	alias sep = packedExpressionTuple!"+";
1000 	alias part1 = PackedTypeTuple!(void, int);
1001 	alias part2 = packedExpressionTuple!0;
1002 
1003 	static assert(JoinTuple!sep.length == 0);
1004 	static assert(is(JoinTuple!(sep, part1) == TypeTuple!(void, int)));
1005 	static assert(PackedGenericTuple!(JoinTuple!(sep, part1, part2)).equals!(void, int, "+", 0));
1006 }
1007 
1008 
1009 /**
1010 Creates a generic tuple comprised of results of applying unary
1011 template $(D Func) to elemetns of $(D A) consecutively.
1012 
1013 Example:
1014 ---
1015 alias squares = MapTuple!(`a * a`, iotaTuple!4);
1016 static assert(squares == expressionTuple!(0, 1, 4, 9));
1017 
1018 static assert(is(MapTuple!(`T[]`, int, long) == TypeTuple!(int[], long[])));
1019 ---
1020 
1021 Analog of $(STDREF algorithm, map) for generic tuples
1022 except $(D Func) can return any count of elements.
1023 */
1024 template MapTuple(alias Func, A...)
1025 {
1026 	alias FuncTemplate = UnaryTemplate!Func;
1027 
1028 	static if (A.length)
1029 		alias MapTuple = GenericTuple!(FuncTemplate!(A[0]), MapTuple!(FuncTemplate, A[1 .. $]));
1030 	else
1031 		alias MapTuple = GenericTuple!();
1032 }
1033 
1034 unittest
1035 {
1036 	static assert(MapTuple!`1`.length == 0);
1037 	static assert(MapTuple!(`1`, const int) == expressionTuple!1);
1038 	static assert(is(MapTuple!(Unqual, int, immutable int) == TypeTuple!(int, int)));
1039 	static assert(is(MapTuple!(`T[]`, int, long) == TypeTuple!(int[], long[])));
1040 	alias squares = MapTuple!(`a * a`, iotaTuple!4);
1041 	static assert(squares == expressionTuple!(0, 1, 4, 9));
1042 }
1043 
1044 
1045 /**
1046 The instantiation of $(D ReduceTuple!(Func, init, A)) first lets $(D result)
1047 be $(D init). Then, for each element $(D x) in $(D A) sequentially, it lets $(D result)
1048 be $(D Inst!(BinaryTemplate!Func, result, x)). Finally, $(D result) is returned.
1049 
1050 Example:
1051 ----
1052 static assert(ReduceTuple!(`a + U.sizeof`, 0, bool, short, int) == 1 + 2 + 4);
1053 static assert(is(ReduceTuple!(`Select!(T.sizeof > U.sizeof, T, U)`, void, bool, long, int) == long));
1054 ----
1055 
1056 Analog of $(STDREF algorithm, reduce) for generic tuples
1057 except there is no overload with multiple functions.
1058 */
1059 template ReduceTuple(alias Func, alias init, A...)
1060 {
1061 	alias Init = init;
1062 	mixin ReduceTupleImpl;
1063 	alias ReduceTuple = Res;
1064 }
1065 
1066 template ReduceTuple(alias Func, Init, A...)
1067 {
1068 	mixin ReduceTupleImpl;
1069 	alias ReduceTuple = Res;
1070 }
1071 
1072 private mixin template ReduceTupleImpl()
1073 {
1074 	alias FuncTemplate = BinaryTemplate!Func;
1075 
1076 	static if(A.length)
1077 		alias Res = .ReduceTuple!(FuncTemplate, FuncTemplate!(Init, A[0]), A[1 .. $]);
1078 	else
1079 		alias Res = Init;
1080 }
1081 
1082 unittest
1083 {
1084 	static assert(is(ReduceTuple!(`true`, void) == void));
1085 	static assert(ReduceTuple!(`true`, 0) == 0);
1086 	static assert(ReduceTuple!(`true`, void, int) == true);
1087 	static assert(ReduceTuple!(`a + U.sizeof`, 0, bool, short, int) == 1 + 2 + 4);
1088 	static assert(is(ReduceTuple!(`Select!(T.sizeof > U.sizeof, T, U)`, void, bool, long, int) == long));
1089 }
1090 
1091 
1092 /**
1093 Creates a generic tuple comprised of unique consecutive elemetns of $(D A).
1094 
1095 Equivalence of elements is assessed by using a binary predicate $(D pred).
1096 
1097 Example:
1098 ----
1099 alias expr = expressionTuple!(1, 2, 2, 2, 3, 3, 4, 1, 1);
1100 static assert(UniqTuple!(`a == b`, expr) == expressionTuple!(1, 2, 3, 4, 1));
1101 static assert(UniqTuple!(`a != b`, expr) == expressionTuple!(1, 1, 1));
1102 ----
1103 
1104 Analog of $(STDREF algorithm, uniq) for generic tuples
1105 except $(D pred) must be explicitly specified.
1106 */
1107 template UniqTuple(alias pred, A...)
1108 {
1109 	alias predTemplate = binaryPred!pred;
1110 
1111 	template Impl(A...) if(A.length >= 1)
1112 	{
1113 		static if(A.length >= 2)
1114 		{
1115 			static if(predTemplate!(A[0], A[1]))
1116 				alias Impl = Impl!(A[0], A[2 .. $]);
1117 			else
1118 				alias Impl = GenericTuple!(A[1], Impl!(A[1], A[2 .. $]));
1119 		}
1120 		else
1121 			alias Impl = A[1 .. $];
1122 	}
1123 
1124 	static if(A.length <= 1)
1125 		alias UniqTuple = A;
1126 	else
1127 		alias UniqTuple = GenericTuple!(A[0], Impl!(A[0], A[1 .. $]));
1128 }
1129 
1130 unittest
1131 {
1132 	alias expr = expressionTuple!(1, 2, 2, 2, 3, 3, 4, 1, 1);
1133 	static assert(UniqTuple!(`a == b`, expr) == expressionTuple!(1, 2, 3, 4, 1));
1134 	static assert(UniqTuple!(`a != b`, expr) == expressionTuple!(1, 1, 1));
1135 }
1136 
1137 
1138 /**
1139 Detect whether a generic tuple $(D A) contains an element
1140 satisfying the predicate $(D pred).
1141 
1142 Example:
1143 ----
1144 static assert(!anyTuple!(`true`));
1145 static assert( anyTuple!(`isIntegral!T`, float, int));
1146 static assert(!anyTuple!(`a < 2`, 2, 3));
1147 ----
1148 
1149 Analog of $(STDREF algorithm, any) for generic tuples
1150 except $(D pred) must be explicitly specified.
1151 */
1152 template anyTuple(alias pred, A...)
1153 {
1154 	alias predTemplate = unaryPred!pred;
1155 
1156 	static if(A.length == 0)
1157 		enum anyTuple = false;
1158 	else static if(!predTemplate!(A[0]))
1159 		enum anyTuple = anyTuple!(pred, A[1 .. $]);
1160 	else
1161 		enum anyTuple = true;
1162 }
1163 
1164 unittest
1165 {
1166 	static assert(!anyTuple!(`true`));
1167 	static assert( anyTuple!(`isIntegral!T`, float, int));
1168 	static assert( anyTuple!(`a < 2`, 1, 2));
1169 	static assert(!anyTuple!(`a < 2`, 2, 3));
1170 }
1171 
1172 
1173 /**
1174 Detect whether all elements of a generic tuple $(D A)
1175 satisfy the predicate $(D pred).
1176 
1177 Returns true for an empty tuple.
1178 
1179 Example:
1180 ----
1181 static assert( allTuple!(`false`));
1182 static assert( allTuple!(`isIntegral!T`, byte, int));
1183 static assert(!allTuple!("a & 1", 1, 2, 3));
1184 ----
1185 
1186 Analog of $(STDREF algorithm, all) for generic tuples
1187 except $(D pred) must be explicitly specified.
1188 */
1189 template allTuple(alias pred, A...)
1190 {
1191 	alias predTemplate = unaryPred!pred;
1192 
1193 	static if(A.length == 0)
1194 		enum allTuple = true;
1195 	else static if(predTemplate!(A[0]))
1196 		enum allTuple = allTuple!(pred, A[1 .. $]);
1197 	else
1198 		enum allTuple = false;
1199 }
1200 
1201 unittest
1202 {
1203 	static assert( allTuple!(`false`));
1204 	static assert(!allTuple!(`false`, 1));
1205 	static assert( allTuple!(`isIntegral!T`, byte, int));
1206 	static assert( allTuple!(`a < 2`, -1, 1));
1207 	static assert(!allTuple!(`a < 2`, -1, 2));
1208     static assert( allTuple!("a & 1", 1, 3, 5, 7, 9));
1209     static assert(!allTuple!("a & 1", 1, 2, 3, 5, 7, 9));
1210 }
1211 
1212 //  internal templates from std.typetuple:
1213 
1214 private template isSame(ab...)
1215 	if (ab.length == 2)
1216 {
1217 	static if (__traits(compiles, expectType!(ab[0]),
1218 	                              expectType!(ab[1])))
1219 	{
1220 		enum isSame = is(ab[0] == ab[1]);
1221 	}
1222 	else static if (!__traits(compiles, expectType!(ab[0])) &&
1223 	                !__traits(compiles, expectType!(ab[1])) &&
1224 	                 __traits(compiles, expectBool!(ab[0] == ab[1])))
1225 	{
1226 		static if (!__traits(compiles, &ab[0]) ||
1227 		           !__traits(compiles, &ab[1]))
1228 			enum isSame = (ab[0] == ab[1]);
1229 		else
1230 			enum isSame = __traits(isSame, ab[0], ab[1]);
1231 	}
1232 	else
1233 	{
1234 		enum isSame = __traits(isSame, ab[0], ab[1]);
1235 	}
1236 }
1237 private template expectType(T) {}
1238 private template expectBool(bool b) {}