1 // Written in the D programming language. 2 3 /** 4 This module implements a variety of type constructors, i.e., templates 5 that allow construction of new, useful general-purpose types. 6 7 $(SCRIPT inhibitQuickIndex = 1;) 8 $(DIVC quickindex, 9 $(BOOKTABLE, 10 $(TR $(TH Category) $(TH Functions)) 11 $(TR $(TD Tuple) $(TD 12 $(LREF isTuple) 13 $(LREF Tuple) 14 $(LREF tuple) 15 $(LREF reverse) 16 )) 17 $(TR $(TD Flags) $(TD 18 $(LREF BitFlags) 19 $(LREF isBitFlagEnum) 20 $(LREF Flag) 21 $(LREF No) 22 $(LREF Yes) 23 )) 24 $(TR $(TD Memory allocation) $(TD 25 $(LREF RefCounted) 26 $(LREF refCounted) 27 $(LREF RefCountedAutoInitialize) 28 $(LREF scoped) 29 $(LREF Unique) 30 )) 31 $(TR $(TD Code generation) $(TD 32 $(LREF AutoImplement) 33 $(LREF BlackHole) 34 $(LREF generateAssertTrap) 35 $(LREF generateEmptyFunction) 36 $(LREF WhiteHole) 37 )) 38 $(TR $(TD Nullable) $(TD 39 $(LREF Nullable) 40 $(LREF nullable) 41 $(LREF NullableRef) 42 $(LREF nullableRef) 43 )) 44 $(TR $(TD Proxies) $(TD 45 $(LREF Proxy) 46 $(LREF rebindable) 47 $(LREF Rebindable) 48 $(LREF ReplaceType) 49 $(LREF unwrap) 50 $(LREF wrap) 51 )) 52 $(TR $(TD Types) $(TD 53 $(LREF alignForSize) 54 $(LREF Ternary) 55 $(LREF Typedef) 56 $(LREF TypedefType) 57 $(LREF UnqualRef) 58 )) 59 )) 60 61 Copyright: Copyright the respective authors, 2008- 62 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). 63 Source: $(PHOBOSSRC std/typecons.d) 64 Authors: $(HTTP erdani.org, Andrei Alexandrescu), 65 $(HTTP bartoszmilewski.wordpress.com, Bartosz Milewski), 66 Don Clugston, 67 Shin Fujishiro, 68 Kenji Hara 69 */ 70 module std.typecons; 71 72 import std.format : singleSpec, FormatSpec, formatValue; 73 import std.meta : AliasSeq, allSatisfy; 74 import std.range.primitives : isOutputRange; 75 import std.traits; 76 import std.internal.attributes : betterC; 77 78 /// 79 @safe unittest 80 { 81 // value tuples 82 alias Coord = Tuple!(int, "x", int, "y", int, "z"); 83 Coord c; 84 c[1] = 1; // access by index 85 c.z = 1; // access by given name 86 assert(c == Coord(0, 1, 1)); 87 88 // names can be omitted 89 alias DicEntry = Tuple!(string, string); 90 91 // tuples can also be constructed on instantiation 92 assert(tuple(2, 3, 4)[1] == 3); 93 // construction on instantiation works with names too 94 assert(tuple!("x", "y", "z")(2, 3, 4).y == 3); 95 96 // Rebindable references to const and immutable objects 97 { 98 class Widget { void foo() const @safe {} } 99 const w1 = new Widget, w2 = new Widget; 100 w1.foo(); 101 // w1 = w2 would not work; can't rebind const object 102 auto r = Rebindable!(const Widget)(w1); 103 // invoke method as if r were a Widget object 104 r.foo(); 105 // rebind r to refer to another object 106 r = w2; 107 } 108 } 109 110 /** 111 Encapsulates unique ownership of a resource. 112 113 When a `Unique!T` goes out of scope it will call `destroy` 114 on the resource `T` that it manages, unless it is transferred. 115 One important consequence of `destroy` is that it will call the 116 destructor of the resource `T`. GC-managed references are not 117 guaranteed to be valid during a destructor call, but other members of 118 `T`, such as file handles or pointers to `malloc` memory, will 119 still be valid during the destructor call. This allows the resource 120 `T` to deallocate or clean up any non-GC resources. 121 122 If it is desirable to persist a `Unique!T` outside of its original 123 scope, then it can be transferred. The transfer can be explicit, by 124 calling `release`, or implicit, when returning Unique from a 125 function. The resource `T` can be a polymorphic class object or 126 instance of an interface, in which case Unique behaves polymorphically 127 too. 128 129 If `T` is a value type, then `Unique!T` will be implemented 130 as a reference to a `T`. 131 */ 132 struct Unique(T) 133 { 134 /** Represents a reference to `T`. Resolves to `T*` if `T` is a value type. */ 135 static if (is(T == class) || is(T == interface)) 136 alias RefT = T; 137 else 138 alias RefT = T*; 139 140 public: 141 // Deferred in case we get some language support for checking uniqueness. 142 version (None) 143 /** 144 Allows safe construction of `Unique`. It creates the resource and 145 guarantees unique ownership of it (unless `T` publishes aliases of 146 `this`). 147 Note: Nested structs/classes cannot be created. 148 Params: 149 args = Arguments to pass to `T`'s constructor. 150 --- 151 static class C {} 152 auto u = Unique!(C).create(); 153 --- 154 */ 155 static Unique!T create(A...)(auto ref A args) 156 if (__traits(compiles, new T(args))) 157 { 158 Unique!T u; 159 u._p = new T(args); 160 return u; 161 } 162 163 /** 164 Constructor that takes an rvalue. 165 It will ensure uniqueness, as long as the rvalue 166 isn't just a view on an lvalue (e.g., a cast). 167 Typical usage: 168 ---- 169 Unique!Foo f = new Foo; 170 ---- 171 */ 172 this(RefT p) 173 { 174 _p = p; 175 } 176 /** 177 Constructor that takes an lvalue. It nulls its source. 178 The nulling will ensure uniqueness as long as there 179 are no previous aliases to the source. 180 */ 181 this(ref RefT p) 182 { 183 _p = p; 184 p = null; 185 assert(p is null); 186 } 187 /** 188 Constructor that takes a `Unique` of a type that is convertible to our type. 189 190 Typically used to transfer a `Unique` rvalue of derived type to 191 a `Unique` of base type. 192 Example: 193 --- 194 class C : Object {} 195 196 Unique!C uc = new C; 197 Unique!Object uo = uc.release; 198 --- 199 */ 200 this(U)(Unique!U u) 201 if (is(u.RefT:RefT)) 202 { 203 _p = u._p; 204 u._p = null; 205 } 206 207 /// Transfer ownership from a `Unique` of a type that is convertible to our type. 208 void opAssign(U)(Unique!U u) 209 if (is(u.RefT:RefT)) 210 { 211 // first delete any resource we own 212 destroy(this); 213 _p = u._p; 214 u._p = null; 215 } 216 217 ~this() 218 { 219 if (_p !is null) 220 { 221 destroy(_p); 222 _p = null; 223 } 224 } 225 226 /** Returns whether the resource exists. */ 227 @property bool isEmpty() const 228 { 229 return _p is null; 230 } 231 /** Transfer ownership to a `Unique` rvalue. Nullifies the current contents. 232 Same as calling std.algorithm.move on it. 233 */ 234 Unique release() 235 { 236 import std.algorithm.mutation : move; 237 return this.move; 238 } 239 240 /** Forwards member access to contents. */ 241 mixin Proxy!_p; 242 243 /** 244 Postblit operator is undefined to prevent the cloning of `Unique` objects. 245 */ 246 @disable this(this); 247 248 private: 249 RefT _p; 250 } 251 252 /// 253 @safe unittest 254 { 255 static struct S 256 { 257 int i; 258 this(int i){this.i = i;} 259 } 260 Unique!S produce() 261 { 262 // Construct a unique instance of S on the heap 263 Unique!S ut = new S(5); 264 // Implicit transfer of ownership 265 return ut; 266 } 267 // Borrow a unique resource by ref 268 void increment(ref Unique!S ur) 269 { 270 ur.i++; 271 } 272 void consume(Unique!S u2) 273 { 274 assert(u2.i == 6); 275 // Resource automatically deleted here 276 } 277 Unique!S u1; 278 assert(u1.isEmpty); 279 u1 = produce(); 280 increment(u1); 281 assert(u1.i == 6); 282 //consume(u1); // Error: u1 is not copyable 283 // Transfer ownership of the resource 284 consume(u1.release); 285 assert(u1.isEmpty); 286 } 287 288 @system unittest 289 { 290 // test conversion to base ref 291 int deleted = 0; 292 class C 293 { 294 ~this(){deleted++;} 295 } 296 // constructor conversion 297 Unique!Object u = Unique!C(new C); 298 static assert(!__traits(compiles, {u = new C;})); 299 assert(!u.isEmpty); 300 destroy(u); 301 assert(deleted == 1); 302 303 Unique!C uc = new C; 304 static assert(!__traits(compiles, {Unique!Object uo = uc;})); 305 Unique!Object uo = new C; 306 // opAssign conversion, deleting uo resource first 307 uo = uc.release; 308 assert(uc.isEmpty); 309 assert(!uo.isEmpty); 310 assert(deleted == 2); 311 } 312 313 @system unittest 314 { 315 class Bar 316 { 317 ~this() { debug(Unique) writeln(" Bar destructor"); } 318 int val() const { return 4; } 319 } 320 alias UBar = Unique!(Bar); 321 UBar g(UBar u) 322 { 323 debug(Unique) writeln("inside g"); 324 return u.release; 325 } 326 auto ub = UBar(new Bar); 327 assert(!ub.isEmpty); 328 assert(ub.val == 4); 329 static assert(!__traits(compiles, {auto ub3 = g(ub);})); 330 auto ub2 = g(ub.release); 331 assert(ub.isEmpty); 332 assert(!ub2.isEmpty); 333 } 334 335 @system unittest 336 { 337 interface Bar 338 { 339 int val() const; 340 } 341 class BarImpl : Bar 342 { 343 static int count; 344 this() 345 { 346 count++; 347 } 348 ~this() 349 { 350 count--; 351 } 352 int val() const { return 4; } 353 } 354 alias UBar = Unique!Bar; 355 UBar g(UBar u) 356 { 357 debug(Unique) writeln("inside g"); 358 return u.release; 359 } 360 void consume(UBar u) 361 { 362 assert(u.val() == 4); 363 // Resource automatically deleted here 364 } 365 auto ub = UBar(new BarImpl); 366 assert(BarImpl.count == 1); 367 assert(!ub.isEmpty); 368 assert(ub.val == 4); 369 static assert(!__traits(compiles, {auto ub3 = g(ub);})); 370 auto ub2 = g(ub.release); 371 assert(ub.isEmpty); 372 assert(!ub2.isEmpty); 373 consume(ub2.release); 374 assert(BarImpl.count == 0); 375 } 376 377 @safe unittest 378 { 379 struct Foo 380 { 381 ~this() { } 382 int val() const { return 3; } 383 @disable this(this); 384 } 385 alias UFoo = Unique!(Foo); 386 387 UFoo f(UFoo u) 388 { 389 return u.release; 390 } 391 392 auto uf = UFoo(new Foo); 393 assert(!uf.isEmpty); 394 assert(uf.val == 3); 395 static assert(!__traits(compiles, {auto uf3 = f(uf);})); 396 auto uf2 = f(uf.release); 397 assert(uf.isEmpty); 398 assert(!uf2.isEmpty); 399 } 400 401 // ensure Unique behaves correctly through const access paths 402 @system unittest 403 { 404 struct Bar {int val;} 405 struct Foo 406 { 407 Unique!Bar bar = new Bar; 408 } 409 410 Foo foo; 411 foo.bar.val = 6; 412 const Foo* ptr = &foo; 413 static assert(is(typeof(ptr) == const(Foo*))); 414 static assert(is(typeof(ptr.bar) == const(Unique!Bar))); 415 static assert(is(typeof(ptr.bar.val) == const(int))); 416 assert(ptr.bar.val == 6); 417 foo.bar.val = 7; 418 assert(ptr.bar.val == 7); 419 } 420 421 // Used in Tuple.toString 422 private template sharedToString(alias field) 423 if (is(typeof(field) == shared)) 424 { 425 static immutable sharedToString = typeof(field).stringof; 426 } 427 428 private template sharedToString(alias field) 429 if (!is(typeof(field) == shared)) 430 { 431 alias sharedToString = field; 432 } 433 434 private enum bool distinctFieldNames(names...) = __traits(compiles, 435 { 436 static foreach (__name; names) 437 static if (is(typeof(__name) : string)) 438 mixin("enum int " ~ __name ~ " = 0;"); 439 }); 440 441 @safe unittest 442 { 443 static assert(!distinctFieldNames!(string, "abc", string, "abc")); 444 static assert(distinctFieldNames!(string, "abc", int, "abd")); 445 static assert(!distinctFieldNames!(int, "abc", string, "abd", int, "abc")); 446 // https://issues.dlang.org/show_bug.cgi?id=19240 447 static assert(!distinctFieldNames!(int, "int")); 448 } 449 450 /** 451 _Tuple of values, for example $(D Tuple!(int, string)) is a record that 452 stores an `int` and a `string`. `Tuple` can be used to bundle 453 values together, notably when returning multiple values from a 454 function. If `obj` is a `Tuple`, the individual members are 455 accessible with the syntax `obj[0]` for the first field, `obj[1]` 456 for the second, and so on. 457 458 See_Also: $(LREF tuple). 459 460 Params: 461 Specs = A list of types (and optionally, member names) that the `Tuple` contains. 462 */ 463 template Tuple(Specs...) 464 if (distinctFieldNames!(Specs)) 465 { 466 import std.meta : staticMap; 467 468 // Parse (type,name) pairs (FieldSpecs) out of the specified 469 // arguments. Some fields would have name, others not. 470 template parseSpecs(Specs...) 471 { 472 static if (Specs.length == 0) 473 { 474 alias parseSpecs = AliasSeq!(); 475 } 476 else static if (is(Specs[0])) 477 { 478 static if (is(typeof(Specs[1]) : string)) 479 { 480 alias parseSpecs = 481 AliasSeq!(FieldSpec!(Specs[0 .. 2]), 482 parseSpecs!(Specs[2 .. $])); 483 } 484 else 485 { 486 alias parseSpecs = 487 AliasSeq!(FieldSpec!(Specs[0]), 488 parseSpecs!(Specs[1 .. $])); 489 } 490 } 491 else 492 { 493 static assert(0, "Attempted to instantiate Tuple with an " 494 ~"invalid argument: "~ Specs[0].stringof); 495 } 496 } 497 498 template FieldSpec(T, string s = "") 499 { 500 alias Type = T; 501 alias name = s; 502 } 503 504 alias fieldSpecs = parseSpecs!Specs; 505 506 // Used with staticMap. 507 alias extractType(alias spec) = spec.Type; 508 alias extractName(alias spec) = spec.name; 509 510 // Generates named fields as follows: 511 // alias name_0 = Identity!(field[0]); 512 // alias name_1 = Identity!(field[1]); 513 // : 514 // NOTE: field[k] is an expression (which yields a symbol of a 515 // variable) and can't be aliased directly. 516 enum injectNamedFields = () 517 { 518 string decl = ""; 519 static foreach (i, val; fieldSpecs) 520 {{ 521 immutable si = i.stringof; 522 decl ~= "alias _" ~ si ~ " = Identity!(field[" ~ si ~ "]);"; 523 if (val.name.length != 0) 524 { 525 decl ~= "alias " ~ val.name ~ " = _" ~ si ~ ";"; 526 } 527 }} 528 return decl; 529 }; 530 531 // Returns Specs for a subtuple this[from .. to] preserving field 532 // names if any. 533 alias sliceSpecs(size_t from, size_t to) = 534 staticMap!(expandSpec, fieldSpecs[from .. to]); 535 536 template expandSpec(alias spec) 537 { 538 static if (spec.name.length == 0) 539 { 540 alias expandSpec = AliasSeq!(spec.Type); 541 } 542 else 543 { 544 alias expandSpec = AliasSeq!(spec.Type, spec.name); 545 } 546 } 547 548 enum areCompatibleTuples(Tup1, Tup2, string op) = isTuple!(OriginalType!Tup2) && is(typeof( 549 (ref Tup1 tup1, ref Tup2 tup2) 550 { 551 static assert(tup1.field.length == tup2.field.length); 552 static foreach (i; 0 .. Tup1.Types.length) 553 {{ 554 auto lhs = typeof(tup1.field[i]).init; 555 auto rhs = typeof(tup2.field[i]).init; 556 static if (op == "=") 557 lhs = rhs; 558 else 559 auto result = mixin("lhs "~op~" rhs"); 560 }} 561 })); 562 563 enum areBuildCompatibleTuples(Tup1, Tup2) = isTuple!Tup2 && is(typeof( 564 { 565 static assert(Tup1.Types.length == Tup2.Types.length); 566 static foreach (i; 0 .. Tup1.Types.length) 567 static assert(isBuildable!(Tup1.Types[i], Tup2.Types[i])); 568 })); 569 570 /+ Returns `true` iff a `T` can be initialized from a `U`. +/ 571 enum isBuildable(T, U) = is(typeof( 572 { 573 U u = U.init; 574 T t = u; 575 })); 576 /+ Helper for partial instantiation +/ 577 template isBuildableFrom(U) 578 { 579 enum isBuildableFrom(T) = isBuildable!(T, U); 580 } 581 582 struct Tuple 583 { 584 /** 585 * The types of the `Tuple`'s components. 586 */ 587 alias Types = staticMap!(extractType, fieldSpecs); 588 589 private alias _Fields = Specs; 590 591 /// 592 static if (Specs.length == 0) @safe unittest 593 { 594 import std.meta : AliasSeq; 595 alias Fields = Tuple!(int, "id", string, float); 596 static assert(is(Fields.Types == AliasSeq!(int, string, float))); 597 } 598 599 /** 600 * The names of the `Tuple`'s components. Unnamed fields have empty names. 601 */ 602 alias fieldNames = staticMap!(extractName, fieldSpecs); 603 604 /// 605 static if (Specs.length == 0) @safe unittest 606 { 607 import std.meta : AliasSeq; 608 alias Fields = Tuple!(int, "id", string, float); 609 static assert(Fields.fieldNames == AliasSeq!("id", "", "")); 610 } 611 612 /** 613 * Use `t.expand` for a `Tuple` `t` to expand it into its 614 * components. The result of `expand` acts as if the `Tuple`'s components 615 * were listed as a list of values. (Ordinarily, a `Tuple` acts as a 616 * single value.) 617 */ 618 Types expand; 619 mixin(injectNamedFields()); 620 621 /// 622 static if (Specs.length == 0) @safe unittest 623 { 624 auto t1 = tuple(1, " hello ", 'a'); 625 assert(t1.toString() == `Tuple!(int, string, char)(1, " hello ", 'a')`); 626 627 void takeSeveralTypes(int n, string s, bool b) 628 { 629 assert(n == 4 && s == "test" && b == false); 630 } 631 632 auto t2 = tuple(4, "test", false); 633 //t.expand acting as a list of values 634 takeSeveralTypes(t2.expand); 635 } 636 637 static if (is(Specs)) 638 { 639 // This is mostly to make t[n] work. 640 alias expand this; 641 } 642 else 643 { 644 @property 645 ref inout(Tuple!Types) _Tuple_super() inout @trusted 646 { 647 static foreach (i; 0 .. Types.length) // Rely on the field layout 648 { 649 static assert(typeof(return).init.tupleof[i].offsetof == 650 expand[i].offsetof); 651 } 652 return *cast(typeof(return)*) &(field[0]); 653 } 654 // This is mostly to make t[n] work. 655 alias _Tuple_super this; 656 } 657 658 // backwards compatibility 659 alias field = expand; 660 661 /** 662 * Constructor taking one value for each field. 663 * 664 * Params: 665 * values = A list of values that are either the same 666 * types as those given by the `Types` field 667 * of this `Tuple`, or can implicitly convert 668 * to those types. They must be in the same 669 * order as they appear in `Types`. 670 */ 671 static if (Types.length > 0) 672 { 673 this(Types values) 674 { 675 field[] = values[]; 676 } 677 } 678 679 /// 680 static if (Specs.length == 0) @safe unittest 681 { 682 alias ISD = Tuple!(int, string, double); 683 auto tup = ISD(1, "test", 3.2); 684 assert(tup.toString() == `Tuple!(int, string, double)(1, "test", 3.2)`); 685 } 686 687 /** 688 * Constructor taking a compatible array. 689 * 690 * Params: 691 * values = A compatible static array to build the `Tuple` from. 692 * Array slices are not supported. 693 */ 694 this(U, size_t n)(U[n] values) 695 if (n == Types.length && allSatisfy!(isBuildableFrom!U, Types)) 696 { 697 static foreach (i; 0 .. Types.length) 698 { 699 field[i] = values[i]; 700 } 701 } 702 703 /// 704 static if (Specs.length == 0) @safe unittest 705 { 706 int[2] ints; 707 Tuple!(int, int) t = ints; 708 } 709 710 /** 711 * Constructor taking a compatible `Tuple`. Two `Tuple`s are compatible 712 * $(B iff) they are both of the same length, and, for each type `T` on the 713 * left-hand side, the corresponding type `U` on the right-hand side can 714 * implicitly convert to `T`. 715 * 716 * Params: 717 * another = A compatible `Tuple` to build from. Its type must be 718 * compatible with the target `Tuple`'s type. 719 */ 720 this(U)(U another) 721 if (areBuildCompatibleTuples!(typeof(this), U)) 722 { 723 field[] = another.field[]; 724 } 725 726 /// 727 static if (Specs.length == 0) @safe unittest 728 { 729 alias IntVec = Tuple!(int, int, int); 730 alias DubVec = Tuple!(double, double, double); 731 732 IntVec iv = tuple(1, 1, 1); 733 734 //Ok, int can implicitly convert to double 735 DubVec dv = iv; 736 //Error: double cannot implicitly convert to int 737 //IntVec iv2 = dv; 738 } 739 740 /** 741 * Comparison for equality. Two `Tuple`s are considered equal 742 * $(B iff) they fulfill the following criteria: 743 * 744 * $(UL 745 * $(LI Each `Tuple` is the same length.) 746 * $(LI For each type `T` on the left-hand side and each type 747 * `U` on the right-hand side, values of type `T` can be 748 * compared with values of type `U`.) 749 * $(LI For each value `v1` on the left-hand side and each value 750 * `v2` on the right-hand side, the expression `v1 == v2` is 751 * true.)) 752 * 753 * Params: 754 * rhs = The `Tuple` to compare against. It must meeting the criteria 755 * for comparison between `Tuple`s. 756 * 757 * Returns: 758 * true if both `Tuple`s are equal, otherwise false. 759 */ 760 bool opEquals(R)(R rhs) 761 if (areCompatibleTuples!(typeof(this), R, "==")) 762 { 763 return field[] == rhs.field[]; 764 } 765 766 /// ditto 767 bool opEquals(R)(R rhs) const 768 if (areCompatibleTuples!(typeof(this), R, "==")) 769 { 770 return field[] == rhs.field[]; 771 } 772 773 /// ditto 774 bool opEquals(R...)(auto ref R rhs) 775 if (R.length > 1 && areCompatibleTuples!(typeof(this), Tuple!R, "==")) 776 { 777 static foreach (i; 0 .. Types.length) 778 if (field[i] != rhs[i]) 779 return false; 780 781 return true; 782 } 783 784 /// 785 static if (Specs.length == 0) @safe unittest 786 { 787 Tuple!(int, string) t1 = tuple(1, "test"); 788 Tuple!(double, string) t2 = tuple(1.0, "test"); 789 //Ok, int can be compared with double and 790 //both have a value of 1 791 assert(t1 == t2); 792 } 793 794 /** 795 * Comparison for ordering. 796 * 797 * Params: 798 * rhs = The `Tuple` to compare against. It must meet the criteria 799 * for comparison between `Tuple`s. 800 * 801 * Returns: 802 * For any values `v1` on the right-hand side and `v2` on the 803 * left-hand side: 804 * 805 * $(UL 806 * $(LI A negative integer if the expression `v1 < v2` is true.) 807 * $(LI A positive integer if the expression `v1 > v2` is true.) 808 * $(LI 0 if the expression `v1 == v2` is true.)) 809 */ 810 int opCmp(R)(R rhs) 811 if (areCompatibleTuples!(typeof(this), R, "<")) 812 { 813 static foreach (i; 0 .. Types.length) 814 { 815 if (field[i] != rhs.field[i]) 816 { 817 return field[i] < rhs.field[i] ? -1 : 1; 818 } 819 } 820 return 0; 821 } 822 823 /// ditto 824 int opCmp(R)(R rhs) const 825 if (areCompatibleTuples!(typeof(this), R, "<")) 826 { 827 static foreach (i; 0 .. Types.length) 828 { 829 if (field[i] != rhs.field[i]) 830 { 831 return field[i] < rhs.field[i] ? -1 : 1; 832 } 833 } 834 return 0; 835 } 836 837 /** 838 The first `v1` for which `v1 > v2` is true determines 839 the result. This could lead to unexpected behaviour. 840 */ 841 static if (Specs.length == 0) @safe unittest 842 { 843 auto tup1 = tuple(1, 1, 1); 844 auto tup2 = tuple(1, 100, 100); 845 assert(tup1 < tup2); 846 847 //Only the first result matters for comparison 848 tup1[0] = 2; 849 assert(tup1 > tup2); 850 } 851 852 /** 853 Concatenate Tuples. 854 Tuple concatenation is only allowed if all named fields are distinct (no named field of this tuple occurs in `t` 855 and no named field of `t` occurs in this tuple). 856 857 Params: 858 t = The `Tuple` to concatenate with 859 860 Returns: A concatenation of this tuple and `t` 861 */ 862 auto opBinary(string op, T)(auto ref T t) 863 if (op == "~" && !(is(T : U[], U) && isTuple!U)) 864 { 865 static if (isTuple!T) 866 { 867 static assert(distinctFieldNames!(_Fields, T._Fields), 868 "Cannot concatenate tuples with duplicate fields: " ~ fieldNames.stringof ~ 869 " - " ~ T.fieldNames.stringof); 870 return Tuple!(_Fields, T._Fields)(expand, t.expand); 871 } 872 else 873 { 874 return Tuple!(_Fields, T)(expand, t); 875 } 876 } 877 878 /// ditto 879 auto opBinaryRight(string op, T)(auto ref T t) 880 if (op == "~" && !(is(T : U[], U) && isTuple!U)) 881 { 882 static if (isTuple!T) 883 { 884 static assert(distinctFieldNames!(_Fields, T._Fields), 885 "Cannot concatenate tuples with duplicate fields: " ~ T.stringof ~ 886 " - " ~ fieldNames.fieldNames.stringof); 887 return Tuple!(T._Fields, _Fields)(t.expand, expand); 888 } 889 else 890 { 891 return Tuple!(T, _Fields)(t, expand); 892 } 893 } 894 895 /** 896 * Assignment from another `Tuple`. 897 * 898 * Params: 899 * rhs = The source `Tuple` to assign from. Each element of the 900 * source `Tuple` must be implicitly assignable to each 901 * respective element of the target `Tuple`. 902 */ 903 ref Tuple opAssign(R)(auto ref R rhs) 904 if (areCompatibleTuples!(typeof(this), R, "=")) 905 { 906 import std.algorithm.mutation : swap; 907 908 static if (is(R : Tuple!Types) && !__traits(isRef, rhs) && isTuple!R) 909 { 910 if (__ctfe) 911 { 912 // Cannot use swap at compile time 913 field[] = rhs.field[]; 914 } 915 else 916 { 917 // Use swap-and-destroy to optimize rvalue assignment 918 swap!(Tuple!Types)(this, rhs); 919 } 920 } 921 else 922 { 923 // Do not swap; opAssign should be called on the fields. 924 field[] = rhs.field[]; 925 } 926 return this; 927 } 928 929 /** 930 * Renames the elements of a $(LREF Tuple). 931 * 932 * `rename` uses the passed `names` and returns a new 933 * $(LREF Tuple) using these names, with the content 934 * unchanged. 935 * If fewer names are passed than there are members 936 * of the $(LREF Tuple) then those trailing members are unchanged. 937 * An empty string will remove the name for that member. 938 * It is an compile-time error to pass more names than 939 * there are members of the $(LREF Tuple). 940 */ 941 ref rename(names...)() inout return 942 if (names.length == 0 || allSatisfy!(isSomeString, typeof(names))) 943 { 944 import std.algorithm.comparison : equal; 945 // to circumvent https://issues.dlang.org/show_bug.cgi?id=16418 946 static if (names.length == 0 || equal([names], [fieldNames])) 947 return this; 948 else 949 { 950 enum nT = Types.length; 951 enum nN = names.length; 952 static assert(nN <= nT, "Cannot have more names than tuple members"); 953 alias allNames = AliasSeq!(names, fieldNames[nN .. $]); 954 955 import std.meta : Alias, aliasSeqOf; 956 957 template GetItem(size_t idx) 958 { 959 import std.array : empty; 960 static if (idx < nT) 961 alias GetItem = Alias!(Types[idx]); 962 else static if (allNames[idx - nT].empty) 963 alias GetItem = AliasSeq!(); 964 else 965 alias GetItem = Alias!(allNames[idx - nT]); 966 } 967 968 import std.range : roundRobin, iota; 969 alias NewTupleT = Tuple!(staticMap!(GetItem, aliasSeqOf!( 970 roundRobin(iota(nT), iota(nT, 2*nT))))); 971 return *(() @trusted => cast(NewTupleT*)&this)(); 972 } 973 } 974 975 /// 976 static if (Specs.length == 0) @safe unittest 977 { 978 auto t0 = tuple(4, "hello"); 979 980 auto t0Named = t0.rename!("val", "tag"); 981 assert(t0Named.val == 4); 982 assert(t0Named.tag == "hello"); 983 984 Tuple!(float, "dat", size_t[2], "pos") t1; 985 t1.pos = [2, 1]; 986 auto t1Named = t1.rename!"height"; 987 t1Named.height = 3.4f; 988 assert(t1Named.height == 3.4f); 989 assert(t1Named.pos == [2, 1]); 990 t1Named.rename!"altitude".altitude = 5; 991 assert(t1Named.height == 5); 992 993 Tuple!(int, "a", int, int, "c") t2; 994 t2 = tuple(3,4,5); 995 auto t2Named = t2.rename!("", "b"); 996 // "a" no longer has a name 997 static assert(!__traits(hasMember, typeof(t2Named), "a")); 998 assert(t2Named[0] == 3); 999 assert(t2Named.b == 4); 1000 assert(t2Named.c == 5); 1001 1002 // not allowed to specify more names than the tuple has members 1003 static assert(!__traits(compiles, t2.rename!("a","b","c","d"))); 1004 1005 // use it in a range pipeline 1006 import std.range : iota, zip; 1007 import std.algorithm.iteration : map, sum; 1008 auto res = zip(iota(1, 4), iota(10, 13)) 1009 .map!(t => t.rename!("a", "b")) 1010 .map!(t => t.a * t.b) 1011 .sum; 1012 assert(res == 68); 1013 1014 const tup = Tuple!(int, "a", int, "b")(2, 3); 1015 const renamed = tup.rename!("c", "d"); 1016 assert(renamed.c + renamed.d == 5); 1017 } 1018 1019 /** 1020 * Overload of $(LREF _rename) that takes an associative array 1021 * `translate` as a template parameter, where the keys are 1022 * either the names or indices of the members to be changed 1023 * and the new names are the corresponding values. 1024 * Every key in `translate` must be the name of a member of the 1025 * $(LREF tuple). 1026 * The same rules for empty strings apply as for the variadic 1027 * template overload of $(LREF _rename). 1028 */ 1029 ref rename(alias translate)() inout 1030 if (is(typeof(translate) : V[K], V, K) && isSomeString!V && 1031 (isSomeString!K || is(K : size_t))) 1032 { 1033 import std.meta : aliasSeqOf; 1034 import std.range : ElementType; 1035 static if (isSomeString!(ElementType!(typeof(translate.keys)))) 1036 { 1037 { 1038 import std.conv : to; 1039 import std.algorithm.iteration : filter; 1040 import std.algorithm.searching : canFind; 1041 enum notFound = translate.keys 1042 .filter!(k => fieldNames.canFind(k) == -1); 1043 static assert(notFound.empty, "Cannot find members " 1044 ~ notFound.to!string ~ " in type " 1045 ~ typeof(this).stringof); 1046 } 1047 return this.rename!(aliasSeqOf!( 1048 { 1049 import std.array : empty; 1050 auto names = [fieldNames]; 1051 foreach (ref n; names) 1052 if (!n.empty) 1053 if (auto p = n in translate) 1054 n = *p; 1055 return names; 1056 }())); 1057 } 1058 else 1059 { 1060 { 1061 import std.algorithm.iteration : filter; 1062 import std.conv : to; 1063 enum invalid = translate.keys. 1064 filter!(k => k < 0 || k >= this.length); 1065 static assert(invalid.empty, "Indices " ~ invalid.to!string 1066 ~ " are out of bounds for tuple with length " 1067 ~ this.length.to!string); 1068 } 1069 return this.rename!(aliasSeqOf!( 1070 { 1071 auto names = [fieldNames]; 1072 foreach (k, v; translate) 1073 names[k] = v; 1074 return names; 1075 }())); 1076 } 1077 } 1078 1079 /// 1080 static if (Specs.length == 0) @safe unittest 1081 { 1082 //replacing names by their current name 1083 1084 Tuple!(float, "dat", size_t[2], "pos") t1; 1085 t1.pos = [2, 1]; 1086 auto t1Named = t1.rename!(["dat": "height"]); 1087 t1Named.height = 3.4; 1088 assert(t1Named.pos == [2, 1]); 1089 t1Named.rename!(["height": "altitude"]).altitude = 5; 1090 assert(t1Named.height == 5); 1091 1092 Tuple!(int, "a", int, "b") t2; 1093 t2 = tuple(3, 4); 1094 auto t2Named = t2.rename!(["a": "b", "b": "c"]); 1095 assert(t2Named.b == 3); 1096 assert(t2Named.c == 4); 1097 1098 const t3 = Tuple!(int, "a", int, "b")(3, 4); 1099 const t3Named = t3.rename!(["a": "b", "b": "c"]); 1100 assert(t3Named.b == 3); 1101 assert(t3Named.c == 4); 1102 } 1103 1104 /// 1105 static if (Specs.length == 0) @safe unittest 1106 { 1107 //replace names by their position 1108 1109 Tuple!(float, "dat", size_t[2], "pos") t1; 1110 t1.pos = [2, 1]; 1111 auto t1Named = t1.rename!([0: "height"]); 1112 t1Named.height = 3.4; 1113 assert(t1Named.pos == [2, 1]); 1114 t1Named.rename!([0: "altitude"]).altitude = 5; 1115 assert(t1Named.height == 5); 1116 1117 Tuple!(int, "a", int, "b", int, "c") t2; 1118 t2 = tuple(3, 4, 5); 1119 auto t2Named = t2.rename!([0: "c", 2: "a"]); 1120 assert(t2Named.a == 5); 1121 assert(t2Named.b == 4); 1122 assert(t2Named.c == 3); 1123 } 1124 1125 static if (Specs.length == 0) @safe unittest 1126 { 1127 //check that empty translations work fine 1128 enum string[string] a0 = null; 1129 enum string[int] a1 = null; 1130 Tuple!(float, "a", float, "b") t0; 1131 1132 auto t1 = t0.rename!a0; 1133 1134 t1.a = 3; 1135 t1.b = 4; 1136 auto t2 = t0.rename!a1; 1137 t2.a = 3; 1138 t2.b = 4; 1139 auto t3 = t0.rename; 1140 t3.a = 3; 1141 t3.b = 4; 1142 } 1143 1144 /** 1145 * Takes a slice by-reference of this `Tuple`. 1146 * 1147 * Params: 1148 * from = A `size_t` designating the starting position of the slice. 1149 * to = A `size_t` designating the ending position (exclusive) of the slice. 1150 * 1151 * Returns: 1152 * A new `Tuple` that is a slice from `[from, to$(RPAREN)` of the original. 1153 * It has the same types and values as the range `[from, to$(RPAREN)` in 1154 * the original. 1155 */ 1156 @property 1157 ref inout(Tuple!(sliceSpecs!(from, to))) slice(size_t from, size_t to)() inout @trusted 1158 if (from <= to && to <= Types.length) 1159 { 1160 static assert( 1161 (typeof(this).alignof % typeof(return).alignof == 0) && 1162 (expand[from].offsetof % typeof(return).alignof == 0), 1163 "Slicing by reference is impossible because of an alignment mistmatch" ~ 1164 " (See https://issues.dlang.org/show_bug.cgi?id=15645)."); 1165 1166 return *cast(typeof(return)*) &(field[from]); 1167 } 1168 1169 /// 1170 static if (Specs.length == 0) @safe unittest 1171 { 1172 Tuple!(int, string, float, double) a; 1173 a[1] = "abc"; 1174 a[2] = 4.5; 1175 auto s = a.slice!(1, 3); 1176 static assert(is(typeof(s) == Tuple!(string, float))); 1177 assert(s[0] == "abc" && s[1] == 4.5); 1178 1179 // https://issues.dlang.org/show_bug.cgi?id=15645 1180 Tuple!(int, short, bool, double) b; 1181 static assert(!__traits(compiles, b.slice!(2, 4))); 1182 } 1183 1184 /** 1185 Creates a hash of this `Tuple`. 1186 1187 Returns: 1188 A `size_t` representing the hash of this `Tuple`. 1189 */ 1190 size_t toHash() const nothrow @safe 1191 { 1192 size_t h = 0; 1193 static foreach (i, T; Types) 1194 {{ 1195 static if (__traits(compiles, h = .hashOf(field[i]))) 1196 const k = .hashOf(field[i]); 1197 else 1198 { 1199 // Workaround for when .hashOf is not both @safe and nothrow. 1200 static if (is(T : shared U, U) && __traits(compiles, (U* a) nothrow @safe => .hashOf(*a)) 1201 && !__traits(hasMember, T, "toHash")) 1202 // BUG: Improperly casts away `shared`! 1203 const k = .hashOf(*(() @trusted => cast(U*) &field[i])()); 1204 else 1205 // BUG: Improperly casts away `shared`! 1206 const k = typeid(T).getHash((() @trusted => cast(const void*) &field[i])()); 1207 } 1208 static if (i == 0) 1209 h = k; 1210 else 1211 // As in boost::hash_combine 1212 // https://www.boost.org/doc/libs/1_55_0/doc/html/hash/reference.html#boost.hash_combine 1213 h ^= k + 0x9e3779b9 + (h << 6) + (h >>> 2); 1214 }} 1215 return h; 1216 } 1217 1218 /** 1219 * Converts to string. 1220 * 1221 * Returns: 1222 * The string representation of this `Tuple`. 1223 */ 1224 string toString()() const 1225 { 1226 import std.array : appender; 1227 auto app = appender!string(); 1228 this.toString((const(char)[] chunk) => app ~= chunk); 1229 return app.data; 1230 } 1231 1232 import std.format : FormatSpec; 1233 1234 /** 1235 * Formats `Tuple` with either `%s`, `%(inner%)` or `%(inner%|sep%)`. 1236 * 1237 * $(TABLE2 Formats supported by Tuple, 1238 * $(THEAD Format, Description) 1239 * $(TROW $(P `%s`), $(P Format like `Tuple!(types)(elements formatted with %s each)`.)) 1240 * $(TROW $(P `%(inner%)`), $(P The format `inner` is applied the expanded `Tuple`$(COMMA) so 1241 * it may contain as many formats as the `Tuple` has fields.)) 1242 * $(TROW $(P `%(inner%|sep%)`), $(P The format `inner` is one format$(COMMA) that is applied 1243 * on all fields of the `Tuple`. The inner format must be compatible to all 1244 * of them.))) 1245 * 1246 * Params: 1247 * sink = A `char` accepting delegate 1248 * fmt = A $(REF FormatSpec, std,format) 1249 */ 1250 void toString(DG)(scope DG sink) const 1251 { 1252 auto f = FormatSpec!char(); 1253 toString(sink, f); 1254 } 1255 1256 /// ditto 1257 void toString(DG, Char)(scope DG sink, scope const ref FormatSpec!Char fmt) const 1258 { 1259 import std.format : formatElement, formattedWrite, FormatException; 1260 if (fmt.nested) 1261 { 1262 if (fmt.sep) 1263 { 1264 foreach (i, Type; Types) 1265 { 1266 static if (i > 0) 1267 { 1268 sink(fmt.sep); 1269 } 1270 // TODO: Change this once formattedWrite() works for shared objects. 1271 static if (is(Type == class) && is(Type == shared)) 1272 { 1273 sink(Type.stringof); 1274 } 1275 else 1276 { 1277 formattedWrite(sink, fmt.nested, this.field[i]); 1278 } 1279 } 1280 } 1281 else 1282 { 1283 formattedWrite(sink, fmt.nested, staticMap!(sharedToString, this.expand)); 1284 } 1285 } 1286 else if (fmt.spec == 's') 1287 { 1288 enum header = Unqual!(typeof(this)).stringof ~ "(", 1289 footer = ")", 1290 separator = ", "; 1291 sink(header); 1292 foreach (i, Type; Types) 1293 { 1294 static if (i > 0) 1295 { 1296 sink(separator); 1297 } 1298 // TODO: Change this once formatElement() works for shared objects. 1299 static if (is(Type == class) && is(Type == shared)) 1300 { 1301 sink(Type.stringof); 1302 } 1303 else 1304 { 1305 FormatSpec!Char f; 1306 formatElement(sink, field[i], f); 1307 } 1308 } 1309 sink(footer); 1310 } 1311 else 1312 { 1313 const spec = fmt.spec; 1314 throw new FormatException( 1315 "Expected '%s' or '%(...%)' or '%(...%|...%)' format specifier for type '" ~ 1316 Unqual!(typeof(this)).stringof ~ "', not '%" ~ spec ~ "'."); 1317 } 1318 } 1319 1320 /// 1321 static if (Types.length == 0) 1322 @safe unittest 1323 { 1324 import std.format : format; 1325 1326 Tuple!(int, double)[3] tupList = [ tuple(1, 1.0), tuple(2, 4.0), tuple(3, 9.0) ]; 1327 1328 // Default format 1329 assert(format("%s", tuple("a", 1)) == `Tuple!(string, int)("a", 1)`); 1330 1331 // One Format for each individual component 1332 assert(format("%(%#x v %.4f w %#x%)", tuple(1, 1.0, 10)) == `0x1 v 1.0000 w 0xa`); 1333 assert(format( "%#x v %.4f w %#x" , tuple(1, 1.0, 10).expand) == `0x1 v 1.0000 w 0xa`); 1334 1335 // One Format for all components 1336 assert(format("%(>%s<%| & %)", tuple("abc", 1, 2.3, [4, 5])) == `>abc< & >1< & >2.3< & >[4, 5]<`); 1337 1338 // Array of Tuples 1339 assert(format("%(%(f(%d) = %.1f%); %)", tupList) == `f(1) = 1.0; f(2) = 4.0; f(3) = 9.0`); 1340 } 1341 1342 /// 1343 static if (Types.length == 0) 1344 @safe unittest 1345 { 1346 import std.exception : assertThrown; 1347 import std.format : format, FormatException; 1348 1349 // Error: %( %) missing. 1350 assertThrown!FormatException( 1351 format("%d, %f", tuple(1, 2.0)) == `1, 2.0` 1352 ); 1353 1354 // Error: %( %| %) missing. 1355 assertThrown!FormatException( 1356 format("%d", tuple(1, 2)) == `1, 2` 1357 ); 1358 1359 // Error: %d inadequate for double 1360 assertThrown!FormatException( 1361 format("%(%d%|, %)", tuple(1, 2.0)) == `1, 2.0` 1362 ); 1363 } 1364 } 1365 } 1366 1367 /// 1368 @safe unittest 1369 { 1370 Tuple!(int, int) point; 1371 // assign coordinates 1372 point[0] = 5; 1373 point[1] = 6; 1374 // read coordinates 1375 auto x = point[0]; 1376 auto y = point[1]; 1377 } 1378 1379 /** 1380 `Tuple` members can be named. It is legal to mix named and unnamed 1381 members. The method above is still applicable to all fields. 1382 */ 1383 @safe unittest 1384 { 1385 alias Entry = Tuple!(int, "index", string, "value"); 1386 Entry e; 1387 e.index = 4; 1388 e.value = "Hello"; 1389 assert(e[1] == "Hello"); 1390 assert(e[0] == 4); 1391 } 1392 1393 /** 1394 A `Tuple` with named fields is a distinct type from a `Tuple` with unnamed 1395 fields, i.e. each naming imparts a separate type for the `Tuple`. Two 1396 `Tuple`s differing in naming only are still distinct, even though they 1397 might have the same structure. 1398 */ 1399 @safe unittest 1400 { 1401 Tuple!(int, "x", int, "y") point1; 1402 Tuple!(int, int) point2; 1403 assert(!is(typeof(point1) == typeof(point2))); 1404 } 1405 1406 /// Use tuples as ranges 1407 @safe unittest 1408 { 1409 import std.algorithm.iteration : sum; 1410 import std.range : only; 1411 auto t = tuple(1, 2); 1412 assert(t.expand.only.sum == 3); 1413 } 1414 1415 // https://issues.dlang.org/show_bug.cgi?id=4582 1416 @safe unittest 1417 { 1418 static assert(!__traits(compiles, Tuple!(string, "id", int, "id"))); 1419 static assert(!__traits(compiles, Tuple!(string, "str", int, "i", string, "str", float))); 1420 } 1421 1422 /// Concatenate tuples 1423 @safe unittest 1424 { 1425 import std.meta : AliasSeq; 1426 auto t = tuple(1, "2") ~ tuple(ushort(42), true); 1427 static assert(is(t.Types == AliasSeq!(int, string, ushort, bool))); 1428 assert(t[1] == "2"); 1429 assert(t[2] == 42); 1430 assert(t[3] == true); 1431 } 1432 1433 // https://issues.dlang.org/show_bug.cgi?id=14637 1434 // tuple concat 1435 @safe unittest 1436 { 1437 auto t = tuple!"foo"(1.0) ~ tuple!"bar"("3"); 1438 static assert(is(t.Types == AliasSeq!(double, string))); 1439 static assert(t.fieldNames == tuple("foo", "bar")); 1440 assert(t.foo == 1.0); 1441 assert(t.bar == "3"); 1442 } 1443 1444 // https://issues.dlang.org/show_bug.cgi?id=18824 1445 // tuple concat 1446 @safe unittest 1447 { 1448 alias Type = Tuple!(int, string); 1449 Type[] arr; 1450 auto t = tuple(2, "s"); 1451 // Test opBinaryRight 1452 arr = arr ~ t; 1453 // Test opBinary 1454 arr = t ~ arr; 1455 static assert(is(typeof(arr) == Type[])); 1456 immutable Type[] b; 1457 auto c = b ~ t; 1458 static assert(is(typeof(c) == immutable(Type)[])); 1459 } 1460 1461 // tuple concat 1462 @safe unittest 1463 { 1464 auto t = tuple!"foo"(1.0) ~ "3"; 1465 static assert(is(t.Types == AliasSeq!(double, string))); 1466 assert(t.foo == 1.0); 1467 assert(t[1]== "3"); 1468 } 1469 1470 // tuple concat 1471 @safe unittest 1472 { 1473 auto t = "2" ~ tuple!"foo"(1.0); 1474 static assert(is(t.Types == AliasSeq!(string, double))); 1475 assert(t.foo == 1.0); 1476 assert(t[0]== "2"); 1477 } 1478 1479 // tuple concat 1480 @safe unittest 1481 { 1482 auto t = "2" ~ tuple!"foo"(1.0) ~ tuple(42, 3.0f) ~ real(1) ~ "a"; 1483 static assert(is(t.Types == AliasSeq!(string, double, int, float, real, string))); 1484 assert(t.foo == 1.0); 1485 assert(t[0] == "2"); 1486 assert(t[1] == 1.0); 1487 assert(t[2] == 42); 1488 assert(t[3] == 3.0f); 1489 assert(t[4] == 1.0); 1490 assert(t[5] == "a"); 1491 } 1492 1493 // ensure that concatenation of tuples with non-distinct fields is forbidden 1494 @safe unittest 1495 { 1496 static assert(!__traits(compiles, 1497 tuple!("a")(0) ~ tuple!("a")("1"))); 1498 static assert(!__traits(compiles, 1499 tuple!("a", "b")(0, 1) ~ tuple!("b", "a")("3", 1))); 1500 static assert(!__traits(compiles, 1501 tuple!("a")(0) ~ tuple!("b", "a")("3", 1))); 1502 static assert(!__traits(compiles, 1503 tuple!("a1", "a")(1.0, 0) ~ tuple!("a2", "a")("3", 0))); 1504 } 1505 1506 // Ensure that Tuple comparison with non-const opEquals works 1507 @safe unittest 1508 { 1509 static struct Bad 1510 { 1511 int a; 1512 1513 bool opEquals(Bad b) 1514 { 1515 return a == b.a; 1516 } 1517 } 1518 1519 auto t = Tuple!(int, Bad, string)(1, Bad(1), "asdf"); 1520 1521 //Error: mutable method Bad.opEquals is not callable using a const object 1522 assert(t == AliasSeq!(1, Bad(1), "asdf")); 1523 } 1524 1525 // Ensure Tuple.toHash works 1526 @safe unittest 1527 { 1528 Tuple!(int, int) point; 1529 assert(point.toHash == typeof(point).init.toHash); 1530 assert(tuple(1, 2) != point); 1531 assert(tuple(1, 2) == tuple(1, 2)); 1532 point[0] = 1; 1533 assert(tuple(1, 2) != point); 1534 point[1] = 2; 1535 assert(tuple(1, 2) == point); 1536 } 1537 1538 @safe @betterC unittest 1539 { 1540 auto t = tuple(1, 2); 1541 assert(t == tuple(1, 2)); 1542 auto t3 = tuple(1, 'd'); 1543 } 1544 1545 // https://issues.dlang.org/show_bug.cgi?id=20850 1546 // Assignment to enum tuple 1547 @safe unittest 1548 { 1549 enum T : Tuple!(int*) { a = T(null) } 1550 T t; 1551 t = T.a; 1552 } 1553 1554 /** 1555 Creates a copy of a $(LREF Tuple) with its fields in _reverse order. 1556 1557 Params: 1558 t = The `Tuple` to copy. 1559 1560 Returns: 1561 A new `Tuple`. 1562 */ 1563 auto reverse(T)(T t) 1564 if (isTuple!T) 1565 { 1566 import std.meta : Reverse; 1567 // @@@BUG@@@ Cannot be an internal function due to forward reference issues. 1568 1569 // @@@BUG@@@ 9929 Need 'this' when calling template with expanded tuple 1570 // return tuple(Reverse!(t.expand)); 1571 1572 ReverseTupleType!T result; 1573 auto tup = t.expand; 1574 result.expand = Reverse!tup; 1575 return result; 1576 } 1577 1578 /// 1579 @safe unittest 1580 { 1581 auto tup = tuple(1, "2"); 1582 assert(tup.reverse == tuple("2", 1)); 1583 } 1584 1585 /* Get a Tuple type with the reverse specification of Tuple T. */ 1586 private template ReverseTupleType(T) 1587 if (isTuple!T) 1588 { 1589 static if (is(T : Tuple!A, A...)) 1590 alias ReverseTupleType = Tuple!(ReverseTupleSpecs!A); 1591 } 1592 1593 /* Reverse the Specs of a Tuple. */ 1594 private template ReverseTupleSpecs(T...) 1595 { 1596 static if (T.length > 1) 1597 { 1598 static if (is(typeof(T[$-1]) : string)) 1599 { 1600 alias ReverseTupleSpecs = AliasSeq!(T[$-2], T[$-1], ReverseTupleSpecs!(T[0 .. $-2])); 1601 } 1602 else 1603 { 1604 alias ReverseTupleSpecs = AliasSeq!(T[$-1], ReverseTupleSpecs!(T[0 .. $-1])); 1605 } 1606 } 1607 else 1608 { 1609 alias ReverseTupleSpecs = T; 1610 } 1611 } 1612 1613 // ensure that internal Tuple unittests are compiled 1614 @safe unittest 1615 { 1616 Tuple!() t; 1617 } 1618 1619 @safe unittest 1620 { 1621 import std.conv; 1622 { 1623 Tuple!(int, "a", int, "b") nosh; 1624 static assert(nosh.length == 2); 1625 nosh.a = 5; 1626 nosh.b = 6; 1627 assert(nosh.a == 5); 1628 assert(nosh.b == 6); 1629 } 1630 { 1631 Tuple!(short, double) b; 1632 static assert(b.length == 2); 1633 b[1] = 5; 1634 auto a = Tuple!(int, real)(b); 1635 assert(a[0] == 0 && a[1] == 5); 1636 a = Tuple!(int, real)(1, 2); 1637 assert(a[0] == 1 && a[1] == 2); 1638 auto c = Tuple!(int, "a", double, "b")(a); 1639 assert(c[0] == 1 && c[1] == 2); 1640 } 1641 { 1642 Tuple!(int, real) nosh; 1643 nosh[0] = 5; 1644 nosh[1] = 0; 1645 assert(nosh[0] == 5 && nosh[1] == 0); 1646 assert(nosh.to!string == "Tuple!(int, real)(5, 0)", nosh.to!string); 1647 Tuple!(int, int) yessh; 1648 nosh = yessh; 1649 } 1650 { 1651 class A {} 1652 Tuple!(int, shared A) nosh; 1653 nosh[0] = 5; 1654 assert(nosh[0] == 5 && nosh[1] is null); 1655 assert(nosh.to!string == "Tuple!(int, shared(A))(5, shared(A))"); 1656 } 1657 { 1658 Tuple!(int, string) t; 1659 t[0] = 10; 1660 t[1] = "str"; 1661 assert(t[0] == 10 && t[1] == "str"); 1662 assert(t.to!string == `Tuple!(int, string)(10, "str")`, t.to!string); 1663 } 1664 { 1665 Tuple!(int, "a", double, "b") x; 1666 static assert(x.a.offsetof == x[0].offsetof); 1667 static assert(x.b.offsetof == x[1].offsetof); 1668 x.b = 4.5; 1669 x.a = 5; 1670 assert(x[0] == 5 && x[1] == 4.5); 1671 assert(x.a == 5 && x.b == 4.5); 1672 } 1673 // indexing 1674 { 1675 Tuple!(int, real) t; 1676 static assert(is(typeof(t[0]) == int)); 1677 static assert(is(typeof(t[1]) == real)); 1678 int* p0 = &t[0]; 1679 real* p1 = &t[1]; 1680 t[0] = 10; 1681 t[1] = -200.0L; 1682 assert(*p0 == t[0]); 1683 assert(*p1 == t[1]); 1684 } 1685 // slicing 1686 { 1687 Tuple!(int, "x", real, "y", double, "z", string) t; 1688 t[0] = 10; 1689 t[1] = 11; 1690 t[2] = 12; 1691 t[3] = "abc"; 1692 auto a = t.slice!(0, 3); 1693 assert(a.length == 3); 1694 assert(a.x == t.x); 1695 assert(a.y == t.y); 1696 assert(a.z == t.z); 1697 auto b = t.slice!(2, 4); 1698 assert(b.length == 2); 1699 assert(b.z == t.z); 1700 assert(b[1] == t[3]); 1701 } 1702 // nesting 1703 { 1704 Tuple!(Tuple!(int, real), Tuple!(string, "s")) t; 1705 static assert(is(typeof(t[0]) == Tuple!(int, real))); 1706 static assert(is(typeof(t[1]) == Tuple!(string, "s"))); 1707 static assert(is(typeof(t[0][0]) == int)); 1708 static assert(is(typeof(t[0][1]) == real)); 1709 static assert(is(typeof(t[1].s) == string)); 1710 t[0] = tuple(10, 20.0L); 1711 t[1].s = "abc"; 1712 assert(t[0][0] == 10); 1713 assert(t[0][1] == 20.0L); 1714 assert(t[1].s == "abc"); 1715 } 1716 // non-POD 1717 { 1718 static struct S 1719 { 1720 int count; 1721 this(this) { ++count; } 1722 ~this() { --count; } 1723 void opAssign(S rhs) { count = rhs.count; } 1724 } 1725 Tuple!(S, S) ss; 1726 Tuple!(S, S) ssCopy = ss; 1727 assert(ssCopy[0].count == 1); 1728 assert(ssCopy[1].count == 1); 1729 ssCopy[1] = ssCopy[0]; 1730 assert(ssCopy[1].count == 2); 1731 } 1732 // https://issues.dlang.org/show_bug.cgi?id=2800 1733 { 1734 static struct R 1735 { 1736 Tuple!(int, int) _front; 1737 @property ref Tuple!(int, int) front() return { return _front; } 1738 @property bool empty() { return _front[0] >= 10; } 1739 void popFront() { ++_front[0]; } 1740 } 1741 foreach (a; R()) 1742 { 1743 static assert(is(typeof(a) == Tuple!(int, int))); 1744 assert(0 <= a[0] && a[0] < 10); 1745 assert(a[1] == 0); 1746 } 1747 } 1748 // Construction with compatible elements 1749 { 1750 auto t1 = Tuple!(int, double)(1, 1); 1751 1752 // https://issues.dlang.org/show_bug.cgi?id=8702 1753 auto t8702a = tuple(tuple(1)); 1754 auto t8702b = Tuple!(Tuple!(int))(Tuple!(int)(1)); 1755 } 1756 // Construction with compatible tuple 1757 { 1758 Tuple!(int, int) x; 1759 x[0] = 10; 1760 x[1] = 20; 1761 Tuple!(int, "a", double, "b") y = x; 1762 assert(y.a == 10); 1763 assert(y.b == 20); 1764 // incompatible 1765 static assert(!__traits(compiles, Tuple!(int, int)(y))); 1766 } 1767 // https://issues.dlang.org/show_bug.cgi?id=6275 1768 { 1769 const int x = 1; 1770 auto t1 = tuple(x); 1771 alias T = Tuple!(const(int)); 1772 auto t2 = T(1); 1773 } 1774 // https://issues.dlang.org/show_bug.cgi?id=9431 1775 { 1776 alias T = Tuple!(int[1][]); 1777 auto t = T([[10]]); 1778 } 1779 // https://issues.dlang.org/show_bug.cgi?id=7666 1780 { 1781 auto tup = tuple(1, "2"); 1782 assert(tup.reverse == tuple("2", 1)); 1783 } 1784 { 1785 Tuple!(int, "x", string, "y") tup = tuple(1, "2"); 1786 auto rev = tup.reverse; 1787 assert(rev == tuple("2", 1)); 1788 assert(rev.x == 1 && rev.y == "2"); 1789 } 1790 { 1791 Tuple!(wchar, dchar, int, "x", string, "y", char, byte, float) tup; 1792 tup = tuple('a', 'b', 3, "4", 'c', cast(byte) 0x0D, 0.00); 1793 auto rev = tup.reverse; 1794 assert(rev == tuple(0.00, cast(byte) 0x0D, 'c', "4", 3, 'b', 'a')); 1795 assert(rev.x == 3 && rev.y == "4"); 1796 } 1797 } 1798 @safe unittest 1799 { 1800 // opEquals 1801 { 1802 struct Equ1 { bool opEquals(Equ1) { return true; } } 1803 auto tm1 = tuple(Equ1.init); 1804 const tc1 = tuple(Equ1.init); 1805 static assert( is(typeof(tm1 == tm1))); 1806 static assert(!is(typeof(tm1 == tc1))); 1807 static assert(!is(typeof(tc1 == tm1))); 1808 static assert(!is(typeof(tc1 == tc1))); 1809 1810 struct Equ2 { bool opEquals(const Equ2) const { return true; } } 1811 auto tm2 = tuple(Equ2.init); 1812 const tc2 = tuple(Equ2.init); 1813 static assert( is(typeof(tm2 == tm2))); 1814 static assert( is(typeof(tm2 == tc2))); 1815 static assert( is(typeof(tc2 == tm2))); 1816 static assert( is(typeof(tc2 == tc2))); 1817 1818 // https://issues.dlang.org/show_bug.cgi?id=8686 1819 struct Equ3 { bool opEquals(T)(T) { return true; } } 1820 auto tm3 = tuple(Equ3.init); 1821 const tc3 = tuple(Equ3.init); 1822 static assert( is(typeof(tm3 == tm3))); 1823 static assert( is(typeof(tm3 == tc3))); 1824 static assert(!is(typeof(tc3 == tm3))); 1825 static assert(!is(typeof(tc3 == tc3))); 1826 1827 struct Equ4 { bool opEquals(T)(T) const { return true; } } 1828 auto tm4 = tuple(Equ4.init); 1829 const tc4 = tuple(Equ4.init); 1830 static assert( is(typeof(tm4 == tm4))); 1831 static assert( is(typeof(tm4 == tc4))); 1832 static assert( is(typeof(tc4 == tm4))); 1833 static assert( is(typeof(tc4 == tc4))); 1834 } 1835 // opCmp 1836 { 1837 struct Cmp1 { int opCmp(Cmp1) { return 0; } } 1838 auto tm1 = tuple(Cmp1.init); 1839 const tc1 = tuple(Cmp1.init); 1840 static assert( is(typeof(tm1 < tm1))); 1841 static assert(!is(typeof(tm1 < tc1))); 1842 static assert(!is(typeof(tc1 < tm1))); 1843 static assert(!is(typeof(tc1 < tc1))); 1844 1845 struct Cmp2 { int opCmp(const Cmp2) const { return 0; } } 1846 auto tm2 = tuple(Cmp2.init); 1847 const tc2 = tuple(Cmp2.init); 1848 static assert( is(typeof(tm2 < tm2))); 1849 static assert( is(typeof(tm2 < tc2))); 1850 static assert( is(typeof(tc2 < tm2))); 1851 static assert( is(typeof(tc2 < tc2))); 1852 1853 struct Cmp3 { int opCmp(T)(T) { return 0; } } 1854 auto tm3 = tuple(Cmp3.init); 1855 const tc3 = tuple(Cmp3.init); 1856 static assert( is(typeof(tm3 < tm3))); 1857 static assert( is(typeof(tm3 < tc3))); 1858 static assert(!is(typeof(tc3 < tm3))); 1859 static assert(!is(typeof(tc3 < tc3))); 1860 1861 struct Cmp4 { int opCmp(T)(T) const { return 0; } } 1862 auto tm4 = tuple(Cmp4.init); 1863 const tc4 = tuple(Cmp4.init); 1864 static assert( is(typeof(tm4 < tm4))); 1865 static assert( is(typeof(tm4 < tc4))); 1866 static assert( is(typeof(tc4 < tm4))); 1867 static assert( is(typeof(tc4 < tc4))); 1868 } 1869 // https://issues.dlang.org/show_bug.cgi?id=14890 1870 static void test14890(inout int[] dummy) 1871 { 1872 alias V = Tuple!(int, int); 1873 1874 V mv; 1875 const V cv; 1876 immutable V iv; 1877 inout V wv; // OK <- NG 1878 inout const V wcv; // OK <- NG 1879 1880 static foreach (v1; AliasSeq!(mv, cv, iv, wv, wcv)) 1881 static foreach (v2; AliasSeq!(mv, cv, iv, wv, wcv)) 1882 { 1883 assert(!(v1 < v2)); 1884 } 1885 } 1886 { 1887 int[2] ints = [ 1, 2 ]; 1888 Tuple!(int, int) t = ints; 1889 assert(t[0] == 1 && t[1] == 2); 1890 Tuple!(long, uint) t2 = ints; 1891 assert(t2[0] == 1 && t2[1] == 2); 1892 } 1893 } 1894 @safe unittest 1895 { 1896 auto t1 = Tuple!(int, "x", string, "y")(1, "a"); 1897 assert(t1.x == 1); 1898 assert(t1.y == "a"); 1899 void foo(Tuple!(int, string) t2) {} 1900 foo(t1); 1901 1902 Tuple!(int, int)[] arr; 1903 arr ~= tuple(10, 20); // OK 1904 arr ~= Tuple!(int, "x", int, "y")(10, 20); // NG -> OK 1905 1906 static assert(is(typeof(Tuple!(int, "x", string, "y").tupleof) == 1907 typeof(Tuple!(int, string ).tupleof))); 1908 } 1909 @safe unittest 1910 { 1911 // https://issues.dlang.org/show_bug.cgi?id=10686 1912 immutable Tuple!(int) t1; 1913 auto r1 = t1[0]; // OK 1914 immutable Tuple!(int, "x") t2; 1915 auto r2 = t2[0]; // error 1916 } 1917 @safe unittest 1918 { 1919 import std.exception : assertCTFEable; 1920 1921 // https://issues.dlang.org/show_bug.cgi?id=10218 1922 assertCTFEable!( 1923 { 1924 auto t = tuple(1); 1925 t = tuple(2); // assignment 1926 }); 1927 } 1928 @safe unittest 1929 { 1930 class Foo{} 1931 Tuple!(immutable(Foo)[]) a; 1932 } 1933 1934 @safe unittest 1935 { 1936 //Test non-assignable 1937 static struct S 1938 { 1939 int* p; 1940 } 1941 alias IS = immutable S; 1942 static assert(!isAssignable!IS); 1943 1944 auto s = IS.init; 1945 1946 alias TIS = Tuple!IS; 1947 TIS a = tuple(s); 1948 TIS b = a; 1949 1950 alias TISIS = Tuple!(IS, IS); 1951 TISIS d = tuple(s, s); 1952 IS[2] ss; 1953 TISIS e = TISIS(ss); 1954 } 1955 1956 // https://issues.dlang.org/show_bug.cgi?id=9819 1957 @safe unittest 1958 { 1959 alias T = Tuple!(int, "x", double, "foo"); 1960 static assert(T.fieldNames[0] == "x"); 1961 static assert(T.fieldNames[1] == "foo"); 1962 1963 alias Fields = Tuple!(int, "id", string, float); 1964 static assert(Fields.fieldNames == AliasSeq!("id", "", "")); 1965 } 1966 1967 // https://issues.dlang.org/show_bug.cgi?id=13837 1968 @safe unittest 1969 { 1970 // New behaviour, named arguments. 1971 static assert(is( 1972 typeof(tuple!("x")(1)) == Tuple!(int, "x"))); 1973 static assert(is( 1974 typeof(tuple!("x")(1.0)) == Tuple!(double, "x"))); 1975 static assert(is( 1976 typeof(tuple!("x")("foo")) == Tuple!(string, "x"))); 1977 static assert(is( 1978 typeof(tuple!("x", "y")(1, 2.0)) == Tuple!(int, "x", double, "y"))); 1979 1980 auto a = tuple!("a", "b", "c")("1", 2, 3.0f); 1981 static assert(is(typeof(a.a) == string)); 1982 static assert(is(typeof(a.b) == int)); 1983 static assert(is(typeof(a.c) == float)); 1984 1985 // Old behaviour, but with explicit type parameters. 1986 static assert(is( 1987 typeof(tuple!(int, double)(1, 2.0)) == Tuple!(int, double))); 1988 static assert(is( 1989 typeof(tuple!(const int)(1)) == Tuple!(const int))); 1990 static assert(is( 1991 typeof(tuple()) == Tuple!())); 1992 1993 // Nonsensical behaviour 1994 static assert(!__traits(compiles, tuple!(1)(2))); 1995 static assert(!__traits(compiles, tuple!("x")(1, 2))); 1996 static assert(!__traits(compiles, tuple!("x", "y")(1))); 1997 static assert(!__traits(compiles, tuple!("x")())); 1998 static assert(!__traits(compiles, tuple!("x", int)(2))); 1999 } 2000 2001 @safe unittest 2002 { 2003 class C { override size_t toHash() const nothrow @safe { return 0; } } 2004 Tuple!(Rebindable!(const C)) a; 2005 Tuple!(const C) b; 2006 a = b; 2007 } 2008 2009 @nogc @safe unittest 2010 { 2011 alias T = Tuple!(string, "s"); 2012 T x; 2013 x = T.init; 2014 } 2015 2016 @safe unittest 2017 { 2018 import std.format : format, FormatException; 2019 import std.exception : assertThrown; 2020 2021 //enum tupStr = tuple(1, 1.0).toString; // toString is *impure*. 2022 //static assert(tupStr == `Tuple!(int, double)(1, 1)`); 2023 } 2024 2025 // https://issues.dlang.org/show_bug.cgi?id=17803, parte uno 2026 @safe unittest 2027 { 2028 auto a = tuple(3, "foo"); 2029 assert(__traits(compiles, { a = (a = a); })); 2030 } 2031 // Ditto 2032 @safe unittest 2033 { 2034 Tuple!(int[]) a, b, c; 2035 a = tuple([0, 1, 2]); 2036 c = b = a; 2037 assert(a[0].length == b[0].length && b[0].length == c[0].length); 2038 assert(a[0].ptr == b[0].ptr && b[0].ptr == c[0].ptr); 2039 } 2040 2041 /** 2042 Constructs a $(LREF Tuple) object instantiated and initialized according to 2043 the given arguments. 2044 2045 Params: 2046 Names = An optional list of strings naming each successive field of the `Tuple` 2047 or a list of types that the elements are being casted to. 2048 For a list of names, 2049 each name matches up with the corresponding field given by `Args`. 2050 A name does not have to be provided for every field, but as 2051 the names must proceed in order, it is not possible to skip 2052 one field and name the next after it. 2053 For a list of types, 2054 there must be exactly as many types as parameters. 2055 */ 2056 template tuple(Names...) 2057 { 2058 /** 2059 Params: 2060 args = Values to initialize the `Tuple` with. The `Tuple`'s type will 2061 be inferred from the types of the values given. 2062 2063 Returns: 2064 A new `Tuple` with its type inferred from the arguments given. 2065 */ 2066 auto tuple(Args...)(Args args) 2067 { 2068 static if (Names.length == 0) 2069 { 2070 // No specified names, just infer types from Args... 2071 return Tuple!Args(args); 2072 } 2073 else static if (!is(typeof(Names[0]) : string)) 2074 { 2075 // Names[0] isn't a string, must be explicit types. 2076 return Tuple!Names(args); 2077 } 2078 else 2079 { 2080 // Names[0] is a string, so must be specifying names. 2081 static assert(Names.length == Args.length, 2082 "Insufficient number of names given."); 2083 2084 // Interleave(a, b).and(c, d) == (a, c, b, d) 2085 // This is to get the interleaving of types and names for Tuple 2086 // e.g. Tuple!(int, "x", string, "y") 2087 template Interleave(A...) 2088 { 2089 template and(B...) if (B.length == 1) 2090 { 2091 alias and = AliasSeq!(A[0], B[0]); 2092 } 2093 2094 template and(B...) if (B.length != 1) 2095 { 2096 alias and = AliasSeq!(A[0], B[0], 2097 Interleave!(A[1..$]).and!(B[1..$])); 2098 } 2099 } 2100 return Tuple!(Interleave!(Args).and!(Names))(args); 2101 } 2102 } 2103 } 2104 2105 /// 2106 @safe unittest 2107 { 2108 auto value = tuple(5, 6.7, "hello"); 2109 assert(value[0] == 5); 2110 assert(value[1] == 6.7); 2111 assert(value[2] == "hello"); 2112 2113 // Field names can be provided. 2114 auto entry = tuple!("index", "value")(4, "Hello"); 2115 assert(entry.index == 4); 2116 assert(entry.value == "Hello"); 2117 } 2118 2119 /** 2120 Returns `true` if and only if `T` is an instance of `std.typecons.Tuple`. 2121 2122 Params: 2123 T = The type to check. 2124 2125 Returns: 2126 true if `T` is a `Tuple` type, false otherwise. 2127 */ 2128 enum isTuple(T) = __traits(compiles, 2129 { 2130 void f(Specs...)(Tuple!Specs tup) {} 2131 f(T.init); 2132 } ); 2133 2134 /// 2135 @safe unittest 2136 { 2137 static assert(isTuple!(Tuple!())); 2138 static assert(isTuple!(Tuple!(int))); 2139 static assert(isTuple!(Tuple!(int, real, string))); 2140 static assert(isTuple!(Tuple!(int, "x", real, "y"))); 2141 static assert(isTuple!(Tuple!(int, Tuple!(real), string))); 2142 } 2143 2144 @safe unittest 2145 { 2146 static assert(isTuple!(const Tuple!(int))); 2147 static assert(isTuple!(immutable Tuple!(int))); 2148 2149 static assert(!isTuple!(int)); 2150 static assert(!isTuple!(const int)); 2151 2152 struct S {} 2153 static assert(!isTuple!(S)); 2154 } 2155 2156 // used by both Rebindable and UnqualRef 2157 private mixin template RebindableCommon(T, U, alias This) 2158 if (is(T == class) || is(T == interface) || isAssociativeArray!T) 2159 { 2160 private union 2161 { 2162 T original; 2163 U stripped; 2164 } 2165 2166 void opAssign(T another) pure nothrow @nogc 2167 { 2168 // If `T` defines `opCast` we must infer the safety 2169 static if (hasMember!(T, "opCast")) 2170 { 2171 // This will allow the compiler to infer the safety of `T.opCast!U` 2172 // without generating any runtime cost 2173 if (false) { stripped = cast(U) another; } 2174 } 2175 () @trusted { stripped = cast(U) another; }(); 2176 } 2177 2178 void opAssign(typeof(this) another) @trusted pure nothrow @nogc 2179 { 2180 stripped = another.stripped; 2181 } 2182 2183 static if (is(T == const U) && is(T == const shared U)) 2184 { 2185 // safely assign immutable to const / const shared 2186 void opAssign(This!(immutable U) another) @trusted pure nothrow @nogc 2187 { 2188 stripped = another.stripped; 2189 } 2190 } 2191 2192 this(T initializer) pure nothrow @nogc 2193 { 2194 // Infer safety from opAssign 2195 opAssign(initializer); 2196 } 2197 2198 @property inout(T) get() @trusted pure nothrow @nogc inout 2199 { 2200 return original; 2201 } 2202 2203 bool opEquals()(auto ref const(typeof(this)) rhs) const 2204 { 2205 // Must forward explicitly because 'stripped' is part of a union. 2206 // The necessary 'toHash' is forwarded to the class via alias this. 2207 return stripped == rhs.stripped; 2208 } 2209 2210 bool opEquals(const(U) rhs) const 2211 { 2212 return stripped == rhs; 2213 } 2214 2215 alias get this; 2216 } 2217 2218 /** 2219 `Rebindable!(T)` is a simple, efficient wrapper that behaves just 2220 like an object of type `T`, except that you can reassign it to 2221 refer to another object. For completeness, `Rebindable!(T)` aliases 2222 itself away to `T` if `T` is a non-const object type. 2223 2224 You may want to use `Rebindable` when you want to have mutable 2225 storage referring to `const` objects, for example an array of 2226 references that must be sorted in place. `Rebindable` does not 2227 break the soundness of D's type system and does not incur any of the 2228 risks usually associated with `cast`. 2229 2230 Params: 2231 T = An object, interface, array slice type, or associative array type. 2232 */ 2233 template Rebindable(T) 2234 if (is(T == class) || is(T == interface) || isDynamicArray!T || isAssociativeArray!T) 2235 { 2236 static if (is(T == const U, U) || is(T == immutable U, U)) 2237 { 2238 static if (isDynamicArray!T) 2239 { 2240 import std.range.primitives : ElementEncodingType; 2241 alias Rebindable = const(ElementEncodingType!T)[]; 2242 } 2243 else 2244 { 2245 struct Rebindable 2246 { 2247 mixin RebindableCommon!(T, U, Rebindable); 2248 } 2249 } 2250 } 2251 else 2252 { 2253 alias Rebindable = T; 2254 } 2255 } 2256 2257 ///Regular `const` object references cannot be reassigned. 2258 @safe unittest 2259 { 2260 class Widget { int x; int y() @safe const { return x; } } 2261 const a = new Widget; 2262 // Fine 2263 a.y(); 2264 // error! can't modify const a 2265 // a.x = 5; 2266 // error! can't modify const a 2267 // a = new Widget; 2268 } 2269 2270 /** 2271 However, `Rebindable!(Widget)` does allow reassignment, 2272 while otherwise behaving exactly like a $(D const Widget). 2273 */ 2274 @safe unittest 2275 { 2276 class Widget { int x; int y() const @safe { return x; } } 2277 auto a = Rebindable!(const Widget)(new Widget); 2278 // Fine 2279 a.y(); 2280 // error! can't modify const a 2281 // a.x = 5; 2282 // Fine 2283 a = new Widget; 2284 } 2285 2286 // https://issues.dlang.org/show_bug.cgi?id=16054 2287 @safe unittest 2288 { 2289 Rebindable!(immutable Object) r; 2290 static assert(__traits(compiles, r.get())); 2291 static assert(!__traits(compiles, &r.get())); 2292 } 2293 2294 @safe unittest 2295 { 2296 class CustomToHash 2297 { 2298 override size_t toHash() const nothrow @trusted { return 42; } 2299 } 2300 Rebindable!(immutable(CustomToHash)) a = new immutable CustomToHash(); 2301 assert(a.toHash() == 42, "Rebindable!A should offer toHash()" 2302 ~ " by forwarding to A.toHash()."); 2303 } 2304 2305 // https://issues.dlang.org/show_bug.cgi?id=18615 2306 // Rebindable!A should use A.opEqualsa 2307 @system unittest 2308 { 2309 class CustomOpEq 2310 { 2311 int x; 2312 override bool opEquals(Object rhsObj) 2313 { 2314 if (auto rhs = cast(const(CustomOpEq)) rhsObj) 2315 return this.x == rhs.x; 2316 else 2317 return false; 2318 } 2319 } 2320 CustomOpEq a = new CustomOpEq(); 2321 CustomOpEq b = new CustomOpEq(); 2322 assert(a !is b); 2323 assert(a == b, "a.x == b.x should be true (0 == 0)."); 2324 2325 Rebindable!(const(CustomOpEq)) ra = a; 2326 Rebindable!(const(CustomOpEq)) rb = b; 2327 assert(ra !is rb); 2328 assert(ra == rb, "Rebindable should use CustomOpEq's opEquals, not 'is'."); 2329 assert(ra == b, "Rebindable!(someQualifier(A)) should be comparable" 2330 ~ " against const(A) via A.opEquals."); 2331 assert(a == rb, "Rebindable!(someQualifier(A)) should be comparable" 2332 ~ " against const(A) via A.opEquals."); 2333 2334 b.x = 1; 2335 assert(a != b); 2336 assert(ra != b, "Rebindable!(someQualifier(A)) should be comparable" 2337 ~ " against const(A) via A.opEquals."); 2338 assert(a != rb, "Rebindable!(someQualifier(A)) should be comparable" 2339 ~ " against const(A) via A.opEquals."); 2340 2341 Rebindable!(const(Object)) o1 = new Object(); 2342 Rebindable!(const(Object)) o2 = new Object(); 2343 assert(o1 !is o2); 2344 assert(o1 == o1, "When the class doesn't provide its own opEquals," 2345 ~ " Rebindable treats 'a == b' as 'a is b' like Object.opEquals."); 2346 assert(o1 != o2, "When the class doesn't provide its own opEquals," 2347 ~ " Rebindable treats 'a == b' as 'a is b' like Object.opEquals."); 2348 assert(o1 != new Object(), "Rebindable!(const(Object)) should be" 2349 ~ " comparable against Object itself and use Object.opEquals."); 2350 } 2351 2352 // https://issues.dlang.org/show_bug.cgi?id=18755 2353 @safe unittest 2354 { 2355 static class Foo 2356 { 2357 auto opCast(T)() @system immutable pure nothrow 2358 { 2359 *(cast(uint*) 0xdeadbeef) = 0xcafebabe; 2360 return T.init; 2361 } 2362 } 2363 2364 static assert(!__traits(compiles, () @safe { 2365 auto r = Rebindable!(immutable Foo)(new Foo); 2366 })); 2367 static assert(__traits(compiles, () @system { 2368 auto r = Rebindable!(immutable Foo)(new Foo); 2369 })); 2370 } 2371 2372 /** 2373 Convenience function for creating a `Rebindable` using automatic type 2374 inference. 2375 2376 Params: 2377 obj = A reference to an object, interface, associative array, or an array slice 2378 to initialize the `Rebindable` with. 2379 2380 Returns: 2381 A newly constructed `Rebindable` initialized with the given reference. 2382 */ 2383 Rebindable!T rebindable(T)(T obj) 2384 if (is(T == class) || is(T == interface) || isDynamicArray!T || isAssociativeArray!T) 2385 { 2386 typeof(return) ret; 2387 ret = obj; 2388 return ret; 2389 } 2390 2391 /// 2392 @system unittest 2393 { 2394 class C 2395 { 2396 int payload; 2397 this(int p) { payload = p; } 2398 } 2399 const c = new C(1); 2400 2401 auto c2 = c.rebindable; 2402 assert(c2.payload == 1); 2403 // passing Rebindable to rebindable 2404 c2 = c2.rebindable; 2405 2406 c2 = new C(2); 2407 assert(c2.payload == 2); 2408 2409 const c3 = c2.get; 2410 assert(c3.payload == 2); 2411 } 2412 2413 /** 2414 This function simply returns the `Rebindable` object passed in. It's useful 2415 in generic programming cases when a given object may be either a regular 2416 `class` or a `Rebindable`. 2417 2418 Params: 2419 obj = An instance of Rebindable!T. 2420 2421 Returns: 2422 `obj` without any modification. 2423 */ 2424 Rebindable!T rebindable(T)(Rebindable!T obj) 2425 { 2426 return obj; 2427 } 2428 2429 // TODO: remove me once the rebindable overloads have been joined 2430 /// 2431 @system unittest 2432 { 2433 class C 2434 { 2435 int payload; 2436 this(int p) { payload = p; } 2437 } 2438 const c = new C(1); 2439 2440 auto c2 = c.rebindable; 2441 assert(c2.payload == 1); 2442 // passing Rebindable to rebindable 2443 c2 = c2.rebindable; 2444 assert(c2.payload == 1); 2445 } 2446 2447 @system unittest 2448 { 2449 interface CI { int foo() const; } 2450 class C : CI { 2451 int foo() const { return 42; } 2452 @property int bar() const { return 23; } 2453 } 2454 Rebindable!(C) obj0; 2455 static assert(is(typeof(obj0) == C)); 2456 2457 Rebindable!(const(C)) obj1; 2458 static assert(is(typeof(obj1.get) == const(C)), typeof(obj1.get).stringof); 2459 static assert(is(typeof(obj1.stripped) == C)); 2460 obj1 = new C; 2461 assert(obj1.get !is null); 2462 obj1 = new const(C); 2463 assert(obj1.get !is null); 2464 2465 Rebindable!(immutable(C)) obj2; 2466 static assert(is(typeof(obj2.get) == immutable(C))); 2467 static assert(is(typeof(obj2.stripped) == C)); 2468 obj2 = new immutable(C); 2469 assert(obj1.get !is null); 2470 2471 // test opDot 2472 assert(obj2.foo() == 42); 2473 assert(obj2.bar == 23); 2474 2475 interface I { final int foo() const { return 42; } } 2476 Rebindable!(I) obj3; 2477 static assert(is(typeof(obj3) == I)); 2478 2479 Rebindable!(const I) obj4; 2480 static assert(is(typeof(obj4.get) == const I)); 2481 static assert(is(typeof(obj4.stripped) == I)); 2482 static assert(is(typeof(obj4.foo()) == int)); 2483 obj4 = new class I {}; 2484 2485 Rebindable!(immutable C) obj5i; 2486 Rebindable!(const C) obj5c; 2487 obj5c = obj5c; 2488 obj5c = obj5i; 2489 obj5i = obj5i; 2490 static assert(!__traits(compiles, obj5i = obj5c)); 2491 2492 // Test the convenience functions. 2493 auto obj5convenience = rebindable(obj5i); 2494 assert(obj5convenience is obj5i); 2495 2496 auto obj6 = rebindable(new immutable(C)); 2497 static assert(is(typeof(obj6) == Rebindable!(immutable C))); 2498 assert(obj6.foo() == 42); 2499 2500 auto obj7 = rebindable(new C); 2501 CI interface1 = obj7; 2502 auto interfaceRebind1 = rebindable(interface1); 2503 assert(interfaceRebind1.foo() == 42); 2504 2505 const interface2 = interface1; 2506 auto interfaceRebind2 = rebindable(interface2); 2507 assert(interfaceRebind2.foo() == 42); 2508 2509 auto arr = [1,2,3,4,5]; 2510 const arrConst = arr; 2511 assert(rebindable(arr) == arr); 2512 assert(rebindable(arrConst) == arr); 2513 2514 // https://issues.dlang.org/show_bug.cgi?id=7654 2515 immutable(char[]) s7654; 2516 Rebindable!(typeof(s7654)) r7654 = s7654; 2517 2518 static foreach (T; AliasSeq!(char, wchar, char, int)) 2519 { 2520 static assert(is(Rebindable!(immutable(T[])) == immutable(T)[])); 2521 static assert(is(Rebindable!(const(T[])) == const(T)[])); 2522 static assert(is(Rebindable!(T[]) == T[])); 2523 } 2524 2525 // https://issues.dlang.org/show_bug.cgi?id=12046 2526 static assert(!__traits(compiles, Rebindable!(int[1]))); 2527 static assert(!__traits(compiles, Rebindable!(const int[1]))); 2528 2529 // Pull request 3341 2530 Rebindable!(immutable int[int]) pr3341 = [123:345]; 2531 assert(pr3341[123] == 345); 2532 immutable int[int] pr3341_aa = [321:543]; 2533 pr3341 = pr3341_aa; 2534 assert(pr3341[321] == 543); 2535 assert(rebindable(pr3341_aa)[321] == 543); 2536 } 2537 2538 /** 2539 Similar to `Rebindable!(T)` but strips all qualifiers from the reference as 2540 opposed to just constness / immutability. Primary intended use case is with 2541 shared (having thread-local reference to shared class data) 2542 2543 Params: 2544 T = A class or interface type. 2545 */ 2546 template UnqualRef(T) 2547 if (is(T == class) || is(T == interface)) 2548 { 2549 static if (is(T == immutable U, U) 2550 || is(T == const shared U, U) 2551 || is(T == const U, U) 2552 || is(T == shared U, U)) 2553 { 2554 struct UnqualRef 2555 { 2556 mixin RebindableCommon!(T, U, UnqualRef); 2557 } 2558 } 2559 else 2560 { 2561 alias UnqualRef = T; 2562 } 2563 } 2564 2565 /// 2566 @system unittest 2567 { 2568 class Data {} 2569 2570 static shared(Data) a; 2571 static UnqualRef!(shared Data) b; 2572 2573 import core.thread; 2574 2575 auto thread = new core.thread.Thread({ 2576 a = new shared Data(); 2577 b = new shared Data(); 2578 }); 2579 2580 thread.start(); 2581 thread.join(); 2582 2583 assert(a !is null); 2584 assert(b is null); 2585 } 2586 2587 @safe unittest 2588 { 2589 class C { } 2590 alias T = UnqualRef!(const shared C); 2591 static assert(is(typeof(T.stripped) == C)); 2592 } 2593 2594 2595 2596 /** 2597 Order the provided members to minimize size while preserving alignment. 2598 Alignment is not always optimal for 80-bit reals, nor for structs declared 2599 as align(1). 2600 2601 Params: 2602 E = A list of the types to be aligned, representing fields 2603 of an aggregate such as a `struct` or `class`. 2604 2605 names = The names of the fields that are to be aligned. 2606 2607 Returns: 2608 A string to be mixed in to an aggregate, such as a `struct` or `class`. 2609 */ 2610 string alignForSize(E...)(const char[][] names...) 2611 { 2612 // Sort all of the members by .alignof. 2613 // BUG: Alignment is not always optimal for align(1) structs 2614 // or 80-bit reals or 64-bit primitives on x86. 2615 // TRICK: Use the fact that .alignof is always a power of 2, 2616 // and maximum 16 on extant systems. Thus, we can perform 2617 // a very limited radix sort. 2618 // Contains the members with .alignof = 64,32,16,8,4,2,1 2619 2620 assert(E.length == names.length, 2621 "alignForSize: There should be as many member names as the types"); 2622 2623 string[7] declaration = ["", "", "", "", "", "", ""]; 2624 2625 foreach (i, T; E) 2626 { 2627 auto a = T.alignof; 2628 auto k = a >= 64? 0 : a >= 32? 1 : a >= 16? 2 : a >= 8? 3 : a >= 4? 4 : a >= 2? 5 : 6; 2629 declaration[k] ~= T.stringof ~ " " ~ names[i] ~ ";\n"; 2630 } 2631 2632 auto s = ""; 2633 foreach (decl; declaration) 2634 s ~= decl; 2635 return s; 2636 } 2637 2638 /// 2639 @safe unittest 2640 { 2641 struct Banner { 2642 mixin(alignForSize!(byte[6], double)(["name", "height"])); 2643 } 2644 } 2645 2646 @safe unittest 2647 { 2648 enum x = alignForSize!(int[], char[3], short, double[5])("x", "y","z", "w"); 2649 struct Foo { int x; } 2650 enum y = alignForSize!(ubyte, Foo, double)("x", "y", "z"); 2651 2652 enum passNormalX = x == "double[5] w;\nint[] x;\nshort z;\nchar[3] y;\n"; 2653 enum passNormalY = y == "double z;\nFoo y;\nubyte x;\n"; 2654 2655 enum passAbnormalX = x == "int[] x;\ndouble[5] w;\nshort z;\nchar[3] y;\n"; 2656 enum passAbnormalY = y == "Foo y;\ndouble z;\nubyte x;\n"; 2657 // ^ blame https://issues.dlang.org/show_bug.cgi?id=231 2658 2659 static assert(passNormalX || passAbnormalX && double.alignof <= (int[]).alignof); 2660 static assert(passNormalY || passAbnormalY && double.alignof <= int.alignof); 2661 } 2662 2663 // https://issues.dlang.org/show_bug.cgi?id=12914 2664 @safe unittest 2665 { 2666 immutable string[] fieldNames = ["x", "y"]; 2667 struct S 2668 { 2669 mixin(alignForSize!(byte, int)(fieldNames)); 2670 } 2671 } 2672 2673 /** 2674 Defines a value paired with a distinctive "null" state that denotes 2675 the absence of a value. If default constructed, a $(D 2676 Nullable!T) object starts in the null state. Assigning it renders it 2677 non-null. Calling `nullify` can nullify it again. 2678 2679 Practically `Nullable!T` stores a `T` and a `bool`. 2680 */ 2681 struct Nullable(T) 2682 { 2683 private union DontCallDestructorT 2684 { 2685 T payload; 2686 } 2687 2688 private DontCallDestructorT _value = DontCallDestructorT.init; 2689 2690 private bool _isNull = true; 2691 2692 /** 2693 * Constructor initializing `this` with `value`. 2694 * 2695 * Params: 2696 * value = The value to initialize this `Nullable` with. 2697 */ 2698 this(inout T value) inout 2699 { 2700 _value.payload = value; 2701 _isNull = false; 2702 } 2703 2704 static if (is(T == struct) && hasElaborateDestructor!T) 2705 { 2706 ~this() 2707 { 2708 if (!_isNull) 2709 { 2710 destroy(_value.payload); 2711 } 2712 } 2713 } 2714 2715 /** 2716 * If they are both null, then they are equal. If one is null and the other 2717 * is not, then they are not equal. If they are both non-null, then they are 2718 * equal if their values are equal. 2719 */ 2720 bool opEquals()(auto ref const(typeof(this)) rhs) const 2721 { 2722 if (_isNull) 2723 return rhs._isNull; 2724 if (rhs._isNull) 2725 return false; 2726 return _value.payload == rhs._value.payload; 2727 } 2728 2729 /// Ditto 2730 bool opEquals(U)(auto ref const(U) rhs) const 2731 if (!is(U : typeof(this)) && is(typeof(this.get == rhs))) 2732 { 2733 return _isNull ? false : rhs == _value.payload; 2734 } 2735 2736 /// 2737 @safe unittest 2738 { 2739 Nullable!int empty; 2740 Nullable!int a = 42; 2741 Nullable!int b = 42; 2742 Nullable!int c = 27; 2743 2744 assert(empty == empty); 2745 assert(empty == Nullable!int.init); 2746 assert(empty != a); 2747 assert(empty != b); 2748 assert(empty != c); 2749 2750 assert(a == b); 2751 assert(a != c); 2752 2753 assert(empty != 42); 2754 assert(a == 42); 2755 assert(c != 42); 2756 } 2757 2758 @safe unittest 2759 { 2760 // Test constness 2761 immutable Nullable!int a = 42; 2762 Nullable!int b = 42; 2763 immutable Nullable!int c = 29; 2764 Nullable!int d = 29; 2765 immutable e = 42; 2766 int f = 29; 2767 assert(a == a); 2768 assert(a == b); 2769 assert(a != c); 2770 assert(a != d); 2771 assert(a == e); 2772 assert(a != f); 2773 2774 // Test rvalue 2775 assert(a == const Nullable!int(42)); 2776 assert(a != Nullable!int(29)); 2777 } 2778 2779 // https://issues.dlang.org/show_bug.cgi?id=17482 2780 @system unittest 2781 { 2782 import std.variant : Variant; 2783 Nullable!Variant a = Variant(12); 2784 assert(a == 12); 2785 Nullable!Variant e; 2786 assert(e != 12); 2787 } 2788 2789 size_t toHash() const @safe nothrow 2790 { 2791 static if (__traits(compiles, .hashOf(_value.payload))) 2792 return _isNull ? 0 : .hashOf(_value.payload); 2793 else 2794 // Workaround for when .hashOf is not both @safe and nothrow. 2795 return _isNull ? 0 : typeid(T).getHash(&_value.payload); 2796 } 2797 2798 /** 2799 * Gives the string `"Nullable.null"` if `isNull` is `true`. Otherwise, the 2800 * result is equivalent to calling $(REF formattedWrite, std,format) on the 2801 * underlying value. 2802 * 2803 * Params: 2804 * writer = A `char` accepting 2805 * $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) 2806 * fmt = A $(REF FormatSpec, std,format) which is used to represent 2807 * the value if this Nullable is not null 2808 * Returns: 2809 * A `string` if `writer` and `fmt` are not set; `void` otherwise. 2810 */ 2811 string toString() 2812 { 2813 import std.array : appender; 2814 auto app = appender!string(); 2815 auto spec = singleSpec("%s"); 2816 toString(app, spec); 2817 return app.data; 2818 } 2819 2820 /// ditto 2821 string toString() const 2822 { 2823 import std.array : appender; 2824 auto app = appender!string(); 2825 auto spec = singleSpec("%s"); 2826 toString(app, spec); 2827 return app.data; 2828 } 2829 2830 /// ditto 2831 void toString(W)(ref W writer, scope const ref FormatSpec!char fmt) 2832 if (isOutputRange!(W, char)) 2833 { 2834 import std.range.primitives : put; 2835 if (isNull) 2836 put(writer, "Nullable.null"); 2837 else 2838 formatValue(writer, _value.payload, fmt); 2839 } 2840 2841 /// ditto 2842 void toString(W)(ref W writer, scope const ref FormatSpec!char fmt) const 2843 if (isOutputRange!(W, char)) 2844 { 2845 import std.range.primitives : put; 2846 if (isNull) 2847 put(writer, "Nullable.null"); 2848 else 2849 formatValue(writer, _value.payload, fmt); 2850 } 2851 2852 /** 2853 * Check if `this` is in the null state. 2854 * 2855 * Returns: 2856 * true $(B iff) `this` is in the null state, otherwise false. 2857 */ 2858 @property bool isNull() const @safe pure nothrow 2859 { 2860 return _isNull; 2861 } 2862 2863 /// 2864 @safe unittest 2865 { 2866 Nullable!int ni; 2867 assert(ni.isNull); 2868 2869 ni = 0; 2870 assert(!ni.isNull); 2871 } 2872 2873 // https://issues.dlang.org/show_bug.cgi?id=14940 2874 @safe unittest 2875 { 2876 import std.array : appender; 2877 import std.format : formattedWrite; 2878 2879 auto app = appender!string(); 2880 Nullable!int a = 1; 2881 formattedWrite(app, "%s", a); 2882 assert(app.data == "1"); 2883 } 2884 2885 // https://issues.dlang.org/show_bug.cgi?id=19799 2886 @safe unittest 2887 { 2888 import std.format : format; 2889 2890 const Nullable!string a = const(Nullable!string)(); 2891 2892 format!"%s"(a); 2893 } 2894 2895 /** 2896 * Forces `this` to the null state. 2897 */ 2898 void nullify()() 2899 { 2900 static if (is(T == class) || is(T == interface)) 2901 _value.payload = null; 2902 else 2903 .destroy(_value.payload); 2904 _isNull = true; 2905 } 2906 2907 /// 2908 @safe unittest 2909 { 2910 Nullable!int ni = 0; 2911 assert(!ni.isNull); 2912 2913 ni.nullify(); 2914 assert(ni.isNull); 2915 } 2916 2917 /** 2918 * Assigns `value` to the internally-held state. If the assignment 2919 * succeeds, `this` becomes non-null. 2920 * 2921 * Params: 2922 * value = A value of type `T` to assign to this `Nullable`. 2923 */ 2924 void opAssign()(T value) 2925 { 2926 import std.algorithm.mutation : moveEmplace, move; 2927 2928 // the lifetime of the value in copy shall be managed by 2929 // this Nullable, so we must avoid calling its destructor. 2930 auto copy = DontCallDestructorT(value); 2931 2932 if (_isNull) 2933 { 2934 // trusted since payload is known to be T.init here. 2935 () @trusted { moveEmplace(copy.payload, _value.payload); }(); 2936 } 2937 else 2938 { 2939 move(copy.payload, _value.payload); 2940 } 2941 _isNull = false; 2942 } 2943 2944 /** 2945 * If this `Nullable` wraps a type that already has a null value 2946 * (such as a pointer), then assigning the null value to this 2947 * `Nullable` is no different than assigning any other value of 2948 * type `T`, and the resulting code will look very strange. It 2949 * is strongly recommended that this be avoided by instead using 2950 * the version of `Nullable` that takes an additional `nullValue` 2951 * template argument. 2952 */ 2953 @safe unittest 2954 { 2955 //Passes 2956 Nullable!(int*) npi; 2957 assert(npi.isNull); 2958 2959 //Passes?! 2960 npi = null; 2961 assert(!npi.isNull); 2962 } 2963 2964 /** 2965 * Gets the value if not null. If `this` is in the null state, and the optional 2966 * parameter `fallback` was provided, it will be returned. Without `fallback`, 2967 * calling `get` with a null state is invalid. 2968 * 2969 * When the fallback type is different from the Nullable type, `get(T)` returns 2970 * the common type. 2971 * 2972 * Params: 2973 * fallback = the value to return in case the `Nullable` is null. 2974 * 2975 * Returns: 2976 * The value held internally by this `Nullable`. 2977 */ 2978 @property ref inout(T) get() inout @safe pure nothrow 2979 { 2980 enum message = "Called `get' on null Nullable!" ~ T.stringof ~ "."; 2981 assert(!isNull, message); 2982 return _value.payload; 2983 } 2984 2985 /// ditto 2986 @property inout(T) get()(inout(T) fallback) inout @safe pure nothrow 2987 { 2988 return isNull ? fallback : _value.payload; 2989 } 2990 2991 /// ditto 2992 @property auto get(U)(inout(U) fallback) inout @safe pure nothrow 2993 { 2994 return isNull ? fallback : _value.payload; 2995 } 2996 2997 //@@@DEPRECATED_2.096@@@ 2998 deprecated( 2999 "Implicit conversion with `alias Nullable.get this` will be removed after 2.096. Please use `.get` explicitly.") 3000 @system unittest 3001 { 3002 import core.exception : AssertError; 3003 import std.exception : assertThrown, assertNotThrown; 3004 3005 Nullable!int ni; 3006 int i = 42; 3007 //`get` is implicitly called. Will throw 3008 //an AssertError in non-release mode 3009 assertThrown!AssertError(i = ni); 3010 assert(i == 42); 3011 3012 ni = 5; 3013 assertNotThrown!AssertError(i = ni); 3014 assert(i == 5); 3015 } 3016 3017 //@@@DEPRECATED_2.096@@@ 3018 deprecated( 3019 "Implicit conversion with `alias Nullable.get this` will be removed after 2.096. Please use `.get` explicitly.") 3020 @property ref inout(T) get_() inout @safe pure nothrow 3021 { 3022 return get; 3023 } 3024 3025 /// 3026 @safe pure nothrow unittest 3027 { 3028 int i = 42; 3029 Nullable!int ni; 3030 int x = ni.get(i); 3031 assert(x == i); 3032 3033 ni = 7; 3034 x = ni.get(i); 3035 assert(x == 7); 3036 } 3037 3038 /** 3039 * Implicitly converts to `T`. 3040 * `this` must not be in the null state. 3041 * This feature is deprecated and will be removed after 2.096. 3042 */ 3043 alias get_ this; 3044 } 3045 3046 /// ditto 3047 auto nullable(T)(T t) 3048 { 3049 return Nullable!T(t); 3050 } 3051 3052 /// 3053 @safe unittest 3054 { 3055 struct CustomerRecord 3056 { 3057 string name; 3058 string address; 3059 int customerNum; 3060 } 3061 3062 Nullable!CustomerRecord getByName(string name) 3063 { 3064 //A bunch of hairy stuff 3065 3066 return Nullable!CustomerRecord.init; 3067 } 3068 3069 auto queryResult = getByName("Doe, John"); 3070 if (!queryResult.isNull) 3071 { 3072 //Process Mr. Doe's customer record 3073 auto address = queryResult.get.address; 3074 auto customerNum = queryResult.get.customerNum; 3075 3076 //Do some things with this customer's info 3077 } 3078 else 3079 { 3080 //Add the customer to the database 3081 } 3082 } 3083 3084 /// 3085 @system unittest 3086 { 3087 import std.exception : assertThrown; 3088 3089 auto a = 42.nullable; 3090 assert(!a.isNull); 3091 assert(a.get == 42); 3092 3093 a.nullify(); 3094 assert(a.isNull); 3095 assertThrown!Throwable(a.get); 3096 } 3097 3098 //@@@DEPRECATED_2.096@@@ 3099 deprecated( 3100 "Implicit conversion with `alias Nullable.get this` will be removed after 2.096. Please use `.get` explicitly.") 3101 @system unittest 3102 { 3103 import std.exception : assertThrown; 3104 3105 Nullable!int a; 3106 assert(a.isNull); 3107 assertThrown!Throwable(a.get); 3108 a = 5; 3109 assert(!a.isNull); 3110 assert(a == 5); 3111 assert(a != 3); 3112 assert(a.get != 3); 3113 a.nullify(); 3114 assert(a.isNull); 3115 a = 3; 3116 assert(a == 3); 3117 a *= 6; 3118 assert(a == 18); 3119 a = a; 3120 assert(a == 18); 3121 a.nullify(); 3122 assertThrown!Throwable(a += 2); 3123 } 3124 @safe unittest 3125 { 3126 auto k = Nullable!int(74); 3127 assert(k == 74); 3128 k.nullify(); 3129 assert(k.isNull); 3130 } 3131 @safe unittest 3132 { 3133 static int f(scope const Nullable!int x) { 3134 return x.isNull ? 42 : x.get; 3135 } 3136 Nullable!int a; 3137 assert(f(a) == 42); 3138 a = 8; 3139 assert(f(a) == 8); 3140 a.nullify(); 3141 assert(f(a) == 42); 3142 } 3143 @system unittest 3144 { 3145 import std.exception : assertThrown; 3146 3147 static struct S { int x; } 3148 Nullable!S s; 3149 assert(s.isNull); 3150 s = S(6); 3151 assert(s == S(6)); 3152 assert(s != S(0)); 3153 assert(s.get != S(0)); 3154 s.get.x = 9190; 3155 assert(s.get.x == 9190); 3156 s.nullify(); 3157 assertThrown!Throwable(s.get.x = 9441); 3158 } 3159 @safe unittest 3160 { 3161 // Ensure Nullable can be used in pure/nothrow/@safe environment. 3162 function() @safe pure nothrow 3163 { 3164 Nullable!int n; 3165 assert(n.isNull); 3166 n = 4; 3167 assert(!n.isNull); 3168 assert(n == 4); 3169 n.nullify(); 3170 assert(n.isNull); 3171 }(); 3172 } 3173 @system unittest 3174 { 3175 // Ensure Nullable can be used when the value is not pure/nothrow/@safe 3176 static struct S 3177 { 3178 int x; 3179 this(this) @system {} 3180 } 3181 3182 Nullable!S s; 3183 assert(s.isNull); 3184 s = S(5); 3185 assert(!s.isNull); 3186 assert(s.get.x == 5); 3187 s.nullify(); 3188 assert(s.isNull); 3189 } 3190 3191 // https://issues.dlang.org/show_bug.cgi?id=9404 3192 @safe unittest 3193 { 3194 alias N = Nullable!int; 3195 3196 void foo(N a) 3197 { 3198 N b; 3199 b = a; // `N b = a;` works fine 3200 } 3201 N n; 3202 foo(n); 3203 } 3204 @safe unittest 3205 { 3206 //Check nullable immutable is constructable 3207 { 3208 auto a1 = Nullable!(immutable int)(); 3209 auto a2 = Nullable!(immutable int)(1); 3210 auto i = a2.get; 3211 } 3212 //Check immutable nullable is constructable 3213 { 3214 auto a1 = immutable (Nullable!int)(); 3215 auto a2 = immutable (Nullable!int)(1); 3216 auto i = a2.get; 3217 } 3218 } 3219 @safe unittest 3220 { 3221 alias NInt = Nullable!int; 3222 3223 //Construct tests 3224 { 3225 //from other Nullable null 3226 NInt a1; 3227 NInt b1 = a1; 3228 assert(b1.isNull); 3229 3230 //from other Nullable non-null 3231 NInt a2 = NInt(1); 3232 NInt b2 = a2; 3233 assert(b2 == 1); 3234 3235 //Construct from similar nullable 3236 auto a3 = immutable(NInt)(); 3237 NInt b3 = a3; 3238 assert(b3.isNull); 3239 } 3240 3241 //Assign tests 3242 { 3243 //from other Nullable null 3244 NInt a1; 3245 NInt b1; 3246 b1 = a1; 3247 assert(b1.isNull); 3248 3249 //from other Nullable non-null 3250 NInt a2 = NInt(1); 3251 NInt b2; 3252 b2 = a2; 3253 assert(b2 == 1); 3254 3255 //Construct from similar nullable 3256 auto a3 = immutable(NInt)(); 3257 NInt b3 = a3; 3258 b3 = a3; 3259 assert(b3.isNull); 3260 } 3261 } 3262 @safe unittest 3263 { 3264 //Check nullable is nicelly embedable in a struct 3265 static struct S1 3266 { 3267 Nullable!int ni; 3268 } 3269 static struct S2 //inspired from 9404 3270 { 3271 Nullable!int ni; 3272 this(S2 other) 3273 { 3274 ni = other.ni; 3275 } 3276 void opAssign(S2 other) 3277 { 3278 ni = other.ni; 3279 } 3280 } 3281 static foreach (S; AliasSeq!(S1, S2)) 3282 {{ 3283 S a; 3284 S b = a; 3285 S c; 3286 c = a; 3287 }} 3288 } 3289 3290 // https://issues.dlang.org/show_bug.cgi?id=10268 3291 @system unittest 3292 { 3293 import std.json; 3294 JSONValue value = null; 3295 auto na = Nullable!JSONValue(value); 3296 3297 struct S1 { int val; } 3298 struct S2 { int* val; } 3299 struct S3 { immutable int* val; } 3300 3301 { 3302 auto sm = S1(1); 3303 immutable si = immutable S1(1); 3304 auto x1 = Nullable!S1(sm); 3305 auto x2 = immutable Nullable!S1(sm); 3306 auto x3 = Nullable!S1(si); 3307 auto x4 = immutable Nullable!S1(si); 3308 assert(x1.get.val == 1); 3309 assert(x2.get.val == 1); 3310 assert(x3.get.val == 1); 3311 assert(x4.get.val == 1); 3312 } 3313 3314 auto nm = 10; 3315 immutable ni = 10; 3316 3317 { 3318 auto sm = S2(&nm); 3319 immutable si = immutable S2(&ni); 3320 auto x1 = Nullable!S2(sm); 3321 static assert(!__traits(compiles, { auto x2 = immutable Nullable!S2(sm); })); 3322 static assert(!__traits(compiles, { auto x3 = Nullable!S2(si); })); 3323 auto x4 = immutable Nullable!S2(si); 3324 assert(*x1.get.val == 10); 3325 assert(*x4.get.val == 10); 3326 } 3327 3328 { 3329 auto sm = S3(&ni); 3330 immutable si = immutable S3(&ni); 3331 auto x1 = Nullable!S3(sm); 3332 auto x2 = immutable Nullable!S3(sm); 3333 auto x3 = Nullable!S3(si); 3334 auto x4 = immutable Nullable!S3(si); 3335 assert(*x1.get.val == 10); 3336 assert(*x2.get.val == 10); 3337 assert(*x3.get.val == 10); 3338 assert(*x4.get.val == 10); 3339 } 3340 } 3341 3342 // https://issues.dlang.org/show_bug.cgi?id=10357 3343 @safe unittest 3344 { 3345 import std.datetime; 3346 Nullable!SysTime time = SysTime(0); 3347 } 3348 3349 // https://issues.dlang.org/show_bug.cgi?id=10915 3350 @system unittest 3351 { 3352 import std.conv : to; 3353 import std.array; 3354 3355 Appender!string buffer; 3356 3357 Nullable!int ni; 3358 assert(ni.to!string() == "Nullable.null"); 3359 assert((cast(const) ni).to!string() == "Nullable.null"); 3360 3361 struct Test { string s; } 3362 alias NullableTest = Nullable!Test; 3363 3364 NullableTest nt = Test("test"); 3365 // test output range version 3366 assert(nt.to!string() == `Test("test")`); 3367 // test appender version 3368 assert(nt.toString() == `Test("test")`); 3369 // test const version 3370 assert((cast(const) nt).toString() == `const(Test)("test")`); 3371 3372 NullableTest ntn = Test("null"); 3373 assert(ntn.to!string() == `Test("null")`); 3374 3375 class TestToString 3376 { 3377 double d; 3378 3379 this (double d) 3380 { 3381 this.d = d; 3382 } 3383 3384 override string toString() 3385 { 3386 return d.to!string(); 3387 } 3388 } 3389 Nullable!TestToString ntts = new TestToString(2.5); 3390 assert(ntts.to!string() == "2.5"); 3391 } 3392 3393 // https://issues.dlang.org/show_bug.cgi?id=14477 3394 @safe unittest 3395 { 3396 static struct DisabledDefaultConstructor 3397 { 3398 @disable this(); 3399 this(int i) { } 3400 } 3401 Nullable!DisabledDefaultConstructor var; 3402 var = DisabledDefaultConstructor(5); 3403 var.nullify; 3404 } 3405 3406 // https://issues.dlang.org/show_bug.cgi?id=17440 3407 @system unittest 3408 { 3409 static interface I { } 3410 3411 static class C : I 3412 { 3413 int canary; 3414 ~this() 3415 { 3416 canary = 0x5050DEAD; 3417 } 3418 } 3419 auto c = new C; 3420 c.canary = 0xA71FE; 3421 auto nc = nullable(c); 3422 nc.nullify; 3423 assert(c.canary == 0xA71FE); 3424 3425 I i = c; 3426 auto ni = nullable(i); 3427 ni.nullify; 3428 assert(c.canary == 0xA71FE); 3429 } 3430 3431 // https://issues.dlang.org/show_bug.cgi?id=19037 3432 @safe unittest 3433 { 3434 import std.datetime : SysTime; 3435 3436 struct Test 3437 { 3438 bool b; 3439 3440 nothrow invariant { assert(b == true); } 3441 3442 SysTime _st; 3443 3444 static bool destroyed; 3445 3446 @disable this(); 3447 this(bool b) { this.b = b; } 3448 ~this() @safe { destroyed = true; } 3449 3450 // mustn't call opAssign on Test.init in Nullable!Test, because the invariant 3451 // will be called before opAssign on the Test.init that is in Nullable 3452 // and Test.init violates its invariant. 3453 void opAssign(Test rhs) @safe { assert(false); } 3454 } 3455 3456 { 3457 Nullable!Test nt; 3458 3459 nt = Test(true); 3460 3461 // destroy value 3462 Test.destroyed = false; 3463 3464 nt.nullify; 3465 3466 assert(Test.destroyed); 3467 3468 Test.destroyed = false; 3469 } 3470 // don't run destructor on T.init in Nullable on scope exit! 3471 assert(!Test.destroyed); 3472 } 3473 // check that the contained type's destructor is called on assignment 3474 @system unittest 3475 { 3476 struct S 3477 { 3478 // can't be static, since we need a specific value's pointer 3479 bool* destroyedRef; 3480 3481 ~this() 3482 { 3483 if (this.destroyedRef) 3484 { 3485 *this.destroyedRef = true; 3486 } 3487 } 3488 } 3489 3490 Nullable!S ns; 3491 3492 bool destroyed; 3493 3494 ns = S(&destroyed); 3495 3496 // reset from rvalue destruction in Nullable's opAssign 3497 destroyed = false; 3498 3499 // overwrite Nullable 3500 ns = S(null); 3501 3502 // the original S should be destroyed. 3503 assert(destroyed == true); 3504 } 3505 // check that the contained type's destructor is still called when required 3506 @system unittest 3507 { 3508 bool destructorCalled = false; 3509 3510 struct S 3511 { 3512 bool* destroyed; 3513 ~this() { *this.destroyed = true; } 3514 } 3515 3516 { 3517 Nullable!S ns; 3518 } 3519 assert(!destructorCalled); 3520 { 3521 Nullable!S ns = Nullable!S(S(&destructorCalled)); 3522 3523 destructorCalled = false; // reset after S was destroyed in the NS constructor 3524 } 3525 assert(destructorCalled); 3526 } 3527 3528 // check that toHash on Nullable is forwarded to the contained type 3529 @system unittest 3530 { 3531 struct S 3532 { 3533 size_t toHash() const @safe pure nothrow { return 5; } 3534 } 3535 3536 Nullable!S s1 = S(); 3537 Nullable!S s2 = Nullable!S(); 3538 3539 assert(typeid(Nullable!S).getHash(&s1) == 5); 3540 assert(typeid(Nullable!S).getHash(&s2) == 0); 3541 } 3542 3543 /** 3544 Just like `Nullable!T`, except that the null state is defined as a 3545 particular value. For example, $(D Nullable!(uint, uint.max)) is an 3546 `uint` that sets aside the value `uint.max` to denote a null 3547 state. $(D Nullable!(T, nullValue)) is more storage-efficient than $(D 3548 Nullable!T) because it does not need to store an extra `bool`. 3549 3550 Params: 3551 T = The wrapped type for which Nullable provides a null value. 3552 3553 nullValue = The null value which denotes the null state of this 3554 `Nullable`. Must be of type `T`. 3555 */ 3556 struct Nullable(T, T nullValue) 3557 { 3558 private T _value = nullValue; 3559 3560 /** 3561 Constructor initializing `this` with `value`. 3562 3563 Params: 3564 value = The value to initialize this `Nullable` with. 3565 */ 3566 this(T value) 3567 { 3568 _value = value; 3569 } 3570 3571 template toString() 3572 { 3573 import std.format : FormatSpec, formatValue; 3574 // Needs to be a template because of https://issues.dlang.org/show_bug.cgi?id=13737. 3575 void toString()(scope void delegate(const(char)[]) sink, scope const ref FormatSpec!char fmt) 3576 { 3577 if (isNull) 3578 { 3579 sink.formatValue("Nullable.null", fmt); 3580 } 3581 else 3582 { 3583 sink.formatValue(_value, fmt); 3584 } 3585 } 3586 } 3587 3588 /** 3589 Check if `this` is in the null state. 3590 3591 Returns: 3592 true $(B iff) `this` is in the null state, otherwise false. 3593 */ 3594 @property bool isNull() const 3595 { 3596 //Need to use 'is' if T is a nullable type and 3597 //nullValue is null, or it's a compiler error 3598 static if (is(CommonType!(T, typeof(null)) == T) && nullValue is null) 3599 { 3600 return _value is nullValue; 3601 } 3602 //Need to use 'is' if T is a float type 3603 //because NaN != NaN 3604 else static if (__traits(isFloating, T) || __traits(compiles, { static assert(!(nullValue == nullValue)); })) 3605 { 3606 return _value is nullValue; 3607 } 3608 else 3609 { 3610 return _value == nullValue; 3611 } 3612 } 3613 3614 /// 3615 @safe unittest 3616 { 3617 Nullable!(int, -1) ni; 3618 //Initialized to "null" state 3619 assert(ni.isNull); 3620 3621 ni = 0; 3622 assert(!ni.isNull); 3623 } 3624 3625 @system unittest 3626 { 3627 assert(typeof(this).init.isNull, typeof(this).stringof ~ 3628 ".isNull does not work correctly because " ~ T.stringof ~ 3629 " has an == operator that is non-reflexive and could not be" ~ 3630 " determined before runtime to be non-reflexive!"); 3631 } 3632 3633 // https://issues.dlang.org/show_bug.cgi?id=11135 3634 // disable test until https://issues.dlang.org/show_bug.cgi?id=15316 gets fixed 3635 version (none) @system unittest 3636 { 3637 static foreach (T; AliasSeq!(float, double, real)) 3638 {{ 3639 Nullable!(T, T.init) nf; 3640 //Initialized to "null" state 3641 assert(nf.isNull); 3642 assert(nf is typeof(nf).init); 3643 3644 nf = 0; 3645 assert(!nf.isNull); 3646 3647 nf.nullify(); 3648 assert(nf.isNull); 3649 }} 3650 } 3651 3652 /** 3653 Forces `this` to the null state. 3654 */ 3655 void nullify()() 3656 { 3657 _value = nullValue; 3658 } 3659 3660 /// 3661 @safe unittest 3662 { 3663 Nullable!(int, -1) ni = 0; 3664 assert(!ni.isNull); 3665 3666 ni = -1; 3667 assert(ni.isNull); 3668 } 3669 3670 /** 3671 Assigns `value` to the internally-held state. If the assignment 3672 succeeds, `this` becomes non-null. No null checks are made. Note 3673 that the assignment may leave `this` in the null state. 3674 3675 Params: 3676 value = A value of type `T` to assign to this `Nullable`. 3677 If it is `nullvalue`, then the internal state of 3678 this `Nullable` will be set to null. 3679 */ 3680 void opAssign()(T value) 3681 { 3682 import std.algorithm.mutation : swap; 3683 3684 swap(value, _value); 3685 } 3686 3687 /** 3688 If this `Nullable` wraps a type that already has a null value 3689 (such as a pointer), and that null value is not given for 3690 `nullValue`, then assigning the null value to this `Nullable` 3691 is no different than assigning any other value of type `T`, 3692 and the resulting code will look very strange. It is strongly 3693 recommended that this be avoided by using `T`'s "built in" 3694 null value for `nullValue`. 3695 */ 3696 @system unittest 3697 { 3698 //Passes 3699 enum nullVal = cast(int*) 0xCAFEBABE; 3700 Nullable!(int*, nullVal) npi; 3701 assert(npi.isNull); 3702 3703 //Passes?! 3704 npi = null; 3705 assert(!npi.isNull); 3706 } 3707 3708 /** 3709 Gets the value. `this` must not be in the null state. 3710 This function is also called for the implicit conversion to `T`. 3711 3712 Preconditions: `isNull` must be `false`. 3713 Returns: 3714 The value held internally by this `Nullable`. 3715 */ 3716 @property ref inout(T) get() inout 3717 { 3718 //@@@6169@@@: We avoid any call that might evaluate nullValue's %s, 3719 //Because it might messup get's purity and safety inference. 3720 enum message = "Called `get' on null Nullable!(" ~ T.stringof ~ ",nullValue)."; 3721 assert(!isNull, message); 3722 return _value; 3723 } 3724 3725 /// 3726 @system unittest 3727 { 3728 import std.exception : assertThrown, assertNotThrown; 3729 3730 Nullable!(int, -1) ni; 3731 //`get` is implicitly called. Will throw 3732 //an error in non-release mode 3733 assertThrown!Throwable(ni == 0); 3734 3735 ni = 0; 3736 assertNotThrown!Throwable(ni == 0); 3737 } 3738 3739 /** 3740 Implicitly converts to `T`. 3741 `this` must not be in the null state. 3742 */ 3743 alias get this; 3744 } 3745 3746 /// ditto 3747 auto nullable(alias nullValue, T)(T t) 3748 if (is (typeof(nullValue) == T)) 3749 { 3750 return Nullable!(T, nullValue)(t); 3751 } 3752 3753 /// 3754 @safe unittest 3755 { 3756 Nullable!(size_t, size_t.max) indexOf(string[] haystack, string needle) 3757 { 3758 //Find the needle, returning -1 if not found 3759 3760 return Nullable!(size_t, size_t.max).init; 3761 } 3762 3763 void sendLunchInvite(string name) 3764 { 3765 } 3766 3767 //It's safer than C... 3768 auto coworkers = ["Jane", "Jim", "Marry", "Fred"]; 3769 auto pos = indexOf(coworkers, "Bob"); 3770 if (!pos.isNull) 3771 { 3772 //Send Bob an invitation to lunch 3773 sendLunchInvite(coworkers[pos]); 3774 } 3775 else 3776 { 3777 //Bob not found; report the error 3778 } 3779 3780 //And there's no overhead 3781 static assert(Nullable!(size_t, size_t.max).sizeof == size_t.sizeof); 3782 } 3783 3784 /// 3785 @system unittest 3786 { 3787 import std.exception : assertThrown; 3788 3789 Nullable!(int, int.min) a; 3790 assert(a.isNull); 3791 assertThrown!Throwable(a.get); 3792 a = 5; 3793 assert(!a.isNull); 3794 assert(a == 5); 3795 static assert(a.sizeof == int.sizeof); 3796 } 3797 3798 /// 3799 @safe unittest 3800 { 3801 auto a = nullable!(int.min)(8); 3802 assert(a == 8); 3803 a.nullify(); 3804 assert(a.isNull); 3805 } 3806 3807 @nogc nothrow pure @safe unittest 3808 { 3809 // https://issues.dlang.org/show_bug.cgi?id=19226 3810 // fully handle non-self-equal nullValue 3811 static struct Fraction 3812 { 3813 int denominator; 3814 bool isNaN() const 3815 { 3816 return denominator == 0; 3817 } 3818 bool opEquals(const Fraction rhs) const 3819 { 3820 return !isNaN && denominator == rhs.denominator; 3821 } 3822 } 3823 alias N = Nullable!(Fraction, Fraction.init); 3824 assert(N.init.isNull); 3825 } 3826 3827 @safe unittest 3828 { 3829 static int f(scope const Nullable!(int, int.min) x) { 3830 return x.isNull ? 42 : x.get; 3831 } 3832 Nullable!(int, int.min) a; 3833 assert(f(a) == 42); 3834 a = 8; 3835 assert(f(a) == 8); 3836 a.nullify(); 3837 assert(f(a) == 42); 3838 } 3839 @safe unittest 3840 { 3841 // Ensure Nullable can be used in pure/nothrow/@safe environment. 3842 function() @safe pure nothrow 3843 { 3844 Nullable!(int, int.min) n; 3845 assert(n.isNull); 3846 n = 4; 3847 assert(!n.isNull); 3848 assert(n == 4); 3849 n.nullify(); 3850 assert(n.isNull); 3851 }(); 3852 } 3853 @system unittest 3854 { 3855 // Ensure Nullable can be used when the value is not pure/nothrow/@system 3856 static struct S 3857 { 3858 int x; 3859 bool opEquals(const S s) const @system { return s.x == x; } 3860 } 3861 3862 Nullable!(S, S(711)) s; 3863 assert(s.isNull); 3864 s = S(5); 3865 assert(!s.isNull); 3866 assert(s.x == 5); 3867 s.nullify(); 3868 assert(s.isNull); 3869 } 3870 @safe unittest 3871 { 3872 //Check nullable is nicelly embedable in a struct 3873 static struct S1 3874 { 3875 Nullable!(int, 0) ni; 3876 } 3877 static struct S2 //inspired from 9404 3878 { 3879 Nullable!(int, 0) ni; 3880 this(S2 other) 3881 { 3882 ni = other.ni; 3883 } 3884 void opAssign(S2 other) 3885 { 3886 ni = other.ni; 3887 } 3888 } 3889 static foreach (S; AliasSeq!(S1, S2)) 3890 {{ 3891 S a; 3892 S b = a; 3893 S c; 3894 c = a; 3895 }} 3896 } 3897 @system unittest 3898 { 3899 import std.conv : to; 3900 3901 // https://issues.dlang.org/show_bug.cgi?id=10915 3902 Nullable!(int, 1) ni = 1; 3903 assert(ni.to!string() == "Nullable.null"); 3904 3905 struct Test { string s; } 3906 alias NullableTest = Nullable!(Test, Test("null")); 3907 3908 NullableTest nt = Test("test"); 3909 assert(nt.to!string() == `Test("test")`); 3910 3911 NullableTest ntn = Test("null"); 3912 assert(ntn.to!string() == "Nullable.null"); 3913 3914 class TestToString 3915 { 3916 double d; 3917 3918 this(double d) 3919 { 3920 this.d = d; 3921 } 3922 3923 override string toString() 3924 { 3925 return d.to!string(); 3926 } 3927 } 3928 alias NullableTestToString = Nullable!(TestToString, null); 3929 3930 NullableTestToString ntts = new TestToString(2.5); 3931 assert(ntts.to!string() == "2.5"); 3932 } 3933 3934 // apply 3935 /** 3936 Unpacks the content of a `Nullable`, performs an operation and packs it again. Does nothing if isNull. 3937 3938 When called on a `Nullable`, `apply` will unpack the value contained in the `Nullable`, 3939 pass it to the function you provide and wrap the result in another `Nullable` (if necessary). 3940 If the `Nullable` is null, `apply` will return null itself. 3941 3942 Params: 3943 t = a `Nullable` 3944 fun = a function operating on the content of the nullable 3945 3946 Returns: 3947 `fun(t.get).nullable` if `!t.isNull`, else `Nullable.init`. 3948 3949 See also: 3950 $(HTTPS en.wikipedia.org/wiki/Monad_(functional_programming)#The_Maybe_monad, The `Maybe` monad) 3951 */ 3952 template apply(alias fun) 3953 { 3954 import std.functional : unaryFun; 3955 3956 auto apply(T)(auto ref T t) 3957 if (isInstanceOf!(Nullable, T) && is(typeof(unaryFun!fun(T.init.get)))) 3958 { 3959 alias FunType = typeof(unaryFun!fun(T.init.get)); 3960 3961 enum MustWrapReturn = !isInstanceOf!(Nullable, FunType); 3962 3963 static if (MustWrapReturn) 3964 { 3965 alias ReturnType = Nullable!FunType; 3966 } 3967 else 3968 { 3969 alias ReturnType = FunType; 3970 } 3971 3972 if (!t.isNull) 3973 { 3974 static if (MustWrapReturn) 3975 { 3976 return unaryFun!fun(t.get).nullable; 3977 } 3978 else 3979 { 3980 return unaryFun!fun(t.get); 3981 } 3982 } 3983 else 3984 { 3985 return ReturnType.init; 3986 } 3987 } 3988 } 3989 3990 /// 3991 nothrow pure @nogc @safe unittest 3992 { 3993 alias toFloat = i => cast(float) i; 3994 3995 Nullable!int sample; 3996 3997 // apply(null) results in a null `Nullable` of the function's return type. 3998 Nullable!float f = sample.apply!toFloat; 3999 assert(sample.isNull && f.isNull); 4000 4001 sample = 3; 4002 4003 // apply(non-null) calls the function and wraps the result in a `Nullable`. 4004 f = sample.apply!toFloat; 4005 assert(!sample.isNull && !f.isNull); 4006 assert(f.get == 3.0f); 4007 } 4008 4009 /// 4010 nothrow pure @nogc @safe unittest 4011 { 4012 alias greaterThree = i => (i > 3) ? i.nullable : Nullable!(typeof(i)).init; 4013 4014 Nullable!int sample; 4015 4016 // when the function already returns a `Nullable`, that `Nullable` is not wrapped. 4017 auto result = sample.apply!greaterThree; 4018 assert(sample.isNull && result.isNull); 4019 4020 // The function may decide to return a null `Nullable`. 4021 sample = 3; 4022 result = sample.apply!greaterThree; 4023 assert(!sample.isNull && result.isNull); 4024 4025 // Or it may return a value already wrapped in a `Nullable`. 4026 sample = 4; 4027 result = sample.apply!greaterThree; 4028 assert(!sample.isNull && !result.isNull); 4029 assert(result.get == 4); 4030 } 4031 4032 // test that Nullable.get(default) can merge types 4033 @safe @nogc nothrow pure 4034 unittest 4035 { 4036 Nullable!ubyte sample = Nullable!ubyte(); 4037 4038 // Test that get(U) returns the common type of the Nullable type and the parameter type. 4039 assert(sample.get(1000) == 1000); 4040 } 4041 4042 // Workaround for https://issues.dlang.org/show_bug.cgi?id=20670 4043 @safe @nogc nothrow pure 4044 unittest 4045 { 4046 immutable struct S { } 4047 4048 S[] array = Nullable!(S[])().get(S[].init); 4049 } 4050 4051 // regression test for https://issues.dlang.org/show_bug.cgi?id=21199 4052 @safe @nogc nothrow pure 4053 unittest 4054 { 4055 struct S { int i; } 4056 assert(S(5).nullable.apply!"a.i" == 5); 4057 } 4058 4059 /** 4060 Just like `Nullable!T`, except that the object refers to a value 4061 sitting elsewhere in memory. This makes assignments overwrite the 4062 initially assigned value. Internally `NullableRef!T` only stores a 4063 pointer to `T` (i.e., $(D Nullable!T.sizeof == (T*).sizeof)). 4064 */ 4065 struct NullableRef(T) 4066 { 4067 private T* _value; 4068 4069 /** 4070 Constructor binding `this` to `value`. 4071 4072 Params: 4073 value = The value to bind to. 4074 */ 4075 this(T* value) @safe pure nothrow 4076 { 4077 _value = value; 4078 } 4079 4080 template toString() 4081 { 4082 import std.format : FormatSpec, formatValue; 4083 // Needs to be a template because of https://issues.dlang.org/show_bug.cgi?id=13737. 4084 void toString()(scope void delegate(const(char)[]) sink, scope const ref FormatSpec!char fmt) 4085 { 4086 if (isNull) 4087 { 4088 sink.formatValue("Nullable.null", fmt); 4089 } 4090 else 4091 { 4092 sink.formatValue(*_value, fmt); 4093 } 4094 } 4095 } 4096 4097 /** 4098 Binds the internal state to `value`. 4099 4100 Params: 4101 value = A pointer to a value of type `T` to bind this `NullableRef` to. 4102 */ 4103 void bind(T* value) @safe pure nothrow 4104 { 4105 _value = value; 4106 } 4107 4108 /// 4109 @safe unittest 4110 { 4111 NullableRef!int nr = new int(42); 4112 assert(nr == 42); 4113 4114 int* n = new int(1); 4115 nr.bind(n); 4116 assert(nr == 1); 4117 } 4118 4119 /** 4120 Returns `true` if and only if `this` is in the null state. 4121 4122 Returns: 4123 true if `this` is in the null state, otherwise false. 4124 */ 4125 @property bool isNull() const @safe pure nothrow 4126 { 4127 return _value is null; 4128 } 4129 4130 /// 4131 @safe unittest 4132 { 4133 NullableRef!int nr; 4134 assert(nr.isNull); 4135 4136 int* n = new int(42); 4137 nr.bind(n); 4138 assert(!nr.isNull && nr == 42); 4139 } 4140 4141 /** 4142 Forces `this` to the null state. 4143 */ 4144 void nullify() @safe pure nothrow 4145 { 4146 _value = null; 4147 } 4148 4149 /// 4150 @safe unittest 4151 { 4152 NullableRef!int nr = new int(42); 4153 assert(!nr.isNull); 4154 4155 nr.nullify(); 4156 assert(nr.isNull); 4157 } 4158 4159 /** 4160 Assigns `value` to the internally-held state. 4161 4162 Params: 4163 value = A value of type `T` to assign to this `NullableRef`. 4164 If the internal state of this `NullableRef` has not 4165 been initialized, an error will be thrown in 4166 non-release mode. 4167 */ 4168 void opAssign()(T value) 4169 if (isAssignable!T) //@@@9416@@@ 4170 { 4171 enum message = "Called `opAssign' on null NullableRef!" ~ T.stringof ~ "."; 4172 assert(!isNull, message); 4173 *_value = value; 4174 } 4175 4176 /// 4177 @system unittest 4178 { 4179 import std.exception : assertThrown, assertNotThrown; 4180 4181 NullableRef!int nr; 4182 assert(nr.isNull); 4183 assertThrown!Throwable(nr = 42); 4184 4185 nr.bind(new int(0)); 4186 assert(!nr.isNull); 4187 assertNotThrown!Throwable(nr = 42); 4188 assert(nr == 42); 4189 } 4190 4191 /** 4192 Gets the value. `this` must not be in the null state. 4193 This function is also called for the implicit conversion to `T`. 4194 */ 4195 @property ref inout(T) get() inout @safe pure nothrow 4196 { 4197 enum message = "Called `get' on null NullableRef!" ~ T.stringof ~ "."; 4198 assert(!isNull, message); 4199 return *_value; 4200 } 4201 4202 /// 4203 @system unittest 4204 { 4205 import std.exception : assertThrown, assertNotThrown; 4206 4207 NullableRef!int nr; 4208 //`get` is implicitly called. Will throw 4209 //an error in non-release mode 4210 assertThrown!Throwable(nr == 0); 4211 4212 nr.bind(new int(0)); 4213 assertNotThrown!Throwable(nr == 0); 4214 } 4215 4216 /** 4217 Implicitly converts to `T`. 4218 `this` must not be in the null state. 4219 */ 4220 alias get this; 4221 } 4222 4223 /// ditto 4224 auto nullableRef(T)(T* t) 4225 { 4226 return NullableRef!T(t); 4227 } 4228 4229 /// 4230 @system unittest 4231 { 4232 import std.exception : assertThrown; 4233 4234 int x = 5, y = 7; 4235 auto a = nullableRef(&x); 4236 assert(!a.isNull); 4237 assert(a == 5); 4238 assert(x == 5); 4239 a = 42; 4240 assert(x == 42); 4241 assert(!a.isNull); 4242 assert(a == 42); 4243 a.nullify(); 4244 assert(x == 42); 4245 assert(a.isNull); 4246 assertThrown!Throwable(a.get); 4247 assertThrown!Throwable(a = 71); 4248 a.bind(&y); 4249 assert(a == 7); 4250 y = 135; 4251 assert(a == 135); 4252 } 4253 @system unittest 4254 { 4255 static int f(scope const NullableRef!int x) { 4256 return x.isNull ? 42 : x.get; 4257 } 4258 int x = 5; 4259 auto a = nullableRef(&x); 4260 assert(f(a) == 5); 4261 a.nullify(); 4262 assert(f(a) == 42); 4263 } 4264 @safe unittest 4265 { 4266 // Ensure NullableRef can be used in pure/nothrow/@safe environment. 4267 function() @safe pure nothrow 4268 { 4269 auto storage = new int; 4270 *storage = 19902; 4271 NullableRef!int n; 4272 assert(n.isNull); 4273 n.bind(storage); 4274 assert(!n.isNull); 4275 assert(n == 19902); 4276 n = 2294; 4277 assert(n == 2294); 4278 assert(*storage == 2294); 4279 n.nullify(); 4280 assert(n.isNull); 4281 }(); 4282 } 4283 @system unittest 4284 { 4285 // Ensure NullableRef can be used when the value is not pure/nothrow/@safe 4286 static struct S 4287 { 4288 int x; 4289 this(this) @system {} 4290 bool opEquals(const S s) const @system { return s.x == x; } 4291 } 4292 4293 auto storage = S(5); 4294 4295 NullableRef!S s; 4296 assert(s.isNull); 4297 s.bind(&storage); 4298 assert(!s.isNull); 4299 assert(s.x == 5); 4300 s.nullify(); 4301 assert(s.isNull); 4302 } 4303 @safe unittest 4304 { 4305 //Check nullable is nicelly embedable in a struct 4306 static struct S1 4307 { 4308 NullableRef!int ni; 4309 } 4310 static struct S2 //inspired from 9404 4311 { 4312 NullableRef!int ni; 4313 this(S2 other) 4314 { 4315 ni = other.ni; 4316 } 4317 void opAssign(S2 other) 4318 { 4319 ni = other.ni; 4320 } 4321 } 4322 static foreach (S; AliasSeq!(S1, S2)) 4323 {{ 4324 S a; 4325 S b = a; 4326 S c; 4327 c = a; 4328 }} 4329 } 4330 4331 // https://issues.dlang.org/show_bug.cgi?id=10915 4332 @system unittest 4333 { 4334 import std.conv : to; 4335 4336 NullableRef!int nri; 4337 assert(nri.to!string() == "Nullable.null"); 4338 4339 struct Test 4340 { 4341 string s; 4342 } 4343 NullableRef!Test nt = new Test("test"); 4344 assert(nt.to!string() == `Test("test")`); 4345 4346 class TestToString 4347 { 4348 double d; 4349 4350 this(double d) 4351 { 4352 this.d = d; 4353 } 4354 4355 override string toString() 4356 { 4357 return d.to!string(); 4358 } 4359 } 4360 TestToString tts = new TestToString(2.5); 4361 NullableRef!TestToString ntts = &tts; 4362 assert(ntts.to!string() == "2.5"); 4363 } 4364 4365 4366 /** 4367 `BlackHole!Base` is a subclass of `Base` which automatically implements 4368 all abstract member functions in `Base` as do-nothing functions. Each 4369 auto-implemented function just returns the default value of the return type 4370 without doing anything. 4371 4372 The name came from 4373 $(HTTP search.cpan.org/~sburke/Class-_BlackHole-0.04/lib/Class/_BlackHole.pm, Class::_BlackHole) 4374 Perl module by Sean M. Burke. 4375 4376 Params: 4377 Base = A non-final class for `BlackHole` to inherit from. 4378 4379 See_Also: 4380 $(LREF AutoImplement), $(LREF generateEmptyFunction) 4381 */ 4382 alias BlackHole(Base) = AutoImplement!(Base, generateEmptyFunction, isAbstractFunction); 4383 4384 /// 4385 @system unittest 4386 { 4387 import std.math : isNaN; 4388 4389 static abstract class C 4390 { 4391 int m_value; 4392 this(int v) { m_value = v; } 4393 int value() @property { return m_value; } 4394 4395 abstract real realValue() @property; 4396 abstract void doSomething(); 4397 } 4398 4399 auto c = new BlackHole!C(42); 4400 assert(c.value == 42); 4401 4402 // Returns real.init which is NaN 4403 assert(c.realValue.isNaN); 4404 // Abstract functions are implemented as do-nothing 4405 c.doSomething(); 4406 } 4407 4408 @system unittest 4409 { 4410 import std.math : isNaN; 4411 4412 // return default 4413 { 4414 interface I_1 { real test(); } 4415 auto o = new BlackHole!I_1; 4416 assert(o.test().isNaN()); // NaN 4417 } 4418 // doc example 4419 { 4420 static class C 4421 { 4422 int m_value; 4423 this(int v) { m_value = v; } 4424 int value() @property { return m_value; } 4425 4426 abstract real realValue() @property; 4427 abstract void doSomething(); 4428 } 4429 4430 auto c = new BlackHole!C(42); 4431 assert(c.value == 42); 4432 4433 assert(c.realValue.isNaN); // NaN 4434 c.doSomething(); 4435 } 4436 4437 // https://issues.dlang.org/show_bug.cgi?id=12058 4438 interface Foo 4439 { 4440 inout(Object) foo() inout; 4441 } 4442 BlackHole!Foo o; 4443 } 4444 4445 nothrow pure @nogc @safe unittest 4446 { 4447 static interface I 4448 { 4449 I foo() nothrow pure @nogc @safe return scope; 4450 } 4451 4452 scope cb = new BlackHole!I(); 4453 cb.foo(); 4454 } 4455 4456 4457 /** 4458 `WhiteHole!Base` is a subclass of `Base` which automatically implements 4459 all abstract member functions as functions that always fail. These functions 4460 simply throw an `Error` and never return. `Whitehole` is useful for 4461 trapping the use of class member functions that haven't been implemented. 4462 4463 The name came from 4464 $(HTTP search.cpan.org/~mschwern/Class-_WhiteHole-0.04/lib/Class/_WhiteHole.pm, Class::_WhiteHole) 4465 Perl module by Michael G Schwern. 4466 4467 Params: 4468 Base = A non-final class for `WhiteHole` to inherit from. 4469 4470 See_Also: 4471 $(LREF AutoImplement), $(LREF generateAssertTrap) 4472 */ 4473 alias WhiteHole(Base) = AutoImplement!(Base, generateAssertTrap, isAbstractFunction); 4474 4475 /// 4476 @system unittest 4477 { 4478 import std.exception : assertThrown; 4479 4480 static class C 4481 { 4482 abstract void notYetImplemented(); 4483 } 4484 4485 auto c = new WhiteHole!C; 4486 assertThrown!NotImplementedError(c.notYetImplemented()); // throws an Error 4487 } 4488 4489 // https://issues.dlang.org/show_bug.cgi?id=20232 4490 nothrow pure @safe unittest 4491 { 4492 static interface I 4493 { 4494 I foo() nothrow pure @safe return scope; 4495 } 4496 4497 if (0) // Just checking attribute interference 4498 { 4499 scope cw = new WhiteHole!I(); 4500 cw.foo(); 4501 } 4502 } 4503 4504 // / ditto 4505 class NotImplementedError : Error 4506 { 4507 this(string method) nothrow pure @safe 4508 { 4509 super(method ~ " is not implemented"); 4510 } 4511 } 4512 4513 @system unittest 4514 { 4515 import std.exception : assertThrown; 4516 // nothrow 4517 { 4518 interface I_1 4519 { 4520 void foo(); 4521 void bar() nothrow; 4522 } 4523 auto o = new WhiteHole!I_1; 4524 assertThrown!NotImplementedError(o.foo()); 4525 assertThrown!NotImplementedError(o.bar()); 4526 } 4527 // doc example 4528 { 4529 static class C 4530 { 4531 abstract void notYetImplemented(); 4532 } 4533 4534 auto c = new WhiteHole!C; 4535 try 4536 { 4537 c.notYetImplemented(); 4538 assert(0); 4539 } 4540 catch (Error e) {} 4541 } 4542 } 4543 4544 4545 /** 4546 `AutoImplement` automatically implements (by default) all abstract member 4547 functions in the class or interface `Base` in specified way. 4548 4549 The second version of `AutoImplement` automatically implements 4550 `Interface`, while deriving from `BaseClass`. 4551 4552 Params: 4553 how = template which specifies _how functions will be implemented/overridden. 4554 4555 Two arguments are passed to `how`: the type `Base` and an alias 4556 to an implemented function. Then `how` must return an implemented 4557 function body as a string. 4558 4559 The generated function body can use these keywords: 4560 $(UL 4561 $(LI `a0`, `a1`, …: arguments passed to the function;) 4562 $(LI `args`: a tuple of the arguments;) 4563 $(LI `self`: an alias to the function itself;) 4564 $(LI `parent`: an alias to the overridden function (if any).) 4565 ) 4566 4567 You may want to use templated property functions (instead of Implicit 4568 Template Properties) to generate complex functions: 4569 -------------------- 4570 // Prints log messages for each call to overridden functions. 4571 string generateLogger(C, alias fun)() @property 4572 { 4573 import std.traits; 4574 enum qname = C.stringof ~ "." ~ __traits(identifier, fun); 4575 string stmt; 4576 4577 stmt ~= q{ struct Importer { import std.stdio; } }; 4578 stmt ~= `Importer.writeln("Log: ` ~ qname ~ `(", args, ")");`; 4579 static if (!__traits(isAbstractFunction, fun)) 4580 { 4581 static if (is(ReturnType!fun == void)) 4582 stmt ~= q{ parent(args); }; 4583 else 4584 stmt ~= q{ 4585 auto r = parent(args); 4586 Importer.writeln("--> ", r); 4587 return r; 4588 }; 4589 } 4590 return stmt; 4591 } 4592 -------------------- 4593 4594 what = template which determines _what functions should be 4595 implemented/overridden. 4596 4597 An argument is passed to `what`: an alias to a non-final member 4598 function in `Base`. Then `what` must return a boolean value. 4599 Return `true` to indicate that the passed function should be 4600 implemented/overridden. 4601 4602 -------------------- 4603 // Sees if fun returns something. 4604 enum bool hasValue(alias fun) = !is(ReturnType!(fun) == void); 4605 -------------------- 4606 4607 4608 Note: 4609 4610 Generated code is inserted in the scope of `std.typecons` module. Thus, 4611 any useful functions outside `std.typecons` cannot be used in the generated 4612 code. To workaround this problem, you may `import` necessary things in a 4613 local struct, as done in the `generateLogger()` template in the above 4614 example. 4615 4616 4617 BUGS: 4618 4619 $(UL 4620 $(LI Variadic arguments to constructors are not forwarded to super.) 4621 $(LI Deep interface inheritance causes compile error with messages like 4622 "Error: function std.typecons._AutoImplement!(Foo)._AutoImplement.bar 4623 does not override any function". [$(BUGZILLA 2525)] ) 4624 $(LI The `parent` keyword is actually a delegate to the super class' 4625 corresponding member function. [$(BUGZILLA 2540)] ) 4626 $(LI Using alias template parameter in `how` and/or `what` may cause 4627 strange compile error. Use template tuple parameter instead to workaround 4628 this problem. [$(BUGZILLA 4217)] ) 4629 ) 4630 */ 4631 class AutoImplement(Base, alias how, alias what = isAbstractFunction) : Base 4632 if (!is(how == class)) 4633 { 4634 private alias autoImplement_helper_ = 4635 AutoImplement_Helper!("autoImplement_helper_", "Base", Base, typeof(this), how, what); 4636 mixin(autoImplement_helper_.code); 4637 } 4638 4639 /// ditto 4640 class AutoImplement( 4641 Interface, BaseClass, alias how, 4642 alias what = isAbstractFunction) : BaseClass, Interface 4643 if (is(Interface == interface) && is(BaseClass == class)) 4644 { 4645 private alias autoImplement_helper_ = AutoImplement_Helper!( 4646 "autoImplement_helper_", "Interface", Interface, typeof(this), how, what); 4647 mixin(autoImplement_helper_.code); 4648 } 4649 4650 /// 4651 @system unittest 4652 { 4653 interface PackageSupplier 4654 { 4655 int foo(); 4656 int bar(); 4657 } 4658 4659 static abstract class AbstractFallbackPackageSupplier : PackageSupplier 4660 { 4661 protected PackageSupplier default_, fallback; 4662 4663 this(PackageSupplier default_, PackageSupplier fallback) 4664 { 4665 this.default_ = default_; 4666 this.fallback = fallback; 4667 } 4668 4669 abstract int foo(); 4670 abstract int bar(); 4671 } 4672 4673 template fallback(T, alias func) 4674 { 4675 import std.format : format; 4676 // for all implemented methods: 4677 // - try default first 4678 // - only on a failure run & return fallback 4679 enum fallback = q{ 4680 scope (failure) return fallback.%1$s(args); 4681 return default_.%1$s(args); 4682 }.format(__traits(identifier, func)); 4683 } 4684 4685 // combines two classes and use the second one as fallback 4686 alias FallbackPackageSupplier = AutoImplement!(AbstractFallbackPackageSupplier, fallback); 4687 4688 class FailingPackageSupplier : PackageSupplier 4689 { 4690 int foo(){ throw new Exception("failure"); } 4691 int bar(){ return 2;} 4692 } 4693 4694 class BackupPackageSupplier : PackageSupplier 4695 { 4696 int foo(){ return -1; } 4697 int bar(){ return -1;} 4698 } 4699 4700 auto registry = new FallbackPackageSupplier(new FailingPackageSupplier(), new BackupPackageSupplier()); 4701 4702 assert(registry.foo() == -1); 4703 assert(registry.bar() == 2); 4704 } 4705 4706 /* 4707 * Code-generating stuffs are encupsulated in this helper template so that 4708 * namespace pollution, which can cause name confliction with Base's public 4709 * members, should be minimized. 4710 */ 4711 private template AutoImplement_Helper(string myName, string baseName, 4712 Base, Self, alias generateMethodBody, alias cherrypickMethod) 4713 { 4714 private static: 4715 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 4716 // Internal stuffs 4717 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 4718 4719 // Returns function overload sets in the class C, filtered with pred. 4720 template enumerateOverloads(C, alias pred) 4721 { 4722 template Impl(names...) 4723 { 4724 import std.meta : Filter; 4725 static if (names.length > 0) 4726 { 4727 alias methods = Filter!(pred, MemberFunctionsTuple!(C, names[0])); 4728 alias next = Impl!(names[1 .. $]); 4729 4730 static if (methods.length > 0) 4731 alias Impl = AliasSeq!(OverloadSet!(names[0], methods), next); 4732 else 4733 alias Impl = next; 4734 } 4735 else 4736 alias Impl = AliasSeq!(); 4737 } 4738 4739 alias enumerateOverloads = Impl!(__traits(allMembers, C)); 4740 } 4741 4742 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 4743 // Target functions 4744 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 4745 4746 // Add a non-final check to the cherrypickMethod. 4747 enum bool canonicalPicker(fun.../+[https://issues.dlang.org/show_bug.cgi?id=4217]+/) = 4748 !__traits(isFinalFunction, fun[0]) && cherrypickMethod!(fun); 4749 4750 /* 4751 * A tuple of overload sets, each item of which consists of functions to be 4752 * implemented by the generated code. 4753 */ 4754 alias targetOverloadSets = enumerateOverloads!(Base, canonicalPicker); 4755 4756 /* 4757 * Super class of this AutoImplement instance 4758 */ 4759 alias Super = BaseTypeTuple!(Self)[0]; 4760 static assert(is(Super == class)); 4761 static assert(is(Base == interface) || is(Super == Base)); 4762 4763 /* 4764 * A tuple of the super class' constructors. Used for forwarding 4765 * constructor calls. 4766 */ 4767 static if (__traits(hasMember, Super, "__ctor")) 4768 alias ctorOverloadSet = OverloadSet!("__ctor", __traits(getOverloads, Super, "__ctor")); 4769 else 4770 alias ctorOverloadSet = OverloadSet!("__ctor"); // empty 4771 4772 4773 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 4774 // Type information 4775 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 4776 4777 /* 4778 * The generated code will be mixed into AutoImplement, which will be 4779 * instantiated in this module's scope. Thus, any user-defined types are 4780 * out of scope and cannot be used directly (i.e. by their names). 4781 * 4782 * We will use FuncInfo instances for accessing return types and parameter 4783 * types of the implemented functions. The instances will be populated to 4784 * the AutoImplement's scope in a certain way; see the populate() below. 4785 */ 4786 4787 // Returns the preferred identifier for the FuncInfo instance for the i-th 4788 // overloaded function with the name. 4789 template INTERNAL_FUNCINFO_ID(string name, size_t i) 4790 { 4791 import std.format : format; 4792 4793 enum string INTERNAL_FUNCINFO_ID = format("F_%s_%s", name, i); 4794 } 4795 4796 /* 4797 * Insert FuncInfo instances about all the target functions here. This 4798 * enables the generated code to access type information via, for example, 4799 * "autoImplement_helper_.F_foo_1". 4800 */ 4801 template populate(overloads...) 4802 { 4803 static if (overloads.length > 0) 4804 { 4805 mixin populate!(overloads[0].name, overloads[0].contents); 4806 mixin populate!(overloads[1 .. $]); 4807 } 4808 } 4809 template populate(string name, methods...) 4810 { 4811 static if (methods.length > 0) 4812 { 4813 mixin populate!(name, methods[0 .. $ - 1]); 4814 // 4815 alias target = methods[$ - 1]; 4816 enum ith = methods.length - 1; 4817 mixin("alias " ~ INTERNAL_FUNCINFO_ID!(name, ith) ~ " = FuncInfo!target;"); 4818 } 4819 } 4820 4821 public mixin populate!(targetOverloadSets); 4822 public mixin populate!( ctorOverloadSet ); 4823 4824 4825 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 4826 // Code-generating policies 4827 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 4828 4829 /* Common policy configurations for generating constructors and methods. */ 4830 template CommonGeneratingPolicy() 4831 { 4832 // base class identifier which generated code should use 4833 enum string BASE_CLASS_ID = baseName; 4834 4835 // FuncInfo instance identifier which generated code should use 4836 template FUNCINFO_ID(string name, size_t i) 4837 { 4838 enum string FUNCINFO_ID = 4839 myName ~ "." ~ INTERNAL_FUNCINFO_ID!(name, i); 4840 } 4841 } 4842 4843 /* Policy configurations for generating constructors. */ 4844 template ConstructorGeneratingPolicy() 4845 { 4846 mixin CommonGeneratingPolicy; 4847 4848 /* Generates constructor body. Just forward to the base class' one. */ 4849 string generateFunctionBody(ctor.../+[https://issues.dlang.org/show_bug.cgi?id=4217]+/)() @property 4850 { 4851 enum varstyle = variadicFunctionStyle!(typeof(&ctor[0])); 4852 4853 static if (varstyle & (Variadic.c | Variadic.d)) 4854 { 4855 // the argptr-forwarding problem 4856 //pragma(msg, "Warning: AutoImplement!(", Base, ") ", 4857 // "ignored variadic arguments to the constructor ", 4858 // FunctionTypeOf!(typeof(&ctor[0])) ); 4859 } 4860 return "super(args);"; 4861 } 4862 } 4863 4864 /* Policy configurations for genearting target methods. */ 4865 template MethodGeneratingPolicy() 4866 { 4867 mixin CommonGeneratingPolicy; 4868 4869 /* Geneartes method body. */ 4870 string generateFunctionBody(func.../+[https://issues.dlang.org/show_bug.cgi?id=4217]+/)() @property 4871 { 4872 return generateMethodBody!(Base, func); // given 4873 } 4874 } 4875 4876 4877 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 4878 // Generated code 4879 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 4880 4881 alias ConstructorGenerator = MemberFunctionGenerator!(ConstructorGeneratingPolicy!()); 4882 alias MethodGenerator = MemberFunctionGenerator!(MethodGeneratingPolicy!()); 4883 4884 public enum string code = 4885 ConstructorGenerator.generateCode!( ctorOverloadSet ) ~ "\n" ~ 4886 MethodGenerator.generateCode!(targetOverloadSets); 4887 4888 debug (SHOW_GENERATED_CODE) 4889 { 4890 pragma(msg, "-------------------- < ", Base, " >"); 4891 pragma(msg, code); 4892 pragma(msg, "--------------------"); 4893 } 4894 } 4895 4896 //debug = SHOW_GENERATED_CODE; 4897 @system unittest 4898 { 4899 import core.vararg; 4900 // no function to implement 4901 { 4902 interface I_1 {} 4903 auto o = new BlackHole!I_1; 4904 } 4905 // parameters 4906 { 4907 interface I_3 { void test(int, in int, out int, ref int, lazy int); } 4908 auto o = new BlackHole!I_3; 4909 } 4910 // use of user-defined type 4911 { 4912 struct S {} 4913 interface I_4 { S test(); } 4914 auto o = new BlackHole!I_4; 4915 } 4916 // overloads 4917 { 4918 interface I_5 4919 { 4920 void test(string); 4921 real test(real); 4922 int test(); 4923 } 4924 auto o = new BlackHole!I_5; 4925 } 4926 // constructor forwarding 4927 { 4928 static class C_6 4929 { 4930 this(int n) { assert(n == 42); } 4931 this(string s) { assert(s == "Deeee"); } 4932 this(...) {} 4933 } 4934 auto o1 = new BlackHole!C_6(42); 4935 auto o2 = new BlackHole!C_6("Deeee"); 4936 auto o3 = new BlackHole!C_6(1, 2, 3, 4); 4937 } 4938 // attributes 4939 { 4940 interface I_7 4941 { 4942 ref int test_ref(); 4943 int test_pure() pure; 4944 int test_nothrow() nothrow; 4945 int test_property() @property; 4946 int test_safe() @safe; 4947 int test_trusted() @trusted; 4948 int test_system() @system; 4949 int test_pure_nothrow() pure nothrow; 4950 } 4951 auto o = new BlackHole!I_7; 4952 } 4953 // storage classes 4954 { 4955 interface I_8 4956 { 4957 void test_const() const; 4958 void test_immutable() immutable; 4959 void test_shared() shared; 4960 void test_shared_const() shared const; 4961 } 4962 auto o = new BlackHole!I_8; 4963 } 4964 // use baseclass 4965 { 4966 static class C_9 4967 { 4968 private string foo_; 4969 4970 this(string s) { 4971 foo_ = s; 4972 } 4973 4974 protected string boilerplate() @property 4975 { 4976 return "Boilerplate stuff."; 4977 } 4978 4979 public string foo() @property 4980 { 4981 return foo_; 4982 } 4983 } 4984 4985 interface I_10 4986 { 4987 string testMethod(size_t); 4988 } 4989 4990 static string generateTestMethod(C, alias fun)() @property 4991 { 4992 return "return this.boilerplate[0 .. a0];"; 4993 } 4994 4995 auto o = new AutoImplement!(I_10, C_9, generateTestMethod)("Testing"); 4996 assert(o.testMethod(11) == "Boilerplate"); 4997 assert(o.foo == "Testing"); 4998 } 4999 /+ // deep inheritance 5000 { 5001 // https://issues.dlang.org/show_bug.cgi?id=2525 5002 // https://issues.dlang.org/show_bug.cgi?id=3525 5003 // NOTE: [r494] func.c(504-571) FuncDeclaration::semantic() 5004 interface I { void foo(); } 5005 interface J : I {} 5006 interface K : J {} 5007 static abstract class C_9 : K {} 5008 auto o = new BlackHole!C_9; 5009 }+/ 5010 } 5011 5012 // https://issues.dlang.org/show_bug.cgi?id=17177 5013 // AutoImplement fails on function overload sets with 5014 // "cannot infer type from overloaded function symbol" 5015 @system unittest 5016 { 5017 static class Issue17177 5018 { 5019 private string n_; 5020 5021 public { 5022 Issue17177 overloaded(string n) 5023 { 5024 this.n_ = n; 5025 5026 return this; 5027 } 5028 5029 string overloaded() 5030 { 5031 return this.n_; 5032 } 5033 } 5034 } 5035 5036 static string how(C, alias fun)() 5037 { 5038 static if (!is(ReturnType!fun == void)) 5039 { 5040 return q{ 5041 return parent(args); 5042 }; 5043 } 5044 else 5045 { 5046 return q{ 5047 parent(args); 5048 }; 5049 } 5050 } 5051 5052 import std.meta : templateNot; 5053 alias Implementation = AutoImplement!(Issue17177, how, templateNot!isFinalFunction); 5054 } 5055 5056 version (StdUnittest) 5057 { 5058 // https://issues.dlang.org/show_bug.cgi?id=10647 5059 // Add prefix "issue10647_" as a workaround for 5060 // https://issues.dlang.org/show_bug.cgi?id=1238 5061 private string issue10647_generateDoNothing(C, alias fun)() @property 5062 { 5063 string stmt; 5064 5065 static if (is(ReturnType!fun == void)) 5066 stmt ~= ""; 5067 else 5068 { 5069 string returnType = ReturnType!fun.stringof; 5070 stmt ~= "return "~returnType~".init;"; 5071 } 5072 return stmt; 5073 } 5074 5075 private template issue10647_isAlwaysTrue(alias fun) 5076 { 5077 enum issue10647_isAlwaysTrue = true; 5078 } 5079 5080 // Do nothing template 5081 private template issue10647_DoNothing(Base) 5082 { 5083 alias issue10647_DoNothing = AutoImplement!(Base, issue10647_generateDoNothing, issue10647_isAlwaysTrue); 5084 } 5085 5086 // A class to be overridden 5087 private class issue10647_Foo{ 5088 void bar(int a) { } 5089 } 5090 } 5091 @system unittest 5092 { 5093 auto foo = new issue10647_DoNothing!issue10647_Foo(); 5094 foo.bar(13); 5095 } 5096 5097 /* 5098 Used by MemberFunctionGenerator. 5099 */ 5100 package template OverloadSet(string nam, T...) 5101 { 5102 enum string name = nam; 5103 alias contents = T; 5104 } 5105 5106 /* 5107 Used by MemberFunctionGenerator. 5108 */ 5109 package template FuncInfo(alias func) 5110 if (is(typeof(&func))) 5111 { 5112 alias RT = ReturnType!(typeof(&func)); 5113 alias PT = Parameters!(typeof(&func)); 5114 } 5115 package template FuncInfo(Func) 5116 { 5117 alias RT = ReturnType!Func; 5118 alias PT = Parameters!Func; 5119 } 5120 5121 /* 5122 General-purpose member function generator. 5123 -------------------- 5124 template GeneratingPolicy() 5125 { 5126 // [optional] the name of the class where functions are derived 5127 enum string BASE_CLASS_ID; 5128 5129 // [optional] define this if you have only function types 5130 enum bool WITHOUT_SYMBOL; 5131 5132 // [optional] Returns preferred identifier for i-th parameter. 5133 template PARAMETER_VARIABLE_ID(size_t i); 5134 5135 // Returns the identifier of the FuncInfo instance for the i-th overload 5136 // of the specified name. The identifier must be accessible in the scope 5137 // where generated code is mixed. 5138 template FUNCINFO_ID(string name, size_t i); 5139 5140 // Returns implemented function body as a string. When WITHOUT_SYMBOL is 5141 // defined, the latter is used. 5142 template generateFunctionBody(alias func); 5143 template generateFunctionBody(string name, FuncType); 5144 } 5145 -------------------- 5146 */ 5147 package template MemberFunctionGenerator(alias Policy) 5148 { 5149 private static: 5150 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 5151 // Internal stuffs 5152 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 5153 import std.format; 5154 alias format = std.format.format; 5155 5156 enum CONSTRUCTOR_NAME = "__ctor"; 5157 5158 // true if functions are derived from a base class 5159 enum WITH_BASE_CLASS = __traits(hasMember, Policy, "BASE_CLASS_ID"); 5160 5161 // true if functions are specified as types, not symbols 5162 enum WITHOUT_SYMBOL = __traits(hasMember, Policy, "WITHOUT_SYMBOL"); 5163 5164 // preferred identifier for i-th parameter variable 5165 static if (__traits(hasMember, Policy, "PARAMETER_VARIABLE_ID")) 5166 { 5167 alias PARAMETER_VARIABLE_ID = Policy.PARAMETER_VARIABLE_ID; 5168 } 5169 else 5170 { 5171 enum string PARAMETER_VARIABLE_ID(size_t i) = format("a%s", i); 5172 // default: a0, a1, ... 5173 } 5174 5175 // Returns a tuple consisting of 0,1,2,...,n-1. For static foreach. 5176 template CountUp(size_t n) 5177 { 5178 static if (n > 0) 5179 alias CountUp = AliasSeq!(CountUp!(n - 1), n - 1); 5180 else 5181 alias CountUp = AliasSeq!(); 5182 } 5183 5184 5185 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 5186 // Code generator 5187 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 5188 5189 /* 5190 * Runs through all the target overload sets and generates D code which 5191 * implements all the functions in the overload sets. 5192 */ 5193 public string generateCode(overloads...)() @property 5194 { 5195 string code = ""; 5196 5197 // run through all the overload sets 5198 foreach (i_; CountUp!(0 + overloads.length)) // workaround 5199 { 5200 enum i = 0 + i_; // workaround 5201 alias oset = overloads[i]; 5202 5203 code ~= generateCodeForOverloadSet!(oset); 5204 5205 static if (WITH_BASE_CLASS && oset.name != CONSTRUCTOR_NAME) 5206 { 5207 // The generated function declarations may hide existing ones 5208 // in the base class (cf. HiddenFuncError), so we put an alias 5209 // declaration here to reveal possible hidden functions. 5210 code ~= format("alias %s = %s.%s;\n", 5211 oset.name, 5212 // super: https://issues.dlang.org/show_bug.cgi?id=2540 5213 Policy.BASE_CLASS_ID, 5214 oset.name); 5215 } 5216 } 5217 return code; 5218 } 5219 5220 // handle each overload set 5221 private string generateCodeForOverloadSet(alias oset)() @property 5222 { 5223 string code = ""; 5224 5225 foreach (i_; CountUp!(0 + oset.contents.length)) // workaround 5226 { 5227 enum i = 0 + i_; // workaround 5228 code ~= generateFunction!( 5229 Policy.FUNCINFO_ID!(oset.name, i), oset.name, 5230 oset.contents[i]) ~ "\n"; 5231 } 5232 return code; 5233 } 5234 5235 /* 5236 * Returns D code which implements the function func. This function 5237 * actually generates only the declarator part; the function body part is 5238 * generated by the functionGenerator() policy. 5239 */ 5240 public string generateFunction( 5241 string myFuncInfo, string name, func... )() @property 5242 { 5243 import std.format : format; 5244 5245 enum isCtor = (name == CONSTRUCTOR_NAME); 5246 5247 string code; // the result 5248 5249 auto paramsRes = generateParameters!(myFuncInfo, func)(); 5250 code ~= paramsRes.imports; 5251 5252 /*** Function Declarator ***/ 5253 { 5254 alias Func = FunctionTypeOf!(func); 5255 alias FA = FunctionAttribute; 5256 enum atts = functionAttributes!(func); 5257 enum realName = isCtor ? "this" : name; 5258 5259 // FIXME?? Make it so that these aren't CTFE funcs any more, since 5260 // Format is deprecated, and format works at compile time? 5261 /* Made them CTFE funcs just for the sake of Format!(...) */ 5262 5263 // return type with optional "ref" 5264 static string make_returnType() 5265 { 5266 string rtype = ""; 5267 5268 if (!isCtor) 5269 { 5270 if (atts & FA.ref_) rtype ~= "ref "; 5271 rtype ~= myFuncInfo ~ ".RT"; 5272 } 5273 return rtype; 5274 } 5275 enum returnType = make_returnType(); 5276 5277 // function attributes attached after declaration 5278 static string make_postAtts() 5279 { 5280 string poatts = ""; 5281 if (atts & FA.pure_ ) poatts ~= " pure"; 5282 if (atts & FA.nothrow_) poatts ~= " nothrow"; 5283 if (atts & FA.property) poatts ~= " @property"; 5284 if (atts & FA.safe ) poatts ~= " @safe"; 5285 if (atts & FA.trusted ) poatts ~= " @trusted"; 5286 if (atts & FA.scope_ ) poatts ~= " scope"; 5287 if (atts & FA.return_ ) poatts ~= " return"; 5288 return poatts; 5289 } 5290 enum postAtts = make_postAtts(); 5291 5292 // function storage class 5293 static string make_storageClass() 5294 { 5295 string postc = ""; 5296 if (is(Func == shared)) postc ~= " shared"; 5297 if (is(Func == const)) postc ~= " const"; 5298 if (is(Func == inout)) postc ~= " inout"; 5299 if (is(Func == immutable)) postc ~= " immutable"; 5300 return postc; 5301 } 5302 enum storageClass = make_storageClass(); 5303 5304 // 5305 if (__traits(isVirtualMethod, func)) 5306 code ~= "override "; 5307 code ~= format("extern(%s) %s %s(%s) %s %s\n", 5308 functionLinkage!(func), 5309 returnType, 5310 realName, 5311 paramsRes.params, 5312 postAtts, storageClass ); 5313 } 5314 5315 /*** Function Body ***/ 5316 code ~= "{\n"; 5317 { 5318 enum nparams = Parameters!(func).length; 5319 5320 /* Declare keywords: args, self and parent. */ 5321 string preamble; 5322 5323 preamble ~= "alias args = AliasSeq!(" ~ enumerateParameters!(nparams) ~ ");\n"; 5324 if (!isCtor) 5325 { 5326 preamble ~= "alias self = " ~ name ~ ";\n"; 5327 if (WITH_BASE_CLASS && !__traits(isAbstractFunction, func)) 5328 preamble ~= `alias parent = __traits(getMember, super, "` ~ name ~ `");`; 5329 } 5330 5331 // Function body 5332 static if (WITHOUT_SYMBOL) 5333 enum fbody = Policy.generateFunctionBody!(name, func); 5334 else 5335 enum fbody = Policy.generateFunctionBody!(func); 5336 5337 code ~= preamble; 5338 code ~= fbody; 5339 } 5340 code ~= "}"; 5341 5342 return code; 5343 } 5344 5345 /* 5346 * Returns D code which declares function parameters, 5347 * and optionally any imports (e.g. core.vararg) 5348 * "ref int a0, real a1, ..." 5349 */ 5350 static struct GenParams { string imports, params; } 5351 private GenParams generateParameters(string myFuncInfo, func...)() 5352 { 5353 alias STC = ParameterStorageClass; 5354 alias stcs = ParameterStorageClassTuple!(func); 5355 enum nparams = stcs.length; 5356 5357 string imports = ""; // any imports required 5358 string params = ""; // parameters 5359 5360 foreach (i, stc; stcs) 5361 { 5362 if (i > 0) params ~= ", "; 5363 5364 // Parameter storage classes. 5365 if (stc & STC.scope_) params ~= "scope "; 5366 if (stc & STC.in_) params ~= "in "; 5367 if (stc & STC.out_ ) params ~= "out "; 5368 if (stc & STC.ref_ ) params ~= "ref "; 5369 if (stc & STC.lazy_ ) params ~= "lazy "; 5370 5371 // Take parameter type from the FuncInfo. 5372 params ~= format("%s.PT[%s]", myFuncInfo, i); 5373 5374 // Declare a parameter variable. 5375 params ~= " " ~ PARAMETER_VARIABLE_ID!(i); 5376 } 5377 5378 // Add some ellipsis part if needed. 5379 auto style = variadicFunctionStyle!(func); 5380 final switch (style) 5381 { 5382 case Variadic.no: 5383 break; 5384 5385 case Variadic.c, Variadic.d: 5386 imports ~= "import core.vararg;\n"; 5387 // (...) or (a, b, ...) 5388 params ~= (nparams == 0) ? "..." : ", ..."; 5389 break; 5390 5391 case Variadic.typesafe: 5392 params ~= " ..."; 5393 break; 5394 } 5395 5396 return typeof(return)(imports, params); 5397 } 5398 5399 // Returns D code which enumerates n parameter variables using comma as the 5400 // separator. "a0, a1, a2, a3" 5401 private string enumerateParameters(size_t n)() @property 5402 { 5403 string params = ""; 5404 5405 foreach (i_; CountUp!(n)) 5406 { 5407 enum i = 0 + i_; // workaround 5408 if (i > 0) params ~= ", "; 5409 params ~= PARAMETER_VARIABLE_ID!(i); 5410 } 5411 return params; 5412 } 5413 } 5414 5415 5416 /** 5417 Predefined how-policies for `AutoImplement`. These templates are also used by 5418 `BlackHole` and `WhiteHole`, respectively. 5419 */ 5420 template generateEmptyFunction(C, func.../+[https://issues.dlang.org/show_bug.cgi?id=4217]+/) 5421 { 5422 static if (is(ReturnType!(func) == void)) 5423 enum string generateEmptyFunction = q{ 5424 }; 5425 else static if (functionAttributes!(func) & FunctionAttribute.ref_) 5426 enum string generateEmptyFunction = q{ 5427 static typeof(return) dummy; 5428 return dummy; 5429 }; 5430 else 5431 enum string generateEmptyFunction = q{ 5432 return typeof(return).init; 5433 }; 5434 } 5435 5436 /// 5437 @system unittest 5438 { 5439 alias BlackHole(Base) = AutoImplement!(Base, generateEmptyFunction); 5440 5441 interface I 5442 { 5443 int foo(); 5444 string bar(); 5445 } 5446 5447 auto i = new BlackHole!I(); 5448 // generateEmptyFunction returns the default value of the return type without doing anything 5449 assert(i.foo == 0); 5450 assert(i.bar is null); 5451 } 5452 5453 /// ditto 5454 template generateAssertTrap(C, func...) 5455 { 5456 enum string generateAssertTrap = 5457 `throw new NotImplementedError("` ~ C.stringof ~ "." 5458 ~ __traits(identifier, func) ~ `");`; 5459 } 5460 5461 /// 5462 @system unittest 5463 { 5464 import std.exception : assertThrown; 5465 5466 alias WhiteHole(Base) = AutoImplement!(Base, generateAssertTrap); 5467 5468 interface I 5469 { 5470 int foo(); 5471 string bar(); 5472 } 5473 5474 auto i = new WhiteHole!I(); 5475 // generateAssertTrap throws an exception for every unimplemented function of the interface 5476 assertThrown!NotImplementedError(i.foo); 5477 assertThrown!NotImplementedError(i.bar); 5478 } 5479 5480 private 5481 { 5482 pragma(mangle, "_d_toObject") 5483 extern(C) pure nothrow Object typecons_d_toObject(void* p); 5484 } 5485 5486 /* 5487 * Avoids opCast operator overloading. 5488 */ 5489 private template dynamicCast(T) 5490 if (is(T == class) || is(T == interface)) 5491 { 5492 @trusted 5493 T dynamicCast(S)(inout S source) 5494 if (is(S == class) || is(S == interface)) 5495 { 5496 static if (is(Unqual!S : Unqual!T)) 5497 { 5498 import std.traits : QualifierOf; 5499 alias Qual = QualifierOf!S; // SharedOf or MutableOf 5500 alias TmpT = Qual!(Unqual!T); 5501 inout(TmpT) tmp = source; // bypass opCast by implicit conversion 5502 return *cast(T*)(&tmp); // + variable pointer cast + dereference 5503 } 5504 else 5505 { 5506 return cast(T) typecons_d_toObject(*cast(void**)(&source)); 5507 } 5508 } 5509 } 5510 5511 @system unittest 5512 { 5513 class C { @disable void opCast(T)(); } 5514 auto c = new C; 5515 static assert(!__traits(compiles, cast(Object) c)); 5516 auto o = dynamicCast!Object(c); 5517 assert(c is o); 5518 5519 interface I { @disable void opCast(T)(); Object instance(); } 5520 interface J { @disable void opCast(T)(); Object instance(); } 5521 class D : I, J { Object instance() { return this; } } 5522 I i = new D(); 5523 static assert(!__traits(compiles, cast(J) i)); 5524 J j = dynamicCast!J(i); 5525 assert(i.instance() is j.instance()); 5526 } 5527 5528 /** 5529 Supports structural based typesafe conversion. 5530 5531 If `Source` has structural conformance with the `interface` `Targets`, 5532 wrap creates an internal wrapper class which inherits `Targets` and 5533 wraps the `src` object, then returns it. 5534 5535 `unwrap` can be used to extract objects which have been wrapped by `wrap`. 5536 */ 5537 template wrap(Targets...) 5538 if (Targets.length >= 1 && allSatisfy!(isMutable, Targets)) 5539 { 5540 import std.meta : staticMap; 5541 5542 // strict upcast 5543 auto wrap(Source)(inout Source src) @trusted pure nothrow 5544 if (Targets.length == 1 && is(Source : Targets[0])) 5545 { 5546 alias T = Select!(is(Source == shared), shared Targets[0], Targets[0]); 5547 return dynamicCast!(inout T)(src); 5548 } 5549 // structural upcast 5550 template wrap(Source) 5551 if (!allSatisfy!(Bind!(isImplicitlyConvertible, Source), Targets)) 5552 { 5553 auto wrap(inout Source src) 5554 { 5555 static assert(hasRequireMethods!(), 5556 "Source "~Source.stringof~ 5557 " does not have structural conformance to "~ 5558 Targets.stringof); 5559 5560 alias T = Select!(is(Source == shared), shared Impl, Impl); 5561 return new inout T(src); 5562 } 5563 5564 template FuncInfo(string s, F) 5565 { 5566 enum name = s; 5567 alias type = F; 5568 } 5569 5570 // https://issues.dlang.org/show_bug.cgi?id=12064: Remove NVI members 5571 template OnlyVirtual(members...) 5572 { 5573 enum notFinal(alias T) = !__traits(isFinalFunction, T); 5574 import std.meta : Filter; 5575 alias OnlyVirtual = Filter!(notFinal, members); 5576 } 5577 5578 // Concat all Targets function members into one tuple 5579 template Concat(size_t i = 0) 5580 { 5581 static if (i >= Targets.length) 5582 alias Concat = AliasSeq!(); 5583 else 5584 { 5585 alias Concat = AliasSeq!(OnlyVirtual!(GetOverloadedMethods!(Targets[i]), Concat!(i + 1))); 5586 } 5587 } 5588 5589 // Remove duplicated functions based on the identifier name and function type covariance 5590 template Uniq(members...) 5591 { 5592 static if (members.length == 0) 5593 alias Uniq = AliasSeq!(); 5594 else 5595 { 5596 alias func = members[0]; 5597 enum name = __traits(identifier, func); 5598 alias type = FunctionTypeOf!func; 5599 template check(size_t i, mem...) 5600 { 5601 static if (i >= mem.length) 5602 enum ptrdiff_t check = -1; 5603 else 5604 { 5605 enum ptrdiff_t check = 5606 __traits(identifier, func) == __traits(identifier, mem[i]) && 5607 !is(DerivedFunctionType!(type, FunctionTypeOf!(mem[i])) == void) 5608 ? i : check!(i + 1, mem); 5609 } 5610 } 5611 enum ptrdiff_t x = 1 + check!(0, members[1 .. $]); 5612 static if (x >= 1) 5613 { 5614 alias typex = DerivedFunctionType!(type, FunctionTypeOf!(members[x])); 5615 alias remain = Uniq!(members[1 .. x], members[x + 1 .. $]); 5616 5617 static if (remain.length >= 1 && remain[0].name == name && 5618 !is(DerivedFunctionType!(typex, remain[0].type) == void)) 5619 { 5620 alias F = DerivedFunctionType!(typex, remain[0].type); 5621 alias Uniq = AliasSeq!(FuncInfo!(name, F), remain[1 .. $]); 5622 } 5623 else 5624 alias Uniq = AliasSeq!(FuncInfo!(name, typex), remain); 5625 } 5626 else 5627 { 5628 alias Uniq = AliasSeq!(FuncInfo!(name, type), Uniq!(members[1 .. $])); 5629 } 5630 } 5631 } 5632 alias TargetMembers = Uniq!(Concat!()); // list of FuncInfo 5633 alias SourceMembers = GetOverloadedMethods!Source; // list of function symbols 5634 5635 // Check whether all of SourceMembers satisfy covariance target in TargetMembers 5636 template hasRequireMethods(size_t i = 0) 5637 { 5638 static if (i >= TargetMembers.length) 5639 enum hasRequireMethods = true; 5640 else 5641 { 5642 enum hasRequireMethods = 5643 findCovariantFunction!(TargetMembers[i], Source, SourceMembers) != -1 && 5644 hasRequireMethods!(i + 1); 5645 } 5646 } 5647 5648 // Internal wrapper class 5649 final class Impl : Structural, Targets 5650 { 5651 private: 5652 Source _wrap_source; 5653 5654 this( inout Source s) inout @safe pure nothrow { _wrap_source = s; } 5655 this(shared inout Source s) shared inout @safe pure nothrow { _wrap_source = s; } 5656 5657 // BUG: making private should work with NVI. 5658 protected final inout(Object) _wrap_getSource() inout @trusted 5659 { 5660 return dynamicCast!(inout Object)(_wrap_source); 5661 } 5662 5663 import std.conv : to; 5664 import std.functional : forward; 5665 template generateFun(size_t i) 5666 { 5667 enum name = TargetMembers[i].name; 5668 enum fa = functionAttributes!(TargetMembers[i].type); 5669 static @property stc() 5670 { 5671 string r; 5672 if (fa & FunctionAttribute.property) r ~= "@property "; 5673 if (fa & FunctionAttribute.ref_) r ~= "ref "; 5674 if (fa & FunctionAttribute.pure_) r ~= "pure "; 5675 if (fa & FunctionAttribute.nothrow_) r ~= "nothrow "; 5676 if (fa & FunctionAttribute.trusted) r ~= "@trusted "; 5677 if (fa & FunctionAttribute.safe) r ~= "@safe "; 5678 return r; 5679 } 5680 static @property mod() 5681 { 5682 alias type = AliasSeq!(TargetMembers[i].type)[0]; 5683 string r; 5684 static if (is(type == immutable)) r ~= " immutable"; 5685 else 5686 { 5687 static if (is(type == shared)) r ~= " shared"; 5688 static if (is(type == const)) r ~= " const"; 5689 else static if (is(type == inout)) r ~= " inout"; 5690 //else --> mutable 5691 } 5692 return r; 5693 } 5694 enum n = to!string(i); 5695 static if (fa & FunctionAttribute.property) 5696 { 5697 static if (Parameters!(TargetMembers[i].type).length == 0) 5698 enum fbody = "_wrap_source."~name; 5699 else 5700 enum fbody = "_wrap_source."~name~" = forward!args"; 5701 } 5702 else 5703 { 5704 enum fbody = "_wrap_source."~name~"(forward!args)"; 5705 } 5706 enum generateFun = 5707 "override "~stc~"ReturnType!(TargetMembers["~n~"].type) " 5708 ~ name~"(Parameters!(TargetMembers["~n~"].type) args) "~mod~ 5709 "{ return "~fbody~"; }"; 5710 } 5711 5712 public: 5713 static foreach (i; 0 .. TargetMembers.length) 5714 mixin(generateFun!i); 5715 } 5716 } 5717 } 5718 /// ditto 5719 template wrap(Targets...) 5720 if (Targets.length >= 1 && !allSatisfy!(isMutable, Targets)) 5721 { 5722 import std.meta : staticMap; 5723 5724 alias wrap = .wrap!(staticMap!(Unqual, Targets)); 5725 } 5726 5727 /// ditto 5728 template unwrap(Target) 5729 if (isMutable!Target) 5730 { 5731 // strict downcast 5732 auto unwrap(Source)(inout Source src) @trusted pure nothrow 5733 if (is(Target : Source)) 5734 { 5735 alias T = Select!(is(Source == shared), shared Target, Target); 5736 return dynamicCast!(inout T)(src); 5737 } 5738 // structural downcast 5739 auto unwrap(Source)(inout Source src) @trusted pure nothrow 5740 if (!is(Target : Source)) 5741 { 5742 alias T = Select!(is(Source == shared), shared Target, Target); 5743 Object o = dynamicCast!(Object)(src); // remove qualifier 5744 do 5745 { 5746 if (auto a = dynamicCast!(Structural)(o)) 5747 { 5748 if (auto d = dynamicCast!(inout T)(o = a._wrap_getSource())) 5749 return d; 5750 } 5751 else if (auto d = dynamicCast!(inout T)(o)) 5752 return d; 5753 else 5754 break; 5755 } while (o); 5756 return null; 5757 } 5758 } 5759 5760 /// ditto 5761 template unwrap(Target) 5762 if (!isMutable!Target) 5763 { 5764 alias unwrap = .unwrap!(Unqual!Target); 5765 } 5766 5767 /// 5768 @system unittest 5769 { 5770 interface Quack 5771 { 5772 int quack(); 5773 @property int height(); 5774 } 5775 interface Flyer 5776 { 5777 @property int height(); 5778 } 5779 class Duck : Quack 5780 { 5781 int quack() { return 1; } 5782 @property int height() { return 10; } 5783 } 5784 class Human 5785 { 5786 int quack() { return 2; } 5787 @property int height() { return 20; } 5788 } 5789 5790 Duck d1 = new Duck(); 5791 Human h1 = new Human(); 5792 5793 interface Refleshable 5794 { 5795 int reflesh(); 5796 } 5797 5798 // does not have structural conformance 5799 static assert(!__traits(compiles, d1.wrap!Refleshable)); 5800 static assert(!__traits(compiles, h1.wrap!Refleshable)); 5801 5802 // strict upcast 5803 Quack qd = d1.wrap!Quack; 5804 assert(qd is d1); 5805 assert(qd.quack() == 1); // calls Duck.quack 5806 // strict downcast 5807 Duck d2 = qd.unwrap!Duck; 5808 assert(d2 is d1); 5809 5810 // structural upcast 5811 Quack qh = h1.wrap!Quack; 5812 assert(qh.quack() == 2); // calls Human.quack 5813 // structural downcast 5814 Human h2 = qh.unwrap!Human; 5815 assert(h2 is h1); 5816 5817 // structural upcast (two steps) 5818 Quack qx = h1.wrap!Quack; // Human -> Quack 5819 Flyer fx = qx.wrap!Flyer; // Quack -> Flyer 5820 assert(fx.height == 20); // calls Human.height 5821 // structural downcast (two steps) 5822 Quack qy = fx.unwrap!Quack; // Flyer -> Quack 5823 Human hy = qy.unwrap!Human; // Quack -> Human 5824 assert(hy is h1); 5825 // structural downcast (one step) 5826 Human hz = fx.unwrap!Human; // Flyer -> Human 5827 assert(hz is h1); 5828 } 5829 5830 /// 5831 @system unittest 5832 { 5833 import std.traits : FunctionAttribute, functionAttributes; 5834 interface A { int run(); } 5835 interface B { int stop(); @property int status(); } 5836 class X 5837 { 5838 int run() { return 1; } 5839 int stop() { return 2; } 5840 @property int status() { return 3; } 5841 } 5842 5843 auto x = new X(); 5844 auto ab = x.wrap!(A, B); 5845 A a = ab; 5846 B b = ab; 5847 assert(a.run() == 1); 5848 assert(b.stop() == 2); 5849 assert(b.status == 3); 5850 static assert(functionAttributes!(typeof(ab).status) & FunctionAttribute.property); 5851 } 5852 5853 // Internal class to support dynamic cross-casting 5854 private interface Structural 5855 { 5856 inout(Object) _wrap_getSource() inout @safe pure nothrow; 5857 } 5858 5859 @system unittest 5860 { 5861 class A 5862 { 5863 int draw() { return 1; } 5864 int draw(int v) { return v; } 5865 5866 int draw() const { return 2; } 5867 int draw() shared { return 3; } 5868 int draw() shared const { return 4; } 5869 int draw() immutable { return 5; } 5870 } 5871 interface Drawable 5872 { 5873 int draw(); 5874 int draw() const; 5875 int draw() shared; 5876 int draw() shared const; 5877 int draw() immutable; 5878 } 5879 interface Drawable2 5880 { 5881 int draw(int v); 5882 } 5883 5884 auto ma = new A(); 5885 auto sa = new shared A(); 5886 auto ia = new immutable A(); 5887 { 5888 Drawable md = ma.wrap!Drawable; 5889 const Drawable cd = ma.wrap!Drawable; 5890 shared Drawable sd = sa.wrap!Drawable; 5891 shared const Drawable scd = sa.wrap!Drawable; 5892 immutable Drawable id = ia.wrap!Drawable; 5893 assert( md.draw() == 1); 5894 assert( cd.draw() == 2); 5895 assert( sd.draw() == 3); 5896 assert(scd.draw() == 4); 5897 assert( id.draw() == 5); 5898 } 5899 { 5900 Drawable2 d = ma.wrap!Drawable2; 5901 static assert(!__traits(compiles, d.draw())); 5902 assert(d.draw(10) == 10); 5903 } 5904 } 5905 5906 // https://issues.dlang.org/show_bug.cgi?id=10377 5907 @system unittest 5908 { 5909 import std.range, std.algorithm; 5910 5911 interface MyInputRange(T) 5912 { 5913 @property T front(); 5914 void popFront(); 5915 @property bool empty(); 5916 } 5917 5918 //auto o = iota(0,10,1).inputRangeObject(); 5919 //pragma(msg, __traits(allMembers, typeof(o))); 5920 auto r = iota(0,10,1).inputRangeObject().wrap!(MyInputRange!int)(); 5921 assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); 5922 } 5923 5924 // https://issues.dlang.org/show_bug.cgi?id=10536 5925 @system unittest 5926 { 5927 interface Interface 5928 { 5929 int foo(); 5930 } 5931 class Pluggable 5932 { 5933 int foo() { return 1; } 5934 @disable void opCast(T, this X)(); // ! 5935 } 5936 5937 Interface i = new Pluggable().wrap!Interface; 5938 assert(i.foo() == 1); 5939 } 5940 @system unittest 5941 { 5942 // Enhancement 10538 5943 interface Interface 5944 { 5945 int foo(); 5946 int bar(int); 5947 } 5948 class Pluggable 5949 { 5950 int opDispatch(string name, A...)(A args) { return 100; } 5951 } 5952 5953 Interface i = wrap!Interface(new Pluggable()); 5954 assert(i.foo() == 100); 5955 assert(i.bar(10) == 100); 5956 } 5957 5958 // https://issues.dlang.org/show_bug.cgi?id=12064 5959 @system unittest 5960 { 5961 interface I 5962 { 5963 int foo(); 5964 final int nvi1(){return foo();} 5965 } 5966 5967 interface J 5968 { 5969 int bar(); 5970 final int nvi2(){return bar();} 5971 } 5972 5973 class Baz 5974 { 5975 int foo() { return 42;} 5976 int bar() { return 12064;} 5977 } 5978 5979 auto baz = new Baz(); 5980 auto foobar = baz.wrap!(I, J)(); 5981 assert(foobar.nvi1 == 42); 5982 assert(foobar.nvi2 == 12064); 5983 } 5984 5985 // Make a tuple of non-static function symbols 5986 package template GetOverloadedMethods(T) 5987 { 5988 import std.meta : Filter; 5989 5990 alias allMembers = __traits(allMembers, T); 5991 template follows(size_t i = 0) 5992 { 5993 static if (i >= allMembers.length) 5994 { 5995 alias follows = AliasSeq!(); 5996 } 5997 else static if (!__traits(compiles, mixin("T."~allMembers[i]))) 5998 { 5999 alias follows = follows!(i + 1); 6000 } 6001 else 6002 { 6003 enum name = allMembers[i]; 6004 6005 template isMethod(alias f) 6006 { 6007 static if (is(typeof(&f) F == F*) && is(F == function)) 6008 enum isMethod = !__traits(isStaticFunction, f); 6009 else 6010 enum isMethod = false; 6011 } 6012 alias follows = AliasSeq!( 6013 std.meta.Filter!(isMethod, __traits(getOverloads, T, name)), 6014 follows!(i + 1)); 6015 } 6016 } 6017 alias GetOverloadedMethods = follows!(); 6018 } 6019 // find a function from Fs that has same identifier and covariant type with f 6020 private template findCovariantFunction(alias finfo, Source, Fs...) 6021 { 6022 template check(size_t i = 0) 6023 { 6024 static if (i >= Fs.length) 6025 enum ptrdiff_t check = -1; 6026 else 6027 { 6028 enum ptrdiff_t check = 6029 (finfo.name == __traits(identifier, Fs[i])) && 6030 isCovariantWith!(FunctionTypeOf!(Fs[i]), finfo.type) 6031 ? i : check!(i + 1); 6032 } 6033 } 6034 enum x = check!(); 6035 static if (x == -1 && is(typeof(Source.opDispatch))) 6036 { 6037 alias Params = Parameters!(finfo.type); 6038 enum ptrdiff_t findCovariantFunction = 6039 is(typeof(( Source).init.opDispatch!(finfo.name)(Params.init))) || 6040 is(typeof(( const Source).init.opDispatch!(finfo.name)(Params.init))) || 6041 is(typeof(( immutable Source).init.opDispatch!(finfo.name)(Params.init))) || 6042 is(typeof(( shared Source).init.opDispatch!(finfo.name)(Params.init))) || 6043 is(typeof((shared const Source).init.opDispatch!(finfo.name)(Params.init))) 6044 ? ptrdiff_t.max : -1; 6045 } 6046 else 6047 enum ptrdiff_t findCovariantFunction = x; 6048 } 6049 6050 private enum TypeModifier 6051 { 6052 mutable = 0, // type is mutable 6053 const_ = 1, // type is const 6054 immutable_ = 2, // type is immutable 6055 shared_ = 4, // type is shared 6056 inout_ = 8, // type is wild 6057 } 6058 private template TypeMod(T) 6059 { 6060 static if (is(T == immutable)) 6061 { 6062 enum mod1 = TypeModifier.immutable_; 6063 enum mod2 = 0; 6064 } 6065 else 6066 { 6067 enum mod1 = is(T == shared) ? TypeModifier.shared_ : 0; 6068 static if (is(T == const)) 6069 enum mod2 = TypeModifier.const_; 6070 else static if (is(T == inout)) 6071 enum mod2 = TypeModifier.inout_; 6072 else 6073 enum mod2 = TypeModifier.mutable; 6074 } 6075 enum TypeMod = cast(TypeModifier)(mod1 | mod2); 6076 } 6077 6078 @system unittest 6079 { 6080 template UnittestFuncInfo(alias f) 6081 { 6082 enum name = __traits(identifier, f); 6083 alias type = FunctionTypeOf!f; 6084 } 6085 6086 class A 6087 { 6088 int draw() { return 1; } 6089 @property int value() { return 2; } 6090 final int run() { return 3; } 6091 } 6092 alias methods = GetOverloadedMethods!A; 6093 6094 alias int F1(); 6095 alias @property int F2(); 6096 alias string F3(); 6097 alias nothrow @trusted uint F4(); 6098 alias int F5(Object); 6099 alias bool F6(Object); 6100 static assert(methods.length == 3 + 4); 6101 static assert(__traits(identifier, methods[0]) == "draw" && is(typeof(&methods[0]) == F1*)); 6102 static assert(__traits(identifier, methods[1]) == "value" && is(typeof(&methods[1]) == F2*)); 6103 static assert(__traits(identifier, methods[2]) == "run" && is(typeof(&methods[2]) == F1*)); 6104 6105 int draw(); 6106 @property int value(); 6107 void opEquals(); 6108 int nomatch(); 6109 static assert(findCovariantFunction!(UnittestFuncInfo!draw, A, methods) == 0); 6110 static assert(findCovariantFunction!(UnittestFuncInfo!value, A, methods) == 1); 6111 static assert(findCovariantFunction!(UnittestFuncInfo!opEquals, A, methods) == -1); 6112 static assert(findCovariantFunction!(UnittestFuncInfo!nomatch, A, methods) == -1); 6113 6114 // considering opDispatch 6115 class B 6116 { 6117 void opDispatch(string name, A...)(A) {} 6118 } 6119 alias methodsB = GetOverloadedMethods!B; 6120 static assert(findCovariantFunction!(UnittestFuncInfo!draw, B, methodsB) == ptrdiff_t.max); 6121 static assert(findCovariantFunction!(UnittestFuncInfo!value, B, methodsB) == ptrdiff_t.max); 6122 static assert(findCovariantFunction!(UnittestFuncInfo!opEquals, B, methodsB) == ptrdiff_t.max); 6123 static assert(findCovariantFunction!(UnittestFuncInfo!nomatch, B, methodsB) == ptrdiff_t.max); 6124 } 6125 6126 package template DerivedFunctionType(T...) 6127 { 6128 static if (!T.length) 6129 { 6130 alias DerivedFunctionType = void; 6131 } 6132 else static if (T.length == 1) 6133 { 6134 static if (is(T[0] == function)) 6135 { 6136 alias DerivedFunctionType = T[0]; 6137 } 6138 else 6139 { 6140 alias DerivedFunctionType = void; 6141 } 6142 } 6143 else static if (is(T[0] P0 == function) && is(T[1] P1 == function)) 6144 { 6145 alias FA = FunctionAttribute; 6146 6147 alias F0 = T[0], R0 = ReturnType!F0, PSTC0 = ParameterStorageClassTuple!F0; 6148 alias F1 = T[1], R1 = ReturnType!F1, PSTC1 = ParameterStorageClassTuple!F1; 6149 enum FA0 = functionAttributes!F0; 6150 enum FA1 = functionAttributes!F1; 6151 6152 template CheckParams(size_t i = 0) 6153 { 6154 static if (i >= P0.length) 6155 enum CheckParams = true; 6156 else 6157 { 6158 enum CheckParams = (is(P0[i] == P1[i]) && PSTC0[i] == PSTC1[i]) && 6159 CheckParams!(i + 1); 6160 } 6161 } 6162 static if (R0.sizeof == R1.sizeof && !is(CommonType!(R0, R1) == void) && 6163 P0.length == P1.length && CheckParams!() && TypeMod!F0 == TypeMod!F1 && 6164 variadicFunctionStyle!F0 == variadicFunctionStyle!F1 && 6165 functionLinkage!F0 == functionLinkage!F1 && 6166 ((FA0 ^ FA1) & (FA.ref_ | FA.property)) == 0) 6167 { 6168 alias R = Select!(is(R0 : R1), R0, R1); 6169 alias FX = FunctionTypeOf!(R function(P0)); 6170 // @system is default 6171 alias FY = SetFunctionAttributes!(FX, functionLinkage!F0, (FA0 | FA1) & ~FA.system); 6172 alias DerivedFunctionType = DerivedFunctionType!(FY, T[2 .. $]); 6173 } 6174 else 6175 alias DerivedFunctionType = void; 6176 } 6177 else 6178 alias DerivedFunctionType = void; 6179 } 6180 @safe unittest 6181 { 6182 // attribute covariance 6183 alias int F1(); 6184 static assert(is(DerivedFunctionType!(F1, F1) == F1)); 6185 alias int F2() pure nothrow; 6186 static assert(is(DerivedFunctionType!(F1, F2) == F2)); 6187 alias int F3() @safe; 6188 alias int F23() @safe pure nothrow; 6189 static assert(is(DerivedFunctionType!(F2, F3) == F23)); 6190 6191 // return type covariance 6192 alias long F4(); 6193 static assert(is(DerivedFunctionType!(F1, F4) == void)); 6194 class C {} 6195 class D : C {} 6196 alias C F5(); 6197 alias D F6(); 6198 static assert(is(DerivedFunctionType!(F5, F6) == F6)); 6199 alias typeof(null) F7(); 6200 alias int[] F8(); 6201 alias int* F9(); 6202 static assert(is(DerivedFunctionType!(F5, F7) == F7)); 6203 static assert(is(DerivedFunctionType!(F7, F8) == void)); 6204 static assert(is(DerivedFunctionType!(F7, F9) == F7)); 6205 6206 // variadic type equality 6207 alias int F10(int); 6208 alias int F11(int...); 6209 alias int F12(int, ...); 6210 static assert(is(DerivedFunctionType!(F10, F11) == void)); 6211 static assert(is(DerivedFunctionType!(F10, F12) == void)); 6212 static assert(is(DerivedFunctionType!(F11, F12) == void)); 6213 6214 // linkage equality 6215 alias extern(C) int F13(int); 6216 alias extern(D) int F14(int); 6217 alias extern(Windows) int F15(int); 6218 static assert(is(DerivedFunctionType!(F13, F14) == void)); 6219 static assert(is(DerivedFunctionType!(F13, F15) == void)); 6220 static assert(is(DerivedFunctionType!(F14, F15) == void)); 6221 6222 // ref & @property equality 6223 alias int F16(int); 6224 alias ref int F17(int); 6225 alias @property int F18(int); 6226 static assert(is(DerivedFunctionType!(F16, F17) == void)); 6227 static assert(is(DerivedFunctionType!(F16, F18) == void)); 6228 static assert(is(DerivedFunctionType!(F17, F18) == void)); 6229 } 6230 6231 package template Bind(alias Template, args1...) 6232 { 6233 alias Bind(args2...) = Template!(args1, args2); 6234 } 6235 6236 6237 /** 6238 Options regarding auto-initialization of a `RefCounted` object (see 6239 the definition of `RefCounted` below). 6240 */ 6241 enum RefCountedAutoInitialize 6242 { 6243 /// Do not auto-initialize the object 6244 no, 6245 /// Auto-initialize the object 6246 yes, 6247 } 6248 6249 /// 6250 @system unittest 6251 { 6252 import core.exception : AssertError; 6253 import std.exception : assertThrown; 6254 6255 struct Foo 6256 { 6257 int a = 42; 6258 } 6259 6260 RefCounted!(Foo, RefCountedAutoInitialize.yes) rcAuto; 6261 RefCounted!(Foo, RefCountedAutoInitialize.no) rcNoAuto; 6262 6263 assert(rcAuto.refCountedPayload.a == 42); 6264 6265 assertThrown!AssertError(rcNoAuto.refCountedPayload); 6266 rcNoAuto.refCountedStore.ensureInitialized; 6267 assert(rcNoAuto.refCountedPayload.a == 42); 6268 } 6269 6270 /** 6271 Defines a reference-counted object containing a `T` value as 6272 payload. 6273 6274 An instance of `RefCounted` is a reference to a structure, 6275 which is referred to as the $(I store), or $(I storage implementation 6276 struct) in this documentation. The store contains a reference count 6277 and the `T` payload. `RefCounted` uses `malloc` to allocate 6278 the store. As instances of `RefCounted` are copied or go out of 6279 scope, they will automatically increment or decrement the reference 6280 count. When the reference count goes down to zero, `RefCounted` 6281 will call `destroy` against the payload and call `free` to 6282 deallocate the store. If the `T` payload contains any references 6283 to GC-allocated memory, then `RefCounted` will add it to the GC memory 6284 that is scanned for pointers, and remove it from GC scanning before 6285 `free` is called on the store. 6286 6287 One important consequence of `destroy` is that it will call the 6288 destructor of the `T` payload. GC-managed references are not 6289 guaranteed to be valid during a destructor call, but other members of 6290 `T`, such as file handles or pointers to `malloc` memory, will 6291 still be valid during the destructor call. This allows the `T` to 6292 deallocate or clean up any non-GC resources immediately after the 6293 reference count has reached zero. 6294 6295 `RefCounted` is unsafe and should be used with care. No references 6296 to the payload should be escaped outside the `RefCounted` object. 6297 6298 The `autoInit` option makes the object ensure the store is 6299 automatically initialized. Leaving $(D autoInit == 6300 RefCountedAutoInitialize.yes) (the default option) is convenient but 6301 has the cost of a test whenever the payload is accessed. If $(D 6302 autoInit == RefCountedAutoInitialize.no), user code must call either 6303 `refCountedStore.isInitialized` or `refCountedStore.ensureInitialized` 6304 before attempting to access the payload. Not doing so results in null 6305 pointer dereference. 6306 */ 6307 struct RefCounted(T, RefCountedAutoInitialize autoInit = 6308 RefCountedAutoInitialize.yes) 6309 if (!is(T == class) && !(is(T == interface))) 6310 { 6311 version (D_BetterC) 6312 { 6313 private enum enableGCScan = false; 6314 } 6315 else 6316 { 6317 private enum enableGCScan = hasIndirections!T; 6318 } 6319 6320 // TODO remove pure when https://issues.dlang.org/show_bug.cgi?id=15862 has been fixed 6321 extern(C) private pure nothrow @nogc static 6322 { 6323 pragma(mangle, "free") void pureFree( void *ptr ); 6324 static if (enableGCScan) 6325 { 6326 pragma(mangle, "gc_addRange") void pureGcAddRange( in void* p, size_t sz, const TypeInfo ti = null ); 6327 pragma(mangle, "gc_removeRange") void pureGcRemoveRange( in void* p ); 6328 } 6329 } 6330 6331 /// `RefCounted` storage implementation. 6332 struct RefCountedStore 6333 { 6334 private struct Impl 6335 { 6336 T _payload; 6337 size_t _count; 6338 } 6339 6340 private Impl* _store; 6341 6342 private void initialize(A...)(auto ref A args) 6343 { 6344 import std.conv : emplace; 6345 6346 allocateStore(); 6347 emplace(&_store._payload, args); 6348 _store._count = 1; 6349 } 6350 6351 private void move(ref T source) nothrow pure 6352 { 6353 import std.algorithm.mutation : moveEmplace; 6354 6355 allocateStore(); 6356 moveEmplace(source, _store._payload); 6357 _store._count = 1; 6358 } 6359 6360 // 'nothrow': can only generate an Error 6361 private void allocateStore() nothrow pure 6362 { 6363 static if (enableGCScan) 6364 { 6365 import std.internal.memory : enforceCalloc; 6366 _store = cast(Impl*) enforceCalloc(1, Impl.sizeof); 6367 pureGcAddRange(&_store._payload, T.sizeof); 6368 } 6369 else 6370 { 6371 import std.internal.memory : enforceMalloc; 6372 _store = cast(Impl*) enforceMalloc(Impl.sizeof); 6373 } 6374 } 6375 6376 /** 6377 Returns `true` if and only if the underlying store has been 6378 allocated and initialized. 6379 */ 6380 @property nothrow @safe pure @nogc 6381 bool isInitialized() const 6382 { 6383 return _store !is null; 6384 } 6385 6386 /** 6387 Returns underlying reference count if it is allocated and initialized 6388 (a positive integer), and `0` otherwise. 6389 */ 6390 @property nothrow @safe pure @nogc 6391 size_t refCount() const 6392 { 6393 return isInitialized ? _store._count : 0; 6394 } 6395 6396 /** 6397 Makes sure the payload was properly initialized. Such a 6398 call is typically inserted before using the payload. 6399 */ 6400 void ensureInitialized() 6401 { 6402 if (!isInitialized) initialize(); 6403 } 6404 6405 } 6406 RefCountedStore _refCounted; 6407 6408 /// Returns storage implementation struct. 6409 @property nothrow @safe 6410 ref inout(RefCountedStore) refCountedStore() inout 6411 { 6412 return _refCounted; 6413 } 6414 6415 /** 6416 Constructor that initializes the payload. 6417 6418 Postcondition: `refCountedStore.isInitialized` 6419 */ 6420 this(A...)(auto ref A args) if (A.length > 0) 6421 { 6422 _refCounted.initialize(args); 6423 } 6424 6425 /// Ditto 6426 this(T val) 6427 { 6428 _refCounted.move(val); 6429 } 6430 6431 /** 6432 Constructor that tracks the reference count appropriately. If $(D 6433 !refCountedStore.isInitialized), does nothing. 6434 */ 6435 this(this) @safe pure nothrow @nogc 6436 { 6437 if (!_refCounted.isInitialized) return; 6438 ++_refCounted._store._count; 6439 } 6440 6441 /** 6442 Destructor that tracks the reference count appropriately. If $(D 6443 !refCountedStore.isInitialized), does nothing. When the reference count goes 6444 down to zero, calls `destroy` agaist the payload and calls `free` 6445 to deallocate the corresponding resource. 6446 */ 6447 ~this() 6448 { 6449 if (!_refCounted.isInitialized) return; 6450 assert(_refCounted._store._count > 0); 6451 if (--_refCounted._store._count) 6452 return; 6453 // Done, deallocate 6454 .destroy(_refCounted._store._payload); 6455 static if (enableGCScan) 6456 { 6457 pureGcRemoveRange(&_refCounted._store._payload); 6458 } 6459 6460 pureFree(_refCounted._store); 6461 _refCounted._store = null; 6462 } 6463 6464 /** 6465 Assignment operators 6466 */ 6467 void opAssign(typeof(this) rhs) 6468 { 6469 import std.algorithm.mutation : swap; 6470 6471 swap(_refCounted._store, rhs._refCounted._store); 6472 } 6473 6474 /// Ditto 6475 void opAssign(T rhs) 6476 { 6477 import std.algorithm.mutation : move; 6478 6479 static if (autoInit == RefCountedAutoInitialize.yes) 6480 { 6481 _refCounted.ensureInitialized(); 6482 } 6483 else 6484 { 6485 assert(_refCounted.isInitialized); 6486 } 6487 move(rhs, _refCounted._store._payload); 6488 } 6489 6490 //version to have a single properly ddoc'ed function (w/ correct sig) 6491 version (StdDdoc) 6492 { 6493 /** 6494 Returns a reference to the payload. If (autoInit == 6495 RefCountedAutoInitialize.yes), calls $(D 6496 refCountedStore.ensureInitialized). Otherwise, just issues $(D 6497 assert(refCountedStore.isInitialized)). Used with $(D alias 6498 refCountedPayload this;), so callers can just use the `RefCounted` 6499 object as a `T`. 6500 6501 $(BLUE The first overload exists only if $(D autoInit == RefCountedAutoInitialize.yes).) 6502 So if $(D autoInit == RefCountedAutoInitialize.no) 6503 or called for a constant or immutable object, then 6504 `refCountedPayload` will also be qualified as safe and nothrow 6505 (but will still assert if not initialized). 6506 */ 6507 @property @trusted 6508 ref T refCountedPayload() return; 6509 6510 /// ditto 6511 @property nothrow @safe pure @nogc 6512 ref inout(T) refCountedPayload() inout return; 6513 } 6514 else 6515 { 6516 static if (autoInit == RefCountedAutoInitialize.yes) 6517 { 6518 //Can't use inout here because of potential mutation 6519 @property 6520 ref T refCountedPayload() return 6521 { 6522 _refCounted.ensureInitialized(); 6523 return _refCounted._store._payload; 6524 } 6525 } 6526 6527 @property nothrow @safe pure @nogc 6528 ref inout(T) refCountedPayload() inout return 6529 { 6530 assert(_refCounted.isInitialized, "Attempted to access an uninitialized payload."); 6531 return _refCounted._store._payload; 6532 } 6533 } 6534 6535 /** 6536 Returns a reference to the payload. If (autoInit == 6537 RefCountedAutoInitialize.yes), calls $(D 6538 refCountedStore.ensureInitialized). Otherwise, just issues $(D 6539 assert(refCountedStore.isInitialized)). 6540 */ 6541 alias refCountedPayload this; 6542 } 6543 6544 /// 6545 @betterC pure @system nothrow @nogc unittest 6546 { 6547 // A pair of an `int` and a `size_t` - the latter being the 6548 // reference count - will be dynamically allocated 6549 auto rc1 = RefCounted!int(5); 6550 assert(rc1 == 5); 6551 // No more allocation, add just one extra reference count 6552 auto rc2 = rc1; 6553 // Reference semantics 6554 rc2 = 42; 6555 assert(rc1 == 42); 6556 // the pair will be freed when rc1 and rc2 go out of scope 6557 } 6558 6559 pure @system unittest 6560 { 6561 RefCounted!int* p; 6562 { 6563 auto rc1 = RefCounted!int(5); 6564 p = &rc1; 6565 assert(rc1 == 5); 6566 assert(rc1._refCounted._store._count == 1); 6567 auto rc2 = rc1; 6568 assert(rc1._refCounted._store._count == 2); 6569 // Reference semantics 6570 rc2 = 42; 6571 assert(rc1 == 42); 6572 rc2 = rc2; 6573 assert(rc2._refCounted._store._count == 2); 6574 rc1 = rc2; 6575 assert(rc1._refCounted._store._count == 2); 6576 } 6577 assert(p._refCounted._store == null); 6578 6579 // RefCounted as a member 6580 struct A 6581 { 6582 RefCounted!int x; 6583 this(int y) 6584 { 6585 x._refCounted.initialize(y); 6586 } 6587 A copy() 6588 { 6589 auto another = this; 6590 return another; 6591 } 6592 } 6593 auto a = A(4); 6594 auto b = a.copy(); 6595 assert(a.x._refCounted._store._count == 2, 6596 "https://issues.dlang.org/show_bug.cgi?id=4356 still unfixed"); 6597 } 6598 6599 @betterC pure @system nothrow @nogc unittest 6600 { 6601 import std.algorithm.mutation : swap; 6602 6603 RefCounted!int p1, p2; 6604 swap(p1, p2); 6605 } 6606 6607 // https://issues.dlang.org/show_bug.cgi?id=6606 6608 @betterC @safe pure nothrow @nogc unittest 6609 { 6610 union U { 6611 size_t i; 6612 void* p; 6613 } 6614 6615 struct S { 6616 U u; 6617 } 6618 6619 alias SRC = RefCounted!S; 6620 } 6621 6622 // https://issues.dlang.org/show_bug.cgi?id=6436 6623 @betterC @system pure unittest 6624 { 6625 struct S { this(ref int val) { assert(val == 3); ++val; } } 6626 6627 int val = 3; 6628 auto s = RefCounted!S(val); 6629 assert(val == 4); 6630 } 6631 6632 // gc_addRange coverage 6633 @betterC @system pure unittest 6634 { 6635 struct S { int* p; } 6636 6637 auto s = RefCounted!S(null); 6638 } 6639 6640 @betterC @system pure nothrow @nogc unittest 6641 { 6642 RefCounted!int a; 6643 a = 5; //This should not assert 6644 assert(a == 5); 6645 6646 RefCounted!int b; 6647 b = a; //This should not assert either 6648 assert(b == 5); 6649 6650 RefCounted!(int*) c; 6651 } 6652 6653 /** 6654 * Initializes a `RefCounted` with `val`. The template parameter 6655 * `T` of `RefCounted` is inferred from `val`. 6656 * This function can be used to move non-copyable values to the heap. 6657 * It also disables the `autoInit` option of `RefCounted`. 6658 * 6659 * Params: 6660 * val = The value to be reference counted 6661 * Returns: 6662 * An initialized `RefCounted` containing `val`. 6663 * See_Also: 6664 * $(HTTP en.cppreference.com/w/cpp/memory/shared_ptr/make_shared, C++'s make_shared) 6665 */ 6666 RefCounted!(T, RefCountedAutoInitialize.no) refCounted(T)(T val) 6667 { 6668 typeof(return) res; 6669 res._refCounted.move(val); 6670 return res; 6671 } 6672 6673 /// 6674 @system unittest 6675 { 6676 static struct File 6677 { 6678 string name; 6679 @disable this(this); // not copyable 6680 ~this() { name = null; } 6681 } 6682 6683 auto file = File("name"); 6684 assert(file.name == "name"); 6685 // file cannot be copied and has unique ownership 6686 static assert(!__traits(compiles, {auto file2 = file;})); 6687 6688 // make the file refcounted to share ownership 6689 import std.algorithm.mutation : move; 6690 auto rcFile = refCounted(move(file)); 6691 assert(rcFile.name == "name"); 6692 assert(file.name == null); 6693 auto rcFile2 = rcFile; 6694 assert(rcFile.refCountedStore.refCount == 2); 6695 // file gets properly closed when last reference is dropped 6696 } 6697 6698 /** 6699 Creates a proxy for the value `a` that will forward all operations 6700 while disabling implicit conversions. The aliased item `a` must be 6701 an $(B lvalue). This is useful for creating a new type from the 6702 "base" type (though this is $(B not) a subtype-supertype 6703 relationship; the new type is not related to the old type in any way, 6704 by design). 6705 6706 The new type supports all operations that the underlying type does, 6707 including all operators such as `+`, `--`, `<`, `[]`, etc. 6708 6709 Params: 6710 a = The value to act as a proxy for all operations. It must 6711 be an lvalue. 6712 */ 6713 mixin template Proxy(alias a) 6714 { 6715 private alias ValueType = typeof({ return a; }()); 6716 6717 /* Determine if 'T.a' can referenced via a const(T). 6718 * Use T* as the parameter because 'scope' inference needs a fully 6719 * analyzed T, which doesn't work when accessibleFrom() is used in a 6720 * 'static if' in the definition of Proxy or T. 6721 */ 6722 private enum bool accessibleFrom(T) = 6723 is(typeof((T* self){ cast(void) mixin("(*self)."~__traits(identifier, a)); })); 6724 6725 static if (is(typeof(this) == class)) 6726 { 6727 override bool opEquals(Object o) 6728 { 6729 if (auto b = cast(typeof(this))o) 6730 { 6731 return a == mixin("b."~__traits(identifier, a)); 6732 } 6733 return false; 6734 } 6735 6736 bool opEquals(T)(T b) 6737 if (is(ValueType : T) || is(typeof(a.opEquals(b))) || is(typeof(b.opEquals(a)))) 6738 { 6739 static if (is(typeof(a.opEquals(b)))) 6740 return a.opEquals(b); 6741 else static if (is(typeof(b.opEquals(a)))) 6742 return b.opEquals(a); 6743 else 6744 return a == b; 6745 } 6746 6747 override int opCmp(Object o) 6748 { 6749 if (auto b = cast(typeof(this))o) 6750 { 6751 return a < mixin("b."~__traits(identifier, a)) ? -1 6752 : a > mixin("b."~__traits(identifier, a)) ? +1 : 0; 6753 } 6754 static if (is(ValueType == class)) 6755 return a.opCmp(o); 6756 else 6757 throw new Exception("Attempt to compare a "~typeid(this).toString~" and a "~typeid(o).toString); 6758 } 6759 6760 int opCmp(T)(auto ref const T b) 6761 if (is(ValueType : T) || is(typeof(a.opCmp(b))) || is(typeof(b.opCmp(a)))) 6762 { 6763 static if (is(typeof(a.opCmp(b)))) 6764 return a.opCmp(b); 6765 else static if (is(typeof(b.opCmp(a)))) 6766 return -b.opCmp(b); 6767 else 6768 return a < b ? -1 : a > b ? +1 : 0; 6769 } 6770 6771 static if (accessibleFrom!(const typeof(this))) 6772 { 6773 override size_t toHash() const nothrow @safe 6774 { 6775 static if (__traits(compiles, .hashOf(a))) 6776 return .hashOf(a); 6777 else 6778 // Workaround for when .hashOf is not both @safe and nothrow. 6779 { 6780 static if (is(typeof(&a) == ValueType*)) 6781 alias v = a; 6782 else 6783 auto v = a; // if a is (property) function 6784 // BUG: Improperly casts away `shared`! 6785 return typeid(ValueType).getHash((() @trusted => cast(const void*) &v)()); 6786 } 6787 } 6788 } 6789 } 6790 else 6791 { 6792 auto ref opEquals(this X, B)(auto ref B b) 6793 { 6794 static if (is(immutable B == immutable typeof(this))) 6795 { 6796 return a == mixin("b."~__traits(identifier, a)); 6797 } 6798 else 6799 return a == b; 6800 } 6801 6802 auto ref opCmp(this X, B)(auto ref B b) 6803 { 6804 static if (is(typeof(a.opCmp(b)))) 6805 return a.opCmp(b); 6806 else static if (is(typeof(b.opCmp(a)))) 6807 return -b.opCmp(a); 6808 else static if (isFloatingPoint!ValueType || isFloatingPoint!B) 6809 return a < b ? -1 : a > b ? +1 : a == b ? 0 : float.nan; 6810 else 6811 return a < b ? -1 : (a > b); 6812 } 6813 6814 static if (accessibleFrom!(const typeof(this))) 6815 { 6816 size_t toHash() const nothrow @safe 6817 { 6818 static if (__traits(compiles, .hashOf(a))) 6819 return .hashOf(a); 6820 else 6821 // Workaround for when .hashOf is not both @safe and nothrow. 6822 { 6823 static if (is(typeof(&a) == ValueType*)) 6824 alias v = a; 6825 else 6826 auto v = a; // if a is (property) function 6827 // BUG: Improperly casts away `shared`! 6828 return typeid(ValueType).getHash((() @trusted => cast(const void*) &v)()); 6829 } 6830 } 6831 } 6832 } 6833 6834 auto ref opCall(this X, Args...)(auto ref Args args) { return a(args); } 6835 6836 auto ref opCast(T, this X)() { return cast(T) a; } 6837 6838 auto ref opIndex(this X, D...)(auto ref D i) { return a[i]; } 6839 auto ref opSlice(this X )() { return a[]; } 6840 auto ref opSlice(this X, B, E)(auto ref B b, auto ref E e) { return a[b .. e]; } 6841 6842 auto ref opUnary (string op, this X )() { return mixin(op~"a"); } 6843 auto ref opIndexUnary(string op, this X, D...)(auto ref D i) { return mixin(op~"a[i]"); } 6844 auto ref opSliceUnary(string op, this X )() { return mixin(op~"a[]"); } 6845 auto ref opSliceUnary(string op, this X, B, E)(auto ref B b, auto ref E e) { return mixin(op~"a[b .. e]"); } 6846 6847 auto ref opBinary(string op, this X, B)(auto ref B b) 6848 if (op == "in" && is(typeof(a in b)) || op != "in") 6849 { 6850 return mixin("a "~op~" b"); 6851 } 6852 auto ref opBinaryRight(string op, this X, B)(auto ref B b) { return mixin("b "~op~" a"); } 6853 6854 static if (!is(typeof(this) == class)) 6855 { 6856 import std.traits; 6857 static if (isAssignable!ValueType) 6858 { 6859 auto ref opAssign(this X)(auto ref typeof(this) v) 6860 { 6861 a = mixin("v."~__traits(identifier, a)); 6862 return this; 6863 } 6864 } 6865 else 6866 { 6867 @disable void opAssign(this X)(auto ref typeof(this) v); 6868 } 6869 } 6870 6871 auto ref opAssign (this X, V )(auto ref V v) if (!is(V == typeof(this))) { return a = v; } 6872 auto ref opIndexAssign(this X, V, D...)(auto ref V v, auto ref D i) { return a[i] = v; } 6873 auto ref opSliceAssign(this X, V )(auto ref V v) { return a[] = v; } 6874 auto ref opSliceAssign(this X, V, B, E)(auto ref V v, auto ref B b, auto ref E e) { return a[b .. e] = v; } 6875 6876 auto ref opOpAssign (string op, this X, V )(auto ref V v) 6877 { 6878 return mixin("a = a "~op~" v"); 6879 } 6880 auto ref opIndexOpAssign(string op, this X, V, D...)(auto ref V v, auto ref D i) 6881 { 6882 return mixin("a[i] " ~op~"= v"); 6883 } 6884 auto ref opSliceOpAssign(string op, this X, V )(auto ref V v) 6885 { 6886 return mixin("a[] " ~op~"= v"); 6887 } 6888 auto ref opSliceOpAssign(string op, this X, V, B, E)(auto ref V v, auto ref B b, auto ref E e) 6889 { 6890 return mixin("a[b .. e] "~op~"= v"); 6891 } 6892 6893 template opDispatch(string name) 6894 { 6895 static if (is(typeof(__traits(getMember, a, name)) == function)) 6896 { 6897 // non template function 6898 auto ref opDispatch(this X, Args...)(auto ref Args args) { return mixin("a."~name~"(args)"); } 6899 } 6900 else static if (is(typeof({ enum x = mixin("a."~name); }))) 6901 { 6902 // built-in type field, manifest constant, and static non-mutable field 6903 enum opDispatch = mixin("a."~name); 6904 } 6905 else static if (is(typeof(mixin("a."~name))) || __traits(getOverloads, a, name).length != 0) 6906 { 6907 // field or property function 6908 @property auto ref opDispatch(this X)() { return mixin("a."~name); } 6909 @property auto ref opDispatch(this X, V)(auto ref V v) { return mixin("a."~name~" = v"); } 6910 } 6911 else 6912 { 6913 // member template 6914 template opDispatch(T...) 6915 { 6916 enum targs = T.length ? "!T" : ""; 6917 auto ref opDispatch(this X, Args...)(auto ref Args args){ return mixin("a."~name~targs~"(args)"); } 6918 } 6919 } 6920 } 6921 6922 import std.traits : isArray; 6923 6924 static if (isArray!ValueType) 6925 { 6926 auto opDollar() const { return a.length; } 6927 } 6928 else static if (is(typeof(a.opDollar!0))) 6929 { 6930 auto ref opDollar(size_t pos)() { return a.opDollar!pos(); } 6931 } 6932 else static if (is(typeof(a.opDollar) == function)) 6933 { 6934 auto ref opDollar() { return a.opDollar(); } 6935 } 6936 else static if (is(typeof(a.opDollar))) 6937 { 6938 alias opDollar = a.opDollar; 6939 } 6940 } 6941 6942 /// 6943 @safe unittest 6944 { 6945 struct MyInt 6946 { 6947 private int value; 6948 mixin Proxy!value; 6949 6950 this(int n){ value = n; } 6951 } 6952 6953 MyInt n = 10; 6954 6955 // Enable operations that original type has. 6956 ++n; 6957 assert(n == 11); 6958 assert(n * 2 == 22); 6959 6960 void func(int n) { } 6961 6962 // Disable implicit conversions to original type. 6963 //int x = n; 6964 //func(n); 6965 } 6966 6967 ///The proxied value must be an $(B lvalue). 6968 @safe unittest 6969 { 6970 struct NewIntType 6971 { 6972 //Won't work; the literal '1' 6973 //is an rvalue, not an lvalue 6974 //mixin Proxy!1; 6975 6976 //Okay, n is an lvalue 6977 int n; 6978 mixin Proxy!n; 6979 6980 this(int n) { this.n = n; } 6981 } 6982 6983 NewIntType nit = 0; 6984 nit++; 6985 assert(nit == 1); 6986 6987 6988 struct NewObjectType 6989 { 6990 Object obj; 6991 //Ok, obj is an lvalue 6992 mixin Proxy!obj; 6993 6994 this (Object o) { obj = o; } 6995 } 6996 6997 NewObjectType not = new Object(); 6998 assert(__traits(compiles, not.toHash())); 6999 } 7000 7001 /** 7002 There is one exception to the fact that the new type is not related to the 7003 old type. $(DDSUBLINK spec/function,pseudo-member, Pseudo-member) 7004 functions are usable with the new type; they will be forwarded on to the 7005 proxied value. 7006 */ 7007 @safe unittest 7008 { 7009 import std.math; 7010 7011 float f = 1.0; 7012 assert(!f.isInfinity); 7013 7014 struct NewFloat 7015 { 7016 float _; 7017 mixin Proxy!_; 7018 7019 this(float f) { _ = f; } 7020 } 7021 7022 NewFloat nf = 1.0f; 7023 assert(!nf.isInfinity); 7024 } 7025 7026 @safe unittest 7027 { 7028 static struct MyInt 7029 { 7030 private int value; 7031 mixin Proxy!value; 7032 this(int n) inout { value = n; } 7033 7034 enum str = "str"; 7035 static immutable arr = [1,2,3]; 7036 } 7037 7038 static foreach (T; AliasSeq!(MyInt, const MyInt, immutable MyInt)) 7039 {{ 7040 T m = 10; 7041 static assert(!__traits(compiles, { int x = m; })); 7042 static assert(!__traits(compiles, { void func(int n){} func(m); })); 7043 assert(m == 10); 7044 assert(m != 20); 7045 assert(m < 20); 7046 assert(+m == 10); 7047 assert(-m == -10); 7048 assert(cast(double) m == 10.0); 7049 assert(m + 10 == 20); 7050 assert(m - 5 == 5); 7051 assert(m * 20 == 200); 7052 assert(m / 2 == 5); 7053 assert(10 + m == 20); 7054 assert(15 - m == 5); 7055 assert(20 * m == 200); 7056 assert(50 / m == 5); 7057 static if (is(T == MyInt)) // mutable 7058 { 7059 assert(++m == 11); 7060 assert(m++ == 11); assert(m == 12); 7061 assert(--m == 11); 7062 assert(m-- == 11); assert(m == 10); 7063 m = m; 7064 m = 20; assert(m == 20); 7065 } 7066 static assert(T.max == int.max); 7067 static assert(T.min == int.min); 7068 static assert(T.init == int.init); 7069 static assert(T.str == "str"); 7070 static assert(T.arr == [1,2,3]); 7071 }} 7072 } 7073 @system unittest 7074 { 7075 static struct MyArray 7076 { 7077 private int[] value; 7078 mixin Proxy!value; 7079 this(int[] arr) { value = arr; } 7080 this(immutable int[] arr) immutable { value = arr; } 7081 } 7082 7083 static foreach (T; AliasSeq!(MyArray, const MyArray, immutable MyArray)) 7084 {{ 7085 static if (is(T == immutable) && !is(typeof({ T a = [1,2,3,4]; }))) 7086 T a = [1,2,3,4].idup; // workaround until qualified ctor is properly supported 7087 else 7088 T a = [1,2,3,4]; 7089 assert(a == [1,2,3,4]); 7090 assert(a != [5,6,7,8]); 7091 assert(+a[0] == 1); 7092 version (LittleEndian) 7093 assert(cast(ulong[]) a == [0x0000_0002_0000_0001, 0x0000_0004_0000_0003]); 7094 else 7095 assert(cast(ulong[]) a == [0x0000_0001_0000_0002, 0x0000_0003_0000_0004]); 7096 assert(a ~ [10,11] == [1,2,3,4,10,11]); 7097 assert(a[0] == 1); 7098 assert(a[] == [1,2,3,4]); 7099 assert(a[2 .. 4] == [3,4]); 7100 static if (is(T == MyArray)) // mutable 7101 { 7102 a = a; 7103 a = [5,6,7,8]; assert(a == [5,6,7,8]); 7104 a[0] = 0; assert(a == [0,6,7,8]); 7105 a[] = 1; assert(a == [1,1,1,1]); 7106 a[0 .. 3] = 2; assert(a == [2,2,2,1]); 7107 a[0] += 2; assert(a == [4,2,2,1]); 7108 a[] *= 2; assert(a == [8,4,4,2]); 7109 a[0 .. 2] /= 2; assert(a == [4,2,4,2]); 7110 } 7111 }} 7112 } 7113 @system unittest 7114 { 7115 class Foo 7116 { 7117 int field; 7118 7119 @property int val1() const { return field; } 7120 @property void val1(int n) { field = n; } 7121 7122 @property ref int val2() { return field; } 7123 7124 int func(int x, int y) const { return x; } 7125 void func1(ref int a) { a = 9; } 7126 7127 T ifti1(T)(T t) { return t; } 7128 void ifti2(Args...)(Args args) { } 7129 void ifti3(T, Args...)(Args args) { } 7130 7131 T opCast(T)(){ return T.init; } 7132 7133 T tempfunc(T)() { return T.init; } 7134 } 7135 class Hoge 7136 { 7137 Foo foo; 7138 mixin Proxy!foo; 7139 this(Foo f) { foo = f; } 7140 } 7141 7142 auto h = new Hoge(new Foo()); 7143 int n; 7144 7145 static assert(!__traits(compiles, { Foo f = h; })); 7146 7147 // field 7148 h.field = 1; // lhs of assign 7149 n = h.field; // rhs of assign 7150 assert(h.field == 1); // lhs of BinExp 7151 assert(1 == h.field); // rhs of BinExp 7152 assert(n == 1); 7153 7154 // getter/setter property function 7155 h.val1 = 4; 7156 n = h.val1; 7157 assert(h.val1 == 4); 7158 assert(4 == h.val1); 7159 assert(n == 4); 7160 7161 // ref getter property function 7162 h.val2 = 8; 7163 n = h.val2; 7164 assert(h.val2 == 8); 7165 assert(8 == h.val2); 7166 assert(n == 8); 7167 7168 // member function 7169 assert(h.func(2,4) == 2); 7170 h.func1(n); 7171 assert(n == 9); 7172 7173 // IFTI 7174 assert(h.ifti1(4) == 4); 7175 h.ifti2(4); 7176 h.ifti3!int(4, 3); 7177 7178 // https://issues.dlang.org/show_bug.cgi?id=5896 test 7179 assert(h.opCast!int() == 0); 7180 assert(cast(int) h == 0); 7181 const ih = new const Hoge(new Foo()); 7182 static assert(!__traits(compiles, ih.opCast!int())); 7183 static assert(!__traits(compiles, cast(int) ih)); 7184 7185 // template member function 7186 assert(h.tempfunc!int() == 0); 7187 } 7188 7189 @system unittest // about Proxy inside a class 7190 { 7191 class MyClass 7192 { 7193 int payload; 7194 mixin Proxy!payload; 7195 this(int i){ payload = i; } 7196 string opCall(string msg){ return msg; } 7197 int pow(int i){ return payload ^^ i; } 7198 } 7199 7200 class MyClass2 7201 { 7202 MyClass payload; 7203 mixin Proxy!payload; 7204 this(int i){ payload = new MyClass(i); } 7205 } 7206 7207 class MyClass3 7208 { 7209 int payload; 7210 mixin Proxy!payload; 7211 this(int i){ payload = i; } 7212 } 7213 7214 // opEquals 7215 Object a = new MyClass(5); 7216 Object b = new MyClass(5); 7217 Object c = new MyClass2(5); 7218 Object d = new MyClass3(5); 7219 assert(a == b); 7220 assert((cast(MyClass) a) == 5); 7221 assert(5 == (cast(MyClass) b)); 7222 assert(5 == cast(MyClass2) c); 7223 assert(a != d); 7224 7225 assert(c != a); 7226 // oops! above line is unexpected, isn't it? 7227 // the reason is below. 7228 // MyClass2.opEquals knows MyClass but, 7229 // MyClass.opEquals doesn't know MyClass2. 7230 // so, c.opEquals(a) is true, but a.opEquals(c) is false. 7231 // furthermore, opEquals(T) couldn't be invoked. 7232 assert((cast(MyClass2) c) != (cast(MyClass) a)); 7233 7234 // opCmp 7235 Object e = new MyClass2(7); 7236 assert(a < cast(MyClass2) e); // OK. and 7237 assert(e > a); // OK, but... 7238 // assert(a < e); // RUNTIME ERROR! 7239 // assert((cast(MyClass) a) < e); // RUNTIME ERROR! 7240 assert(3 < cast(MyClass) a); 7241 assert((cast(MyClass2) e) < 11); 7242 7243 // opCall 7244 assert((cast(MyClass2) e)("hello") == "hello"); 7245 7246 // opCast 7247 assert((cast(MyClass)(cast(MyClass2) c)) == a); 7248 assert((cast(int)(cast(MyClass2) c)) == 5); 7249 7250 // opIndex 7251 class MyClass4 7252 { 7253 string payload; 7254 mixin Proxy!payload; 7255 this(string s){ payload = s; } 7256 } 7257 class MyClass5 7258 { 7259 MyClass4 payload; 7260 mixin Proxy!payload; 7261 this(string s){ payload = new MyClass4(s); } 7262 } 7263 auto f = new MyClass4("hello"); 7264 assert(f[1] == 'e'); 7265 auto g = new MyClass5("hello"); 7266 assert(f[1] == 'e'); 7267 7268 // opSlice 7269 assert(f[2 .. 4] == "ll"); 7270 7271 // opUnary 7272 assert(-(cast(MyClass2) c) == -5); 7273 7274 // opBinary 7275 assert((cast(MyClass) a) + (cast(MyClass2) c) == 10); 7276 assert(5 + cast(MyClass) a == 10); 7277 7278 // opAssign 7279 (cast(MyClass2) c) = 11; 7280 assert((cast(MyClass2) c) == 11); 7281 (cast(MyClass2) c) = new MyClass(13); 7282 assert((cast(MyClass2) c) == 13); 7283 7284 // opOpAssign 7285 assert((cast(MyClass2) c) += 4); 7286 assert((cast(MyClass2) c) == 17); 7287 7288 // opDispatch 7289 assert((cast(MyClass2) c).pow(2) == 289); 7290 7291 // opDollar 7292 assert(f[2..$-1] == "ll"); 7293 7294 // toHash 7295 int[Object] hash; 7296 hash[a] = 19; 7297 hash[c] = 21; 7298 assert(hash[b] == 19); 7299 assert(hash[c] == 21); 7300 } 7301 7302 @safe unittest 7303 { 7304 struct MyInt 7305 { 7306 int payload; 7307 7308 mixin Proxy!payload; 7309 } 7310 7311 MyInt v; 7312 v = v; 7313 7314 struct Foo 7315 { 7316 @disable void opAssign(typeof(this)); 7317 } 7318 struct MyFoo 7319 { 7320 Foo payload; 7321 7322 mixin Proxy!payload; 7323 } 7324 MyFoo f; 7325 static assert(!__traits(compiles, f = f)); 7326 7327 struct MyFoo2 7328 { 7329 Foo payload; 7330 7331 mixin Proxy!payload; 7332 7333 // override default Proxy behavior 7334 void opAssign(typeof(this) rhs){} 7335 } 7336 MyFoo2 f2; 7337 f2 = f2; 7338 } 7339 7340 // https://issues.dlang.org/show_bug.cgi?id=8613 7341 @safe unittest 7342 { 7343 static struct Name 7344 { 7345 mixin Proxy!val; 7346 private string val; 7347 this(string s) { val = s; } 7348 } 7349 7350 bool[Name] names; 7351 names[Name("a")] = true; 7352 bool* b = Name("a") in names; 7353 } 7354 7355 // workaround for https://issues.dlang.org/show_bug.cgi?id=19669 7356 private enum isDIP1000 = __traits(compiles, () @safe { 7357 int x; 7358 int* p; 7359 p = &x; 7360 }); 7361 // excludes struct S; it's 'mixin Proxy!foo' doesn't compile with -dip1000 7362 static if (isDIP1000) {} else 7363 @system unittest 7364 { 7365 // https://issues.dlang.org/show_bug.cgi?id=14213 7366 // using function for the payload 7367 static struct S 7368 { 7369 int foo() { return 12; } 7370 mixin Proxy!foo; 7371 } 7372 S s; 7373 assert(s + 1 == 13); 7374 assert(s * 2 == 24); 7375 } 7376 7377 @system unittest 7378 { 7379 static class C 7380 { 7381 int foo() { return 12; } 7382 mixin Proxy!foo; 7383 } 7384 C c = new C(); 7385 } 7386 7387 // Check all floating point comparisons for both Proxy and Typedef, 7388 // also against int and a Typedef!int, to be as regression-proof 7389 // as possible. https://issues.dlang.org/show_bug.cgi?id=15561 7390 @safe unittest 7391 { 7392 static struct MyFloatImpl 7393 { 7394 float value; 7395 mixin Proxy!value; 7396 } 7397 static void allFail(T0, T1)(T0 a, T1 b) 7398 { 7399 assert(!(a == b)); 7400 assert(!(a<b)); 7401 assert(!(a <= b)); 7402 assert(!(a>b)); 7403 assert(!(a >= b)); 7404 } 7405 static foreach (T1; AliasSeq!(MyFloatImpl, Typedef!float, Typedef!double, 7406 float, real, Typedef!int, int)) 7407 { 7408 static foreach (T2; AliasSeq!(MyFloatImpl, Typedef!float)) 7409 {{ 7410 T1 a; 7411 T2 b; 7412 7413 static if (isFloatingPoint!T1 || isFloatingPoint!(TypedefType!T1)) 7414 allFail(a, b); 7415 a = 3; 7416 allFail(a, b); 7417 7418 b = 4; 7419 assert(a != b); 7420 assert(a<b); 7421 assert(a <= b); 7422 assert(!(a>b)); 7423 assert(!(a >= b)); 7424 7425 a = 4; 7426 assert(a == b); 7427 assert(!(a<b)); 7428 assert(a <= b); 7429 assert(!(a>b)); 7430 assert(a >= b); 7431 }} 7432 } 7433 } 7434 7435 /** 7436 $(B Typedef) allows the creation of a unique type which is 7437 based on an existing type. Unlike the `alias` feature, 7438 $(B Typedef) ensures the two types are not considered as equals. 7439 7440 Params: 7441 7442 init = Optional initial value for the new type. 7443 cookie = Optional, used to create multiple unique types which are 7444 based on the same origin type `T` 7445 7446 Note: If a library routine cannot handle the Typedef type, 7447 you can use the `TypedefType` template to extract the 7448 type which the Typedef wraps. 7449 */ 7450 struct Typedef(T, T init = T.init, string cookie=null) 7451 { 7452 private T Typedef_payload = init; 7453 7454 // https://issues.dlang.org/show_bug.cgi?id=18415 7455 // prevent default construction if original type does too. 7456 static if ((is(T == struct) || is(T == union)) && !is(typeof({T t;}))) 7457 { 7458 @disable this(); 7459 } 7460 7461 this(T init) 7462 { 7463 Typedef_payload = init; 7464 } 7465 7466 this(Typedef tdef) 7467 { 7468 this(tdef.Typedef_payload); 7469 } 7470 7471 // We need to add special overload for cast(Typedef!X) exp, 7472 // thus we can't simply inherit Proxy!Typedef_payload 7473 T2 opCast(T2 : Typedef!(T, Unused), this X, T, Unused...)() 7474 { 7475 return T2(cast(T) Typedef_payload); 7476 } 7477 7478 auto ref opCast(T2, this X)() 7479 { 7480 return cast(T2) Typedef_payload; 7481 } 7482 7483 mixin Proxy!Typedef_payload; 7484 7485 pure nothrow @nogc @safe @property 7486 { 7487 alias TD = typeof(this); 7488 static if (isIntegral!T) 7489 { 7490 static TD min() {return TD(T.min);} 7491 static TD max() {return TD(T.max);} 7492 } 7493 else static if (isFloatingPoint!T) 7494 { 7495 static TD infinity() {return TD(T.infinity);} 7496 static TD nan() {return TD(T.nan);} 7497 static TD dig() {return TD(T.dig);} 7498 static TD epsilon() {return TD(T.epsilon);} 7499 static TD mant_dig() {return TD(T.mant_dig);} 7500 static TD max_10_exp() {return TD(T.max_10_exp);} 7501 static TD max_exp() {return TD(T.max_exp);} 7502 static TD min_10_exp() {return TD(T.min_10_exp);} 7503 static TD min_exp() {return TD(T.min_exp);} 7504 static TD max() {return TD(T.max);} 7505 static TD min_normal() {return TD(T.min_normal);} 7506 TD re() {return TD(Typedef_payload.re);} 7507 TD im() {return TD(Typedef_payload.im);} 7508 } 7509 } 7510 7511 /** 7512 * Convert wrapped value to a human readable string 7513 */ 7514 string toString(this T)() 7515 { 7516 import std.array : appender; 7517 auto app = appender!string(); 7518 auto spec = singleSpec("%s"); 7519 toString(app, spec); 7520 return app.data; 7521 } 7522 7523 /// ditto 7524 void toString(this T, W)(ref W writer, scope const ref FormatSpec!char fmt) 7525 if (isOutputRange!(W, char)) 7526 { 7527 formatValue(writer, Typedef_payload, fmt); 7528 } 7529 7530 /// 7531 @safe unittest 7532 { 7533 import std.conv : to; 7534 7535 int i = 123; 7536 auto td = Typedef!int(i); 7537 assert(i.to!string == td.to!string); 7538 } 7539 } 7540 7541 /// 7542 @safe unittest 7543 { 7544 alias MyInt = Typedef!int; 7545 MyInt foo = 10; 7546 foo++; 7547 assert(foo == 11); 7548 } 7549 7550 /// custom initialization values 7551 @safe unittest 7552 { 7553 alias MyIntInit = Typedef!(int, 42); 7554 static assert(is(TypedefType!MyIntInit == int)); 7555 static assert(MyIntInit() == 42); 7556 } 7557 7558 /// Typedef creates a new type 7559 @safe unittest 7560 { 7561 alias MyInt = Typedef!int; 7562 static void takeInt(int) {} 7563 static void takeMyInt(MyInt) {} 7564 7565 int i; 7566 takeInt(i); // ok 7567 static assert(!__traits(compiles, takeMyInt(i))); 7568 7569 MyInt myInt; 7570 static assert(!__traits(compiles, takeInt(myInt))); 7571 takeMyInt(myInt); // ok 7572 } 7573 7574 /// Use the optional `cookie` argument to create different types of the same base type 7575 @safe unittest 7576 { 7577 alias TypeInt1 = Typedef!int; 7578 alias TypeInt2 = Typedef!int; 7579 7580 // The two Typedefs are the same type. 7581 static assert(is(TypeInt1 == TypeInt2)); 7582 7583 alias MoneyEuros = Typedef!(float, float.init, "euros"); 7584 alias MoneyDollars = Typedef!(float, float.init, "dollars"); 7585 7586 // The two Typedefs are _not_ the same type. 7587 static assert(!is(MoneyEuros == MoneyDollars)); 7588 } 7589 7590 // https://issues.dlang.org/show_bug.cgi?id=12461 7591 @safe unittest 7592 { 7593 alias Int = Typedef!int; 7594 7595 Int a, b; 7596 a += b; 7597 assert(a == 0); 7598 } 7599 7600 /** 7601 Get the underlying type which a `Typedef` wraps. 7602 If `T` is not a `Typedef` it will alias itself to `T`. 7603 */ 7604 template TypedefType(T) 7605 { 7606 static if (is(T : Typedef!Arg, Arg)) 7607 alias TypedefType = Arg; 7608 else 7609 alias TypedefType = T; 7610 } 7611 7612 /// 7613 @safe unittest 7614 { 7615 import std.conv : to; 7616 7617 alias MyInt = Typedef!int; 7618 static assert(is(TypedefType!MyInt == int)); 7619 7620 /// Instantiating with a non-Typedef will return that type 7621 static assert(is(TypedefType!int == int)); 7622 7623 string num = "5"; 7624 7625 // extract the needed type 7626 MyInt myInt = MyInt( num.to!(TypedefType!MyInt) ); 7627 assert(myInt == 5); 7628 7629 // cast to the underlying type to get the value that's being wrapped 7630 int x = cast(TypedefType!MyInt) myInt; 7631 7632 alias MyIntInit = Typedef!(int, 42); 7633 static assert(is(TypedefType!MyIntInit == int)); 7634 static assert(MyIntInit() == 42); 7635 } 7636 7637 @safe unittest 7638 { 7639 Typedef!int x = 10; 7640 static assert(!__traits(compiles, { int y = x; })); 7641 static assert(!__traits(compiles, { long z = x; })); 7642 7643 Typedef!int y = 10; 7644 assert(x == y); 7645 7646 static assert(Typedef!int.init == int.init); 7647 7648 Typedef!(float, 1.0) z; // specifies the init 7649 assert(z == 1.0); 7650 7651 static assert(typeof(z).init == 1.0); 7652 7653 alias Dollar = Typedef!(int, 0, "dollar"); 7654 alias Yen = Typedef!(int, 0, "yen"); 7655 static assert(!is(Dollar == Yen)); 7656 7657 Typedef!(int[3]) sa; 7658 static assert(sa.length == 3); 7659 static assert(typeof(sa).length == 3); 7660 7661 Typedef!(int[3]) dollar1; 7662 assert(dollar1[0..$] is dollar1[0 .. 3]); 7663 7664 Typedef!(int[]) dollar2; 7665 dollar2.length = 3; 7666 assert(dollar2[0..$] is dollar2[0 .. 3]); 7667 7668 static struct Dollar1 7669 { 7670 static struct DollarToken {} 7671 enum opDollar = DollarToken.init; 7672 auto opSlice(size_t, DollarToken) { return 1; } 7673 auto opSlice(size_t, size_t) { return 2; } 7674 } 7675 7676 Typedef!Dollar1 drange1; 7677 assert(drange1[0..$] == 1); 7678 assert(drange1[0 .. 1] == 2); 7679 7680 static struct Dollar2 7681 { 7682 size_t opDollar(size_t pos)() { return pos == 0 ? 1 : 100; } 7683 size_t opIndex(size_t i, size_t j) { return i + j; } 7684 } 7685 7686 Typedef!Dollar2 drange2; 7687 assert(drange2[$, $] == 101); 7688 7689 static struct Dollar3 7690 { 7691 size_t opDollar() { return 123; } 7692 size_t opIndex(size_t i) { return i; } 7693 } 7694 7695 Typedef!Dollar3 drange3; 7696 assert(drange3[$] == 123); 7697 } 7698 7699 // https://issues.dlang.org/show_bug.cgi?id=18415 7700 @safe @nogc pure nothrow unittest 7701 { 7702 struct NoDefCtorS{@disable this();} 7703 union NoDefCtorU{@disable this();} 7704 static assert(!is(typeof({Typedef!NoDefCtorS s;}))); 7705 static assert(!is(typeof({Typedef!NoDefCtorU u;}))); 7706 } 7707 7708 // https://issues.dlang.org/show_bug.cgi?id=11703 7709 @safe @nogc pure nothrow unittest 7710 { 7711 alias I = Typedef!int; 7712 static assert(is(typeof(I.min) == I)); 7713 static assert(is(typeof(I.max) == I)); 7714 7715 alias F = Typedef!double; 7716 static assert(is(typeof(F.infinity) == F)); 7717 static assert(is(typeof(F.epsilon) == F)); 7718 7719 F f; 7720 assert(!is(typeof(F.re).stringof == double)); 7721 assert(!is(typeof(F.im).stringof == double)); 7722 } 7723 7724 @safe unittest 7725 { 7726 // https://issues.dlang.org/show_bug.cgi?id=8655 7727 import std.typecons; 7728 import std.bitmanip; 7729 static import core.stdc.config; 7730 7731 alias c_ulong = Typedef!(core.stdc.config.c_ulong); 7732 7733 static struct Foo 7734 { 7735 mixin(bitfields!( 7736 c_ulong, "NameOffset", 31, 7737 c_ulong, "NameIsString", 1 7738 )); 7739 } 7740 } 7741 7742 // https://issues.dlang.org/show_bug.cgi?id=12596 7743 @safe unittest 7744 { 7745 import std.typecons; 7746 alias TD = Typedef!int; 7747 TD x = TD(1); 7748 TD y = TD(x); 7749 assert(x == y); 7750 } 7751 7752 @safe unittest // about toHash 7753 { 7754 import std.typecons; 7755 { 7756 alias TD = Typedef!int; 7757 int[TD] td; 7758 td[TD(1)] = 1; 7759 assert(td[TD(1)] == 1); 7760 } 7761 7762 { 7763 alias TD = Typedef!(int[]); 7764 int[TD] td; 7765 td[TD([1,2,3,4])] = 2; 7766 assert(td[TD([1,2,3,4])] == 2); 7767 } 7768 7769 { 7770 alias TD = Typedef!(int[][]); 7771 int[TD] td; 7772 td[TD([[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]])] = 3; 7773 assert(td[TD([[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]])] == 3); 7774 } 7775 7776 { 7777 struct MyStruct{ int x; } 7778 alias TD = Typedef!MyStruct; 7779 int[TD] td; 7780 td[TD(MyStruct(10))] = 4; 7781 assert(TD(MyStruct(20)) !in td); 7782 assert(td[TD(MyStruct(10))] == 4); 7783 } 7784 7785 { 7786 static struct MyStruct2 7787 { 7788 int x; 7789 size_t toHash() const nothrow @safe { return x; } 7790 bool opEquals(ref const MyStruct2 r) const { return r.x == x; } 7791 } 7792 7793 alias TD = Typedef!MyStruct2; 7794 int[TD] td; 7795 td[TD(MyStruct2(50))] = 5; 7796 assert(td[TD(MyStruct2(50))] == 5); 7797 } 7798 7799 { 7800 class MyClass{} 7801 alias TD = Typedef!MyClass; 7802 int[TD] td; 7803 auto c = new MyClass; 7804 td[TD(c)] = 6; 7805 assert(TD(new MyClass) !in td); 7806 assert(td[TD(c)] == 6); 7807 } 7808 } 7809 7810 @system unittest 7811 { 7812 alias String = Typedef!(char[]); 7813 alias CString = Typedef!(const(char)[]); 7814 CString cs = "fubar"; 7815 String s = cast(String) cs; 7816 assert(cs == s); 7817 char[] s2 = cast(char[]) cs; 7818 const(char)[] cs2 = cast(const(char)[])s; 7819 assert(s2 == cs2); 7820 } 7821 7822 @system unittest // toString 7823 { 7824 import std.meta : AliasSeq; 7825 import std.conv : to; 7826 7827 struct TestS {} 7828 class TestC {} 7829 7830 static foreach (T; AliasSeq!(int, bool, float, double, real, 7831 char, dchar, wchar, 7832 TestS, TestC, 7833 int*, int[], int[2], int[int])) 7834 {{ 7835 T t; 7836 7837 Typedef!T td; 7838 Typedef!(const T) ctd; 7839 Typedef!(immutable T) itd; 7840 7841 assert(t.to!string() == td.to!string()); 7842 7843 static if (!(is(T == TestS) || is(T == TestC))) 7844 { 7845 assert(t.to!string() == ctd.to!string()); 7846 assert(t.to!string() == itd.to!string()); 7847 } 7848 }} 7849 } 7850 7851 @safe @nogc unittest // typedef'ed type with custom operators 7852 { 7853 static struct MyInt 7854 { 7855 int value; 7856 int opCmp(MyInt other) 7857 { 7858 if (value < other.value) 7859 return -1; 7860 return !(value == other.value); 7861 } 7862 } 7863 7864 auto m1 = Typedef!MyInt(MyInt(1)); 7865 auto m2 = Typedef!MyInt(MyInt(2)); 7866 assert(m1 < m2); 7867 } 7868 7869 /** 7870 Allocates a `class` object right inside the current scope, 7871 therefore avoiding the overhead of `new`. This facility is unsafe; 7872 it is the responsibility of the user to not escape a reference to the 7873 object outside the scope. 7874 7875 The class destructor will be called when the result of `scoped()` is 7876 itself destroyed. 7877 7878 Scoped class instances can be embedded in a parent `class` or `struct`, 7879 just like a child struct instance. Scoped member variables must have 7880 type `typeof(scoped!Class(args))`, and be initialized with a call to 7881 scoped. See below for an example. 7882 7883 Note: 7884 It's illegal to move a class instance even if you are sure there 7885 are no pointers to it. As such, it is illegal to move a scoped object. 7886 */ 7887 template scoped(T) 7888 if (is(T == class)) 7889 { 7890 // _d_newclass now use default GC alignment (looks like (void*).sizeof * 2 for 7891 // small objects). We will just use the maximum of filed alignments. 7892 alias alignment = classInstanceAlignment!T; 7893 alias aligned = _alignUp!alignment; 7894 7895 static struct Scoped 7896 { 7897 // Addition of `alignment` is required as `Scoped_store` can be misaligned in memory. 7898 private void[aligned(__traits(classInstanceSize, T) + size_t.sizeof) + alignment] Scoped_store = void; 7899 7900 @property inout(T) Scoped_payload() inout 7901 { 7902 void* alignedStore = cast(void*) aligned(cast(size_t) Scoped_store.ptr); 7903 // As `Scoped` can be unaligned moved in memory class instance should be moved accordingly. 7904 immutable size_t d = alignedStore - Scoped_store.ptr; 7905 size_t* currD = cast(size_t*) &Scoped_store[$ - size_t.sizeof]; 7906 if (d != *currD) 7907 { 7908 import core.stdc..string : memmove; 7909 memmove(alignedStore, Scoped_store.ptr + *currD, __traits(classInstanceSize, T)); 7910 *currD = d; 7911 } 7912 return cast(inout(T)) alignedStore; 7913 } 7914 alias Scoped_payload this; 7915 7916 @disable this(); 7917 @disable this(this); 7918 7919 ~this() 7920 { 7921 // `destroy` will also write .init but we have no functions in druntime 7922 // for deterministic finalization and memory releasing for now. 7923 .destroy(Scoped_payload); 7924 } 7925 } 7926 7927 /** Returns the _scoped object. 7928 Params: args = Arguments to pass to `T`'s constructor. 7929 */ 7930 @system auto scoped(Args...)(auto ref Args args) 7931 { 7932 import std.conv : emplace; 7933 7934 Scoped result = void; 7935 void* alignedStore = cast(void*) aligned(cast(size_t) result.Scoped_store.ptr); 7936 immutable size_t d = alignedStore - result.Scoped_store.ptr; 7937 *cast(size_t*) &result.Scoped_store[$ - size_t.sizeof] = d; 7938 emplace!(Unqual!T)(result.Scoped_store[d .. $ - size_t.sizeof], args); 7939 return result; 7940 } 7941 } 7942 7943 /// 7944 @system unittest 7945 { 7946 class A 7947 { 7948 int x; 7949 this() {x = 0;} 7950 this(int i){x = i;} 7951 ~this() {} 7952 } 7953 7954 // Standard usage, constructing A on the stack 7955 auto a1 = scoped!A(); 7956 a1.x = 42; 7957 7958 // Result of `scoped` call implicitly converts to a class reference 7959 A aRef = a1; 7960 assert(aRef.x == 42); 7961 7962 // Scoped destruction 7963 { 7964 auto a2 = scoped!A(1); 7965 assert(a2.x == 1); 7966 aRef = a2; 7967 // a2 is destroyed here, calling A's destructor 7968 } 7969 // aRef is now an invalid reference 7970 7971 // Here the temporary scoped A is immediately destroyed. 7972 // This means the reference is then invalid. 7973 version (Bug) 7974 { 7975 // Wrong, should use `auto` 7976 A invalid = scoped!A(); 7977 } 7978 7979 // Restrictions 7980 version (Bug) 7981 { 7982 import std.algorithm.mutation : move; 7983 auto invalid = a1.move; // illegal, scoped objects can't be moved 7984 } 7985 static assert(!is(typeof({ 7986 auto e1 = a1; // illegal, scoped objects can't be copied 7987 assert([a1][0].x == 42); // ditto 7988 }))); 7989 static assert(!is(typeof({ 7990 alias ScopedObject = typeof(a1); 7991 auto e2 = ScopedObject(); // illegal, must be built via scoped!A 7992 auto e3 = ScopedObject(1); // ditto 7993 }))); 7994 7995 // Use with alias 7996 alias makeScopedA = scoped!A; 7997 auto a3 = makeScopedA(); 7998 auto a4 = makeScopedA(1); 7999 8000 // Use as member variable 8001 struct B 8002 { 8003 typeof(scoped!A()) a; // note the trailing parentheses 8004 8005 this(int i) 8006 { 8007 // construct member 8008 a = scoped!A(i); 8009 } 8010 } 8011 8012 // Stack-allocate 8013 auto b1 = B(5); 8014 aRef = b1.a; 8015 assert(aRef.x == 5); 8016 destroy(b1); // calls A's destructor for b1.a 8017 // aRef is now an invalid reference 8018 8019 // Heap-allocate 8020 auto b2 = new B(6); 8021 assert(b2.a.x == 6); 8022 destroy(*b2); // calls A's destructor for b2.a 8023 } 8024 8025 private size_t _alignUp(size_t alignment)(size_t n) 8026 if (alignment > 0 && !((alignment - 1) & alignment)) 8027 { 8028 enum badEnd = alignment - 1; // 0b11, 0b111, ... 8029 return (n + badEnd) & ~badEnd; 8030 } 8031 8032 // https://issues.dlang.org/show_bug.cgi?id=6580 testcase 8033 @system unittest 8034 { 8035 enum alignment = (void*).alignof; 8036 8037 static class C0 { } 8038 static class C1 { byte b; } 8039 static class C2 { byte[2] b; } 8040 static class C3 { byte[3] b; } 8041 static class C7 { byte[7] b; } 8042 static assert(scoped!C0().sizeof % alignment == 0); 8043 static assert(scoped!C1().sizeof % alignment == 0); 8044 static assert(scoped!C2().sizeof % alignment == 0); 8045 static assert(scoped!C3().sizeof % alignment == 0); 8046 static assert(scoped!C7().sizeof % alignment == 0); 8047 8048 enum longAlignment = long.alignof; 8049 static class C1long 8050 { 8051 long long_; byte byte_ = 4; 8052 this() { } 8053 this(long _long, ref int i) { long_ = _long; ++i; } 8054 } 8055 static class C2long { byte[2] byte_ = [5, 6]; long long_ = 7; } 8056 static assert(scoped!C1long().sizeof % longAlignment == 0); 8057 static assert(scoped!C2long().sizeof % longAlignment == 0); 8058 8059 void alignmentTest() 8060 { 8061 int var = 5; 8062 auto c1long = scoped!C1long(3, var); 8063 assert(var == 6); 8064 auto c2long = scoped!C2long(); 8065 assert(cast(uint)&c1long.long_ % longAlignment == 0); 8066 assert(cast(uint)&c2long.long_ % longAlignment == 0); 8067 assert(c1long.long_ == 3 && c1long.byte_ == 4); 8068 assert(c2long.byte_ == [5, 6] && c2long.long_ == 7); 8069 } 8070 8071 alignmentTest(); 8072 8073 version (DigitalMars) 8074 { 8075 void test(size_t size) 8076 { 8077 import core.stdc.stdlib; 8078 alloca(size); 8079 alignmentTest(); 8080 } 8081 foreach (i; 0 .. 10) 8082 test(i); 8083 } 8084 else 8085 { 8086 void test(size_t size)() 8087 { 8088 byte[size] arr; 8089 alignmentTest(); 8090 } 8091 static foreach (i; 0 .. 11) 8092 test!i(); 8093 } 8094 } 8095 8096 // Original https://issues.dlang.org/show_bug.cgi?id=6580 testcase 8097 @system unittest 8098 { 8099 class C { int i; byte b; } 8100 8101 auto sa = [scoped!C(), scoped!C()]; 8102 assert(cast(uint)&sa[0].i % int.alignof == 0); 8103 assert(cast(uint)&sa[1].i % int.alignof == 0); // fails 8104 } 8105 8106 @system unittest 8107 { 8108 class A { int x = 1; } 8109 auto a1 = scoped!A(); 8110 assert(a1.x == 1); 8111 auto a2 = scoped!A(); 8112 a1.x = 42; 8113 a2.x = 53; 8114 assert(a1.x == 42); 8115 } 8116 8117 @system unittest 8118 { 8119 class A { int x = 1; this() { x = 2; } } 8120 auto a1 = scoped!A(); 8121 assert(a1.x == 2); 8122 auto a2 = scoped!A(); 8123 a1.x = 42; 8124 a2.x = 53; 8125 assert(a1.x == 42); 8126 } 8127 8128 @system unittest 8129 { 8130 class A { int x = 1; this(int y) { x = y; } ~this() {} } 8131 auto a1 = scoped!A(5); 8132 assert(a1.x == 5); 8133 auto a2 = scoped!A(42); 8134 a1.x = 42; 8135 a2.x = 53; 8136 assert(a1.x == 42); 8137 } 8138 8139 @system unittest 8140 { 8141 class A { static bool dead; ~this() { dead = true; } } 8142 class B : A { static bool dead; ~this() { dead = true; } } 8143 { 8144 auto b = scoped!B(); 8145 } 8146 assert(B.dead, "asdasd"); 8147 assert(A.dead, "asdasd"); 8148 } 8149 8150 // https://issues.dlang.org/show_bug.cgi?id=8039 testcase 8151 @system unittest 8152 { 8153 static int dels; 8154 static struct S { ~this(){ ++dels; } } 8155 8156 static class A { S s; } 8157 dels = 0; { scoped!A(); } 8158 assert(dels == 1); 8159 8160 static class B { S[2] s; } 8161 dels = 0; { scoped!B(); } 8162 assert(dels == 2); 8163 8164 static struct S2 { S[3] s; } 8165 static class C { S2[2] s; } 8166 dels = 0; { scoped!C(); } 8167 assert(dels == 6); 8168 8169 static class D: A { S2[2] s; } 8170 dels = 0; { scoped!D(); } 8171 assert(dels == 1+6); 8172 } 8173 8174 @system unittest 8175 { 8176 // https://issues.dlang.org/show_bug.cgi?id=4500 8177 class A 8178 { 8179 this() { a = this; } 8180 this(int i) { a = this; } 8181 A a; 8182 bool check() { return this is a; } 8183 } 8184 8185 auto a1 = scoped!A(); 8186 assert(a1.check()); 8187 8188 auto a2 = scoped!A(1); 8189 assert(a2.check()); 8190 8191 a1.a = a1; 8192 assert(a1.check()); 8193 } 8194 8195 @system unittest 8196 { 8197 static class A 8198 { 8199 static int sdtor; 8200 8201 this() { ++sdtor; assert(sdtor == 1); } 8202 ~this() { assert(sdtor == 1); --sdtor; } 8203 } 8204 8205 interface Bob {} 8206 8207 static class ABob : A, Bob 8208 { 8209 this() { ++sdtor; assert(sdtor == 2); } 8210 ~this() { assert(sdtor == 2); --sdtor; } 8211 } 8212 8213 A.sdtor = 0; 8214 scope(exit) assert(A.sdtor == 0); 8215 auto abob = scoped!ABob(); 8216 } 8217 8218 @safe unittest 8219 { 8220 static class A { this(int) {} } 8221 static assert(!__traits(compiles, scoped!A())); 8222 } 8223 8224 @system unittest 8225 { 8226 static class A { @property inout(int) foo() inout { return 1; } } 8227 8228 auto a1 = scoped!A(); 8229 assert(a1.foo == 1); 8230 static assert(is(typeof(a1.foo) == int)); 8231 8232 auto a2 = scoped!(const(A))(); 8233 assert(a2.foo == 1); 8234 static assert(is(typeof(a2.foo) == const(int))); 8235 8236 auto a3 = scoped!(immutable(A))(); 8237 assert(a3.foo == 1); 8238 static assert(is(typeof(a3.foo) == immutable(int))); 8239 8240 const c1 = scoped!A(); 8241 assert(c1.foo == 1); 8242 static assert(is(typeof(c1.foo) == const(int))); 8243 8244 const c2 = scoped!(const(A))(); 8245 assert(c2.foo == 1); 8246 static assert(is(typeof(c2.foo) == const(int))); 8247 8248 const c3 = scoped!(immutable(A))(); 8249 assert(c3.foo == 1); 8250 static assert(is(typeof(c3.foo) == immutable(int))); 8251 } 8252 8253 @system unittest 8254 { 8255 class C { this(ref int val) { assert(val == 3); ++val; } } 8256 8257 int val = 3; 8258 auto s = scoped!C(val); 8259 assert(val == 4); 8260 } 8261 8262 @system unittest 8263 { 8264 class C 8265 { 8266 this(){} 8267 this(int){} 8268 this(int, int){} 8269 } 8270 alias makeScopedC = scoped!C; 8271 8272 auto a = makeScopedC(); 8273 auto b = makeScopedC(1); 8274 auto c = makeScopedC(1, 1); 8275 8276 static assert(is(typeof(a) == typeof(b))); 8277 static assert(is(typeof(b) == typeof(c))); 8278 } 8279 8280 /** 8281 Defines a simple, self-documenting yes/no flag. This makes it easy for 8282 APIs to define functions accepting flags without resorting to $(D 8283 bool), which is opaque in calls, and without needing to define an 8284 enumerated type separately. Using `Flag!"Name"` instead of $(D 8285 bool) makes the flag's meaning visible in calls. Each yes/no flag has 8286 its own type, which makes confusions and mix-ups impossible. 8287 8288 Example: 8289 8290 Code calling `getLine` (usually far away from its definition) can't be 8291 understood without looking at the documentation, even by users familiar with 8292 the API: 8293 ---- 8294 string getLine(bool keepTerminator) 8295 { 8296 ... 8297 if (keepTerminator) ... 8298 ... 8299 } 8300 ... 8301 auto line = getLine(false); 8302 ---- 8303 8304 Assuming the reverse meaning (i.e. "ignoreTerminator") and inserting the wrong 8305 code compiles and runs with erroneous results. 8306 8307 After replacing the boolean parameter with an instantiation of `Flag`, code 8308 calling `getLine` can be easily read and understood even by people not 8309 fluent with the API: 8310 8311 ---- 8312 string getLine(Flag!"keepTerminator" keepTerminator) 8313 { 8314 ... 8315 if (keepTerminator) ... 8316 ... 8317 } 8318 ... 8319 auto line = getLine(Yes.keepTerminator); 8320 ---- 8321 8322 The structs `Yes` and `No` are provided as shorthand for 8323 `Flag!"Name".yes` and `Flag!"Name".no` and are preferred for brevity and 8324 readability. These convenience structs mean it is usually unnecessary and 8325 counterproductive to create an alias of a `Flag` as a way of avoiding typing 8326 out the full type while specifying the affirmative or negative options. 8327 8328 Passing categorical data by means of unstructured `bool` 8329 parameters is classified under "simple-data coupling" by Steve 8330 McConnell in the $(LUCKY Code Complete) book, along with three other 8331 kinds of coupling. The author argues citing several studies that 8332 coupling has a negative effect on code quality. `Flag` offers a 8333 simple structuring method for passing yes/no flags to APIs. 8334 */ 8335 template Flag(string name) { 8336 /// 8337 enum Flag : bool 8338 { 8339 /** 8340 When creating a value of type `Flag!"Name"`, use $(D 8341 Flag!"Name".no) for the negative option. When using a value 8342 of type `Flag!"Name"`, compare it against $(D 8343 Flag!"Name".no) or just `false` or `0`. */ 8344 no = false, 8345 8346 /** When creating a value of type `Flag!"Name"`, use $(D 8347 Flag!"Name".yes) for the affirmative option. When using a 8348 value of type `Flag!"Name"`, compare it against $(D 8349 Flag!"Name".yes). 8350 */ 8351 yes = true 8352 } 8353 } 8354 8355 /// 8356 @safe unittest 8357 { 8358 Flag!"abc" flag; 8359 8360 assert(flag == Flag!"abc".no); 8361 assert(flag == No.abc); 8362 assert(!flag); 8363 if (flag) assert(0); 8364 } 8365 8366 /// 8367 @safe unittest 8368 { 8369 auto flag = Yes.abc; 8370 8371 assert(flag); 8372 assert(flag == Yes.abc); 8373 if (!flag) assert(0); 8374 if (flag) {} else assert(0); 8375 } 8376 8377 /** 8378 Convenience names that allow using e.g. `Yes.encryption` instead of 8379 `Flag!"encryption".yes` and `No.encryption` instead of $(D 8380 Flag!"encryption".no). 8381 */ 8382 struct Yes 8383 { 8384 template opDispatch(string name) 8385 { 8386 enum opDispatch = Flag!name.yes; 8387 } 8388 } 8389 //template yes(string name) { enum Flag!name yes = Flag!name.yes; } 8390 8391 /// Ditto 8392 struct No 8393 { 8394 template opDispatch(string name) 8395 { 8396 enum opDispatch = Flag!name.no; 8397 } 8398 } 8399 8400 /// 8401 @safe unittest 8402 { 8403 Flag!"abc" flag; 8404 8405 assert(flag == Flag!"abc".no); 8406 assert(flag == No.abc); 8407 assert(!flag); 8408 if (flag) assert(0); 8409 } 8410 8411 /// 8412 @safe unittest 8413 { 8414 auto flag = Yes.abc; 8415 8416 assert(flag); 8417 assert(flag == Yes.abc); 8418 if (!flag) assert(0); 8419 if (flag) {} else assert(0); 8420 } 8421 8422 /** 8423 Detect whether an enum is of integral type and has only "flag" values 8424 (i.e. values with a bit count of exactly 1). 8425 Additionally, a zero value is allowed for compatibility with enums including 8426 a "None" value. 8427 */ 8428 template isBitFlagEnum(E) 8429 { 8430 static if (is(E Base == enum) && isIntegral!Base) 8431 { 8432 enum isBitFlagEnum = (E.min >= 0) && 8433 { 8434 static foreach (immutable flag; EnumMembers!E) 8435 {{ 8436 Base value = flag; 8437 value &= value - 1; 8438 if (value != 0) return false; 8439 }} 8440 return true; 8441 }(); 8442 } 8443 else 8444 { 8445 enum isBitFlagEnum = false; 8446 } 8447 } 8448 8449 /// 8450 @safe pure nothrow unittest 8451 { 8452 enum A 8453 { 8454 None, 8455 A = 1 << 0, 8456 B = 1 << 1, 8457 C = 1 << 2, 8458 D = 1 << 3, 8459 } 8460 8461 static assert(isBitFlagEnum!A); 8462 } 8463 8464 /// Test an enum with default (consecutive) values 8465 @safe pure nothrow unittest 8466 { 8467 enum B 8468 { 8469 A, 8470 B, 8471 C, 8472 D // D == 3 8473 } 8474 8475 static assert(!isBitFlagEnum!B); 8476 } 8477 8478 /// Test an enum with non-integral values 8479 @safe pure nothrow unittest 8480 { 8481 enum C: double 8482 { 8483 A = 1 << 0, 8484 B = 1 << 1 8485 } 8486 8487 static assert(!isBitFlagEnum!C); 8488 } 8489 8490 /** 8491 A typesafe structure for storing combinations of enum values. 8492 8493 This template defines a simple struct to represent bitwise OR combinations of 8494 enum values. It can be used if all the enum values are integral constants with 8495 a bit count of at most 1, or if the `unsafe` parameter is explicitly set to 8496 Yes. 8497 This is much safer than using the enum itself to store 8498 the OR combination, which can produce surprising effects like this: 8499 ---- 8500 enum E 8501 { 8502 A = 1 << 0, 8503 B = 1 << 1 8504 } 8505 E e = E.A | E.B; 8506 // will throw SwitchError 8507 final switch (e) 8508 { 8509 case E.A: 8510 return; 8511 case E.B: 8512 return; 8513 } 8514 ---- 8515 */ 8516 struct BitFlags(E, Flag!"unsafe" unsafe = No.unsafe) 8517 if (unsafe || isBitFlagEnum!(E)) 8518 { 8519 @safe @nogc pure nothrow: 8520 private: 8521 enum isBaseEnumType(T) = is(E == T); 8522 alias Base = OriginalType!E; 8523 Base mValue; 8524 static struct Negation 8525 { 8526 @safe @nogc pure nothrow: 8527 private: 8528 Base mValue; 8529 8530 // Prevent non-copy construction outside the module. 8531 @disable this(); 8532 this(Base value) 8533 { 8534 mValue = value; 8535 } 8536 } 8537 8538 public: 8539 this(E flag) 8540 { 8541 this = flag; 8542 } 8543 8544 this(T...)(T flags) 8545 if (allSatisfy!(isBaseEnumType, T)) 8546 { 8547 this = flags; 8548 } 8549 8550 bool opCast(B: bool)() const 8551 { 8552 return mValue != 0; 8553 } 8554 8555 Base opCast(B)() const 8556 if (isImplicitlyConvertible!(Base, B)) 8557 { 8558 return mValue; 8559 } 8560 8561 Negation opUnary(string op)() const 8562 if (op == "~") 8563 { 8564 return Negation(~mValue); 8565 } 8566 8567 auto ref opAssign(T...)(T flags) 8568 if (allSatisfy!(isBaseEnumType, T)) 8569 { 8570 mValue = 0; 8571 foreach (E flag; flags) 8572 { 8573 mValue |= flag; 8574 } 8575 return this; 8576 } 8577 8578 auto ref opAssign(E flag) 8579 { 8580 mValue = flag; 8581 return this; 8582 } 8583 8584 auto ref opOpAssign(string op: "|")(BitFlags flags) 8585 { 8586 mValue |= flags.mValue; 8587 return this; 8588 } 8589 8590 auto ref opOpAssign(string op: "&")(BitFlags flags) 8591 { 8592 mValue &= flags.mValue; 8593 return this; 8594 } 8595 8596 auto ref opOpAssign(string op: "|")(E flag) 8597 { 8598 mValue |= flag; 8599 return this; 8600 } 8601 8602 auto ref opOpAssign(string op: "&")(E flag) 8603 { 8604 mValue &= flag; 8605 return this; 8606 } 8607 8608 auto ref opOpAssign(string op: "&")(Negation negatedFlags) 8609 { 8610 mValue &= negatedFlags.mValue; 8611 return this; 8612 } 8613 8614 auto opBinary(string op)(BitFlags flags) const 8615 if (op == "|" || op == "&") 8616 { 8617 BitFlags result = this; 8618 result.opOpAssign!op(flags); 8619 return result; 8620 } 8621 8622 auto opBinary(string op)(E flag) const 8623 if (op == "|" || op == "&") 8624 { 8625 BitFlags result = this; 8626 result.opOpAssign!op(flag); 8627 return result; 8628 } 8629 8630 auto opBinary(string op: "&")(Negation negatedFlags) const 8631 { 8632 BitFlags result = this; 8633 result.opOpAssign!op(negatedFlags); 8634 return result; 8635 } 8636 8637 auto opBinaryRight(string op)(E flag) const 8638 if (op == "|" || op == "&") 8639 { 8640 return opBinary!op(flag); 8641 } 8642 8643 bool opDispatch(string name)() const 8644 if (__traits(hasMember, E, name)) 8645 { 8646 enum e = __traits(getMember, E, name); 8647 return (mValue & e) == e; 8648 } 8649 8650 void opDispatch(string name)(bool set) 8651 if (__traits(hasMember, E, name)) 8652 { 8653 enum e = __traits(getMember, E, name); 8654 if (set) 8655 mValue |= e; 8656 else 8657 mValue &= ~e; 8658 } 8659 } 8660 8661 /// Set values with the | operator and test with & 8662 @safe @nogc pure nothrow unittest 8663 { 8664 enum Enum 8665 { 8666 A = 1 << 0, 8667 } 8668 8669 // A default constructed BitFlags has no value set 8670 immutable BitFlags!Enum flags_empty; 8671 assert(!flags_empty.A); 8672 8673 // Value can be set with the | operator 8674 immutable flags_A = flags_empty | Enum.A; 8675 8676 // and tested using property access 8677 assert(flags_A.A); 8678 8679 // or the & operator 8680 assert(flags_A & Enum.A); 8681 // which commutes. 8682 assert(Enum.A & flags_A); 8683 } 8684 8685 /// A default constructed BitFlags has no value set 8686 @safe @nogc pure nothrow unittest 8687 { 8688 enum Enum 8689 { 8690 None, 8691 A = 1 << 0, 8692 B = 1 << 1, 8693 C = 1 << 2 8694 } 8695 8696 immutable BitFlags!Enum flags_empty; 8697 assert(!(flags_empty & (Enum.A | Enum.B | Enum.C))); 8698 assert(!(flags_empty & Enum.A) && !(flags_empty & Enum.B) && !(flags_empty & Enum.C)); 8699 } 8700 8701 // BitFlags can be variadically initialized 8702 @safe @nogc pure nothrow unittest 8703 { 8704 import std.traits : EnumMembers; 8705 8706 enum Enum 8707 { 8708 A = 1 << 0, 8709 B = 1 << 1, 8710 C = 1 << 2 8711 } 8712 8713 // Values can also be set using property access 8714 BitFlags!Enum flags; 8715 flags.A = true; 8716 assert(flags & Enum.A); 8717 flags.A = false; 8718 assert(!(flags & Enum.A)); 8719 8720 // BitFlags can be variadically initialized 8721 immutable BitFlags!Enum flags_AB = BitFlags!Enum(Enum.A, Enum.B); 8722 assert(flags_AB.A && flags_AB.B && !flags_AB.C); 8723 8724 // You can use the EnumMembers template to set all flags 8725 immutable BitFlags!Enum flags_all = EnumMembers!Enum; 8726 assert(flags_all.A && flags_all.B && flags_all.C); 8727 } 8728 8729 /// Binary operations: subtracting and intersecting flags 8730 @safe @nogc pure nothrow unittest 8731 { 8732 enum Enum 8733 { 8734 A = 1 << 0, 8735 B = 1 << 1, 8736 C = 1 << 2, 8737 } 8738 immutable BitFlags!Enum flags_AB = BitFlags!Enum(Enum.A, Enum.B); 8739 immutable BitFlags!Enum flags_BC = BitFlags!Enum(Enum.B, Enum.C); 8740 8741 // Use the ~ operator for subtracting flags 8742 immutable BitFlags!Enum flags_B = flags_AB & ~BitFlags!Enum(Enum.A); 8743 assert(!flags_B.A && flags_B.B && !flags_B.C); 8744 8745 // use & between BitFlags for intersection 8746 assert(flags_B == (flags_BC & flags_AB)); 8747 } 8748 8749 /// All the binary operators work in their assignment version 8750 @safe @nogc pure nothrow unittest 8751 { 8752 enum Enum 8753 { 8754 A = 1 << 0, 8755 B = 1 << 1, 8756 } 8757 8758 BitFlags!Enum flags_empty, temp, flags_AB; 8759 flags_AB = Enum.A | Enum.B; 8760 8761 temp |= flags_AB; 8762 assert(temp == (flags_empty | flags_AB)); 8763 8764 temp = flags_empty; 8765 temp |= Enum.B; 8766 assert(temp == (flags_empty | Enum.B)); 8767 8768 temp = flags_empty; 8769 temp &= flags_AB; 8770 assert(temp == (flags_empty & flags_AB)); 8771 8772 temp = flags_empty; 8773 temp &= Enum.A; 8774 assert(temp == (flags_empty & Enum.A)); 8775 } 8776 8777 /// Conversion to bool and int 8778 @safe @nogc pure nothrow unittest 8779 { 8780 enum Enum 8781 { 8782 A = 1 << 0, 8783 B = 1 << 1, 8784 } 8785 8786 BitFlags!Enum flags; 8787 8788 // BitFlags with no value set evaluate to false 8789 assert(!flags); 8790 8791 // BitFlags with at least one value set evaluate to true 8792 flags |= Enum.A; 8793 assert(flags); 8794 8795 // This can be useful to check intersection between BitFlags 8796 BitFlags!Enum flags_AB = Enum.A | Enum.B; 8797 assert(flags & flags_AB); 8798 assert(flags & Enum.A); 8799 8800 // You can of course get you raw value out of flags 8801 auto value = cast(int) flags; 8802 assert(value == Enum.A); 8803 } 8804 8805 /// You need to specify the `unsafe` parameter for enums with custom values 8806 @safe @nogc pure nothrow unittest 8807 { 8808 enum UnsafeEnum 8809 { 8810 A = 1, 8811 B = 2, 8812 C = 4, 8813 BC = B|C 8814 } 8815 static assert(!__traits(compiles, { BitFlags!UnsafeEnum flags; })); 8816 BitFlags!(UnsafeEnum, Yes.unsafe) flags; 8817 8818 // property access tests for exact match of unsafe enums 8819 flags.B = true; 8820 assert(!flags.BC); // only B 8821 flags.C = true; 8822 assert(flags.BC); // both B and C 8823 flags.B = false; 8824 assert(!flags.BC); // only C 8825 8826 // property access sets all bits of unsafe enum group 8827 flags = flags.init; 8828 flags.BC = true; 8829 assert(!flags.A && flags.B && flags.C); 8830 flags.A = true; 8831 flags.BC = false; 8832 assert(flags.A && !flags.B && !flags.C); 8833 } 8834 8835 private enum false_(T) = false; 8836 8837 // ReplaceType 8838 /** 8839 Replaces all occurrences of `From` into `To`, in one or more types `T`. For 8840 example, `ReplaceType!(int, uint, Tuple!(int, float)[string])` yields 8841 `Tuple!(uint, float)[string]`. The types in which replacement is performed 8842 may be arbitrarily complex, including qualifiers, built-in type constructors 8843 (pointers, arrays, associative arrays, functions, and delegates), and template 8844 instantiations; replacement proceeds transitively through the type definition. 8845 However, member types in `struct`s or `class`es are not replaced because there 8846 are no ways to express the types resulting after replacement. 8847 8848 This is an advanced type manipulation necessary e.g. for replacing the 8849 placeholder type `This` in $(REF Algebraic, std,variant). 8850 8851 Returns: `ReplaceType` aliases itself to the type(s) that result after 8852 replacement. 8853 */ 8854 alias ReplaceType(From, To, T...) = ReplaceTypeUnless!(false_, From, To, T); 8855 8856 /// 8857 @safe unittest 8858 { 8859 static assert( 8860 is(ReplaceType!(int, string, int[]) == string[]) && 8861 is(ReplaceType!(int, string, int[int]) == string[string]) && 8862 is(ReplaceType!(int, string, const(int)[]) == const(string)[]) && 8863 is(ReplaceType!(int, string, Tuple!(int[], float)) 8864 == Tuple!(string[], float)) 8865 ); 8866 } 8867 8868 /** 8869 Like $(LREF ReplaceType), but does not perform replacement in types for which 8870 `pred` evaluates to `true`. 8871 */ 8872 template ReplaceTypeUnless(alias pred, From, To, T...) 8873 { 8874 import std.meta; 8875 8876 static if (T.length == 1) 8877 { 8878 static if (pred!(T[0])) 8879 alias ReplaceTypeUnless = T[0]; 8880 else static if (is(T[0] == From)) 8881 alias ReplaceTypeUnless = To; 8882 else static if (is(T[0] == const(U), U)) 8883 alias ReplaceTypeUnless = const(ReplaceTypeUnless!(pred, From, To, U)); 8884 else static if (is(T[0] == immutable(U), U)) 8885 alias ReplaceTypeUnless = immutable(ReplaceTypeUnless!(pred, From, To, U)); 8886 else static if (is(T[0] == shared(U), U)) 8887 alias ReplaceTypeUnless = shared(ReplaceTypeUnless!(pred, From, To, U)); 8888 else static if (is(T[0] == U*, U)) 8889 { 8890 static if (is(U == function)) 8891 alias ReplaceTypeUnless = replaceTypeInFunctionTypeUnless!(pred, From, To, T[0]); 8892 else 8893 alias ReplaceTypeUnless = ReplaceTypeUnless!(pred, From, To, U)*; 8894 } 8895 else static if (is(T[0] == delegate)) 8896 { 8897 alias ReplaceTypeUnless = replaceTypeInFunctionTypeUnless!(pred, From, To, T[0]); 8898 } 8899 else static if (is(T[0] == function)) 8900 { 8901 static assert(0, "Function types not supported," ~ 8902 " use a function pointer type instead of " ~ T[0].stringof); 8903 } 8904 else static if (is(T[0] == U!V, alias U, V...)) 8905 { 8906 template replaceTemplateArgs(T...) 8907 { 8908 static if (is(typeof(T[0]))) // template argument is value or symbol 8909 enum replaceTemplateArgs = T[0]; 8910 else 8911 alias replaceTemplateArgs = ReplaceTypeUnless!(pred, From, To, T[0]); 8912 } 8913 alias ReplaceTypeUnless = U!(staticMap!(replaceTemplateArgs, V)); 8914 } 8915 else static if (is(T[0] == struct)) 8916 // don't match with alias this struct below 8917 // https://issues.dlang.org/show_bug.cgi?id=15168 8918 alias ReplaceTypeUnless = T[0]; 8919 else static if (is(T[0] == U[], U)) 8920 alias ReplaceTypeUnless = ReplaceTypeUnless!(pred, From, To, U)[]; 8921 else static if (is(T[0] == U[n], U, size_t n)) 8922 alias ReplaceTypeUnless = ReplaceTypeUnless!(pred, From, To, U)[n]; 8923 else static if (is(T[0] == U[V], U, V)) 8924 alias ReplaceTypeUnless = 8925 ReplaceTypeUnless!(pred, From, To, U)[ReplaceTypeUnless!(pred, From, To, V)]; 8926 else 8927 alias ReplaceTypeUnless = T[0]; 8928 } 8929 else static if (T.length > 1) 8930 { 8931 alias ReplaceTypeUnless = AliasSeq!(ReplaceTypeUnless!(pred, From, To, T[0]), 8932 ReplaceTypeUnless!(pred, From, To, T[1 .. $])); 8933 } 8934 else 8935 { 8936 alias ReplaceTypeUnless = AliasSeq!(); 8937 } 8938 } 8939 8940 /// 8941 @safe unittest 8942 { 8943 import std.traits : isArray; 8944 8945 static assert( 8946 is(ReplaceTypeUnless!(isArray, int, string, int*) == string*) && 8947 is(ReplaceTypeUnless!(isArray, int, string, int[]) == int[]) && 8948 is(ReplaceTypeUnless!(isArray, int, string, Tuple!(int, int[])) 8949 == Tuple!(string, int[])) 8950 ); 8951 } 8952 8953 private template replaceTypeInFunctionTypeUnless(alias pred, From, To, fun) 8954 { 8955 alias RX = ReplaceTypeUnless!(pred, From, To, ReturnType!fun); 8956 alias PX = AliasSeq!(ReplaceTypeUnless!(pred, From, To, Parameters!fun)); 8957 // Wrapping with AliasSeq is neccesary because ReplaceType doesn't return 8958 // tuple if Parameters!fun.length == 1 8959 8960 string gen() 8961 { 8962 enum linkage = functionLinkage!fun; 8963 alias attributes = functionAttributes!fun; 8964 enum variadicStyle = variadicFunctionStyle!fun; 8965 alias storageClasses = ParameterStorageClassTuple!fun; 8966 8967 string result; 8968 8969 result ~= "extern(" ~ linkage ~ ") "; 8970 static if (attributes & FunctionAttribute.ref_) 8971 { 8972 result ~= "ref "; 8973 } 8974 8975 result ~= "RX"; 8976 static if (is(fun == delegate)) 8977 result ~= " delegate"; 8978 else 8979 result ~= " function"; 8980 8981 result ~= "("; 8982 static foreach (i; 0 .. PX.length) 8983 { 8984 if (i) 8985 result ~= ", "; 8986 if (storageClasses[i] & ParameterStorageClass.scope_) 8987 result ~= "scope "; 8988 if (storageClasses[i] & ParameterStorageClass.out_) 8989 result ~= "out "; 8990 if (storageClasses[i] & ParameterStorageClass.ref_) 8991 result ~= "ref "; 8992 if (storageClasses[i] & ParameterStorageClass.lazy_) 8993 result ~= "lazy "; 8994 if (storageClasses[i] & ParameterStorageClass.return_) 8995 result ~= "return "; 8996 8997 result ~= "PX[" ~ i.stringof ~ "]"; 8998 } 8999 static if (variadicStyle == Variadic.typesafe) 9000 result ~= " ..."; 9001 else static if (variadicStyle != Variadic.no) 9002 result ~= ", ..."; 9003 result ~= ")"; 9004 9005 static if (attributes & FunctionAttribute.pure_) 9006 result ~= " pure"; 9007 static if (attributes & FunctionAttribute.nothrow_) 9008 result ~= " nothrow"; 9009 static if (attributes & FunctionAttribute.property) 9010 result ~= " @property"; 9011 static if (attributes & FunctionAttribute.trusted) 9012 result ~= " @trusted"; 9013 static if (attributes & FunctionAttribute.safe) 9014 result ~= " @safe"; 9015 static if (attributes & FunctionAttribute.nogc) 9016 result ~= " @nogc"; 9017 static if (attributes & FunctionAttribute.system) 9018 result ~= " @system"; 9019 static if (attributes & FunctionAttribute.const_) 9020 result ~= " const"; 9021 static if (attributes & FunctionAttribute.immutable_) 9022 result ~= " immutable"; 9023 static if (attributes & FunctionAttribute.inout_) 9024 result ~= " inout"; 9025 static if (attributes & FunctionAttribute.shared_) 9026 result ~= " shared"; 9027 static if (attributes & FunctionAttribute.return_) 9028 result ~= " return"; 9029 9030 return result; 9031 } 9032 9033 mixin("alias replaceTypeInFunctionTypeUnless = " ~ gen() ~ ";"); 9034 } 9035 9036 @safe unittest 9037 { 9038 template Test(Ts...) 9039 { 9040 static if (Ts.length) 9041 { 9042 //pragma(msg, "Testing: ReplaceType!("~Ts[0].stringof~", " 9043 // ~Ts[1].stringof~", "~Ts[2].stringof~")"); 9044 static assert(is(ReplaceType!(Ts[0], Ts[1], Ts[2]) == Ts[3]), 9045 "ReplaceType!("~Ts[0].stringof~", "~Ts[1].stringof~", " 9046 ~Ts[2].stringof~") == " 9047 ~ReplaceType!(Ts[0], Ts[1], Ts[2]).stringof); 9048 alias Test = Test!(Ts[4 .. $]); 9049 } 9050 else alias Test = void; 9051 } 9052 9053 //import core.stdc.stdio; 9054 alias RefFun1 = ref int function(float, long); 9055 alias RefFun2 = ref float function(float, long); 9056 extern(C) int printf(const char*, ...) nothrow @nogc @system; 9057 extern(C) float floatPrintf(const char*, ...) nothrow @nogc @system; 9058 int func(float); 9059 9060 int x; 9061 struct S1 { void foo() { x = 1; } } 9062 struct S2 { void bar() { x = 2; } } 9063 9064 alias Pass = Test!( 9065 int, float, typeof(&func), float delegate(float), 9066 int, float, typeof(&printf), typeof(&floatPrintf), 9067 int, float, int function(out long, ...), 9068 float function(out long, ...), 9069 int, float, int function(ref float, long), 9070 float function(ref float, long), 9071 int, float, int function(ref int, long), 9072 float function(ref float, long), 9073 int, float, int function(out int, long), 9074 float function(out float, long), 9075 int, float, int function(lazy int, long), 9076 float function(lazy float, long), 9077 int, float, int function(out long, ref const int), 9078 float function(out long, ref const float), 9079 int, int, int, int, 9080 int, float, int, float, 9081 int, float, const int, const float, 9082 int, float, immutable int, immutable float, 9083 int, float, shared int, shared float, 9084 int, float, int*, float*, 9085 int, float, const(int)*, const(float)*, 9086 int, float, const(int*), const(float*), 9087 const(int)*, float, const(int*), const(float), 9088 int*, float, const(int)*, const(int)*, 9089 int, float, int[], float[], 9090 int, float, int[42], float[42], 9091 int, float, const(int)[42], const(float)[42], 9092 int, float, const(int[42]), const(float[42]), 9093 int, float, int[int], float[float], 9094 int, float, int[double], float[double], 9095 int, float, double[int], double[float], 9096 int, float, int function(float, long), float function(float, long), 9097 int, float, int function(float), float function(float), 9098 int, float, int function(float, int), float function(float, float), 9099 int, float, int delegate(float, long), float delegate(float, long), 9100 int, float, int delegate(float), float delegate(float), 9101 int, float, int delegate(float, int), float delegate(float, float), 9102 int, float, Unique!int, Unique!float, 9103 int, float, Tuple!(float, int), Tuple!(float, float), 9104 int, float, RefFun1, RefFun2, 9105 S1, S2, 9106 S1[1][][S1]* function(), 9107 S2[1][][S2]* function(), 9108 int, string, 9109 int[3] function( int[] arr, int[2] ...) pure @trusted, 9110 string[3] function(string[] arr, string[2] ...) pure @trusted, 9111 ); 9112 9113 // https://issues.dlang.org/show_bug.cgi?id=15168 9114 static struct T1 { string s; alias s this; } 9115 static struct T2 { char[10] s; alias s this; } 9116 static struct T3 { string[string] s; alias s this; } 9117 alias Pass2 = Test!( 9118 ubyte, ubyte, T1, T1, 9119 ubyte, ubyte, T2, T2, 9120 ubyte, ubyte, T3, T3, 9121 ); 9122 } 9123 9124 // https://issues.dlang.org/show_bug.cgi?id=17116 9125 @safe unittest 9126 { 9127 alias ConstDg = void delegate(float) const; 9128 alias B = void delegate(int) const; 9129 alias A = ReplaceType!(float, int, ConstDg); 9130 static assert(is(B == A)); 9131 } 9132 9133 // https://issues.dlang.org/show_bug.cgi?id=19696 9134 @safe unittest 9135 { 9136 static struct T(U) {} 9137 static struct S { T!int t; alias t this; } 9138 static assert(is(ReplaceType!(float, float, S) == S)); 9139 } 9140 9141 // https://issues.dlang.org/show_bug.cgi?id=19697 9142 @safe unittest 9143 { 9144 class D(T) {} 9145 class C : D!C {} 9146 static assert(is(ReplaceType!(float, float, C))); 9147 } 9148 9149 // https://issues.dlang.org/show_bug.cgi?id=16132 9150 @safe unittest 9151 { 9152 interface I(T) {} 9153 class C : I!int {} 9154 static assert(is(ReplaceType!(int, string, C) == C)); 9155 } 9156 9157 /** 9158 Ternary type with three truth values: 9159 9160 $(UL 9161 $(LI `Ternary.yes` for `true`) 9162 $(LI `Ternary.no` for `false`) 9163 $(LI `Ternary.unknown` as an unknown state) 9164 ) 9165 9166 Also known as trinary, trivalent, or trilean. 9167 9168 See_Also: 9169 $(HTTP en.wikipedia.org/wiki/Three-valued_logic, 9170 Three Valued Logic on Wikipedia) 9171 */ 9172 struct Ternary 9173 { 9174 @safe @nogc nothrow pure: 9175 9176 private ubyte value = 6; 9177 private static Ternary make(ubyte b) 9178 { 9179 Ternary r = void; 9180 r.value = b; 9181 return r; 9182 } 9183 9184 /** 9185 The possible states of the `Ternary` 9186 */ 9187 enum no = make(0); 9188 /// ditto 9189 enum yes = make(2); 9190 /// ditto 9191 enum unknown = make(6); 9192 9193 /** 9194 Construct and assign from a `bool`, receiving `no` for `false` and `yes` 9195 for `true`. 9196 */ 9197 this(bool b) { value = b << 1; } 9198 9199 /// ditto 9200 void opAssign(bool b) { value = b << 1; } 9201 9202 /** 9203 Construct a ternary value from another ternary value 9204 */ 9205 this(const Ternary b) { value = b.value; } 9206 9207 /** 9208 $(TABLE Truth table for logical operations, 9209 $(TR $(TH `a`) $(TH `b`) $(TH `$(TILDE)a`) $(TH `a | b`) $(TH `a & b`) $(TH `a ^ b`)) 9210 $(TR $(TD `no`) $(TD `no`) $(TD `yes`) $(TD `no`) $(TD `no`) $(TD `no`)) 9211 $(TR $(TD `no`) $(TD `yes`) $(TD) $(TD `yes`) $(TD `no`) $(TD `yes`)) 9212 $(TR $(TD `no`) $(TD `unknown`) $(TD) $(TD `unknown`) $(TD `no`) $(TD `unknown`)) 9213 $(TR $(TD `yes`) $(TD `no`) $(TD `no`) $(TD `yes`) $(TD `no`) $(TD `yes`)) 9214 $(TR $(TD `yes`) $(TD `yes`) $(TD) $(TD `yes`) $(TD `yes`) $(TD `no`)) 9215 $(TR $(TD `yes`) $(TD `unknown`) $(TD) $(TD `yes`) $(TD `unknown`) $(TD `unknown`)) 9216 $(TR $(TD `unknown`) $(TD `no`) $(TD `unknown`) $(TD `unknown`) $(TD `no`) $(TD `unknown`)) 9217 $(TR $(TD `unknown`) $(TD `yes`) $(TD) $(TD `yes`) $(TD `unknown`) $(TD `unknown`)) 9218 $(TR $(TD `unknown`) $(TD `unknown`) $(TD) $(TD `unknown`) $(TD `unknown`) $(TD `unknown`)) 9219 ) 9220 */ 9221 Ternary opUnary(string s)() if (s == "~") 9222 { 9223 return make((386 >> value) & 6); 9224 } 9225 9226 /// ditto 9227 Ternary opBinary(string s)(Ternary rhs) if (s == "|") 9228 { 9229 return make((25_512 >> (value + rhs.value)) & 6); 9230 } 9231 9232 /// ditto 9233 Ternary opBinary(string s)(Ternary rhs) if (s == "&") 9234 { 9235 return make((26_144 >> (value + rhs.value)) & 6); 9236 } 9237 9238 /// ditto 9239 Ternary opBinary(string s)(Ternary rhs) if (s == "^") 9240 { 9241 return make((26_504 >> (value + rhs.value)) & 6); 9242 } 9243 9244 /// ditto 9245 Ternary opBinary(string s)(bool rhs) 9246 if (s == "|" || s == "&" || s == "^") 9247 { 9248 return this.opBinary!s(Ternary(rhs)); 9249 } 9250 } 9251 9252 /// 9253 @safe @nogc nothrow pure 9254 unittest 9255 { 9256 Ternary a; 9257 assert(a == Ternary.unknown); 9258 9259 assert(~Ternary.yes == Ternary.no); 9260 assert(~Ternary.no == Ternary.yes); 9261 assert(~Ternary.unknown == Ternary.unknown); 9262 } 9263 9264 @safe @nogc nothrow pure 9265 unittest 9266 { 9267 alias f = Ternary.no, t = Ternary.yes, u = Ternary.unknown; 9268 Ternary[27] truthTableAnd = 9269 [ 9270 t, t, t, 9271 t, u, u, 9272 t, f, f, 9273 u, t, u, 9274 u, u, u, 9275 u, f, f, 9276 f, t, f, 9277 f, u, f, 9278 f, f, f, 9279 ]; 9280 9281 Ternary[27] truthTableOr = 9282 [ 9283 t, t, t, 9284 t, u, t, 9285 t, f, t, 9286 u, t, t, 9287 u, u, u, 9288 u, f, u, 9289 f, t, t, 9290 f, u, u, 9291 f, f, f, 9292 ]; 9293 9294 Ternary[27] truthTableXor = 9295 [ 9296 t, t, f, 9297 t, u, u, 9298 t, f, t, 9299 u, t, u, 9300 u, u, u, 9301 u, f, u, 9302 f, t, t, 9303 f, u, u, 9304 f, f, f, 9305 ]; 9306 9307 for (auto i = 0; i != truthTableAnd.length; i += 3) 9308 { 9309 assert((truthTableAnd[i] & truthTableAnd[i + 1]) 9310 == truthTableAnd[i + 2]); 9311 assert((truthTableOr[i] | truthTableOr[i + 1]) 9312 == truthTableOr[i + 2]); 9313 assert((truthTableXor[i] ^ truthTableXor[i + 1]) 9314 == truthTableXor[i + 2]); 9315 } 9316 9317 Ternary a; 9318 assert(a == Ternary.unknown); 9319 static assert(!is(typeof({ if (a) {} }))); 9320 assert(!is(typeof({ auto b = Ternary(3); }))); 9321 a = true; 9322 assert(a == Ternary.yes); 9323 a = false; 9324 assert(a == Ternary.no); 9325 a = Ternary.unknown; 9326 assert(a == Ternary.unknown); 9327 Ternary b; 9328 b = a; 9329 assert(b == a); 9330 assert(~Ternary.yes == Ternary.no); 9331 assert(~Ternary.no == Ternary.yes); 9332 assert(~Ternary.unknown == Ternary.unknown); 9333 } 9334 9335 @safe @nogc nothrow pure 9336 unittest 9337 { 9338 Ternary a = Ternary(true); 9339 assert(a == Ternary.yes); 9340 assert((a & false) == Ternary.no); 9341 assert((a | false) == Ternary.yes); 9342 assert((a ^ true) == Ternary.no); 9343 assert((a ^ false) == Ternary.yes); 9344 }