1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 /** 6 * This module is suited for computations on template arguments, both types and 7 * values at compile time. 8 * 9 * It contains different algorithms for iterating, searching and modifying 10 * template arguments. 11 * 12 * Copyright: Eugene Wissner 2017-2020. 13 * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, 14 * Mozilla Public License, v. 2.0). 15 * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) 16 * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/meta/tanya/meta/metafunction.d, 17 * tanya/meta/metafunction.d) 18 */ 19 module tanya.meta.metafunction; 20 21 import tanya.meta.trait; 22 import tanya.meta.transform; 23 24 /** 25 * Finds the minimum value in $(D_PARAM Args) according to $(D_PARAM pred). 26 * 27 * $(D_PARAM Args) should contain at least one element. 28 * 29 * $(D_PARAM pred) can evaluate to: 30 * $(UL 31 * $(LI $(D_KEYWORD bool): $(D_KEYWORD true) means 32 * $(D_INLINECODE Args[0] < Args[1]).) 33 * $(LI $(D_KEYWORD int): a negative number means that 34 * $(D_INLINECODE Args[0] < Args[1]), a positive number that 35 * $(D_INLINECODE Args[0] > Args[1]), `0` if they equal.) 36 * ) 37 * 38 * Params: 39 * pred = Template predicate. 40 * Args = Elements for which you want to find the minimum value. 41 * 42 * Returns: The minimum. 43 * 44 * See_Also: $(D_PSYMBOL isLess). 45 */ 46 template Min(alias pred, Args...) 47 if (Args.length > 0 && __traits(isTemplate, pred)) 48 { 49 static if (Args.length == 1) 50 { 51 alias Min = Alias!(Args[0]); 52 } 53 else static if (isLess!(pred, Args[1], Args[0])) 54 { 55 alias Min = Min!(pred, Args[1], Args[2 .. $]); 56 } 57 else 58 { 59 alias Min = Min!(pred, Args[0], Args[2 .. $]); 60 } 61 } 62 63 /// 64 @nogc nothrow pure @safe unittest 65 { 66 enum bool cmp(alias T, alias U) = T < U; 67 static assert(Min!(cmp, 8, 4, 5, 3, 13) == 3); 68 static assert(Min!(cmp, 8) == 8); 69 } 70 71 /** 72 * Finds the maximum value in $(D_PARAM Args) according to $(D_PARAM pred). 73 * 74 * $(D_PARAM Args) should contain at least one element. 75 * 76 * $(D_PARAM pred) can evaluate to: 77 * $(UL 78 * $(LI $(D_KEYWORD bool): $(D_KEYWORD true) means 79 * $(D_INLINECODE Args[0] < Args[1]).) 80 * $(LI $(D_KEYWORD int): a negative number means that 81 * $(D_INLINECODE Args[0] < Args[1]), a positive number that 82 * $(D_INLINECODE Args[0] > Args[1]), `0` if they equal.) 83 * ) 84 * 85 * Params: 86 * pred = Template predicate. 87 * Args = Elements for which you want to find the maximum value. 88 * 89 * Returns: The maximum. 90 * 91 * See_Also: $(D_PSYMBOL isLess). 92 */ 93 template Max(alias pred, Args...) 94 if (Args.length > 0 && __traits(isTemplate, pred)) 95 { 96 static if (Args.length == 1) 97 { 98 alias Max = Alias!(Args[0]); 99 } 100 else static if (isGreater!(pred, Args[1], Args[0])) 101 { 102 alias Max = Max!(pred, Args[1], Args[2 .. $]); 103 } 104 else 105 { 106 alias Max = Max!(pred, Args[0], Args[2 .. $]); 107 } 108 } 109 110 /// 111 @nogc nothrow pure @safe unittest 112 { 113 enum bool cmp(alias T, alias U) = T < U; 114 static assert(Max!(cmp, 8, 4, 5, 3, 13) == 13); 115 static assert(Max!(cmp, 8) == 8); 116 } 117 118 /** 119 * Zips one or more $(D_PSYMBOL Pack)s with $(D_PARAM f). 120 * 121 * Given $(D_PARAM f) and tuples t1, t2, ..., tk, where tk[i] denotes the 122 * $(I i)-th element of the tuple $(I k)-th tuple, $(D_PSYMBOL ZipWith) 123 * produces a sequence: 124 * 125 * --- 126 * f(t1[0], t2[0], ... tk[0]), 127 * f(t1[1], t2[1], ... tk[1]), 128 * ... 129 * f(tk[0], tk[1], ... tk[i]), 130 * --- 131 * 132 * $(D_PSYMBOL ZipWith) begins with the first elements from $(D_PARAM Packs) 133 * and applies $(D_PARAM f) to them, then it takes the second 134 * ones and does the same, and so on. 135 * 136 * If not all argument tuples have the same length, $(D_PSYMBOL ZipWith) will 137 * zip only `n` elements from each tuple, where `n` is the length of the 138 * shortest tuple in the argument list. Remaining elements in the longer tuples 139 * are just ignored. 140 * 141 * Params: 142 * f = Some template that can be applied to the elements of 143 * $(D_PARAM Packs). 144 * Packs = $(D_PSYMBOL Pack) instances. 145 * 146 * Returns: A sequence, whose $(I i)-th element contains the $(I i)-th element 147 * from each of the $(D_PARAM Packs). 148 */ 149 template ZipWith(alias f, Packs...) 150 if (Packs.length > 0 151 && __traits(isTemplate, f) 152 && (allSatisfy!(ApplyLeft!(isInstanceOf, Pack), Packs) 153 || allSatisfy!(ApplyLeft!(isInstanceOf, Tuple), Packs))) 154 { 155 private template GetIth(size_t i, Args...) 156 { 157 static if ((Args.length == 0) || (Args[0].Seq.length <= i)) 158 { 159 alias GetIth = AliasSeq!(); 160 } 161 else 162 { 163 alias GetIth = AliasSeq!(Args[0].Seq[i], GetIth!(i, Args[1 .. $])); 164 } 165 } 166 private template Iterate(size_t i, Args...) 167 { 168 alias Pack = GetIth!(i, Args); 169 170 static if (Pack.length < Packs.length) 171 { 172 alias Iterate = AliasSeq!(); 173 } 174 else 175 { 176 alias Iterate = AliasSeq!(f!Pack, Iterate!(i + 1, Args)); 177 } 178 } 179 alias ZipWith = Iterate!(0, Packs); 180 } 181 182 /// 183 @nogc nothrow pure @safe unittest 184 { 185 alias Result1 = ZipWith!(AliasSeq, Pack!(1, 2), Pack!(5, 6), Pack!(9, 10)); 186 static assert(Result1 == AliasSeq!(1, 5, 9, 2, 6, 10)); 187 188 alias Result2 = ZipWith!(AliasSeq, Pack!(1, 2, 3), Pack!(4, 5)); 189 static assert(Result2 == AliasSeq!(1, 4, 2, 5)); 190 191 alias Result3 = ZipWith!(AliasSeq, Pack!(), Pack!(4, 5)); 192 static assert(Result3.length == 0); 193 } 194 195 /** 196 * Holds a typed sequence of template parameters. 197 * 198 * Different than $(D_PSYMBOL AliasSeq), $(D_PSYMBOL Pack) doesn't unpack 199 * its template parameters automatically. Consider: 200 * 201 * --- 202 * template A(Args...) 203 * { 204 * static assert(Args.length == 4); 205 * } 206 * 207 * alias AInstance = A!(AliasSeq!(int, uint), AliasSeq!(float, double)); 208 * --- 209 * 210 * Using $(D_PSYMBOL AliasSeq) template `A` gets 4 parameters instead of 2, 211 * because $(D_PSYMBOL AliasSeq) is just an alias for its template parameters. 212 * 213 * With $(D_PSYMBOL Pack) it is possible to pass distinguishable 214 * sequences of parameters to a template. So: 215 * 216 * --- 217 * template B(Args...) 218 * { 219 * static assert(Args.length == 2); 220 * } 221 * 222 * alias BInstance = B!(Pack!(int, uint), Pack!(float, double)); 223 * --- 224 * 225 * Params: 226 * Args = Elements of this $(D_PSYMBOL Pack). 227 * 228 * See_Also: $(D_PSYMBOL AliasSeq). 229 */ 230 struct Pack(Args...) 231 { 232 /// Elements in this tuple as $(D_PSYMBOL AliasSeq). 233 alias Seq = Args; 234 235 /// The length of the tuple. 236 enum size_t length = Args.length; 237 238 alias Seq this; 239 } 240 241 /// 242 @nogc nothrow pure @safe unittest 243 { 244 alias A = Pack!short; 245 alias B = Pack!(3, 8, 9); 246 alias C = Pack!(A, B); 247 248 static assert(C.length == 2); 249 250 static assert(A.length == 1); 251 static assert(is(A.Seq == AliasSeq!short)); 252 static assert(B.length == 3); 253 static assert(B.Seq == AliasSeq!(3, 8, 9)); 254 255 alias D = Pack!(); 256 static assert(D.length == 0); 257 static assert(is(D.Seq == AliasSeq!())); 258 } 259 260 /** 261 * Unordered sequence of unique aliases. 262 * 263 * $(D_PARAM Args) can contain duplicates, but they will be filtered out, so 264 * $(D_PSYMBOL Set) contains only unique items. $(D_PSYMBOL isEqual) is used 265 * for determining if two items are equal. 266 * 267 * Params: 268 * Args = Elements of this $(D_PSYMBOL Set). 269 */ 270 struct Set(Args...) 271 { 272 /// Elements in this set as $(D_PSYMBOL AliasSeq). 273 alias Seq = NoDuplicates!Args; 274 275 /// The length of the set. 276 enum size_t length = Seq.length; 277 278 alias Seq this; 279 } 280 281 /// 282 @nogc nothrow pure @safe unittest 283 { 284 alias S1 = Set!(int, 5, 5, int, 4); 285 static assert(S1.length == 3); 286 } 287 288 /** 289 * Produces a $(D_PSYMBOL Set) containing all elements of the given 290 * $(D_PARAM Sets). 291 * 292 * Params: 293 * Sets = List of $(D_PSYMBOL Set) instances. 294 * 295 * Returns: Set-theoretic union of all $(D_PARAM Sets). 296 * 297 * See_Also: $(D_PSYMBOL Set). 298 */ 299 template Union(Sets...) 300 if (allSatisfy!(ApplyLeft!(isInstanceOf, Set), Sets)) 301 { 302 private template Impl(Sets...) 303 { 304 static if (Sets.length == 0) 305 { 306 alias Impl = AliasSeq!(); 307 } 308 else 309 { 310 alias Impl = AliasSeq!(Sets[0].Seq, Impl!(Sets[1 .. $])); 311 } 312 } 313 alias Union = Set!(Impl!Sets); 314 } 315 316 /// 317 @nogc nothrow pure @safe unittest 318 { 319 alias S1 = Set!(2, 5, 8, 4); 320 alias S2 = Set!(3, 8, 4, 1); 321 static assert(Union!(S1, S2).Seq == AliasSeq!(2, 5, 8, 4, 3, 1)); 322 } 323 324 /** 325 * Produces a $(D_PSYMBOL Set) that containing elements of 326 * $(D_INLINECODE Sets[0]) that are also elements of all other sets in 327 * $(D_PARAM Sets). 328 * 329 * Params: 330 * Sets = List of $(D_PSYMBOL Set) instances. 331 * 332 * Returns: Set-theoretic intersection of all $(D_PARAM Sets). 333 * 334 * See_Also: $(D_PSYMBOL Set). 335 */ 336 template Intersection(Sets...) 337 if (allSatisfy!(ApplyLeft!(isInstanceOf, Set), Sets)) 338 { 339 private template Impl(Args...) 340 if (Args.length > 0) 341 { 342 alias Equal = ApplyLeft!(isEqual, Args[0]); 343 static if (Args.length == 1) 344 { 345 enum bool Impl = true; 346 } 347 else static if (!anySatisfy!(Equal, Args[1].Seq)) 348 { 349 enum bool Impl = false; 350 } 351 else 352 { 353 enum bool Impl = Impl!(Args[0], Args[2 .. $]); 354 } 355 } 356 357 private enum bool FilterImpl(Args...) = Impl!(Args[0], Sets[1 .. $]); 358 359 static if (Sets.length == 0) 360 { 361 alias Intersection = Set!(); 362 } 363 else 364 { 365 alias Intersection = Set!(Filter!(FilterImpl, Sets[0].Seq)); 366 } 367 } 368 369 /// 370 @nogc nothrow pure @safe unittest 371 { 372 alias S1 = Set!(2, 5, 8, 4); 373 alias S2 = Set!(3, 8, 4, 1); 374 static assert(Intersection!(S1, S2).Seq == AliasSeq!(8, 4)); 375 376 static assert(Intersection!(S1).Seq == AliasSeq!(2, 5, 8, 4)); 377 static assert(Intersection!().length == 0); 378 } 379 380 /** 381 * Produces a $(D_PSYMBOL Set) that contains all elements of 382 * $(D_PARAM S1) that are not members of $(D_PARAM S2). 383 * 384 * Params: 385 * S1 = A $(D_PSYMBOL Set). 386 * S2 = A $(D_PSYMBOL Set). 387 * 388 * Returns: Set-theoretic difference of two sets $(D_PARAM S1) and 389 * $(D_PARAM S2). 390 * 391 * See_Also: $(D_PSYMBOL Set). 392 */ 393 template Difference(alias S1, alias S2) 394 if (isInstanceOf!(Set, S1) && isInstanceOf!(Set, S2)) 395 { 396 private template Impl(Args...) 397 { 398 alias Equal = ApplyLeft!(isEqual, Args[0]); 399 enum bool Impl = !anySatisfy!(Equal, S2.Seq); 400 } 401 402 static if (S1.length == 0) 403 { 404 alias Difference = Set!(); 405 } 406 else static if (S2.length == 1) 407 { 408 alias Difference = S1; 409 } 410 else 411 { 412 alias Difference = Set!(Filter!(Impl, S1.Seq)); 413 } 414 } 415 416 /// 417 @nogc nothrow pure @safe unittest 418 { 419 alias S1 = Set!(2, 5, 8, 4); 420 alias S2 = Set!(3, 8, 4, 1); 421 static assert(Difference!(S1, S2).Seq == AliasSeq!(2, 5)); 422 static assert(Difference!(S2, S1).Seq == AliasSeq!(3, 1)); 423 static assert(Difference!(S1, Set!()).Seq == AliasSeq!(2, 5, 8, 4)); 424 } 425 426 /** 427 * Tests whether $(D_INLINECODE Args[0]) is less than or equal to 428 * $(D_INLINECODE Args[1]) according to $(D_PARAM cmp). 429 * 430 * $(D_PARAM cmp) can evaluate to: 431 * $(UL 432 * $(LI $(D_KEYWORD bool): $(D_KEYWORD true) means 433 * $(D_INLINECODE Args[0] < Args[1]).) 434 * $(LI $(D_KEYWORD int): a negative number means that 435 * $(D_INLINECODE Args[0] < Args[1]), a positive number that 436 * $(D_INLINECODE Args[0] > Args[1]), `0` if they equal.) 437 * ) 438 * 439 * Params: 440 * Args = Two aliases to compare for equality. 441 * 442 * Returns: $(D_KEYWORD true) if $(D_INLINECODE Args[0]) is less than or equal 443 * to $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise. 444 */ 445 template isLessEqual(alias cmp, Args...) 446 if (Args.length == 2 && __traits(isTemplate, cmp)) 447 { 448 private enum result = cmp!(Args[1], Args[0]); 449 static if (is(typeof(result) == bool)) 450 { 451 enum bool isLessEqual = !result; 452 } 453 else 454 { 455 enum bool isLessEqual = result >= 0; 456 } 457 } 458 459 /// 460 @nogc nothrow pure @safe unittest 461 { 462 enum bool boolCmp(T, U) = T.sizeof < U.sizeof; 463 static assert(isLessEqual!(boolCmp, byte, int)); 464 static assert(isLessEqual!(boolCmp, uint, int)); 465 static assert(!isLessEqual!(boolCmp, long, int)); 466 467 enum ptrdiff_t intCmp(T, U) = T.sizeof - U.sizeof; 468 static assert(isLessEqual!(intCmp, byte, int)); 469 static assert(isLessEqual!(intCmp, uint, int)); 470 static assert(!isLessEqual!(intCmp, long, int)); 471 } 472 473 /** 474 * Tests whether $(D_INLINECODE Args[0]) is greater than or equal to 475 * $(D_INLINECODE Args[1]) according to $(D_PARAM cmp). 476 * 477 * $(D_PARAM cmp) can evaluate to: 478 * $(UL 479 * $(LI $(D_KEYWORD bool): $(D_KEYWORD true) means 480 * $(D_INLINECODE Args[0] < Args[1]).) 481 * $(LI $(D_KEYWORD int): a negative number means that 482 * $(D_INLINECODE Args[0] < Args[1]), a positive number that 483 * $(D_INLINECODE Args[0] > Args[1]), `0` if they equal.) 484 * ) 485 * 486 * Params: 487 * Args = Two aliases to compare for equality. 488 * 489 * Returns: $(D_KEYWORD true) if $(D_INLINECODE Args[0]) is greater than or 490 * equal to $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise. 491 */ 492 template isGreaterEqual(alias cmp, Args...) 493 if (Args.length == 2 && __traits(isTemplate, cmp)) 494 { 495 private enum result = cmp!Args; 496 static if (is(typeof(result) == bool)) 497 { 498 enum bool isGreaterEqual = !result; 499 } 500 else 501 { 502 enum bool isGreaterEqual = result >= 0; 503 } 504 } 505 506 /// 507 @nogc nothrow pure @safe unittest 508 { 509 enum bool boolCmp(T, U) = T.sizeof < U.sizeof; 510 static assert(!isGreaterEqual!(boolCmp, byte, int)); 511 static assert(isGreaterEqual!(boolCmp, uint, int)); 512 static assert(isGreaterEqual!(boolCmp, long, int)); 513 514 enum ptrdiff_t intCmp(T, U) = T.sizeof - U.sizeof; 515 static assert(!isGreaterEqual!(intCmp, byte, int)); 516 static assert(isGreaterEqual!(intCmp, uint, int)); 517 static assert(isGreaterEqual!(intCmp, long, int)); 518 } 519 520 /** 521 * Tests whether $(D_INLINECODE Args[0]) is less than 522 * $(D_INLINECODE Args[1]) according to $(D_PARAM cmp). 523 * 524 * $(D_PARAM cmp) can evaluate to: 525 * $(UL 526 * $(LI $(D_KEYWORD bool): $(D_KEYWORD true) means 527 * $(D_INLINECODE Args[0] < Args[1]).) 528 * $(LI $(D_KEYWORD int): a negative number means that 529 * $(D_INLINECODE Args[0] < Args[1]), a positive number that 530 * $(D_INLINECODE Args[0] > Args[1]), `0` if they equal.) 531 * ) 532 * 533 * Params: 534 * Args = Two aliases to compare for equality. 535 * 536 * Returns: $(D_KEYWORD true) if $(D_INLINECODE Args[0]) is less than 537 * $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise. 538 */ 539 template isLess(alias cmp, Args...) 540 if (Args.length == 2 && __traits(isTemplate, cmp)) 541 { 542 private enum result = cmp!Args; 543 static if (is(typeof(result) == bool)) 544 { 545 enum bool isLess = result; 546 } 547 else 548 { 549 enum bool isLess = result < 0; 550 } 551 } 552 553 /// 554 @nogc nothrow pure @safe unittest 555 { 556 enum bool boolCmp(T, U) = T.sizeof < U.sizeof; 557 static assert(isLess!(boolCmp, byte, int)); 558 static assert(!isLess!(boolCmp, uint, int)); 559 static assert(!isLess!(boolCmp, long, int)); 560 561 enum ptrdiff_t intCmp(T, U) = T.sizeof - U.sizeof; 562 static assert(isLess!(intCmp, byte, int)); 563 static assert(!isLess!(intCmp, uint, int)); 564 static assert(!isLess!(intCmp, long, int)); 565 } 566 567 /** 568 * Tests whether $(D_INLINECODE Args[0]) is greater than 569 * $(D_INLINECODE Args[1]) according to $(D_PARAM cmp). 570 * 571 * $(D_PARAM cmp) can evaluate to: 572 * $(UL 573 * $(LI $(D_KEYWORD bool): $(D_KEYWORD true) means 574 * $(D_INLINECODE Args[0] < Args[1]).) 575 * $(LI $(D_KEYWORD int): a negative number means that 576 * $(D_INLINECODE Args[0] < Args[1]), a positive number that 577 * $(D_INLINECODE Args[0] > Args[1]), `0` if they equal.) 578 * ) 579 * 580 * Params: 581 * Args = Two aliases to compare for equality. 582 * 583 * Returns: $(D_KEYWORD true) if $(D_INLINECODE Args[0]) is greater than 584 * $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise. 585 */ 586 template isGreater(alias cmp, Args...) 587 if (Args.length == 2 && __traits(isTemplate, cmp)) 588 { 589 private enum result = cmp!Args; 590 static if (is(typeof(result) == bool)) 591 { 592 enum bool isGreater = !result && cmp!(Args[1], Args[0]); 593 } 594 else 595 { 596 enum bool isGreater = result > 0; 597 } 598 } 599 600 /// 601 @nogc nothrow pure @safe unittest 602 { 603 enum bool boolCmp(T, U) = T.sizeof < U.sizeof; 604 static assert(!isGreater!(boolCmp, byte, int)); 605 static assert(!isGreater!(boolCmp, uint, int)); 606 static assert(isGreater!(boolCmp, long, int)); 607 608 enum ptrdiff_t intCmp(T, U) = T.sizeof - U.sizeof; 609 static assert(!isGreater!(intCmp, byte, int)); 610 static assert(!isGreater!(intCmp, uint, int)); 611 static assert(isGreater!(intCmp, long, int)); 612 } 613 614 /** 615 * Tests whether $(D_INLINECODE Args[0]) is equal to $(D_INLINECODE Args[1]). 616 * 617 * $(D_PSYMBOL isEqual) checks first if $(D_PARAM Args) can be compared directly. If not, they are compared as types: 618 * $(D_INLINECODE is(Args[0] == Args[1])). It it fails, the arguments are 619 * considered to be not equal. 620 * 621 * If two items cannot be compared (for example comparing a type with a 622 * number), they are considered not equal. 623 * 624 * Params: 625 * Args = Two aliases to compare for equality. 626 * 627 * Returns: $(D_KEYWORD true) if $(D_INLINECODE Args[0]) is equal to 628 * $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise. 629 */ 630 template isEqual(Args...) 631 if (Args.length == 2) 632 { 633 static if ((is(typeof(Args[0] == Args[1])) && (Args[0] == Args[1])) 634 || (isTypeTuple!Args && is(Args[0] == Args[1])) 635 || __traits(isSame, Args[0], Args[1])) 636 { 637 enum bool isEqual = true; 638 } 639 else 640 { 641 enum bool isEqual = false; 642 } 643 } 644 645 /// 646 @nogc nothrow pure @safe unittest 647 { 648 static assert(isEqual!(int, int)); 649 static assert(isEqual!(8, 8)); 650 static assert(!isEqual!(int, const(int))); 651 static assert(!isEqual!(5, int)); 652 static assert(!isEqual!(5, 8)); 653 } 654 655 /** 656 * Tests whether $(D_INLINECODE Args[0]) isn't equal to 657 * $(D_INLINECODE Args[1]). 658 * 659 * $(D_PSYMBOL isNotEqual) checks first if $(D_PARAM Args) can be compared directly. If not, they are compared as types: 660 * $(D_INLINECODE is(Args[0] == Args[1])). It it fails, the arguments are 661 * considered to be not equal. 662 * 663 * Params: 664 * Args = Two aliases to compare for equality. 665 * 666 * Returns: $(D_KEYWORD true) if $(D_INLINECODE Args[0]) isn't equal to 667 * $(D_INLINECODE Args[1]), $(D_KEYWORD false) otherwise. 668 */ 669 template isNotEqual(Args...) 670 if (Args.length == 2) 671 { 672 enum bool isNotEqual = !isEqual!Args; 673 } 674 675 /// 676 @nogc nothrow pure @safe unittest 677 { 678 static assert(!isNotEqual!(int, int)); 679 static assert(isNotEqual!(5, int)); 680 static assert(isNotEqual!(5, 8)); 681 } 682 683 /** 684 * Instantiates the template $(D_PARAM T) with $(D_PARAM Args). 685 * 686 * Params: 687 * T = Template. 688 * Args = Template parameters. 689 * 690 * Returns: Instantiated template. 691 */ 692 alias Instantiate(alias T, Args...) = T!Args; 693 694 /// 695 @nogc nothrow pure @safe unittest 696 { 697 template Template(T) 698 { 699 alias Template = T; 700 } 701 alias Seq = AliasSeq!(Template, Template); 702 703 alias Instance1 = Instantiate!(Seq[0], int); 704 static assert(is(Instance1 == int)); 705 706 alias Instance2 = Instantiate!(Seq[1], float); 707 static assert(is(Instance2 == float)); 708 } 709 710 /** 711 * Creates an alias for $(D_PARAM T). 712 * 713 * In contrast to the $(D_KEYWORD alias)-keyword $(D_PSYMBOL Alias) can alias 714 * any kind of D symbol that can be used as argument to template alias 715 * parameters. 716 * 717 * $(UL 718 * $(LI Types) 719 * $(LI Local and global names) 720 * $(LI Module names) 721 * $(LI Template names) 722 * $(LI Template instance names) 723 * $(LI Literals) 724 * ) 725 * 726 * Params: 727 * T = A symbol. 728 * 729 * Returns: An alias for $(D_PARAM T). 730 * 731 * See_Also: $(LINK2 https://dlang.org/spec/template.html#aliasparameters, 732 * Template Alias Parameters). 733 */ 734 alias Alias(alias T) = T; 735 736 /// ditto 737 alias Alias(T) = T; 738 739 /// 740 @nogc nothrow pure @safe unittest 741 { 742 static assert(is(Alias!int)); 743 744 static assert(is(typeof(Alias!5))); 745 static assert(is(typeof(Alias!(() {})))); 746 747 int i; 748 static assert(is(typeof(Alias!i))); 749 } 750 751 /** 752 * Holds a sequence of aliases. 753 * 754 * $(D_PSYMBOL AliasSeq) can be used to pass multiple parameters to a template 755 * at once. $(D_PSYMBOL AliasSeq) behaves as it were just $(D_PARAM Args). Note 756 * that because of this property, if multiple instances of 757 * $(D_PSYMBOL AliasSeq) are passed to a template, they are not distinguishable 758 * from each other and act as a single sequence. There is also no way to make 759 * $(D_PSYMBOL AliasSeq) nested, it always unpacks its elements. 760 * 761 * Params: 762 * Args = Symbol sequence. 763 * 764 * Returns: An alias for sequence $(D_PARAM Args). 765 * 766 * See_Also: $(D_PSYMBOL Alias). 767 */ 768 alias AliasSeq(Args...) = Args; 769 770 /// 771 @nogc nothrow pure @safe unittest 772 { 773 static assert(is(typeof({ alias T = AliasSeq!(short, 5); }))); 774 static assert(is(typeof({ alias T = AliasSeq!(int, short, 5); }))); 775 static assert(is(typeof({ alias T = AliasSeq!(() {}, short, 5); }))); 776 static assert(is(typeof({ alias T = AliasSeq!(); }))); 777 778 static assert(AliasSeq!().length == 0); 779 static assert(AliasSeq!(int, short, 5).length == 3); 780 781 alias A = AliasSeq!(short, float); 782 alias B = AliasSeq!(ushort, double); 783 alias C = AliasSeq!(A, B); 784 static assert(C.length == 4); 785 } 786 787 /** 788 * Tests whether all the items of $(D_PARAM L) satisfy the condition 789 * $(D_PARAM F). 790 * 791 * $(D_PARAM F) is a template that accepts one parameter and returns a boolean, 792 * so $(D_INLINECODE F!([0]) && F!([1])) and so on, can be called. 793 * 794 * Params: 795 * F = Template predicate. 796 * L = List of items to test. 797 * 798 * Returns: $(D_KEYWORD true) if all the items of $(D_PARAM L) satisfy 799 * $(D_PARAM F), $(D_KEYWORD false) otherwise. 800 */ 801 enum bool allSatisfy(alias F, L...) = Filter!(templateNot!F, L).length == 0; 802 803 /// 804 @nogc nothrow pure @safe unittest 805 { 806 static assert(allSatisfy!(isSigned, int, short, byte, long)); 807 static assert(!allSatisfy!(isUnsigned, uint, ushort, float, ulong)); 808 } 809 810 /** 811 * Tests whether any of the items of $(D_PARAM L) satisfy the condition 812 * $(D_PARAM F). 813 * 814 * $(D_PARAM F) is a template that accepts one parameter and returns a boolean, 815 * so $(D_INLINECODE F!([0]) && F!([1])) and so on, can be called. 816 * 817 * Params: 818 * F = Template predicate. 819 * L = List of items to test. 820 * 821 * Returns: $(D_KEYWORD true) if any of the items of $(D_PARAM L) satisfy 822 * $(D_PARAM F), $(D_KEYWORD false) otherwise. 823 */ 824 enum bool anySatisfy(alias F, L...) = Filter!(F, L).length != 0; 825 826 /// 827 @nogc nothrow pure @safe unittest 828 { 829 static assert(anySatisfy!(isSigned, int, short, byte, long)); 830 static assert(anySatisfy!(isUnsigned, uint, ushort, float, ulong)); 831 static assert(!anySatisfy!(isSigned, uint, ushort, ulong)); 832 } 833 834 private template indexOf(Args...) 835 { 836 static foreach (i, Arg; Args[1 .. $]) 837 { 838 static if (!is(typeof(indexOf) == ptrdiff_t) && isEqual!(Args[0], Arg)) 839 { 840 enum ptrdiff_t indexOf = i; 841 } 842 } 843 static if (!is(typeof(indexOf) == ptrdiff_t)) 844 { 845 enum ptrdiff_t indexOf = -1; 846 } 847 } 848 849 /** 850 * Returns the index of the first occurrence of $(D_PARAM T) in $(D_PARAM L). 851 * `-1` is returned if $(D_PARAM T) is not found. 852 * 853 * Params: 854 * T = The item to search for. 855 * L = Symbol sequence. 856 * 857 * Returns: The index of the first occurrence of $(D_PARAM T) in $(D_PARAM L). 858 */ 859 template staticIndexOf(T, L...) 860 { 861 enum ptrdiff_t staticIndexOf = indexOf!(T, L); 862 } 863 864 /// ditto 865 template staticIndexOf(alias T, L...) 866 { 867 enum ptrdiff_t staticIndexOf = indexOf!(T, L); 868 } 869 870 /// 871 @nogc nothrow pure @safe unittest 872 { 873 static assert(staticIndexOf!(int) == -1); 874 static assert(staticIndexOf!(int, int) == 0); 875 static assert(staticIndexOf!(int, float, double, int, real) == 2); 876 static assert(staticIndexOf!(3, () {}, uint, 5, 3) == 3); 877 } 878 879 /** 880 * Looks for $(D_PARAM T) in $(D_PARAM L) and returns $(D_KEYWORD true) if it 881 * could be found and $(D_KEYWORD false) otherwise. 882 * 883 * Params: 884 * T = The item to search for. 885 * L = Symbol sequence. 886 * 887 * Returns: $(D_KEYWORD true) if $(D_PARAM T) can be found in $(D_PARAM L), 888 * $(D_KEYWORD false) otherwise. 889 */ 890 enum bool canFind(T, L...) = staticIndexOf!(T, L) != -1; 891 892 /// ditto 893 enum bool canFind(alias T, L...) = staticIndexOf!(T, L) != -1; 894 895 /// 896 @nogc nothrow pure @safe unittest 897 { 898 static assert(!canFind!(int)); 899 static assert(canFind!(int, int)); 900 static assert(canFind!(int, float, double, int, real)); 901 static assert(canFind!(3, () {}, uint, 5, 3)); 902 } 903 904 /* 905 * Tests whether $(D_PARAM T) is a template. 906 * 907 * $(D_PSYMBOL isTemplate) isn't $(D_KEYWORD true) for template instances, 908 * since the latter already represent some type. Only not instantiated 909 * templates, i.e. that accept some template parameters, are considered 910 * templates. 911 * 912 * Params: 913 * T = A symbol. 914 * 915 * Returns: $(D_KEYWORD true) if $(D_PARAM T) is a template, 916 * $(D_KEYWORD false) otherwise. 917 */ 918 private enum bool isTemplate(alias T) = __traits(isTemplate, T); 919 920 /// 921 @nogc nothrow pure @safe unittest 922 { 923 static struct S(T) 924 { 925 } 926 static assert(isTemplate!S); 927 static assert(!isTemplate!(S!int)); 928 } 929 930 /** 931 * Combines multiple templates with logical AND. So $(D_PSYMBOL templateAnd) 932 * evaluates to $(D_INLINECODE Preds[0] && Preds[1] && Preds[2]) and so on. 933 * 934 * Empty $(D_PARAM Preds) evaluates to $(D_KEYWORD true). 935 * 936 * Params: 937 * Preds = Template predicates. 938 * 939 * Returns: The constructed template. 940 */ 941 template templateAnd(Preds...) 942 if (allSatisfy!(isTemplate, Preds)) 943 { 944 template templateAnd(T...) 945 { 946 static if (Preds.length == 0) 947 { 948 enum bool templateAnd = true; 949 } 950 else static if (Instantiate!(Preds[0], T)) 951 { 952 alias templateAnd = Instantiate!(.templateAnd!(Preds[1 .. $]), T); 953 } 954 else 955 { 956 enum bool templateAnd = false; 957 } 958 } 959 } 960 961 /// 962 @nogc nothrow pure @safe unittest 963 { 964 alias isMutableInt = templateAnd!(isIntegral, isMutable); 965 static assert(isMutableInt!int); 966 static assert(!isMutableInt!(const int)); 967 static assert(!isMutableInt!float); 968 969 alias alwaysTrue = templateAnd!(); 970 static assert(alwaysTrue!int); 971 972 alias isIntegral = templateAnd!(.isIntegral); 973 static assert(isIntegral!int); 974 static assert(isIntegral!(const int)); 975 static assert(!isIntegral!float); 976 } 977 978 /** 979 * Combines multiple templates with logical OR. So $(D_PSYMBOL templateOr) 980 * evaluates to $(D_INLINECODE Preds[0] || Preds[1] || Preds[2]) and so on. 981 * 982 * Empty $(D_PARAM Preds) evaluates to $(D_KEYWORD false). 983 * 984 * Params: 985 * Preds = Template predicates. 986 * 987 * Returns: The constructed template. 988 */ 989 template templateOr(Preds...) 990 if (allSatisfy!(isTemplate, Preds)) 991 { 992 template templateOr(T...) 993 { 994 static if (Preds.length == 0) 995 { 996 enum bool templateOr = false; 997 } 998 else static if (Instantiate!(Preds[0], T)) 999 { 1000 enum bool templateOr = true; 1001 } 1002 else 1003 { 1004 alias templateOr = Instantiate!(.templateOr!(Preds[1 .. $]), T); 1005 } 1006 } 1007 } 1008 1009 /// 1010 @nogc nothrow pure @safe unittest 1011 { 1012 alias isMutableOrInt = templateOr!(isIntegral, isMutable); 1013 static assert(isMutableOrInt!int); 1014 static assert(isMutableOrInt!(const int)); 1015 static assert(isMutableOrInt!float); 1016 static assert(!isMutableOrInt!(const float)); 1017 1018 alias alwaysFalse = templateOr!(); 1019 static assert(!alwaysFalse!int); 1020 1021 alias isIntegral = templateOr!(.isIntegral); 1022 static assert(isIntegral!int); 1023 static assert(isIntegral!(const int)); 1024 static assert(!isIntegral!float); 1025 } 1026 1027 /** 1028 * Params: 1029 * pred = Template predicate. 1030 * 1031 * Returns: Negated $(D_PARAM pred). 1032 */ 1033 template templateNot(alias pred) 1034 if (__traits(isTemplate, pred)) 1035 { 1036 enum bool templateNot(T...) = !pred!T; 1037 } 1038 1039 /// 1040 @nogc nothrow pure @safe unittest 1041 { 1042 alias isNotIntegral = templateNot!isIntegral; 1043 static assert(!isNotIntegral!int); 1044 static assert(isNotIntegral!(char[])); 1045 } 1046 1047 /** 1048 * Tests whether $(D_PARAM L) is sorted in ascending order according to 1049 * $(D_PARAM cmp). 1050 * 1051 * $(D_PARAM cmp) can evaluate to: 1052 * $(UL 1053 * $(LI $(D_KEYWORD bool): $(D_KEYWORD true) means 1054 * $(D_INLINECODE a[i] < a[i + 1]).) 1055 * $(LI $(D_KEYWORD int): a negative number means that 1056 * $(D_INLINECODE a[i] < a[i + 1]), a positive number that 1057 * $(D_INLINECODE a[i] > a[i + 1]), `0` if they equal.) 1058 * ) 1059 * 1060 * Params: 1061 * cmp = Sorting template predicate. 1062 * L = Elements to be tested. 1063 * 1064 * Returns: $(D_KEYWORD true) if $(D_PARAM L) is sorted, $(D_KEYWORD false) 1065 * if not. 1066 */ 1067 template isSorted(alias cmp, L...) 1068 if (__traits(isTemplate, cmp)) 1069 { 1070 static if (L.length <= 1) 1071 { 1072 enum bool isSorted = true; 1073 } 1074 else 1075 { 1076 // `L` is sorted if the both halves and the boundary values are sorted. 1077 enum bool isSorted = isLessEqual!(cmp, L[$ / 2 - 1], L[$ / 2]) 1078 && isSorted!(cmp, L[0 .. $ / 2]) 1079 && isSorted!(cmp, L[$ / 2 .. $]); 1080 } 1081 } 1082 1083 /// 1084 @nogc nothrow pure @safe unittest 1085 { 1086 enum cmp(T, U) = T.sizeof < U.sizeof; 1087 static assert(isSorted!(cmp)); 1088 static assert(isSorted!(cmp, byte)); 1089 static assert(isSorted!(cmp, byte, ubyte, short, uint)); 1090 static assert(!isSorted!(cmp, long, byte, ubyte, short, uint)); 1091 } 1092 1093 /** 1094 * Params: 1095 * T = A template. 1096 * Args = The first arguments for $(D_PARAM T). 1097 * 1098 * Returns: $(D_PARAM T) with $(D_PARAM Args) applied to it as its first 1099 * arguments. 1100 */ 1101 template ApplyLeft(alias T, Args...) 1102 { 1103 alias ApplyLeft(U...) = T!(Args, U); 1104 } 1105 1106 /// 1107 @nogc nothrow pure @safe unittest 1108 { 1109 alias allAreIntegral = ApplyLeft!(allSatisfy, isIntegral); 1110 static assert(allAreIntegral!(int, uint)); 1111 static assert(!allAreIntegral!(int, float, uint)); 1112 } 1113 1114 /** 1115 * Params: 1116 * T = A template. 1117 * Args = The last arguments for $(D_PARAM T). 1118 * 1119 * Returns: $(D_PARAM T) with $(D_PARAM Args) applied to it as itslast 1120 * arguments. 1121 */ 1122 template ApplyRight(alias T, Args...) 1123 { 1124 alias ApplyRight(U...) = T!(U, Args); 1125 } 1126 1127 /// 1128 @nogc nothrow pure @safe unittest 1129 { 1130 alias intIs = ApplyRight!(allSatisfy, int); 1131 static assert(intIs!(isIntegral)); 1132 static assert(!intIs!(isUnsigned)); 1133 } 1134 1135 /** 1136 * Params: 1137 * n = The number of times to repeat $(D_PARAM L). 1138 * L = The sequence to be repeated. 1139 * 1140 * Returns: $(D_PARAM L) repeated $(D_PARAM n) times. 1141 */ 1142 template Repeat(size_t n, L...) 1143 if (n > 0) 1144 { 1145 static if (n == 1) 1146 { 1147 alias Repeat = L; 1148 } 1149 else 1150 { 1151 alias Repeat = AliasSeq!(L, Repeat!(n - 1, L)); 1152 } 1153 } 1154 1155 /// 1156 @nogc nothrow pure @safe unittest 1157 { 1158 static assert(is(Repeat!(1, uint, int) == AliasSeq!(uint, int))); 1159 static assert(is(Repeat!(2, uint, int) == AliasSeq!(uint, int, uint, int))); 1160 static assert(is(Repeat!(3) == AliasSeq!())); 1161 } 1162 1163 private template ReplaceOne(L...) 1164 { 1165 static if (L.length == 2) 1166 { 1167 alias ReplaceOne = AliasSeq!(); 1168 } 1169 else static if (isEqual!(L[0], L[2])) 1170 { 1171 alias ReplaceOne = AliasSeq!(L[1], L[3 .. $]); 1172 } 1173 else 1174 { 1175 alias ReplaceOne = AliasSeq!(L[2], ReplaceOne!(L[0], L[1], L[3 .. $])); 1176 } 1177 } 1178 1179 /** 1180 * Replaces the first occurrence of $(D_PARAM T) in $(D_PARAM L) with 1181 * $(D_PARAM U). 1182 * 1183 * Params: 1184 * T = The symbol to be replaced. 1185 * U = Replacement. 1186 * L = List of symbols. 1187 * 1188 * Returns: $(D_PARAM L) with the first occurrence of $(D_PARAM T) replaced. 1189 */ 1190 template Replace(T, U, L...) 1191 { 1192 alias Replace = ReplaceOne!(T, U, L); 1193 } 1194 1195 /// ditto 1196 template Replace(alias T, U, L...) 1197 { 1198 alias Replace = ReplaceOne!(T, U, L); 1199 } 1200 1201 /// ditto 1202 template Replace(T, alias U, L...) 1203 { 1204 alias Replace = ReplaceOne!(T, U, L); 1205 } 1206 1207 /// ditto 1208 template Replace(alias T, alias U, L...) 1209 { 1210 alias Replace = ReplaceOne!(T, U, L); 1211 } 1212 1213 /// 1214 @nogc nothrow pure @safe unittest 1215 { 1216 static assert(is(Replace!(int, uint, int) == AliasSeq!(uint))); 1217 static assert(is(Replace!(int, uint, short, int, int, ushort) 1218 == AliasSeq!(short, uint, int, ushort))); 1219 1220 static assert(Replace!(5, 8, 1, 2, 5, 5) == AliasSeq!(1, 2, 8, 5)); 1221 } 1222 1223 private template ReplaceAllImpl(L...) 1224 { 1225 static if (L.length == 2) 1226 { 1227 alias ReplaceAllImpl = AliasSeq!(); 1228 } 1229 else 1230 { 1231 private alias Rest = ReplaceAllImpl!(L[0], L[1], L[3 .. $]); 1232 static if (isEqual!(L[0], L[2])) 1233 { 1234 alias ReplaceAllImpl = AliasSeq!(L[1], Rest); 1235 } 1236 else 1237 { 1238 alias ReplaceAllImpl = AliasSeq!(L[2], Rest); 1239 } 1240 } 1241 } 1242 1243 /** 1244 * Replaces all occurrences of $(D_PARAM T) in $(D_PARAM L) with $(D_PARAM U). 1245 * 1246 * Params: 1247 * T = The symbol to be replaced. 1248 * U = Replacement. 1249 * L = List of symbols. 1250 * 1251 * Returns: $(D_PARAM L) with all occurrences of $(D_PARAM T) replaced. 1252 */ 1253 template ReplaceAll(T, U, L...) 1254 { 1255 alias ReplaceAll = ReplaceAllImpl!(T, U, L); 1256 } 1257 1258 /// ditto 1259 template ReplaceAll(alias T, U, L...) 1260 { 1261 alias ReplaceAll = ReplaceAllImpl!(T, U, L); 1262 } 1263 1264 /// ditto 1265 template ReplaceAll(T, alias U, L...) 1266 { 1267 alias ReplaceAll = ReplaceAllImpl!(T, U, L); 1268 } 1269 1270 /// ditto 1271 template ReplaceAll(alias T, alias U, L...) 1272 { 1273 alias ReplaceAll = ReplaceAllImpl!(T, U, L); 1274 } 1275 1276 /// 1277 @nogc nothrow pure @safe unittest 1278 { 1279 static assert(is(ReplaceAll!(int, uint, int) == AliasSeq!(uint))); 1280 static assert(is(ReplaceAll!(int, uint, short, int, int, ushort) 1281 == AliasSeq!(short, uint, uint, ushort))); 1282 1283 static assert(ReplaceAll!(5, 8, 1, 2, 5, 5) == AliasSeq!(1, 2, 8, 8)); 1284 } 1285 1286 /** 1287 * Params: 1288 * L = List of symbols. 1289 * 1290 * Returns: $(D_PARAM L) with elements in reversed order. 1291 */ 1292 template Reverse(L...) 1293 { 1294 static if (L.length == 0) 1295 { 1296 alias Reverse = AliasSeq!(); 1297 } 1298 else 1299 { 1300 alias Reverse = AliasSeq!(L[$ - 1], Reverse!(L[0 .. $ - 1])); 1301 } 1302 } 1303 1304 /// 1305 @nogc nothrow pure @safe unittest 1306 { 1307 static assert(is(Reverse!(byte, short, int) == AliasSeq!(int, short, byte))); 1308 } 1309 1310 /** 1311 * Applies $(D_PARAM F) to all elements of $(D_PARAM T). 1312 * 1313 * Params: 1314 * F = Template predicate. 1315 * T = List of symbols. 1316 * 1317 * Returns: Elements $(D_PARAM T) after applying $(D_PARAM F) to them. 1318 */ 1319 template Map(alias F, T...) 1320 if (__traits(isTemplate, F)) 1321 { 1322 static if (T.length == 0) 1323 { 1324 alias Map = AliasSeq!(); 1325 } 1326 else 1327 { 1328 alias Map = AliasSeq!(F!(T[0]), Map!(F, T[1 .. $])); 1329 } 1330 } 1331 1332 /// 1333 @nogc nothrow pure @safe unittest 1334 { 1335 static assert(is(Map!(Unqual, const int, immutable short) 1336 == AliasSeq!(int, short))); 1337 } 1338 1339 /** 1340 * Sorts $(D_PARAM L) in ascending order according to $(D_PARAM cmp). 1341 * 1342 * $(D_PARAM cmp) can evaluate to: 1343 * $(UL 1344 * $(LI $(D_KEYWORD bool): $(D_KEYWORD true) means 1345 * $(D_INLINECODE a[i] < a[i + 1]).) 1346 * $(LI $(D_KEYWORD int): a negative number means that 1347 * $(D_INLINECODE a[i] < a[i + 1]), a positive number that 1348 * $(D_INLINECODE a[i] > a[i + 1]), `0` if they equal.) 1349 * ) 1350 * 1351 * Merge sort is used to sort the arguments. 1352 * 1353 * Params: 1354 * cmp = Sorting template predicate. 1355 * L = Elements to be sorted. 1356 * 1357 * Returns: Elements of $(D_PARAM L) in ascending order. 1358 * 1359 * See_Also: $(LINK2 https://en.wikipedia.org/wiki/Merge_sort, Merge sort). 1360 */ 1361 template Sort(alias cmp, L...) 1362 if (__traits(isTemplate, cmp)) 1363 { 1364 private template merge(size_t A, size_t B) 1365 { 1366 static if (A + B == L.length) 1367 { 1368 alias merge = AliasSeq!(); 1369 } 1370 else static if (B >= Right.length 1371 || (A < Left.length && isLessEqual!(cmp, Left[A], Right[B]))) 1372 { 1373 alias merge = AliasSeq!(Left[A], merge!(A + 1, B)); 1374 } 1375 else 1376 { 1377 alias merge = AliasSeq!(Right[B], merge!(A, B + 1)); 1378 } 1379 } 1380 1381 static if (L.length <= 1) 1382 { 1383 alias Sort = L; 1384 } 1385 else 1386 { 1387 private alias Left = Sort!(cmp, L[0 .. $ / 2]); 1388 private alias Right = Sort!(cmp, L[$ / 2 .. $]); 1389 alias Sort = merge!(0, 0); 1390 } 1391 } 1392 1393 /// 1394 @nogc nothrow pure @safe unittest 1395 { 1396 enum cmp(T, U) = T.sizeof < U.sizeof; 1397 static assert(is(Sort!(cmp, long, short, byte, int) 1398 == AliasSeq!(byte, short, int, long))); 1399 } 1400 1401 @nogc nothrow pure @safe unittest 1402 { 1403 enum cmp(int T, int U) = T - U; 1404 static assert(Sort!(cmp, 5, 17, 9, 12, 2, 10, 14) 1405 == AliasSeq!(2, 5, 9, 10, 12, 14, 17)); 1406 } 1407 1408 private enum bool DerivedToFrontCmp(A, B) = is(A : B); 1409 1410 /** 1411 * Returns $(D_PARAM L) sorted in such a way that the most derived types come 1412 * first. 1413 * 1414 * Params: 1415 * L = Type tuple. 1416 * 1417 * Returns: Sorted $(D_PARAM L). 1418 */ 1419 template DerivedToFront(L...) 1420 { 1421 alias DerivedToFront = Sort!(DerivedToFrontCmp, L); 1422 } 1423 1424 /// 1425 @nogc nothrow pure @safe unittest 1426 { 1427 class A 1428 { 1429 } 1430 class B : A 1431 { 1432 } 1433 class C : B 1434 { 1435 } 1436 static assert(is(DerivedToFront!(B, A, C) == AliasSeq!(C, B, A))); 1437 } 1438 1439 /** 1440 * Returns the type from the type tuple $(D_PARAM L) that is most derived from 1441 * $(D_PARAM T). 1442 * 1443 * Params: 1444 * T = The type to compare to. 1445 * L = Type tuple. 1446 * 1447 * Returns: The type most derived from $(D_PARAM T). 1448 */ 1449 template MostDerived(T, L...) 1450 { 1451 static if (L.length == 0) 1452 { 1453 alias MostDerived = T; 1454 } 1455 else static if (is(T : L[0])) 1456 { 1457 alias MostDerived = MostDerived!(T, L[1 .. $]); 1458 } 1459 else 1460 { 1461 alias MostDerived = MostDerived!(L[0], L[1 .. $]); 1462 } 1463 } 1464 1465 /// 1466 @nogc nothrow pure @safe unittest 1467 { 1468 class A 1469 { 1470 } 1471 class B : A 1472 { 1473 } 1474 class C : B 1475 { 1476 } 1477 static assert(is(MostDerived!(A, C, B) == C)); 1478 } 1479 1480 private template EraseOne(L...) 1481 if (L.length > 0) 1482 { 1483 static if (L.length == 1) 1484 { 1485 alias EraseOne = AliasSeq!(); 1486 } 1487 else static if (isEqual!(L[0 .. 2])) 1488 { 1489 alias EraseOne = AliasSeq!(L[2 .. $]); 1490 } 1491 else 1492 { 1493 alias EraseOne = AliasSeq!(L[1], EraseOne!(L[0], L[2 .. $])); 1494 } 1495 } 1496 1497 /** 1498 * Removes the first occurrence of $(D_PARAM T) from the alias sequence 1499 * $(D_PARAL L). 1500 * 1501 * Params: 1502 * T = The item to be removed. 1503 * L = Alias sequence. 1504 * 1505 * Returns: $(D_PARAM L) with the first occurrence of $(D_PARAM T) removed. 1506 */ 1507 template Erase(T, L...) 1508 { 1509 alias Erase = EraseOne!(T, L); 1510 } 1511 1512 /// ditto 1513 template Erase(alias T, L...) 1514 { 1515 alias Erase = EraseOne!(T, L); 1516 } 1517 1518 /// 1519 @nogc nothrow pure @safe unittest 1520 { 1521 static assert(is(Erase!(int, short, int, int, uint) == AliasSeq!(short, int, uint))); 1522 static assert(is(Erase!(int, short, uint) == AliasSeq!(short, uint))); 1523 } 1524 1525 private template EraseAllImpl(L...) 1526 { 1527 static if (L.length == 1) 1528 { 1529 alias EraseAllImpl = AliasSeq!(); 1530 } 1531 else static if (isEqual!(L[0 .. 2])) 1532 { 1533 alias EraseAllImpl = EraseAllImpl!(L[0], L[2 .. $]); 1534 } 1535 else 1536 { 1537 alias EraseAllImpl = AliasSeq!(L[1], EraseAllImpl!(L[0], L[2 .. $])); 1538 } 1539 } 1540 1541 /** 1542 * Removes all occurrences of $(D_PARAM T) from the alias sequence $(D_PARAL L). 1543 * 1544 * Params: 1545 * T = The item to be removed. 1546 * L = Alias sequence. 1547 * 1548 * Returns: $(D_PARAM L) with all occurrences of $(D_PARAM T) removed. 1549 */ 1550 template EraseAll(T, L...) 1551 { 1552 alias EraseAll = EraseAllImpl!(T, L); 1553 } 1554 1555 /// ditto 1556 template EraseAll(alias T, L...) 1557 { 1558 alias EraseAll = EraseAllImpl!(T, L); 1559 } 1560 1561 /// 1562 @nogc nothrow pure @safe unittest 1563 { 1564 static assert(is(EraseAll!(int, short, int, int, uint) == AliasSeq!(short, uint))); 1565 static assert(is(EraseAll!(int, short, uint) == AliasSeq!(short, uint))); 1566 static assert(is(EraseAll!(int, int, int) == AliasSeq!())); 1567 } 1568 1569 /** 1570 * Returns an alias sequence which contains only items that satisfy the 1571 * condition $(D_PARAM pred). 1572 * 1573 * Params: 1574 * pred = Template predicate. 1575 * L = Alias sequence. 1576 * 1577 * Returns: $(D_PARAM L) filtered so that it contains only items that satisfy 1578 * $(D_PARAM pred). 1579 */ 1580 template Filter(alias pred, L...) 1581 if (__traits(isTemplate, pred)) 1582 { 1583 static if (L.length == 0) 1584 { 1585 alias Filter = AliasSeq!(); 1586 } 1587 else static if (pred!(L[0])) 1588 { 1589 alias Filter = AliasSeq!(L[0], Filter!(pred, L[1 .. $])); 1590 } 1591 else 1592 { 1593 alias Filter = Filter!(pred, L[1 .. $]); 1594 } 1595 } 1596 1597 /// 1598 @nogc nothrow pure @safe unittest 1599 { 1600 alias Given = AliasSeq!(real, int, bool, uint); 1601 static assert(is(Filter!(isIntegral, Given) == AliasSeq!(int, uint))); 1602 } 1603 1604 /** 1605 * Removes all duplicates from the alias sequence $(D_PARAM L). 1606 * 1607 * Params: 1608 * L = Alias sequence. 1609 * 1610 * Returns: $(D_PARAM L) containing only unique items. 1611 */ 1612 template NoDuplicates(L...) 1613 { 1614 static if (L.length == 0) 1615 { 1616 alias NoDuplicates = AliasSeq!(); 1617 } 1618 else 1619 { 1620 private alias Rest = NoDuplicates!(EraseAll!(L[0], L[1 .. $])); 1621 alias NoDuplicates = AliasSeq!(L[0], Rest); 1622 } 1623 } 1624 1625 /// 1626 @nogc nothrow pure @safe unittest 1627 { 1628 alias Given = AliasSeq!(int, uint, int, short, short, uint); 1629 static assert(is(NoDuplicates!Given == AliasSeq!(int, uint, short))); 1630 } 1631 1632 /** 1633 * Converts an input range $(D_PARAM range) into an alias sequence. 1634 * 1635 * Params: 1636 * range = Input range. 1637 * 1638 * Returns: Alias sequence with items from $(D_PARAM range). 1639 */ 1640 template aliasSeqOf(alias range) 1641 { 1642 static if (isArray!(typeof(range))) 1643 { 1644 static if (range.length == 0) 1645 { 1646 alias aliasSeqOf = AliasSeq!(); 1647 } 1648 else 1649 { 1650 alias aliasSeqOf = AliasSeq!(range[0], aliasSeqOf!(range[1 .. $])); 1651 } 1652 } 1653 else 1654 { 1655 ReturnType!(typeof(&range.front))[] toArray(typeof(range) range) 1656 { 1657 typeof(return) result; 1658 foreach (r; range) 1659 { 1660 result ~= r; 1661 } 1662 return result; 1663 } 1664 alias aliasSeqOf = aliasSeqOf!(toArray(range)); 1665 } 1666 } 1667 1668 /// 1669 @nogc nothrow pure @safe unittest 1670 { 1671 static assert(aliasSeqOf!([0, 1, 2, 3]) == AliasSeq!(0, 1, 2, 3)); 1672 } 1673 1674 /** 1675 * Produces a alias sequence consisting of every $(D_PARAM n)th element of 1676 * $(D_PARAM Args), starting with the first. 1677 * 1678 * Params: 1679 * n = Step. 1680 * Args = The items to stride. 1681 * 1682 * Returns: Alias sequence of every $(D_PARAM n)th element of $(D_PARAM Args). 1683 */ 1684 template Stride(size_t n, Args...) 1685 if (n > 0) 1686 { 1687 static if (Args.length > n) 1688 { 1689 alias Stride = AliasSeq!(Args[0], Stride!(n, Args[n .. $])); 1690 } 1691 else static if (Args.length > 0) 1692 { 1693 alias Stride = AliasSeq!(Args[0]); 1694 } 1695 else 1696 { 1697 alias Stride = AliasSeq!(); 1698 } 1699 } 1700 1701 /// 1702 @nogc nothrow pure @safe unittest 1703 { 1704 static assert(Stride!(3, 1, 2, 3, 4, 5, 6, 7, 8) == AliasSeq!(1, 4, 7)); 1705 static assert(Stride!(2, 1, 2, 3) == AliasSeq!(1, 3)); 1706 static assert(Stride!(2, 1, 2) == AliasSeq!(1)); 1707 static assert(Stride!(2, 1) == AliasSeq!(1)); 1708 static assert(Stride!(1, 1, 2, 3) == AliasSeq!(1, 2, 3)); 1709 static assert(is(Stride!3 == AliasSeq!())); 1710 } 1711 1712 /** 1713 * Aliases itself to $(D_INLINECODE T[0]) if $(D_PARAM cond) is $(D_KEYWORD true), 1714 * to $(D_INLINECODE T[1]) if $(D_KEYWORD false). 1715 * 1716 * Params: 1717 * cond = Template predicate. 1718 * T = Two arguments. 1719 * 1720 * Returns: $(D_INLINECODE T[0]) if $(D_PARAM cond) is $(D_KEYWORD true), 1721 * $(D_INLINECODE T[1]) otherwise. 1722 */ 1723 template Select(bool cond, T...) 1724 if (T.length == 2) 1725 { 1726 static if (cond) 1727 { 1728 alias Select = T[0]; 1729 } 1730 else 1731 { 1732 alias Select = T[1]; 1733 } 1734 } 1735 1736 /// 1737 @nogc nothrow pure @safe unittest 1738 { 1739 static assert(is(Select!(true, int, float) == int)); 1740 static assert(is(Select!(false, int, float) == float)); 1741 } 1742 1743 /** 1744 * Attaches a numeric index to each element from $(D_PARAM Args). 1745 * 1746 * $(D_PSYMBOL EnumerateFrom) returns a sequence of tuples ($(D_PSYMBOL Pack)s) 1747 * consisting of the index of each element and the element itself. 1748 * 1749 * Params: 1750 * start = Enumeration initial value. 1751 * Args = Enumerated sequence. 1752 * 1753 * See_Also: $(D_PSYMBOL Enumerate). 1754 */ 1755 template EnumerateFrom(size_t start, Args...) 1756 { 1757 static if (Args.length == 0) 1758 { 1759 alias EnumerateFrom = AliasSeq!(); 1760 } 1761 else 1762 { 1763 alias EnumerateFrom = AliasSeq!(Pack!(start, Args[0]), EnumerateFrom!(start + 1, Args[1 .. $])); 1764 } 1765 } 1766 1767 /// 1768 @nogc nothrow pure @safe unittest 1769 { 1770 static assert(EnumerateFrom!(0, int, uint, bool).length == 3); 1771 } 1772 1773 /// 1774 @nogc nothrow pure @safe unittest 1775 { 1776 alias Expected = AliasSeq!(Pack!(cast(size_t) 0, int), 1777 Pack!(cast(size_t) 1, uint)); 1778 static assert(is(EnumerateFrom!(0, int, uint) == Expected)); 1779 } 1780 1781 /** 1782 * Attaches a numeric index to each element from $(D_PARAM Args). 1783 * 1784 * $(D_PSYMBOL EnumerateFrom) returns a sequence of tuples ($(D_PSYMBOL Pack)s) 1785 * consisting of the index of each element and the element itself. 1786 * 1787 * Params: 1788 * Args = Enumerated sequence. 1789 * 1790 * See_Also: $(D_PSYMBOL EnumerateFrom). 1791 */ 1792 alias Enumerate(Args...) = EnumerateFrom!(0, Args); 1793 1794 /// 1795 @nogc nothrow pure @safe unittest 1796 { 1797 alias Expected = AliasSeq!(Pack!(cast(size_t) 0, int), 1798 Pack!(cast(size_t) 1, uint)); 1799 static assert(is(Enumerate!(int, uint) == Expected)); 1800 }