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