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