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) {}