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 @(imported!"core.attribute".mutableRefInit) 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 static if (isCopyable!T) 3260 this(inout T value) inout 3261 { 3262 _value.payload = value; 3263 _isNull = false; 3264 } 3265 else 3266 this(T value) inout 3267 { 3268 import std.algorithm.mutation : move; 3269 _value.payload = move(value); 3270 _isNull = false; 3271 } 3272 3273 static if (hasElaborateDestructor!T) 3274 { 3275 ~this() 3276 { 3277 if (!_isNull) 3278 { 3279 destroy(_value.payload); 3280 } 3281 } 3282 } 3283 3284 static if (!isCopyable!T) 3285 @disable this(this); 3286 else 3287 static if (__traits(hasPostblit, T)) 3288 { 3289 this(this) 3290 { 3291 if (!_isNull) 3292 _value.payload.__xpostblit(); 3293 } 3294 } 3295 else static if (__traits(hasCopyConstructor, T)) 3296 { 3297 this(ref return scope inout Nullable!T rhs) inout 3298 { 3299 _isNull = rhs._isNull; 3300 if (!_isNull) 3301 _value.payload = rhs._value.payload; 3302 else 3303 _value = DontCallDestructorT.init; 3304 } 3305 } 3306 3307 /** 3308 * If they are both null, then they are equal. If one is null and the other 3309 * is not, then they are not equal. If they are both non-null, then they are 3310 * equal if their values are equal. 3311 */ 3312 bool opEquals(this This, Rhs)(auto ref Rhs rhs) 3313 if (!is(CommonType!(This, Rhs) == void)) 3314 { 3315 static if (is(This == Rhs)) 3316 { 3317 if (_isNull) 3318 return rhs._isNull; 3319 if (rhs._isNull) 3320 return false; 3321 return _value.payload == rhs._value.payload; 3322 } 3323 else 3324 { 3325 alias Common = CommonType!(This, Rhs); 3326 return cast(Common) this == cast(Common) rhs; 3327 } 3328 } 3329 3330 /// Ditto 3331 bool opEquals(this This, Rhs)(auto ref Rhs rhs) 3332 if (is(CommonType!(This, Rhs) == void) && is(typeof(this.get == rhs))) 3333 { 3334 return _isNull ? false : rhs == _value.payload; 3335 } 3336 3337 /// 3338 @safe unittest 3339 { 3340 Nullable!int empty; 3341 Nullable!int a = 42; 3342 Nullable!int b = 42; 3343 Nullable!int c = 27; 3344 3345 assert(empty == empty); 3346 assert(empty == Nullable!int.init); 3347 assert(empty != a); 3348 assert(empty != b); 3349 assert(empty != c); 3350 3351 assert(a == b); 3352 assert(a != c); 3353 3354 assert(empty != 42); 3355 assert(a == 42); 3356 assert(c != 42); 3357 } 3358 3359 @safe unittest 3360 { 3361 // Test constness 3362 immutable Nullable!int a = 42; 3363 Nullable!int b = 42; 3364 immutable Nullable!int c = 29; 3365 Nullable!int d = 29; 3366 immutable e = 42; 3367 int f = 29; 3368 assert(a == a); 3369 assert(a == b); 3370 assert(a != c); 3371 assert(a != d); 3372 assert(a == e); 3373 assert(a != f); 3374 3375 // Test rvalue 3376 assert(a == const Nullable!int(42)); 3377 assert(a != Nullable!int(29)); 3378 } 3379 3380 // https://issues.dlang.org/show_bug.cgi?id=17482 3381 @system unittest 3382 { 3383 import std.variant : Variant; 3384 Nullable!Variant a = Variant(12); 3385 assert(a == 12); 3386 Nullable!Variant e; 3387 assert(e != 12); 3388 } 3389 3390 size_t toHash() const @safe nothrow 3391 { 3392 static if (__traits(compiles, .hashOf(_value.payload))) 3393 return _isNull ? 0 : .hashOf(_value.payload); 3394 else 3395 // Workaround for when .hashOf is not both @safe and nothrow. 3396 return _isNull ? 0 : typeid(T).getHash(&_value.payload); 3397 } 3398 3399 /** 3400 * Gives the string `"Nullable.null"` if `isNull` is `true`. Otherwise, the 3401 * result is equivalent to calling $(REF formattedWrite, std,format) on the 3402 * underlying value. 3403 * 3404 * Params: 3405 * writer = A `char` accepting 3406 * $(REF_ALTTEXT output range, isOutputRange, std, range, primitives) 3407 * fmt = A $(REF FormatSpec, std,format) which is used to represent 3408 * the value if this Nullable is not null 3409 * Returns: 3410 * A `string` if `writer` and `fmt` are not set; `void` otherwise. 3411 */ 3412 string toString() 3413 { 3414 import std.array : appender; 3415 auto app = appender!string(); 3416 auto spec = singleSpec("%s"); 3417 toString(app, spec); 3418 return app.data; 3419 } 3420 3421 /// ditto 3422 string toString() const 3423 { 3424 import std.array : appender; 3425 auto app = appender!string(); 3426 auto spec = singleSpec("%s"); 3427 toString(app, spec); 3428 return app.data; 3429 } 3430 3431 /// ditto 3432 void toString(W)(ref W writer, scope const ref FormatSpec!char fmt) 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 /// ditto 3443 void toString(W)(ref W writer, scope const ref FormatSpec!char fmt) const 3444 if (isOutputRange!(W, char)) 3445 { 3446 import std.range.primitives : put; 3447 if (isNull) 3448 put(writer, "Nullable.null"); 3449 else 3450 formatValue(writer, _value.payload, fmt); 3451 } 3452 3453 /** 3454 * Check if `this` is in the null state. 3455 * 3456 * Returns: 3457 * true $(B iff) `this` is in the null state, otherwise false. 3458 */ 3459 @property bool isNull() const @safe pure nothrow 3460 { 3461 return _isNull; 3462 } 3463 3464 /// 3465 @safe unittest 3466 { 3467 Nullable!int ni; 3468 assert(ni.isNull); 3469 3470 ni = 0; 3471 assert(!ni.isNull); 3472 } 3473 3474 // https://issues.dlang.org/show_bug.cgi?id=14940 3475 @safe unittest 3476 { 3477 import std.array : appender; 3478 import std.format.write : formattedWrite; 3479 3480 auto app = appender!string(); 3481 Nullable!int a = 1; 3482 formattedWrite(app, "%s", a); 3483 assert(app.data == "1"); 3484 } 3485 3486 // https://issues.dlang.org/show_bug.cgi?id=19799 3487 @safe unittest 3488 { 3489 import std.format : format; 3490 3491 const Nullable!string a = const(Nullable!string)(); 3492 3493 format!"%s"(a); 3494 } 3495 3496 /** 3497 * Forces `this` to the null state. 3498 */ 3499 void nullify()() 3500 { 3501 static if (is(T == class) || is(T == interface)) 3502 _value.payload = null; 3503 else 3504 .destroy(_value.payload); 3505 _isNull = true; 3506 } 3507 3508 /// 3509 @safe unittest 3510 { 3511 Nullable!int ni = 0; 3512 assert(!ni.isNull); 3513 3514 ni.nullify(); 3515 assert(ni.isNull); 3516 } 3517 3518 /** 3519 * Assigns `value` to the internally-held state. If the assignment 3520 * succeeds, `this` becomes non-null. 3521 * 3522 * Params: 3523 * value = A value of type `T` to assign to this `Nullable`. 3524 */ 3525 ref Nullable opAssign()(T value) return 3526 { 3527 import std.algorithm.mutation : moveEmplace, move; 3528 3529 if (_isNull) 3530 { 3531 // trusted since payload is known to be uninitialized. 3532 () @trusted { moveEmplace(value, _value.payload); }(); 3533 } 3534 else 3535 { 3536 move(value, _value.payload); 3537 } 3538 _isNull = false; 3539 return this; 3540 } 3541 3542 /** 3543 * If this `Nullable` wraps a type that already has a null value 3544 * (such as a pointer), then assigning the null value to this 3545 * `Nullable` is no different than assigning any other value of 3546 * type `T`, and the resulting code will look very strange. It 3547 * is strongly recommended that this be avoided by instead using 3548 * the version of `Nullable` that takes an additional `nullValue` 3549 * template argument. 3550 */ 3551 @safe unittest 3552 { 3553 //Passes 3554 Nullable!(int*) npi; 3555 assert(npi.isNull); 3556 3557 //Passes?! 3558 npi = null; 3559 assert(!npi.isNull); 3560 } 3561 3562 /** 3563 * Gets the value if not null. If `this` is in the null state, and the optional 3564 * parameter `fallback` was provided, it will be returned. Without `fallback`, 3565 * calling `get` with a null state is invalid. 3566 * 3567 * When the fallback type is different from the Nullable type, `get(T)` returns 3568 * the common type. 3569 * 3570 * Params: 3571 * fallback = the value to return in case the `Nullable` is null. 3572 * 3573 * Returns: 3574 * The value held internally by this `Nullable`. 3575 */ 3576 @property ref inout(T) get() inout @safe pure nothrow 3577 { 3578 enum message = "Called `get' on null Nullable!" ~ T.stringof ~ "."; 3579 assert(!isNull, message); 3580 return _value.payload; 3581 } 3582 3583 /// ditto 3584 @property inout(T) get()(inout(T) fallback) inout 3585 { 3586 return isNull ? fallback : _value.payload; 3587 } 3588 3589 /// ditto 3590 @property auto get(U)(inout(U) fallback) inout 3591 { 3592 return isNull ? fallback : _value.payload; 3593 } 3594 3595 /// $(MREF_ALTTEXT Range interface, std, range, primitives) functions. 3596 alias empty = isNull; 3597 3598 /// ditto 3599 alias popFront = nullify; 3600 3601 /// ditto 3602 alias popBack = nullify; 3603 3604 /// ditto 3605 @property ref inout(T) front() inout @safe pure nothrow 3606 { 3607 return get(); 3608 } 3609 3610 /// ditto 3611 alias back = front; 3612 3613 /// ditto 3614 static if (isCopyable!T) 3615 @property inout(typeof(this)) save() inout 3616 { 3617 return this; 3618 } 3619 3620 /// ditto 3621 static if (isCopyable!T) 3622 inout(typeof(this)) opIndex(size_t[2] dim) inout 3623 in (dim[0] <= length && dim[1] <= length && dim[1] >= dim[0]) 3624 { 3625 return (dim[0] == 0 && dim[1] == 1) ? this : this.init; 3626 } 3627 /// ditto 3628 size_t[2] opSlice(size_t dim : 0)(size_t from, size_t to) const 3629 { 3630 return [from, to]; 3631 } 3632 3633 /// ditto 3634 @property size_t length() const @safe pure nothrow 3635 { 3636 return !empty; 3637 } 3638 3639 /// ditto 3640 alias opDollar(size_t dim : 0) = length; 3641 3642 /// ditto 3643 ref inout(T) opIndex(size_t index) inout @safe pure nothrow 3644 in (index < length) 3645 { 3646 return get(); 3647 } 3648 3649 /** 3650 * Converts `Nullable` to a range. Works even when the contained type is `immutable`. 3651 */ 3652 auto opSlice(this This)() 3653 { 3654 static struct NullableRange 3655 { 3656 private This value; 3657 3658 // starts out true if value is null 3659 private bool empty_; 3660 3661 @property bool empty() const @safe pure nothrow 3662 { 3663 return empty_; 3664 } 3665 3666 void popFront() @safe pure nothrow 3667 { 3668 empty_ = true; 3669 } 3670 3671 alias popBack = popFront; 3672 3673 @property ref inout(typeof(value.get())) front() inout @safe pure nothrow 3674 { 3675 return value.get(); 3676 } 3677 3678 alias back = front; 3679 3680 @property inout(typeof(this)) save() inout 3681 { 3682 return this; 3683 } 3684 3685 size_t[2] opSlice(size_t dim : 0)(size_t from, size_t to) const 3686 { 3687 return [from, to]; 3688 } 3689 3690 @property size_t length() const @safe pure nothrow 3691 { 3692 return !empty; 3693 } 3694 3695 alias opDollar(size_t dim : 0) = length; 3696 3697 ref inout(typeof(value.get())) opIndex(size_t index) inout @safe pure nothrow 3698 in (index < length) 3699 { 3700 return value.get(); 3701 } 3702 3703 inout(typeof(this)) opIndex(size_t[2] dim) inout 3704 in (dim[0] <= length && dim[1] <= length && dim[1] >= dim[0]) 3705 { 3706 return (dim[0] == 0 && dim[1] == 1) ? this : this.init; 3707 } 3708 3709 auto opIndex() inout 3710 { 3711 return this; 3712 } 3713 } 3714 return NullableRange(this, isNull); 3715 } 3716 } 3717 3718 /// ditto 3719 auto nullable(T)(T t) 3720 { 3721 return Nullable!T(t); 3722 } 3723 3724 /// 3725 @safe unittest 3726 { 3727 struct CustomerRecord 3728 { 3729 string name; 3730 string address; 3731 int customerNum; 3732 } 3733 3734 Nullable!CustomerRecord getByName(string name) 3735 { 3736 //A bunch of hairy stuff 3737 3738 return Nullable!CustomerRecord.init; 3739 } 3740 3741 auto queryResult = getByName("Doe, John"); 3742 if (!queryResult.isNull) 3743 { 3744 //Process Mr. Doe's customer record 3745 auto address = queryResult.get.address; 3746 auto customerNum = queryResult.get.customerNum; 3747 3748 //Do some things with this customer's info 3749 } 3750 else 3751 { 3752 //Add the customer to the database 3753 } 3754 } 3755 3756 /// 3757 @system unittest 3758 { 3759 import std.exception : assertThrown; 3760 3761 auto a = 42.nullable; 3762 assert(!a.isNull); 3763 assert(a.get == 42); 3764 3765 a.nullify(); 3766 assert(a.isNull); 3767 assertThrown!Throwable(a.get); 3768 } 3769 /// 3770 @safe unittest 3771 { 3772 import std.algorithm.iteration : each, joiner; 3773 Nullable!int a = 42; 3774 Nullable!int b; 3775 // Add each value to an array 3776 int[] arr; 3777 a.each!((n) => arr ~= n); 3778 assert(arr == [42]); 3779 b.each!((n) => arr ~= n); 3780 assert(arr == [42]); 3781 // Take first value from an array of Nullables 3782 Nullable!int[] c = new Nullable!int[](10); 3783 c[7] = Nullable!int(42); 3784 assert(c.joiner.front == 42); 3785 } 3786 @safe unittest 3787 { 3788 auto k = Nullable!int(74); 3789 assert(k == 74); 3790 k.nullify(); 3791 assert(k.isNull); 3792 } 3793 @safe unittest 3794 { 3795 static int f(scope const Nullable!int x) { 3796 return x.isNull ? 42 : x.get; 3797 } 3798 Nullable!int a; 3799 assert(f(a) == 42); 3800 a = 8; 3801 assert(f(a) == 8); 3802 a.nullify(); 3803 assert(f(a) == 42); 3804 } 3805 @system unittest 3806 { 3807 import std.exception : assertThrown; 3808 3809 static struct S { int x; } 3810 Nullable!S s; 3811 assert(s.isNull); 3812 s = S(6); 3813 assert(s == S(6)); 3814 assert(s != S(0)); 3815 assert(s.get != S(0)); 3816 s.get.x = 9190; 3817 assert(s.get.x == 9190); 3818 s.nullify(); 3819 assertThrown!Throwable(s.get.x = 9441); 3820 } 3821 @safe unittest 3822 { 3823 // Ensure Nullable can be used in pure/nothrow/@safe environment. 3824 function() @safe pure nothrow 3825 { 3826 Nullable!int n; 3827 assert(n.isNull); 3828 n = 4; 3829 assert(!n.isNull); 3830 assert(n == 4); 3831 n.nullify(); 3832 assert(n.isNull); 3833 }(); 3834 } 3835 @system unittest 3836 { 3837 // Ensure Nullable can be used when the value is not pure/nothrow/@safe 3838 static struct S 3839 { 3840 int x; 3841 this(this) @system {} 3842 } 3843 3844 Nullable!S s; 3845 assert(s.isNull); 3846 s = S(5); 3847 assert(!s.isNull); 3848 assert(s.get.x == 5); 3849 s.nullify(); 3850 assert(s.isNull); 3851 } 3852 3853 // https://issues.dlang.org/show_bug.cgi?id=9404 3854 @safe unittest 3855 { 3856 alias N = Nullable!int; 3857 3858 void foo(N a) 3859 { 3860 N b; 3861 b = a; // `N b = a;` works fine 3862 } 3863 N n; 3864 foo(n); 3865 } 3866 @safe unittest 3867 { 3868 //Check nullable immutable is constructable 3869 { 3870 auto a1 = Nullable!(immutable int)(); 3871 auto a2 = Nullable!(immutable int)(1); 3872 auto i = a2.get; 3873 } 3874 //Check immutable nullable is constructable 3875 { 3876 auto a1 = immutable (Nullable!int)(); 3877 auto a2 = immutable (Nullable!int)(1); 3878 auto i = a2.get; 3879 } 3880 } 3881 @safe unittest 3882 { 3883 alias NInt = Nullable!int; 3884 3885 //Construct tests 3886 { 3887 //from other Nullable null 3888 NInt a1; 3889 NInt b1 = a1; 3890 assert(b1.isNull); 3891 3892 //from other Nullable non-null 3893 NInt a2 = NInt(1); 3894 NInt b2 = a2; 3895 assert(b2 == 1); 3896 3897 //Construct from similar nullable 3898 auto a3 = immutable(NInt)(); 3899 NInt b3 = a3; 3900 assert(b3.isNull); 3901 } 3902 3903 //Assign tests 3904 { 3905 //from other Nullable null 3906 NInt a1; 3907 NInt b1; 3908 b1 = a1; 3909 assert(b1.isNull); 3910 3911 //from other Nullable non-null 3912 NInt a2 = NInt(1); 3913 NInt b2; 3914 b2 = a2; 3915 assert(b2 == 1); 3916 3917 //Construct from similar nullable 3918 auto a3 = immutable(NInt)(); 3919 NInt b3 = a3; 3920 b3 = a3; 3921 assert(b3.isNull); 3922 } 3923 } 3924 @safe unittest 3925 { 3926 //Check nullable is nicelly embedable in a struct 3927 static struct S1 3928 { 3929 Nullable!int ni; 3930 } 3931 static struct S2 //inspired from 9404 3932 { 3933 Nullable!int ni; 3934 this(ref S2 other) 3935 { 3936 ni = other.ni; 3937 } 3938 void opAssign(ref S2 other) 3939 { 3940 ni = other.ni; 3941 } 3942 } 3943 static foreach (S; AliasSeq!(S1, S2)) 3944 {{ 3945 S a; 3946 S b = a; 3947 S c; 3948 c = a; 3949 }} 3950 } 3951 3952 // https://issues.dlang.org/show_bug.cgi?id=10268 3953 @system unittest 3954 { 3955 import std.json; 3956 JSONValue value = null; 3957 auto na = Nullable!JSONValue(value); 3958 3959 struct S1 { int val; } 3960 struct S2 { int* val; } 3961 struct S3 { immutable int* val; } 3962 3963 { 3964 auto sm = S1(1); 3965 immutable si = immutable S1(1); 3966 auto x1 = Nullable!S1(sm); 3967 auto x2 = immutable Nullable!S1(sm); 3968 auto x3 = Nullable!S1(si); 3969 auto x4 = immutable Nullable!S1(si); 3970 assert(x1.get.val == 1); 3971 assert(x2.get.val == 1); 3972 assert(x3.get.val == 1); 3973 assert(x4.get.val == 1); 3974 } 3975 3976 auto nm = 10; 3977 immutable ni = 10; 3978 3979 { 3980 auto sm = S2(&nm); 3981 immutable si = immutable S2(&ni); 3982 auto x1 = Nullable!S2(sm); 3983 static assert(!__traits(compiles, { auto x2 = immutable Nullable!S2(sm); })); 3984 static assert(!__traits(compiles, { auto x3 = Nullable!S2(si); })); 3985 auto x4 = immutable Nullable!S2(si); 3986 assert(*x1.get.val == 10); 3987 assert(*x4.get.val == 10); 3988 } 3989 3990 { 3991 auto sm = S3(&ni); 3992 immutable si = immutable S3(&ni); 3993 auto x1 = Nullable!S3(sm); 3994 auto x2 = immutable Nullable!S3(sm); 3995 auto x3 = Nullable!S3(si); 3996 auto x4 = immutable Nullable!S3(si); 3997 assert(*x1.get.val == 10); 3998 assert(*x2.get.val == 10); 3999 assert(*x3.get.val == 10); 4000 assert(*x4.get.val == 10); 4001 } 4002 } 4003 4004 // https://issues.dlang.org/show_bug.cgi?id=10357 4005 @safe unittest 4006 { 4007 import std.datetime; 4008 Nullable!SysTime time = SysTime(0); 4009 } 4010 4011 // https://issues.dlang.org/show_bug.cgi?id=10915 4012 @system unittest 4013 { 4014 import std.conv : to; 4015 import std.array; 4016 4017 Appender!string buffer; 4018 4019 Nullable!int ni; 4020 assert(ni.to!string() == "Nullable.null"); 4021 assert((cast(const) ni).to!string() == "Nullable.null"); 4022 4023 struct Test { string s; } 4024 alias NullableTest = Nullable!Test; 4025 4026 NullableTest nt = Test("test"); 4027 // test output range version 4028 assert(nt.to!string() == `Test("test")`); 4029 // test appender version 4030 assert(nt.toString() == `Test("test")`); 4031 // test const version 4032 assert((cast(const) nt).toString() == `const(Test)("test")`); 4033 4034 NullableTest ntn = Test("null"); 4035 assert(ntn.to!string() == `Test("null")`); 4036 4037 class TestToString 4038 { 4039 double d; 4040 4041 this (double d) 4042 { 4043 this.d = d; 4044 } 4045 4046 override string toString() 4047 { 4048 return d.to!string(); 4049 } 4050 } 4051 Nullable!TestToString ntts = new TestToString(2.5); 4052 assert(ntts.to!string() == "2.5"); 4053 } 4054 4055 // https://issues.dlang.org/show_bug.cgi?id=14477 4056 @safe unittest 4057 { 4058 static struct DisabledDefaultConstructor 4059 { 4060 @disable this(); 4061 this(int i) { } 4062 } 4063 Nullable!DisabledDefaultConstructor var; 4064 var = DisabledDefaultConstructor(5); 4065 var.nullify; 4066 } 4067 4068 // https://issues.dlang.org/show_bug.cgi?id=17440 4069 @system unittest 4070 { 4071 static interface I { } 4072 4073 static class C : I 4074 { 4075 int canary; 4076 ~this() 4077 { 4078 canary = 0x5050DEAD; 4079 } 4080 } 4081 auto c = new C; 4082 c.canary = 0xA71FE; 4083 auto nc = nullable(c); 4084 nc.nullify; 4085 assert(c.canary == 0xA71FE); 4086 4087 I i = c; 4088 auto ni = nullable(i); 4089 ni.nullify; 4090 assert(c.canary == 0xA71FE); 4091 } 4092 4093 // https://issues.dlang.org/show_bug.cgi?id=19037 4094 @safe unittest 4095 { 4096 import std.datetime : SysTime; 4097 4098 struct Test 4099 { 4100 SysTime _st; 4101 4102 static bool destroyed; 4103 4104 @disable this(); 4105 this(int _dummy) {} 4106 ~this() @safe { destroyed = true; } 4107 4108 // mustn't call opAssign on Test.init in Nullable!Test, because the invariant 4109 // will be called before opAssign on the Test.init that is in Nullable 4110 // and Test.init violates its invariant. 4111 void opAssign(Test rhs) @safe { assert(false); } 4112 } 4113 4114 { 4115 Nullable!Test nt; 4116 4117 nt = Test(1); 4118 4119 // destroy value 4120 Test.destroyed = false; 4121 4122 nt.nullify; 4123 4124 assert(Test.destroyed); 4125 4126 Test.destroyed = false; 4127 } 4128 // don't run destructor on T.init in Nullable on scope exit! 4129 assert(!Test.destroyed); 4130 } 4131 // check that the contained type's destructor is called on assignment 4132 @system unittest 4133 { 4134 struct S 4135 { 4136 // can't be static, since we need a specific value's pointer 4137 bool* destroyedRef; 4138 4139 ~this() 4140 { 4141 if (this.destroyedRef) 4142 { 4143 *this.destroyedRef = true; 4144 } 4145 } 4146 } 4147 4148 Nullable!S ns; 4149 4150 bool destroyed; 4151 4152 ns = S(&destroyed); 4153 4154 // reset from rvalue destruction in Nullable's opAssign 4155 destroyed = false; 4156 4157 // overwrite Nullable 4158 ns = S(null); 4159 4160 // the original S should be destroyed. 4161 assert(destroyed == true); 4162 } 4163 // check that the contained type's destructor is still called when required 4164 @system unittest 4165 { 4166 bool destructorCalled = false; 4167 4168 struct S 4169 { 4170 bool* destroyed; 4171 ~this() { *this.destroyed = true; } 4172 } 4173 4174 { 4175 Nullable!S ns; 4176 } 4177 assert(!destructorCalled); 4178 { 4179 Nullable!S ns = Nullable!S(S(&destructorCalled)); 4180 4181 destructorCalled = false; // reset after S was destroyed in the NS constructor 4182 } 4183 assert(destructorCalled); 4184 } 4185 4186 // check that toHash on Nullable is forwarded to the contained type 4187 @system unittest 4188 { 4189 struct S 4190 { 4191 size_t toHash() const @safe pure nothrow { return 5; } 4192 } 4193 4194 Nullable!S s1 = S(); 4195 Nullable!S s2 = Nullable!S(); 4196 4197 assert(typeid(Nullable!S).getHash(&s1) == 5); 4198 assert(typeid(Nullable!S).getHash(&s2) == 0); 4199 } 4200 4201 // https://issues.dlang.org/show_bug.cgi?id=21704 4202 @safe unittest 4203 { 4204 import std.array : staticArray; 4205 4206 bool destroyed; 4207 4208 struct Probe 4209 { 4210 ~this() { destroyed = true; } 4211 } 4212 4213 { 4214 Nullable!(Probe[1]) test = [Probe()].staticArray; 4215 destroyed = false; 4216 } 4217 assert(destroyed); 4218 } 4219 4220 // https://issues.dlang.org/show_bug.cgi?id=21705 4221 @safe unittest 4222 { 4223 static struct S 4224 { 4225 int n; 4226 bool opEquals(S rhs) { return n == rhs.n; } 4227 } 4228 4229 Nullable!S test1 = S(1), test2 = S(1); 4230 S s = S(1); 4231 4232 assert(test1 == s); 4233 assert(test1 == test2); 4234 } 4235 4236 // https://issues.dlang.org/show_bug.cgi?id=22101 4237 @safe unittest 4238 { 4239 static int impure; 4240 4241 struct S 4242 { 4243 ~this() { impure++; } 4244 } 4245 4246 Nullable!S s; 4247 s.get(S()); 4248 } 4249 4250 // https://issues.dlang.org/show_bug.cgi?id=22100 4251 @safe unittest 4252 { 4253 Nullable!int a, b, c; 4254 a = b = c = 5; 4255 a = b = c = nullable(5); 4256 } 4257 4258 // https://issues.dlang.org/show_bug.cgi?id=18374 4259 @safe pure nothrow unittest 4260 { 4261 import std.algorithm.comparison : equal; 4262 import std.range : only, takeNone; 4263 import std.range.primitives : hasAssignableElements, hasLength, 4264 hasLvalueElements, hasSlicing, hasSwappableElements, 4265 isRandomAccessRange; 4266 Nullable!int a = 42; 4267 assert(!a.empty); 4268 assert(a.front == 42); 4269 assert(a.back == 42); 4270 assert(a[0] == 42); 4271 assert(a.equal(only(42))); 4272 assert(a[0 .. $].equal(only(42))); 4273 a[0] = 43; 4274 assert(a.equal(only(43))); 4275 --a[0]; 4276 assert(a.equal(only(42))); 4277 Nullable!int b; 4278 assert(b.empty); 4279 assert(b.equal(takeNone(b))); 4280 Nullable!int c = a.save(); 4281 assert(!c.empty); 4282 c.popFront(); 4283 assert(!a.empty); 4284 assert(c.empty); 4285 4286 assert(isRandomAccessRange!(Nullable!int)); 4287 assert(hasLength!(Nullable!int)); 4288 assert(hasSlicing!(Nullable!int)); 4289 assert(hasAssignableElements!(Nullable!int)); 4290 assert(hasSwappableElements!(Nullable!int)); 4291 assert(hasLvalueElements!(Nullable!int)); 4292 } 4293 4294 // https://issues.dlang.org/show_bug.cgi?id=23640 4295 @safe pure nothrow unittest 4296 { 4297 import std.algorithm.comparison : equal; 4298 import std.range : only; 4299 import std.range.primitives : hasLength, hasSlicing, 4300 isRandomAccessRange; 4301 static immutable struct S { int[] array; } 4302 auto value = S([42]); 4303 alias ImmutableNullable = immutable Nullable!S; 4304 auto a = ImmutableNullable(value)[]; 4305 alias Range = typeof(a); 4306 assert(isRandomAccessRange!Range); 4307 assert(hasLength!Range); 4308 assert(hasSlicing!Range); 4309 assert(!a.empty); 4310 assert(a.front == value); 4311 assert(a.back == value); 4312 assert(a[0] == value); 4313 assert(a.equal(only(value))); 4314 assert(a[0 .. $].equal(only(value))); 4315 Range b = a.save(); 4316 assert(!b.empty); 4317 b.popFront(); 4318 assert(!a.empty); 4319 assert(b.empty); 4320 } 4321 4322 /** 4323 Just like `Nullable!T`, except that the null state is defined as a 4324 particular value. For example, $(D Nullable!(uint, uint.max)) is an 4325 `uint` that sets aside the value `uint.max` to denote a null 4326 state. $(D Nullable!(T, nullValue)) is more storage-efficient than $(D 4327 Nullable!T) because it does not need to store an extra `bool`. 4328 4329 Params: 4330 T = The wrapped type for which Nullable provides a null value. 4331 4332 nullValue = The null value which denotes the null state of this 4333 `Nullable`. Must be of type `T`. 4334 */ 4335 struct Nullable(T, T nullValue) 4336 { 4337 private T _value = nullValue; 4338 4339 /** 4340 Constructor initializing `this` with `value`. 4341 4342 Params: 4343 value = The value to initialize this `Nullable` with. 4344 */ 4345 this(T value) 4346 { 4347 _value = value; 4348 } 4349 4350 template toString() 4351 { 4352 import std.format.spec : FormatSpec; 4353 import std.format.write : formatValue; 4354 // Needs to be a template because of https://issues.dlang.org/show_bug.cgi?id=13737. 4355 void toString()(scope void delegate(const(char)[]) sink, scope const ref FormatSpec!char fmt) 4356 { 4357 if (isNull) 4358 { 4359 sink.formatValue("Nullable.null", fmt); 4360 } 4361 else 4362 { 4363 sink.formatValue(_value, fmt); 4364 } 4365 } 4366 4367 void toString()(scope void delegate(const(char)[]) sink, scope const ref FormatSpec!char fmt) const 4368 { 4369 if (isNull) 4370 { 4371 sink.formatValue("Nullable.null", fmt); 4372 } 4373 else 4374 { 4375 sink.formatValue(_value, fmt); 4376 } 4377 } 4378 } 4379 4380 @system unittest 4381 { 4382 import std.conv : to; 4383 4384 const Nullable!(ulong, 0) x = 1; 4385 assert(x.to!string == "1"); 4386 } 4387 4388 /** 4389 Check if `this` is in the null state. 4390 4391 Returns: 4392 true $(B iff) `this` is in the null state, otherwise false. 4393 */ 4394 @property bool isNull() const 4395 { 4396 //Need to use 'is' if T is a nullable type and 4397 //nullValue is null, or it's a compiler error 4398 static if (is(CommonType!(T, typeof(null)) == T) && nullValue is null) 4399 { 4400 return _value is nullValue; 4401 } 4402 //Need to use 'is' if T is a float type 4403 //because NaN != NaN 4404 else static if (__traits(isFloating, T) || __traits(compiles, { static assert(!(nullValue == nullValue)); })) 4405 { 4406 return _value is nullValue; 4407 } 4408 else 4409 { 4410 return _value == nullValue; 4411 } 4412 } 4413 4414 /// 4415 @safe unittest 4416 { 4417 Nullable!(int, -1) ni; 4418 //Initialized to "null" state 4419 assert(ni.isNull); 4420 4421 ni = 0; 4422 assert(!ni.isNull); 4423 } 4424 4425 @system unittest 4426 { 4427 assert(typeof(this).init.isNull, typeof(this).stringof ~ 4428 ".isNull does not work correctly because " ~ T.stringof ~ 4429 " has an == operator that is non-reflexive and could not be" ~ 4430 " determined before runtime to be non-reflexive!"); 4431 } 4432 4433 // https://issues.dlang.org/show_bug.cgi?id=11135 4434 // disable test until https://issues.dlang.org/show_bug.cgi?id=15316 gets fixed 4435 version (none) @system unittest 4436 { 4437 static foreach (T; AliasSeq!(float, double, real)) 4438 {{ 4439 Nullable!(T, T.init) nf; 4440 //Initialized to "null" state 4441 assert(nf.isNull); 4442 assert(nf is typeof(nf).init); 4443 4444 nf = 0; 4445 assert(!nf.isNull); 4446 4447 nf.nullify(); 4448 assert(nf.isNull); 4449 }} 4450 } 4451 4452 /** 4453 Forces `this` to the null state. 4454 */ 4455 void nullify()() 4456 { 4457 _value = nullValue; 4458 } 4459 4460 /// 4461 @safe unittest 4462 { 4463 Nullable!(int, -1) ni = 0; 4464 assert(!ni.isNull); 4465 4466 ni = -1; 4467 assert(ni.isNull); 4468 } 4469 4470 /** 4471 Assigns `value` to the internally-held state. If the assignment 4472 succeeds, `this` becomes non-null. No null checks are made. Note 4473 that the assignment may leave `this` in the null state. 4474 4475 Params: 4476 value = A value of type `T` to assign to this `Nullable`. 4477 If it is `nullvalue`, then the internal state of 4478 this `Nullable` will be set to null. 4479 */ 4480 void opAssign()(T value) 4481 { 4482 import std.algorithm.mutation : swap; 4483 4484 swap(value, _value); 4485 } 4486 4487 /** 4488 If this `Nullable` wraps a type that already has a null value 4489 (such as a pointer), and that null value is not given for 4490 `nullValue`, then assigning the null value to this `Nullable` 4491 is no different than assigning any other value of type `T`, 4492 and the resulting code will look very strange. It is strongly 4493 recommended that this be avoided by using `T`'s "built in" 4494 null value for `nullValue`. 4495 */ 4496 @system unittest 4497 { 4498 //Passes 4499 enum nullVal = cast(int*) 0xCAFEBABE; 4500 Nullable!(int*, nullVal) npi; 4501 assert(npi.isNull); 4502 4503 //Passes?! 4504 npi = null; 4505 assert(!npi.isNull); 4506 } 4507 4508 /** 4509 Gets the value. `this` must not be in the null state. 4510 This function is also called for the implicit conversion to `T`. 4511 4512 Preconditions: `isNull` must be `false`. 4513 Returns: 4514 The value held internally by this `Nullable`. 4515 */ 4516 @property ref inout(T) get() inout 4517 { 4518 //@@@6169@@@: We avoid any call that might evaluate nullValue's %s, 4519 //Because it might messup get's purity and safety inference. 4520 enum message = "Called `get' on null Nullable!(" ~ T.stringof ~ ",nullValue)."; 4521 assert(!isNull, message); 4522 return _value; 4523 } 4524 4525 /// 4526 @system unittest 4527 { 4528 import std.exception : assertThrown, assertNotThrown; 4529 4530 Nullable!(int, -1) ni; 4531 //`get` is implicitly called. Will throw 4532 //an error in non-release mode 4533 assertThrown!Throwable(ni == 0); 4534 4535 ni = 0; 4536 assertNotThrown!Throwable(ni == 0); 4537 } 4538 4539 /** 4540 Implicitly converts to `T`. 4541 `this` must not be in the null state. 4542 */ 4543 alias get this; 4544 } 4545 4546 /// ditto 4547 auto nullable(alias nullValue, T)(T t) 4548 if (is (typeof(nullValue) == T)) 4549 { 4550 return Nullable!(T, nullValue)(t); 4551 } 4552 4553 /// 4554 @safe unittest 4555 { 4556 Nullable!(size_t, size_t.max) indexOf(string[] haystack, string needle) 4557 { 4558 //Find the needle, returning -1 if not found 4559 4560 return Nullable!(size_t, size_t.max).init; 4561 } 4562 4563 void sendLunchInvite(string name) 4564 { 4565 } 4566 4567 //It's safer than C... 4568 auto coworkers = ["Jane", "Jim", "Marry", "Fred"]; 4569 auto pos = indexOf(coworkers, "Bob"); 4570 if (!pos.isNull) 4571 { 4572 //Send Bob an invitation to lunch 4573 sendLunchInvite(coworkers[pos]); 4574 } 4575 else 4576 { 4577 //Bob not found; report the error 4578 } 4579 4580 //And there's no overhead 4581 static assert(Nullable!(size_t, size_t.max).sizeof == size_t.sizeof); 4582 } 4583 4584 /// 4585 @system unittest 4586 { 4587 import std.exception : assertThrown; 4588 4589 Nullable!(int, int.min) a; 4590 assert(a.isNull); 4591 assertThrown!Throwable(a.get); 4592 a = 5; 4593 assert(!a.isNull); 4594 assert(a == 5); 4595 static assert(a.sizeof == int.sizeof); 4596 } 4597 4598 /// 4599 @safe unittest 4600 { 4601 auto a = nullable!(int.min)(8); 4602 assert(a == 8); 4603 a.nullify(); 4604 assert(a.isNull); 4605 } 4606 4607 @nogc nothrow pure @safe unittest 4608 { 4609 // https://issues.dlang.org/show_bug.cgi?id=19226 4610 // fully handle non-self-equal nullValue 4611 static struct Fraction 4612 { 4613 int denominator; 4614 bool isNaN() const 4615 { 4616 return denominator == 0; 4617 } 4618 bool opEquals(const Fraction rhs) const 4619 { 4620 return !isNaN && denominator == rhs.denominator; 4621 } 4622 } 4623 alias N = Nullable!(Fraction, Fraction.init); 4624 assert(N.init.isNull); 4625 } 4626 4627 @safe unittest 4628 { 4629 static int f(scope const Nullable!(int, int.min) x) { 4630 return x.isNull ? 42 : x.get; 4631 } 4632 Nullable!(int, int.min) a; 4633 assert(f(a) == 42); 4634 a = 8; 4635 assert(f(a) == 8); 4636 a.nullify(); 4637 assert(f(a) == 42); 4638 } 4639 @safe unittest 4640 { 4641 // Ensure Nullable can be used in pure/nothrow/@safe environment. 4642 function() @safe pure nothrow 4643 { 4644 Nullable!(int, int.min) n; 4645 assert(n.isNull); 4646 n = 4; 4647 assert(!n.isNull); 4648 assert(n == 4); 4649 n.nullify(); 4650 assert(n.isNull); 4651 }(); 4652 } 4653 @system unittest 4654 { 4655 // Ensure Nullable can be used when the value is not pure/nothrow/@system 4656 static struct S 4657 { 4658 int x; 4659 bool opEquals(const S s) const @system { return s.x == x; } 4660 } 4661 4662 Nullable!(S, S(711)) s; 4663 assert(s.isNull); 4664 s = S(5); 4665 assert(!s.isNull); 4666 assert(s.x == 5); 4667 s.nullify(); 4668 assert(s.isNull); 4669 } 4670 @safe unittest 4671 { 4672 //Check nullable is nicelly embedable in a struct 4673 static struct S1 4674 { 4675 Nullable!(int, 0) ni; 4676 } 4677 static struct S2 //inspired from 9404 4678 { 4679 Nullable!(int, 0) ni; 4680 this(S2 other) 4681 { 4682 ni = other.ni; 4683 } 4684 void opAssign(S2 other) 4685 { 4686 ni = other.ni; 4687 } 4688 } 4689 static foreach (S; AliasSeq!(S1, S2)) 4690 {{ 4691 S a; 4692 S b = a; 4693 S c; 4694 c = a; 4695 }} 4696 } 4697 @system unittest 4698 { 4699 import std.conv : to; 4700 4701 // https://issues.dlang.org/show_bug.cgi?id=10915 4702 Nullable!(int, 1) ni = 1; 4703 assert(ni.to!string() == "Nullable.null"); 4704 4705 struct Test { string s; } 4706 alias NullableTest = Nullable!(Test, Test("null")); 4707 4708 NullableTest nt = Test("test"); 4709 assert(nt.to!string() == `Test("test")`); 4710 4711 NullableTest ntn = Test("null"); 4712 assert(ntn.to!string() == "Nullable.null"); 4713 4714 class TestToString 4715 { 4716 double d; 4717 4718 this(double d) 4719 { 4720 this.d = d; 4721 } 4722 4723 override string toString() 4724 { 4725 return d.to!string(); 4726 } 4727 } 4728 alias NullableTestToString = Nullable!(TestToString, null); 4729 4730 NullableTestToString ntts = new TestToString(2.5); 4731 assert(ntts.to!string() == "2.5"); 4732 } 4733 4734 // apply 4735 /** 4736 Unpacks the content of a `Nullable`, performs an operation and packs it again. Does nothing if isNull. 4737 4738 When called on a `Nullable`, `apply` will unpack the value contained in the `Nullable`, 4739 pass it to the function you provide and wrap the result in another `Nullable` (if necessary). 4740 If the `Nullable` is null, `apply` will return null itself. 4741 4742 Params: 4743 t = a `Nullable` 4744 fun = a function operating on the content of the nullable 4745 4746 Returns: 4747 `fun(t.get).nullable` if `!t.isNull`, else `Nullable.init`. 4748 4749 See also: 4750 $(HTTPS en.wikipedia.org/wiki/Monad_(functional_programming)#The_Maybe_monad, The `Maybe` monad) 4751 */ 4752 template apply(alias fun) 4753 { 4754 import std.functional : unaryFun; 4755 4756 auto apply(T)(auto ref T t) 4757 if (isInstanceOf!(Nullable, T)) 4758 { 4759 alias FunType = typeof(unaryFun!fun(T.init.get)); 4760 4761 enum MustWrapReturn = !isInstanceOf!(Nullable, FunType); 4762 4763 static if (MustWrapReturn) 4764 { 4765 alias ReturnType = Nullable!FunType; 4766 } 4767 else 4768 { 4769 alias ReturnType = FunType; 4770 } 4771 4772 if (!t.isNull) 4773 { 4774 static if (MustWrapReturn) 4775 { 4776 return unaryFun!fun(t.get).nullable; 4777 } 4778 else 4779 { 4780 return unaryFun!fun(t.get); 4781 } 4782 } 4783 else 4784 { 4785 return ReturnType.init; 4786 } 4787 } 4788 } 4789 4790 /// 4791 nothrow pure @nogc @safe unittest 4792 { 4793 alias toFloat = i => cast(float) i; 4794 4795 Nullable!int sample; 4796 4797 // apply(null) results in a null `Nullable` of the function's return type. 4798 Nullable!float f = sample.apply!toFloat; 4799 assert(sample.isNull && f.isNull); 4800 4801 sample = 3; 4802 4803 // apply(non-null) calls the function and wraps the result in a `Nullable`. 4804 f = sample.apply!toFloat; 4805 assert(!sample.isNull && !f.isNull); 4806 assert(f.get == 3.0f); 4807 } 4808 4809 /// 4810 nothrow pure @nogc @safe unittest 4811 { 4812 alias greaterThree = i => (i > 3) ? i.nullable : Nullable!(typeof(i)).init; 4813 4814 Nullable!int sample; 4815 4816 // when the function already returns a `Nullable`, that `Nullable` is not wrapped. 4817 auto result = sample.apply!greaterThree; 4818 assert(sample.isNull && result.isNull); 4819 4820 // The function may decide to return a null `Nullable`. 4821 sample = 3; 4822 result = sample.apply!greaterThree; 4823 assert(!sample.isNull && result.isNull); 4824 4825 // Or it may return a value already wrapped in a `Nullable`. 4826 sample = 4; 4827 result = sample.apply!greaterThree; 4828 assert(!sample.isNull && !result.isNull); 4829 assert(result.get == 4); 4830 } 4831 4832 // test that Nullable.get(default) can merge types 4833 @safe @nogc nothrow pure 4834 unittest 4835 { 4836 Nullable!ubyte sample = Nullable!ubyte(); 4837 4838 // Test that get(U) returns the common type of the Nullable type and the parameter type. 4839 assert(sample.get(1000) == 1000); 4840 } 4841 4842 // Workaround for https://issues.dlang.org/show_bug.cgi?id=20670 4843 @safe @nogc nothrow pure 4844 unittest 4845 { 4846 immutable struct S { } 4847 4848 S[] array = Nullable!(S[])().get(S[].init); 4849 } 4850 4851 // regression test for https://issues.dlang.org/show_bug.cgi?id=21199 4852 @safe @nogc nothrow pure 4853 unittest 4854 { 4855 struct S { int i; } 4856 assert(S(5).nullable.apply!"a.i" == 5); 4857 } 4858 4859 // regression test for https://issues.dlang.org/show_bug.cgi?id=22176 4860 @safe @nogc nothrow pure 4861 unittest 4862 { 4863 struct S 4864 { 4865 int i; 4866 invariant(i != 0); 4867 4868 // Nullable shouldn't cause S to generate an 4869 // opAssign that would check the invariant. 4870 Nullable!int j; 4871 } 4872 S s; 4873 s = S(5); 4874 } 4875 4876 /** 4877 Just like `Nullable!T`, except that the object refers to a value 4878 sitting elsewhere in memory. This makes assignments overwrite the 4879 initially assigned value. Internally `NullableRef!T` only stores a 4880 pointer to `T` (i.e., $(D Nullable!T.sizeof == (T*).sizeof)). 4881 */ 4882 struct NullableRef(T) 4883 { 4884 private T* _value; 4885 4886 /** 4887 Constructor binding `this` to `value`. 4888 4889 Params: 4890 value = The value to bind to. 4891 */ 4892 this(T* value) @safe pure nothrow 4893 { 4894 _value = value; 4895 } 4896 4897 template toString() 4898 { 4899 import std.format.spec : FormatSpec; 4900 import std.format.write : formatValue; 4901 // Needs to be a template because of https://issues.dlang.org/show_bug.cgi?id=13737. 4902 void toString()(scope void delegate(const(char)[]) sink, scope const ref FormatSpec!char fmt) 4903 { 4904 if (isNull) 4905 { 4906 sink.formatValue("Nullable.null", fmt); 4907 } 4908 else 4909 { 4910 sink.formatValue(*_value, fmt); 4911 } 4912 } 4913 4914 void toString()(scope void delegate(const(char)[]) sink, scope const ref FormatSpec!char fmt) const 4915 { 4916 if (isNull) 4917 { 4918 sink.formatValue("Nullable.null", fmt); 4919 } 4920 else 4921 { 4922 sink.formatValue(*_value, fmt); 4923 } 4924 } 4925 } 4926 4927 @system unittest 4928 { 4929 import std.conv : to; 4930 4931 const NullableRef!(ulong) x = new ulong(1); 4932 assert(x.to!string == "1"); 4933 } 4934 4935 /** 4936 Binds the internal state to `value`. 4937 4938 Params: 4939 value = A pointer to a value of type `T` to bind this `NullableRef` to. 4940 */ 4941 void bind(T* value) @safe pure nothrow 4942 { 4943 _value = value; 4944 } 4945 4946 /// 4947 @safe unittest 4948 { 4949 NullableRef!int nr = new int(42); 4950 assert(nr == 42); 4951 4952 int* n = new int(1); 4953 nr.bind(n); 4954 assert(nr == 1); 4955 } 4956 4957 /** 4958 Returns `true` if and only if `this` is in the null state. 4959 4960 Returns: 4961 true if `this` is in the null state, otherwise false. 4962 */ 4963 @property bool isNull() const @safe pure nothrow 4964 { 4965 return _value is null; 4966 } 4967 4968 /// 4969 @safe unittest 4970 { 4971 NullableRef!int nr; 4972 assert(nr.isNull); 4973 4974 int* n = new int(42); 4975 nr.bind(n); 4976 assert(!nr.isNull && nr == 42); 4977 } 4978 4979 /** 4980 Forces `this` to the null state. 4981 */ 4982 void nullify() @safe pure nothrow 4983 { 4984 _value = null; 4985 } 4986 4987 /// 4988 @safe unittest 4989 { 4990 NullableRef!int nr = new int(42); 4991 assert(!nr.isNull); 4992 4993 nr.nullify(); 4994 assert(nr.isNull); 4995 } 4996 4997 /** 4998 Assigns `value` to the internally-held state. 4999 5000 Params: 5001 value = A value of type `T` to assign to this `NullableRef`. 5002 If the internal state of this `NullableRef` has not 5003 been initialized, an error will be thrown in 5004 non-release mode. 5005 */ 5006 void opAssign()(T value) 5007 if (isAssignable!T) //@@@9416@@@ 5008 { 5009 enum message = "Called `opAssign' on null NullableRef!" ~ T.stringof ~ "."; 5010 assert(!isNull, message); 5011 *_value = value; 5012 } 5013 5014 /// 5015 @system unittest 5016 { 5017 import std.exception : assertThrown, assertNotThrown; 5018 5019 NullableRef!int nr; 5020 assert(nr.isNull); 5021 assertThrown!Throwable(nr = 42); 5022 5023 nr.bind(new int(0)); 5024 assert(!nr.isNull); 5025 assertNotThrown!Throwable(nr = 42); 5026 assert(nr == 42); 5027 } 5028 5029 /** 5030 Gets the value. `this` must not be in the null state. 5031 This function is also called for the implicit conversion to `T`. 5032 */ 5033 @property ref inout(T) get() inout @safe pure nothrow 5034 { 5035 enum message = "Called `get' on null NullableRef!" ~ T.stringof ~ "."; 5036 assert(!isNull, message); 5037 return *_value; 5038 } 5039 5040 /// 5041 @system unittest 5042 { 5043 import std.exception : assertThrown, assertNotThrown; 5044 5045 NullableRef!int nr; 5046 //`get` is implicitly called. Will throw 5047 //an error in non-release mode 5048 assertThrown!Throwable(nr == 0); 5049 5050 nr.bind(new int(0)); 5051 assertNotThrown!Throwable(nr == 0); 5052 } 5053 5054 /** 5055 Implicitly converts to `T`. 5056 `this` must not be in the null state. 5057 */ 5058 alias get this; 5059 } 5060 5061 /// ditto 5062 auto nullableRef(T)(T* t) 5063 { 5064 return NullableRef!T(t); 5065 } 5066 5067 /// 5068 @system unittest 5069 { 5070 import std.exception : assertThrown; 5071 5072 int x = 5, y = 7; 5073 auto a = nullableRef(&x); 5074 assert(!a.isNull); 5075 assert(a == 5); 5076 assert(x == 5); 5077 a = 42; 5078 assert(x == 42); 5079 assert(!a.isNull); 5080 assert(a == 42); 5081 a.nullify(); 5082 assert(x == 42); 5083 assert(a.isNull); 5084 assertThrown!Throwable(a.get); 5085 assertThrown!Throwable(a = 71); 5086 a.bind(&y); 5087 assert(a == 7); 5088 y = 135; 5089 assert(a == 135); 5090 } 5091 @system unittest 5092 { 5093 static int f(scope const NullableRef!int x) { 5094 return x.isNull ? 42 : x.get; 5095 } 5096 int x = 5; 5097 auto a = nullableRef(&x); 5098 assert(f(a) == 5); 5099 a.nullify(); 5100 assert(f(a) == 42); 5101 } 5102 @safe unittest 5103 { 5104 // Ensure NullableRef can be used in pure/nothrow/@safe environment. 5105 function() @safe pure nothrow 5106 { 5107 auto storage = new int; 5108 *storage = 19902; 5109 NullableRef!int n; 5110 assert(n.isNull); 5111 n.bind(storage); 5112 assert(!n.isNull); 5113 assert(n == 19902); 5114 n = 2294; 5115 assert(n == 2294); 5116 assert(*storage == 2294); 5117 n.nullify(); 5118 assert(n.isNull); 5119 }(); 5120 } 5121 @system unittest 5122 { 5123 // Ensure NullableRef can be used when the value is not pure/nothrow/@safe 5124 static struct S 5125 { 5126 int x; 5127 this(this) @system {} 5128 bool opEquals(const S s) const @system { return s.x == x; } 5129 } 5130 5131 auto storage = S(5); 5132 5133 NullableRef!S s; 5134 assert(s.isNull); 5135 s.bind(&storage); 5136 assert(!s.isNull); 5137 assert(s.x == 5); 5138 s.nullify(); 5139 assert(s.isNull); 5140 } 5141 @safe unittest 5142 { 5143 //Check nullable is nicelly embedable in a struct 5144 static struct S1 5145 { 5146 NullableRef!int ni; 5147 } 5148 static struct S2 //inspired from 9404 5149 { 5150 NullableRef!int ni; 5151 this(S2 other) 5152 { 5153 ni = other.ni; 5154 } 5155 void opAssign(S2 other) 5156 { 5157 ni = other.ni; 5158 } 5159 } 5160 static foreach (S; AliasSeq!(S1, S2)) 5161 {{ 5162 S a; 5163 S b = a; 5164 S c; 5165 c = a; 5166 }} 5167 } 5168 5169 // https://issues.dlang.org/show_bug.cgi?id=10915 5170 @system unittest 5171 { 5172 import std.conv : to; 5173 5174 NullableRef!int nri; 5175 assert(nri.to!string() == "Nullable.null"); 5176 5177 struct Test 5178 { 5179 string s; 5180 } 5181 NullableRef!Test nt = new Test("test"); 5182 assert(nt.to!string() == `Test("test")`); 5183 5184 class TestToString 5185 { 5186 double d; 5187 5188 this(double d) 5189 { 5190 this.d = d; 5191 } 5192 5193 override string toString() 5194 { 5195 return d.to!string(); 5196 } 5197 } 5198 TestToString tts = new TestToString(2.5); 5199 NullableRef!TestToString ntts = &tts; 5200 assert(ntts.to!string() == "2.5"); 5201 } 5202 5203 5204 /** 5205 `BlackHole!Base` is a subclass of `Base` which automatically implements 5206 all abstract member functions in `Base` as do-nothing functions. Each 5207 auto-implemented function just returns the default value of the return type 5208 without doing anything. 5209 5210 The name came from 5211 $(HTTP search.cpan.org/~sburke/Class-_BlackHole-0.04/lib/Class/_BlackHole.pm, Class::_BlackHole) 5212 Perl module by Sean M. Burke. 5213 5214 Params: 5215 Base = A non-final class for `BlackHole` to inherit from. 5216 5217 See_Also: 5218 $(LREF AutoImplement), $(LREF generateEmptyFunction) 5219 */ 5220 alias BlackHole(Base) = AutoImplement!(Base, generateEmptyFunction, isAbstractFunction); 5221 5222 /// 5223 @system unittest 5224 { 5225 import std.math.traits : isNaN; 5226 5227 static abstract class C 5228 { 5229 int m_value; 5230 this(int v) { m_value = v; } 5231 int value() @property { return m_value; } 5232 5233 abstract real realValue() @property; 5234 abstract void doSomething(); 5235 } 5236 5237 auto c = new BlackHole!C(42); 5238 assert(c.value == 42); 5239 5240 // Returns real.init which is NaN 5241 assert(c.realValue.isNaN); 5242 // Abstract functions are implemented as do-nothing 5243 c.doSomething(); 5244 } 5245 5246 @system unittest 5247 { 5248 import std.math.traits : isNaN; 5249 5250 // return default 5251 { 5252 interface I_1 { real test(); } 5253 auto o = new BlackHole!I_1; 5254 assert(o.test().isNaN()); // NaN 5255 } 5256 // doc example 5257 { 5258 static class C 5259 { 5260 int m_value; 5261 this(int v) { m_value = v; } 5262 int value() @property { return m_value; } 5263 5264 abstract real realValue() @property; 5265 abstract void doSomething(); 5266 } 5267 5268 auto c = new BlackHole!C(42); 5269 assert(c.value == 42); 5270 5271 assert(c.realValue.isNaN); // NaN 5272 c.doSomething(); 5273 } 5274 5275 // https://issues.dlang.org/show_bug.cgi?id=12058 5276 interface Foo 5277 { 5278 inout(Object) foo() inout; 5279 } 5280 BlackHole!Foo o; 5281 } 5282 5283 nothrow pure @nogc @safe unittest 5284 { 5285 static interface I 5286 { 5287 I foo() nothrow pure @nogc @safe return scope; 5288 } 5289 5290 scope cb = new BlackHole!I(); 5291 cb.foo(); 5292 } 5293 5294 5295 /** 5296 `WhiteHole!Base` is a subclass of `Base` which automatically implements 5297 all abstract member functions as functions that always fail. These functions 5298 simply throw an `Error` and never return. `Whitehole` is useful for 5299 trapping the use of class member functions that haven't been implemented. 5300 5301 The name came from 5302 $(HTTP search.cpan.org/~mschwern/Class-_WhiteHole-0.04/lib/Class/_WhiteHole.pm, Class::_WhiteHole) 5303 Perl module by Michael G Schwern. 5304 5305 Params: 5306 Base = A non-final class for `WhiteHole` to inherit from. 5307 5308 See_Also: 5309 $(LREF AutoImplement), $(LREF generateAssertTrap) 5310 */ 5311 alias WhiteHole(Base) = AutoImplement!(Base, generateAssertTrap, isAbstractFunction); 5312 5313 /// 5314 @system unittest 5315 { 5316 import std.exception : assertThrown; 5317 5318 static class C 5319 { 5320 abstract void notYetImplemented(); 5321 } 5322 5323 auto c = new WhiteHole!C; 5324 assertThrown!NotImplementedError(c.notYetImplemented()); // throws an Error 5325 } 5326 5327 // https://issues.dlang.org/show_bug.cgi?id=20232 5328 nothrow pure @safe unittest 5329 { 5330 static interface I 5331 { 5332 I foo() nothrow pure @safe return scope; 5333 } 5334 5335 if (0) // Just checking attribute interference 5336 { 5337 scope cw = new WhiteHole!I(); 5338 cw.foo(); 5339 } 5340 } 5341 5342 // / ditto 5343 class NotImplementedError : Error 5344 { 5345 this(string method) nothrow pure @safe 5346 { 5347 super(method ~ " is not implemented"); 5348 } 5349 } 5350 5351 @system unittest 5352 { 5353 import std.exception : assertThrown; 5354 // nothrow 5355 { 5356 interface I_1 5357 { 5358 void foo(); 5359 void bar() nothrow; 5360 } 5361 auto o = new WhiteHole!I_1; 5362 assertThrown!NotImplementedError(o.foo()); 5363 assertThrown!NotImplementedError(o.bar()); 5364 } 5365 // doc example 5366 { 5367 static class C 5368 { 5369 abstract void notYetImplemented(); 5370 } 5371 5372 auto c = new WhiteHole!C; 5373 try 5374 { 5375 c.notYetImplemented(); 5376 assert(0); 5377 } 5378 catch (Error e) {} 5379 } 5380 } 5381 5382 5383 /** 5384 `AutoImplement` automatically implements (by default) all abstract member 5385 functions in the class or interface `Base` in specified way. 5386 5387 The second version of `AutoImplement` automatically implements 5388 `Interface`, while deriving from `BaseClass`. 5389 5390 Params: 5391 how = template which specifies _how functions will be implemented/overridden. 5392 5393 Two arguments are passed to `how`: the type `Base` and an alias 5394 to an implemented function. Then `how` must return an implemented 5395 function body as a string. 5396 5397 The generated function body can use these keywords: 5398 $(UL 5399 $(LI `a0`, `a1`, …: arguments passed to the function;) 5400 $(LI `args`: a tuple of the arguments;) 5401 $(LI `self`: an alias to the function itself;) 5402 $(LI `parent`: an alias to the overridden function (if any).) 5403 ) 5404 5405 You may want to use templated property functions (instead of Implicit 5406 Template Properties) to generate complex functions: 5407 -------------------- 5408 // Prints log messages for each call to overridden functions. 5409 string generateLogger(C, alias fun)() @property 5410 { 5411 import std.traits; 5412 enum qname = C.stringof ~ "." ~ __traits(identifier, fun); 5413 string stmt; 5414 5415 stmt ~= q{ struct Importer { import std.stdio; } }; 5416 stmt ~= `Importer.writeln("Log: ` ~ qname ~ `(", args, ")");`; 5417 static if (!__traits(isAbstractFunction, fun)) 5418 { 5419 static if (is(ReturnType!fun == void)) 5420 stmt ~= q{ parent(args); }; 5421 else 5422 stmt ~= q{ 5423 auto r = parent(args); 5424 Importer.writeln("--> ", r); 5425 return r; 5426 }; 5427 } 5428 return stmt; 5429 } 5430 -------------------- 5431 5432 what = template which determines _what functions should be 5433 implemented/overridden. 5434 5435 An argument is passed to `what`: an alias to a non-final member 5436 function in `Base`. Then `what` must return a boolean value. 5437 Return `true` to indicate that the passed function should be 5438 implemented/overridden. 5439 5440 -------------------- 5441 // Sees if fun returns something. 5442 enum bool hasValue(alias fun) = !is(ReturnType!(fun) == void); 5443 -------------------- 5444 5445 5446 Note: 5447 5448 Generated code is inserted in the scope of `std.typecons` module. Thus, 5449 any useful functions outside `std.typecons` cannot be used in the generated 5450 code. To workaround this problem, you may `import` necessary things in a 5451 local struct, as done in the `generateLogger()` template in the above 5452 example. 5453 5454 5455 BUGS: 5456 5457 $(UL 5458 $(LI Variadic arguments to constructors are not forwarded to super.) 5459 $(LI Deep interface inheritance causes compile error with messages like 5460 "Error: function std.typecons._AutoImplement!(Foo)._AutoImplement.bar 5461 does not override any function". [$(BUGZILLA 2525)] ) 5462 $(LI The `parent` keyword is actually a delegate to the super class' 5463 corresponding member function. [$(BUGZILLA 2540)] ) 5464 $(LI Using alias template parameter in `how` and/or `what` may cause 5465 strange compile error. Use template tuple parameter instead to workaround 5466 this problem. [$(BUGZILLA 4217)] ) 5467 ) 5468 */ 5469 class AutoImplement(Base, alias how, alias what = isAbstractFunction) : Base 5470 if (!is(how == class)) 5471 { 5472 private alias autoImplement_helper_ = 5473 AutoImplement_Helper!("autoImplement_helper_", "Base", Base, typeof(this), how, what); 5474 mixin(autoImplement_helper_.code); 5475 } 5476 5477 /// ditto 5478 class AutoImplement( 5479 Interface, BaseClass, alias how, 5480 alias what = isAbstractFunction) : BaseClass, Interface 5481 if (is(Interface == interface) && is(BaseClass == class)) 5482 { 5483 private alias autoImplement_helper_ = AutoImplement_Helper!( 5484 "autoImplement_helper_", "Interface", Interface, typeof(this), how, what); 5485 mixin(autoImplement_helper_.code); 5486 } 5487 5488 /// 5489 @system unittest 5490 { 5491 interface PackageSupplier 5492 { 5493 int foo(); 5494 int bar(); 5495 } 5496 5497 static abstract class AbstractFallbackPackageSupplier : PackageSupplier 5498 { 5499 protected PackageSupplier default_, fallback; 5500 5501 this(PackageSupplier default_, PackageSupplier fallback) 5502 { 5503 this.default_ = default_; 5504 this.fallback = fallback; 5505 } 5506 5507 abstract int foo(); 5508 abstract int bar(); 5509 } 5510 5511 template fallback(T, alias func) 5512 { 5513 import std.format : format; 5514 // for all implemented methods: 5515 // - try default first 5516 // - only on a failure run & return fallback 5517 enum fallback = q{ 5518 try 5519 { 5520 return default_.%1$s(args); 5521 } 5522 catch (Exception) 5523 { 5524 return fallback.%1$s(args); 5525 } 5526 }.format(__traits(identifier, func)); 5527 } 5528 5529 // combines two classes and use the second one as fallback 5530 alias FallbackPackageSupplier = AutoImplement!(AbstractFallbackPackageSupplier, fallback); 5531 5532 class FailingPackageSupplier : PackageSupplier 5533 { 5534 int foo(){ throw new Exception("failure"); } 5535 int bar(){ return 2;} 5536 } 5537 5538 class BackupPackageSupplier : PackageSupplier 5539 { 5540 int foo(){ return -1; } 5541 int bar(){ return -1;} 5542 } 5543 5544 auto registry = new FallbackPackageSupplier(new FailingPackageSupplier(), new BackupPackageSupplier()); 5545 5546 assert(registry.foo() == -1); 5547 assert(registry.bar() == 2); 5548 } 5549 5550 /* 5551 * Code-generating stuffs are encupsulated in this helper template so that 5552 * namespace pollution, which can cause name confliction with Base's public 5553 * members, should be minimized. 5554 */ 5555 private template AutoImplement_Helper(string myName, string baseName, 5556 Base, Self, alias generateMethodBody, alias cherrypickMethod) 5557 { 5558 private static: 5559 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 5560 // Internal stuffs 5561 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 5562 5563 // Returns function overload sets in the class C, filtered with pred. 5564 template enumerateOverloads(C, alias pred) 5565 { 5566 template Impl(names...) 5567 { 5568 import std.meta : Filter; 5569 static if (names.length > 0) 5570 { 5571 alias methods = Filter!(pred, MemberFunctionsTuple!(C, names[0])); 5572 alias next = Impl!(names[1 .. $]); 5573 5574 static if (methods.length > 0) 5575 alias Impl = AliasSeq!(OverloadSet!(names[0], methods), next); 5576 else 5577 alias Impl = next; 5578 } 5579 else 5580 alias Impl = AliasSeq!(); 5581 } 5582 5583 alias enumerateOverloads = Impl!(__traits(allMembers, C)); 5584 } 5585 5586 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 5587 // Target functions 5588 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 5589 5590 // Add a non-final check to the cherrypickMethod. 5591 enum bool canonicalPicker(fun.../+[https://issues.dlang.org/show_bug.cgi?id=4217]+/) = 5592 !__traits(isFinalFunction, fun[0]) && cherrypickMethod!(fun); 5593 5594 /* 5595 * A tuple of overload sets, each item of which consists of functions to be 5596 * implemented by the generated code. 5597 */ 5598 alias targetOverloadSets = enumerateOverloads!(Base, canonicalPicker); 5599 5600 /* 5601 * Super class of this AutoImplement instance 5602 */ 5603 alias Super = BaseTypeTuple!(Self)[0]; 5604 static assert(is(Super == class)); 5605 static assert(is(Base == interface) || is(Super == Base)); 5606 5607 /* 5608 * A tuple of the super class' constructors. Used for forwarding 5609 * constructor calls. 5610 */ 5611 static if (__traits(hasMember, Super, "__ctor")) 5612 alias ctorOverloadSet = OverloadSet!("__ctor", __traits(getOverloads, Super, "__ctor")); 5613 else 5614 alias ctorOverloadSet = OverloadSet!("__ctor"); // empty 5615 5616 5617 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 5618 // Type information 5619 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 5620 5621 /* 5622 * The generated code will be mixed into AutoImplement, which will be 5623 * instantiated in this module's scope. Thus, any user-defined types are 5624 * out of scope and cannot be used directly (i.e. by their names). 5625 * 5626 * We will use FuncInfo instances for accessing return types and parameter 5627 * types of the implemented functions. The instances will be populated to 5628 * the AutoImplement's scope in a certain way; see the populate() below. 5629 */ 5630 5631 // Returns the preferred identifier for the FuncInfo instance for the i-th 5632 // overloaded function with the name. 5633 template INTERNAL_FUNCINFO_ID(string name, size_t i) 5634 { 5635 import std.format : format; 5636 5637 enum string INTERNAL_FUNCINFO_ID = format("F_%s_%s", name, i); 5638 } 5639 5640 /* 5641 * Insert FuncInfo instances about all the target functions here. This 5642 * enables the generated code to access type information via, for example, 5643 * "autoImplement_helper_.F_foo_1". 5644 */ 5645 template populate(overloads...) 5646 { 5647 static if (overloads.length > 0) 5648 { 5649 mixin populate!(overloads[0].name, overloads[0].contents); 5650 mixin populate!(overloads[1 .. $]); 5651 } 5652 } 5653 template populate(string name, methods...) 5654 { 5655 static if (methods.length > 0) 5656 { 5657 mixin populate!(name, methods[0 .. $ - 1]); 5658 // 5659 alias target = methods[$ - 1]; 5660 enum ith = methods.length - 1; 5661 mixin("alias " ~ INTERNAL_FUNCINFO_ID!(name, ith) ~ " = FuncInfo!target;"); 5662 } 5663 } 5664 5665 public mixin populate!(targetOverloadSets); 5666 public mixin populate!( ctorOverloadSet ); 5667 5668 5669 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 5670 // Code-generating policies 5671 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 5672 5673 /* Common policy configurations for generating constructors and methods. */ 5674 template CommonGeneratingPolicy() 5675 { 5676 // base class identifier which generated code should use 5677 enum string BASE_CLASS_ID = baseName; 5678 5679 // FuncInfo instance identifier which generated code should use 5680 template FUNCINFO_ID(string name, size_t i) 5681 { 5682 enum string FUNCINFO_ID = 5683 myName ~ "." ~ INTERNAL_FUNCINFO_ID!(name, i); 5684 } 5685 } 5686 5687 /* Policy configurations for generating constructors. */ 5688 template ConstructorGeneratingPolicy() 5689 { 5690 mixin CommonGeneratingPolicy; 5691 5692 /* Generates constructor body. Just forward to the base class' one. */ 5693 string generateFunctionBody(ctor.../+[https://issues.dlang.org/show_bug.cgi?id=4217]+/)() @property 5694 { 5695 enum varstyle = variadicFunctionStyle!(typeof(&ctor[0])); 5696 5697 static if (varstyle & (Variadic.c | Variadic.d)) 5698 { 5699 // the argptr-forwarding problem 5700 //pragma(msg, "Warning: AutoImplement!(", Base, ") ", 5701 // "ignored variadic arguments to the constructor ", 5702 // FunctionTypeOf!(typeof(&ctor[0])) ); 5703 } 5704 return "super(args);"; 5705 } 5706 } 5707 5708 /* Policy configurations for genearting target methods. */ 5709 template MethodGeneratingPolicy() 5710 { 5711 mixin CommonGeneratingPolicy; 5712 5713 /* Geneartes method body. */ 5714 string generateFunctionBody(func.../+[https://issues.dlang.org/show_bug.cgi?id=4217]+/)() @property 5715 { 5716 return generateMethodBody!(Base, func); // given 5717 } 5718 } 5719 5720 5721 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 5722 // Generated code 5723 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 5724 5725 alias ConstructorGenerator = MemberFunctionGenerator!(ConstructorGeneratingPolicy!()); 5726 alias MethodGenerator = MemberFunctionGenerator!(MethodGeneratingPolicy!()); 5727 5728 public enum string code = 5729 ConstructorGenerator.generateCode!( ctorOverloadSet ) ~ "\n" ~ 5730 MethodGenerator.generateCode!(targetOverloadSets); 5731 5732 debug (SHOW_GENERATED_CODE) 5733 { 5734 pragma(msg, "-------------------- < ", Base, " >"); 5735 pragma(msg, code); 5736 pragma(msg, "--------------------"); 5737 } 5738 } 5739 5740 //debug = SHOW_GENERATED_CODE; 5741 @system unittest 5742 { 5743 import core.vararg; 5744 // no function to implement 5745 { 5746 interface I_1 {} 5747 auto o = new BlackHole!I_1; 5748 } 5749 // parameters 5750 { 5751 interface I_3 { void test(int, in int, out int, ref int, lazy int); } 5752 auto o = new BlackHole!I_3; 5753 } 5754 // use of user-defined type 5755 { 5756 struct S {} 5757 interface I_4 { S test(); } 5758 auto o = new BlackHole!I_4; 5759 } 5760 // overloads 5761 { 5762 interface I_5 5763 { 5764 void test(string); 5765 real test(real); 5766 int test(); 5767 } 5768 auto o = new BlackHole!I_5; 5769 } 5770 // constructor forwarding 5771 { 5772 static class C_6 5773 { 5774 this(int n) { assert(n == 42); } 5775 this(string s) { assert(s == "Deeee"); } 5776 this(...) {} 5777 } 5778 auto o1 = new BlackHole!C_6(42); 5779 auto o2 = new BlackHole!C_6("Deeee"); 5780 auto o3 = new BlackHole!C_6(1, 2, 3, 4); 5781 } 5782 // attributes 5783 { 5784 interface I_7 5785 { 5786 ref int test_ref(); 5787 int test_pure() pure; 5788 int test_nothrow() nothrow; 5789 int test_property() @property; 5790 int test_safe() @safe; 5791 int test_trusted() @trusted; 5792 int test_system() @system; 5793 int test_pure_nothrow() pure nothrow; 5794 } 5795 auto o = new BlackHole!I_7; 5796 } 5797 // storage classes 5798 { 5799 interface I_8 5800 { 5801 void test_const() const; 5802 void test_immutable() immutable; 5803 void test_shared() shared; 5804 void test_shared_const() shared const; 5805 } 5806 auto o = new BlackHole!I_8; 5807 } 5808 // use baseclass 5809 { 5810 static class C_9 5811 { 5812 private string foo_; 5813 5814 this(string s) { 5815 foo_ = s; 5816 } 5817 5818 protected string boilerplate() @property 5819 { 5820 return "Boilerplate stuff."; 5821 } 5822 5823 public string foo() @property 5824 { 5825 return foo_; 5826 } 5827 } 5828 5829 interface I_10 5830 { 5831 string testMethod(size_t); 5832 } 5833 5834 static string generateTestMethod(C, alias fun)() @property 5835 { 5836 return "return this.boilerplate[0 .. a0];"; 5837 } 5838 5839 auto o = new AutoImplement!(I_10, C_9, generateTestMethod)("Testing"); 5840 assert(o.testMethod(11) == "Boilerplate"); 5841 assert(o.foo == "Testing"); 5842 } 5843 /+ // deep inheritance 5844 { 5845 // https://issues.dlang.org/show_bug.cgi?id=2525 5846 // https://issues.dlang.org/show_bug.cgi?id=3525 5847 // NOTE: [r494] func.c(504-571) FuncDeclaration::semantic() 5848 interface I { void foo(); } 5849 interface J : I {} 5850 interface K : J {} 5851 static abstract class C_9 : K {} 5852 auto o = new BlackHole!C_9; 5853 }+/ 5854 // test `parent` alias 5855 { 5856 interface I_11 5857 { 5858 void simple(int) @safe; 5859 int anotherSimple(string); 5860 int overloaded(int); 5861 /+ XXX [BUG 19715] 5862 void overloaded(string) @safe; 5863 +/ 5864 } 5865 5866 static class C_11 5867 { 5868 import std.traits : Parameters, ReturnType; 5869 import std.meta : Alias; 5870 5871 protected ReturnType!fn _impl(alias fn)(Parameters!fn) 5872 if (is(Alias!(__traits(parent, fn)) == interface)) 5873 { 5874 static if (!is(typeof(return) == void)) 5875 return typeof(return).init; 5876 } 5877 } 5878 5879 template tpl(I, alias fn) 5880 if (is(I == interface) && __traits(isSame, __traits(parent, fn), I)) 5881 { 5882 enum string tpl = q{ 5883 enum bool haveReturn = !is(typeof(return) == void); 5884 5885 static if (is(typeof(return) == void)) 5886 _impl!parent(args); 5887 else 5888 return _impl!parent(args); 5889 }; 5890 } 5891 5892 auto o = new AutoImplement!(I_11, C_11, tpl); 5893 } 5894 } 5895 5896 // https://issues.dlang.org/show_bug.cgi?id=17177 5897 // AutoImplement fails on function overload sets with 5898 // "cannot infer type from overloaded function symbol" 5899 @system unittest 5900 { 5901 static class Issue17177 5902 { 5903 private string n_; 5904 5905 public { 5906 Issue17177 overloaded(string n) 5907 { 5908 this.n_ = n; 5909 5910 return this; 5911 } 5912 5913 string overloaded() 5914 { 5915 return this.n_; 5916 } 5917 } 5918 } 5919 5920 static string how(C, alias fun)() 5921 { 5922 static if (!is(ReturnType!fun == void)) 5923 { 5924 return q{ 5925 return parent(args); 5926 }; 5927 } 5928 else 5929 { 5930 return q{ 5931 parent(args); 5932 }; 5933 } 5934 } 5935 5936 import std.meta : templateNot; 5937 alias Implementation = AutoImplement!(Issue17177, how, templateNot!isFinalFunction); 5938 } 5939 5940 version (StdUnittest) 5941 { 5942 // https://issues.dlang.org/show_bug.cgi?id=10647 5943 // Add prefix "issue10647_" as a workaround for 5944 // https://issues.dlang.org/show_bug.cgi?id=1238 5945 private string issue10647_generateDoNothing(C, alias fun)() @property 5946 { 5947 string stmt; 5948 5949 static if (is(ReturnType!fun == void)) 5950 stmt ~= ""; 5951 else 5952 { 5953 string returnType = ReturnType!fun.stringof; 5954 stmt ~= "return "~returnType~".init;"; 5955 } 5956 return stmt; 5957 } 5958 5959 private template issue10647_isAlwaysTrue(alias fun) 5960 { 5961 enum issue10647_isAlwaysTrue = true; 5962 } 5963 5964 // Do nothing template 5965 private template issue10647_DoNothing(Base) 5966 { 5967 alias issue10647_DoNothing = AutoImplement!(Base, issue10647_generateDoNothing, issue10647_isAlwaysTrue); 5968 } 5969 5970 // A class to be overridden 5971 private class issue10647_Foo{ 5972 void bar(int a) { } 5973 } 5974 } 5975 5976 @system unittest 5977 { 5978 auto foo = new issue10647_DoNothing!issue10647_Foo(); 5979 foo.bar(13); 5980 } 5981 5982 /* 5983 Used by MemberFunctionGenerator. 5984 */ 5985 package template OverloadSet(string nam, T...) 5986 { 5987 enum string name = nam; 5988 alias contents = T; 5989 } 5990 5991 /* 5992 Used by MemberFunctionGenerator. 5993 */ 5994 package template FuncInfo(alias func) 5995 if (is(typeof(&func))) 5996 { 5997 alias RT = ReturnType!(typeof(&func)); 5998 alias PT = Parameters!(typeof(&func)); 5999 } 6000 package template FuncInfo(Func) 6001 { 6002 alias RT = ReturnType!Func; 6003 alias PT = Parameters!Func; 6004 } 6005 6006 /* 6007 General-purpose member function generator. 6008 -------------------- 6009 template GeneratingPolicy() 6010 { 6011 // [optional] the name of the class where functions are derived 6012 enum string BASE_CLASS_ID; 6013 6014 // [optional] define this if you have only function types 6015 enum bool WITHOUT_SYMBOL; 6016 6017 // [optional] Returns preferred identifier for i-th parameter. 6018 template PARAMETER_VARIABLE_ID(size_t i); 6019 6020 // Returns the identifier of the FuncInfo instance for the i-th overload 6021 // of the specified name. The identifier must be accessible in the scope 6022 // where generated code is mixed. 6023 template FUNCINFO_ID(string name, size_t i); 6024 6025 // Returns implemented function body as a string. When WITHOUT_SYMBOL is 6026 // defined, the latter is used. 6027 template generateFunctionBody(alias func); 6028 template generateFunctionBody(string name, FuncType); 6029 } 6030 -------------------- 6031 */ 6032 package template MemberFunctionGenerator(alias Policy) 6033 { 6034 private static: 6035 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 6036 // Internal stuffs 6037 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 6038 import std.format; 6039 alias format = std.format.format; 6040 6041 enum CONSTRUCTOR_NAME = "__ctor"; 6042 6043 // true if functions are derived from a base class 6044 enum WITH_BASE_CLASS = __traits(hasMember, Policy, "BASE_CLASS_ID"); 6045 6046 // true if functions are specified as types, not symbols 6047 enum WITHOUT_SYMBOL = __traits(hasMember, Policy, "WITHOUT_SYMBOL"); 6048 6049 // preferred identifier for i-th parameter variable 6050 static if (__traits(hasMember, Policy, "PARAMETER_VARIABLE_ID")) 6051 { 6052 alias PARAMETER_VARIABLE_ID = Policy.PARAMETER_VARIABLE_ID; 6053 } 6054 else 6055 { 6056 enum string PARAMETER_VARIABLE_ID(size_t i) = format("a%s", i); 6057 // default: a0, a1, ... 6058 } 6059 6060 // Returns a tuple consisting of 0,1,2,...,n-1. For static foreach. 6061 template CountUp(size_t n) 6062 { 6063 static if (n > 0) 6064 alias CountUp = AliasSeq!(CountUp!(n - 1), n - 1); 6065 else 6066 alias CountUp = AliasSeq!(); 6067 } 6068 6069 6070 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 6071 // Code generator 6072 //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::// 6073 6074 /* 6075 * Runs through all the target overload sets and generates D code which 6076 * implements all the functions in the overload sets. 6077 */ 6078 public string generateCode(overloads...)() @property 6079 { 6080 string code = ""; 6081 6082 // run through all the overload sets 6083 foreach (i_; CountUp!(0 + overloads.length)) // workaround 6084 { 6085 enum i = 0 + i_; // workaround 6086 alias oset = overloads[i]; 6087 6088 code ~= generateCodeForOverloadSet!(oset); 6089 6090 static if (WITH_BASE_CLASS && oset.name != CONSTRUCTOR_NAME) 6091 { 6092 // The generated function declarations may hide existing ones 6093 // in the base class (cf. HiddenFuncError), so we put an alias 6094 // declaration here to reveal possible hidden functions. 6095 code ~= format("alias %s = %s.%s;\n", 6096 oset.name, 6097 // super: https://issues.dlang.org/show_bug.cgi?id=2540 6098 Policy.BASE_CLASS_ID, 6099 oset.name); 6100 } 6101 } 6102 return code; 6103 } 6104 6105 // handle each overload set 6106 string generateCodeForOverloadSet(alias oset)() @property 6107 { 6108 string code = ""; 6109 6110 foreach (i_; CountUp!(0 + oset.contents.length)) // workaround 6111 { 6112 enum i = 0 + i_; // workaround 6113 code ~= generateFunction!( 6114 Policy.FUNCINFO_ID!(oset.name, i), oset.name, 6115 oset.contents[i]) ~ "\n"; 6116 } 6117 return code; 6118 } 6119 6120 /* 6121 * Returns D code which implements the function func. This function 6122 * actually generates only the declarator part; the function body part is 6123 * generated by the functionGenerator() policy. 6124 */ 6125 public string generateFunction( 6126 string myFuncInfo, string name, func... )() @property 6127 { 6128 import std.format : format; 6129 6130 enum isCtor = (name == CONSTRUCTOR_NAME); 6131 6132 string code; // the result 6133 6134 auto paramsRes = generateParameters!(myFuncInfo, func)(); 6135 code ~= paramsRes.imports; 6136 6137 /*** Function Declarator ***/ 6138 { 6139 alias Func = FunctionTypeOf!(func); 6140 alias FA = FunctionAttribute; 6141 enum atts = functionAttributes!(func); 6142 enum realName = isCtor ? "this" : name; 6143 6144 // FIXME?? Make it so that these aren't CTFE funcs any more, since 6145 // Format is deprecated, and format works at compile time? 6146 /* Made them CTFE funcs just for the sake of Format!(...) */ 6147 6148 // return type with optional "ref" 6149 static string make_returnType() 6150 { 6151 string rtype = ""; 6152 6153 if (!isCtor) 6154 { 6155 if (atts & FA.ref_) rtype ~= "ref "; 6156 rtype ~= myFuncInfo ~ ".RT"; 6157 } 6158 return rtype; 6159 } 6160 enum returnType = make_returnType(); 6161 6162 // function attributes attached after declaration 6163 static string make_postAtts() 6164 { 6165 string poatts = ""; 6166 if (atts & FA.pure_ ) poatts ~= " pure"; 6167 if (atts & FA.nothrow_) poatts ~= " nothrow"; 6168 if (atts & FA.property) poatts ~= " @property"; 6169 if (atts & FA.safe ) poatts ~= " @safe"; 6170 if (atts & FA.trusted ) poatts ~= " @trusted"; 6171 if (atts & FA.scope_ ) poatts ~= " scope"; 6172 if (atts & FA.return_ ) poatts ~= " return"; 6173 return poatts; 6174 } 6175 enum postAtts = make_postAtts(); 6176 6177 // function storage class 6178 static string make_storageClass() 6179 { 6180 string postc = ""; 6181 if (is(Func == shared)) postc ~= " shared"; 6182 if (is(Func == const)) postc ~= " const"; 6183 if (is(Func == inout)) postc ~= " inout"; 6184 if (is(Func == immutable)) postc ~= " immutable"; 6185 return postc; 6186 } 6187 enum storageClass = make_storageClass(); 6188 6189 // 6190 if (__traits(isVirtualMethod, func)) 6191 code ~= "override "; 6192 code ~= format("extern(%s) %s %s(%s) %s %s\n", 6193 functionLinkage!(func), 6194 returnType, 6195 realName, 6196 paramsRes.params, 6197 postAtts, storageClass ); 6198 } 6199 6200 /*** Function Body ***/ 6201 code ~= "{\n"; 6202 { 6203 enum nparams = Parameters!(func).length; 6204 6205 /* Declare keywords: args, self and parent. */ 6206 string preamble; 6207 6208 preamble ~= "alias args = AliasSeq!(" ~ enumerateParameters!(nparams) ~ ");\n"; 6209 if (!isCtor) 6210 { 6211 preamble ~= "alias self = " ~ name ~ ";\n"; 6212 static if (WITH_BASE_CLASS) 6213 preamble ~= `alias parent = __traits(getMember, ` ~ Policy.BASE_CLASS_ID ~ `, "` ~ name ~ `");`; 6214 } 6215 6216 // Function body 6217 static if (WITHOUT_SYMBOL) 6218 enum fbody = Policy.generateFunctionBody!(name, func); 6219 else 6220 enum fbody = Policy.generateFunctionBody!(func); 6221 6222 code ~= preamble; 6223 code ~= fbody; 6224 } 6225 code ~= "}"; 6226 6227 return code; 6228 } 6229 6230 /* 6231 * Returns D code which declares function parameters, 6232 * and optionally any imports (e.g. core.vararg) 6233 * "ref int a0, real a1, ..." 6234 */ 6235 static struct GenParams { string imports, params; } 6236 GenParams generateParameters(string myFuncInfo, func...)() 6237 { 6238 alias STC = ParameterStorageClass; 6239 alias stcs = ParameterStorageClassTuple!(func); 6240 enum nparams = stcs.length; 6241 6242 string imports = ""; // any imports required 6243 string params = ""; // parameters 6244 6245 foreach (i, stc; stcs) 6246 { 6247 if (i > 0) params ~= ", "; 6248 6249 // Parameter storage classes. 6250 if (stc & STC.scope_) params ~= "scope "; 6251 if (stc & STC.in_) params ~= "in "; 6252 if (stc & STC.out_ ) params ~= "out "; 6253 if (stc & STC.ref_ ) params ~= "ref "; 6254 if (stc & STC.lazy_ ) params ~= "lazy "; 6255 6256 // Take parameter type from the FuncInfo. 6257 params ~= format("%s.PT[%s]", myFuncInfo, i); 6258 6259 // Declare a parameter variable. 6260 params ~= " " ~ PARAMETER_VARIABLE_ID!(i); 6261 } 6262 6263 // Add some ellipsis part if needed. 6264 auto style = variadicFunctionStyle!(func); 6265 final switch (style) 6266 { 6267 case Variadic.no: 6268 break; 6269 6270 case Variadic.c, Variadic.d: 6271 imports ~= "import core.vararg;\n"; 6272 // (...) or (a, b, ...) 6273 params ~= (nparams == 0) ? "..." : ", ..."; 6274 break; 6275 6276 case Variadic.typesafe: 6277 params ~= " ..."; 6278 break; 6279 } 6280 6281 return typeof(return)(imports, params); 6282 } 6283 6284 // Returns D code which enumerates n parameter variables using comma as the 6285 // separator. "a0, a1, a2, a3" 6286 string enumerateParameters(size_t n)() @property 6287 { 6288 string params = ""; 6289 6290 foreach (i_; CountUp!(n)) 6291 { 6292 enum i = 0 + i_; // workaround 6293 if (i > 0) params ~= ", "; 6294 params ~= PARAMETER_VARIABLE_ID!(i); 6295 } 6296 return params; 6297 } 6298 } 6299 6300 6301 /** 6302 Predefined how-policies for `AutoImplement`. These templates are also used by 6303 `BlackHole` and `WhiteHole`, respectively. 6304 */ 6305 template generateEmptyFunction(C, func.../+[https://issues.dlang.org/show_bug.cgi?id=4217]+/) 6306 { 6307 static if (is(ReturnType!(func) == void)) 6308 enum string generateEmptyFunction = q{ 6309 }; 6310 else static if (functionAttributes!(func) & FunctionAttribute.ref_) 6311 enum string generateEmptyFunction = q{ 6312 static typeof(return) dummy; 6313 return dummy; 6314 }; 6315 else 6316 enum string generateEmptyFunction = q{ 6317 return typeof(return).init; 6318 }; 6319 } 6320 6321 /// 6322 @system unittest 6323 { 6324 alias BlackHole(Base) = AutoImplement!(Base, generateEmptyFunction); 6325 6326 interface I 6327 { 6328 int foo(); 6329 string bar(); 6330 } 6331 6332 auto i = new BlackHole!I(); 6333 // generateEmptyFunction returns the default value of the return type without doing anything 6334 assert(i.foo == 0); 6335 assert(i.bar is null); 6336 } 6337 6338 /// ditto 6339 template generateAssertTrap(C, func...) 6340 { 6341 enum string generateAssertTrap = 6342 `throw new NotImplementedError("` ~ C.stringof ~ "." 6343 ~ __traits(identifier, func) ~ `");`; 6344 } 6345 6346 /// 6347 @system unittest 6348 { 6349 import std.exception : assertThrown; 6350 6351 alias WhiteHole(Base) = AutoImplement!(Base, generateAssertTrap); 6352 6353 interface I 6354 { 6355 int foo(); 6356 string bar(); 6357 } 6358 6359 auto i = new WhiteHole!I(); 6360 // generateAssertTrap throws an exception for every unimplemented function of the interface 6361 assertThrown!NotImplementedError(i.foo); 6362 assertThrown!NotImplementedError(i.bar); 6363 } 6364 6365 private 6366 { 6367 pragma(mangle, "_d_toObject") 6368 extern(C) pure nothrow Object typecons_d_toObject(void* p); 6369 } 6370 6371 /* 6372 * Avoids opCast operator overloading. 6373 */ 6374 private template dynamicCast(T) 6375 if (is(T == class) || is(T == interface)) 6376 { 6377 @trusted 6378 T dynamicCast(S)(inout S source) 6379 if (is(S == class) || is(S == interface)) 6380 { 6381 static if (is(Unqual!S : Unqual!T)) 6382 { 6383 import std.traits : QualifierOf; 6384 alias Qual = QualifierOf!S; // SharedOf or MutableOf 6385 alias TmpT = Qual!(Unqual!T); 6386 inout(TmpT) tmp = source; // bypass opCast by implicit conversion 6387 return *cast(T*)(&tmp); // + variable pointer cast + dereference 6388 } 6389 else 6390 { 6391 return cast(T) typecons_d_toObject(*cast(void**)(&source)); 6392 } 6393 } 6394 } 6395 6396 @system unittest 6397 { 6398 class C { @disable void opCast(T)(); } 6399 auto c = new C; 6400 static assert(!__traits(compiles, cast(Object) c)); 6401 auto o = dynamicCast!Object(c); 6402 assert(c is o); 6403 6404 interface I { @disable void opCast(T)(); Object instance(); } 6405 interface J { @disable void opCast(T)(); Object instance(); } 6406 class D : I, J { Object instance() { return this; } } 6407 I i = new D(); 6408 static assert(!__traits(compiles, cast(J) i)); 6409 J j = dynamicCast!J(i); 6410 assert(i.instance() is j.instance()); 6411 } 6412 6413 /** 6414 Supports structural based typesafe conversion. 6415 6416 If `Source` has structural conformance with the `interface` `Targets`, 6417 wrap creates an internal wrapper class which inherits `Targets` and 6418 wraps the `src` object, then returns it. 6419 6420 `unwrap` can be used to extract objects which have been wrapped by `wrap`. 6421 */ 6422 template wrap(Targets...) 6423 if (Targets.length >= 1 && allSatisfy!(isMutable, Targets)) 6424 { 6425 import std.meta : staticMap; 6426 6427 // strict upcast 6428 auto wrap(Source)(inout Source src) @trusted pure nothrow 6429 if (Targets.length == 1 && is(Source : Targets[0])) 6430 { 6431 alias T = Select!(is(Source == shared), shared Targets[0], Targets[0]); 6432 return dynamicCast!(inout T)(src); 6433 } 6434 // structural upcast 6435 template wrap(Source) 6436 if (!allSatisfy!(Bind!(isImplicitlyConvertible, Source), Targets)) 6437 { 6438 auto wrap(inout Source src) 6439 { 6440 static assert(hasRequireMethods!(), 6441 "Source "~Source.stringof~ 6442 " does not have structural conformance to "~ 6443 Targets.stringof); 6444 6445 alias T = Select!(is(Source == shared), shared Impl, Impl); 6446 return new inout T(src); 6447 } 6448 6449 template FuncInfo(string s, F) 6450 { 6451 enum name = s; 6452 alias type = F; 6453 } 6454 6455 // https://issues.dlang.org/show_bug.cgi?id=12064: Remove NVI members 6456 template OnlyVirtual(members...) 6457 { 6458 enum notFinal(alias T) = !__traits(isFinalFunction, T); 6459 import std.meta : Filter; 6460 alias OnlyVirtual = Filter!(notFinal, members); 6461 } 6462 6463 // Concat all Targets function members into one tuple 6464 template Concat(size_t i = 0) 6465 { 6466 static if (i >= Targets.length) 6467 alias Concat = AliasSeq!(); 6468 else 6469 { 6470 alias Concat = AliasSeq!(OnlyVirtual!(GetOverloadedMethods!(Targets[i]), Concat!(i + 1))); 6471 } 6472 } 6473 6474 // Remove duplicated functions based on the identifier name and function type covariance 6475 template Uniq(members...) 6476 { 6477 static if (members.length == 0) 6478 alias Uniq = AliasSeq!(); 6479 else 6480 { 6481 alias func = members[0]; 6482 enum name = __traits(identifier, func); 6483 alias type = FunctionTypeOf!func; 6484 template check(size_t i, mem...) 6485 { 6486 static if (i >= mem.length) 6487 enum ptrdiff_t check = -1; 6488 else 6489 { 6490 enum ptrdiff_t check = 6491 __traits(identifier, func) == __traits(identifier, mem[i]) && 6492 !is(DerivedFunctionType!(type, FunctionTypeOf!(mem[i])) == void) 6493 ? i : check!(i + 1, mem); 6494 } 6495 } 6496 enum ptrdiff_t x = 1 + check!(0, members[1 .. $]); 6497 static if (x >= 1) 6498 { 6499 alias typex = DerivedFunctionType!(type, FunctionTypeOf!(members[x])); 6500 alias remain = Uniq!(members[1 .. x], members[x + 1 .. $]); 6501 6502 static if (remain.length >= 1 && remain[0].name == name && 6503 !is(DerivedFunctionType!(typex, remain[0].type) == void)) 6504 { 6505 alias F = DerivedFunctionType!(typex, remain[0].type); 6506 alias Uniq = AliasSeq!(FuncInfo!(name, F), remain[1 .. $]); 6507 } 6508 else 6509 alias Uniq = AliasSeq!(FuncInfo!(name, typex), remain); 6510 } 6511 else 6512 { 6513 alias Uniq = AliasSeq!(FuncInfo!(name, type), Uniq!(members[1 .. $])); 6514 } 6515 } 6516 } 6517 alias TargetMembers = Uniq!(Concat!()); // list of FuncInfo 6518 alias SourceMembers = GetOverloadedMethods!Source; // list of function symbols 6519 6520 // Check whether all of SourceMembers satisfy covariance target in TargetMembers 6521 template hasRequireMethods(size_t i = 0) 6522 { 6523 static if (i >= TargetMembers.length) 6524 enum hasRequireMethods = true; 6525 else 6526 { 6527 enum hasRequireMethods = 6528 findCovariantFunction!(TargetMembers[i], Source, SourceMembers) != -1 && 6529 hasRequireMethods!(i + 1); 6530 } 6531 } 6532 6533 // Internal wrapper class 6534 final class Impl : Structural, Targets 6535 { 6536 private: 6537 Source _wrap_source; 6538 6539 this( inout Source s) inout @safe pure nothrow { _wrap_source = s; } 6540 this(shared inout Source s) shared inout @safe pure nothrow { _wrap_source = s; } 6541 6542 // BUG: making private should work with NVI. 6543 protected final inout(Object) _wrap_getSource() inout @trusted 6544 { 6545 return dynamicCast!(inout Object)(_wrap_source); 6546 } 6547 6548 import std.conv : to; 6549 import core.lifetime : forward; 6550 template generateFun(size_t i) 6551 { 6552 enum name = TargetMembers[i].name; 6553 enum fa = functionAttributes!(TargetMembers[i].type); 6554 static @property stc() 6555 { 6556 string r; 6557 if (fa & FunctionAttribute.property) r ~= "@property "; 6558 if (fa & FunctionAttribute.ref_) r ~= "ref "; 6559 if (fa & FunctionAttribute.pure_) r ~= "pure "; 6560 if (fa & FunctionAttribute.nothrow_) r ~= "nothrow "; 6561 if (fa & FunctionAttribute.trusted) r ~= "@trusted "; 6562 if (fa & FunctionAttribute.safe) r ~= "@safe "; 6563 return r; 6564 } 6565 static @property mod() 6566 { 6567 alias type = AliasSeq!(TargetMembers[i].type)[0]; 6568 string r; 6569 static if (is(type == immutable)) r ~= " immutable"; 6570 else 6571 { 6572 static if (is(type == shared)) r ~= " shared"; 6573 static if (is(type == const)) r ~= " const"; 6574 else static if (is(type == inout)) r ~= " inout"; 6575 //else --> mutable 6576 } 6577 return r; 6578 } 6579 enum n = to!string(i); 6580 static if (fa & FunctionAttribute.property) 6581 { 6582 static if (Parameters!(TargetMembers[i].type).length == 0) 6583 enum fbody = "_wrap_source."~name; 6584 else 6585 enum fbody = "_wrap_source."~name~" = forward!args"; 6586 } 6587 else 6588 { 6589 enum fbody = "_wrap_source."~name~"(forward!args)"; 6590 } 6591 enum generateFun = 6592 "override "~stc~"ReturnType!(TargetMembers["~n~"].type) " 6593 ~ name~"(Parameters!(TargetMembers["~n~"].type) args) "~mod~ 6594 "{ return "~fbody~"; }"; 6595 } 6596 6597 public: 6598 static foreach (i; 0 .. TargetMembers.length) 6599 mixin(generateFun!i); 6600 } 6601 } 6602 } 6603 /// ditto 6604 template wrap(Targets...) 6605 if (Targets.length >= 1 && !allSatisfy!(isMutable, Targets)) 6606 { 6607 import std.meta : staticMap; 6608 6609 alias wrap = .wrap!(staticMap!(Unqual, Targets)); 6610 } 6611 6612 /// ditto 6613 template unwrap(Target) 6614 if (isMutable!Target) 6615 { 6616 // strict downcast 6617 auto unwrap(Source)(inout Source src) @trusted pure nothrow 6618 if (is(Target : Source)) 6619 { 6620 alias T = Select!(is(Source == shared), shared Target, Target); 6621 return dynamicCast!(inout T)(src); 6622 } 6623 // structural downcast 6624 auto unwrap(Source)(inout Source src) @trusted pure nothrow 6625 if (!is(Target : Source)) 6626 { 6627 alias T = Select!(is(Source == shared), shared Target, Target); 6628 Object o = dynamicCast!(Object)(src); // remove qualifier 6629 do 6630 { 6631 if (auto a = dynamicCast!(Structural)(o)) 6632 { 6633 if (auto d = dynamicCast!(inout T)(o = a._wrap_getSource())) 6634 return d; 6635 } 6636 else if (auto d = dynamicCast!(inout T)(o)) 6637 return d; 6638 else 6639 break; 6640 } while (o); 6641 return null; 6642 } 6643 } 6644 6645 /// ditto 6646 template unwrap(Target) 6647 if (!isMutable!Target) 6648 { 6649 alias unwrap = .unwrap!(Unqual!Target); 6650 } 6651 6652 /// 6653 @system unittest 6654 { 6655 interface Quack 6656 { 6657 int quack(); 6658 @property int height(); 6659 } 6660 interface Flyer 6661 { 6662 @property int height(); 6663 } 6664 class Duck : Quack 6665 { 6666 int quack() { return 1; } 6667 @property int height() { return 10; } 6668 } 6669 class Human 6670 { 6671 int quack() { return 2; } 6672 @property int height() { return 20; } 6673 } 6674 6675 Duck d1 = new Duck(); 6676 Human h1 = new Human(); 6677 6678 interface Refleshable 6679 { 6680 int reflesh(); 6681 } 6682 6683 // does not have structural conformance 6684 static assert(!__traits(compiles, d1.wrap!Refleshable)); 6685 static assert(!__traits(compiles, h1.wrap!Refleshable)); 6686 6687 // strict upcast 6688 Quack qd = d1.wrap!Quack; 6689 assert(qd is d1); 6690 assert(qd.quack() == 1); // calls Duck.quack 6691 // strict downcast 6692 Duck d2 = qd.unwrap!Duck; 6693 assert(d2 is d1); 6694 6695 // structural upcast 6696 Quack qh = h1.wrap!Quack; 6697 assert(qh.quack() == 2); // calls Human.quack 6698 // structural downcast 6699 Human h2 = qh.unwrap!Human; 6700 assert(h2 is h1); 6701 6702 // structural upcast (two steps) 6703 Quack qx = h1.wrap!Quack; // Human -> Quack 6704 Flyer fx = qx.wrap!Flyer; // Quack -> Flyer 6705 assert(fx.height == 20); // calls Human.height 6706 // structural downcast (two steps) 6707 Quack qy = fx.unwrap!Quack; // Flyer -> Quack 6708 Human hy = qy.unwrap!Human; // Quack -> Human 6709 assert(hy is h1); 6710 // structural downcast (one step) 6711 Human hz = fx.unwrap!Human; // Flyer -> Human 6712 assert(hz is h1); 6713 } 6714 6715 /// 6716 @system unittest 6717 { 6718 import std.traits : FunctionAttribute, functionAttributes; 6719 interface A { int run(); } 6720 interface B { int stop(); @property int status(); } 6721 class X 6722 { 6723 int run() { return 1; } 6724 int stop() { return 2; } 6725 @property int status() { return 3; } 6726 } 6727 6728 auto x = new X(); 6729 auto ab = x.wrap!(A, B); 6730 A a = ab; 6731 B b = ab; 6732 assert(a.run() == 1); 6733 assert(b.stop() == 2); 6734 assert(b.status == 3); 6735 static assert(functionAttributes!(typeof(ab).status) & FunctionAttribute.property); 6736 } 6737 6738 // Internal class to support dynamic cross-casting 6739 private interface Structural 6740 { 6741 inout(Object) _wrap_getSource() inout @safe pure nothrow; 6742 } 6743 6744 @system unittest 6745 { 6746 class A 6747 { 6748 int draw() { return 1; } 6749 int draw(int v) { return v; } 6750 6751 int draw() const { return 2; } 6752 int draw() shared { return 3; } 6753 int draw() shared const { return 4; } 6754 int draw() immutable { return 5; } 6755 } 6756 interface Drawable 6757 { 6758 int draw(); 6759 int draw() const; 6760 int draw() shared; 6761 int draw() shared const; 6762 int draw() immutable; 6763 } 6764 interface Drawable2 6765 { 6766 int draw(int v); 6767 } 6768 6769 auto ma = new A(); 6770 auto sa = new shared A(); 6771 auto ia = new immutable A(); 6772 { 6773 Drawable md = ma.wrap!Drawable; 6774 const Drawable cd = ma.wrap!Drawable; 6775 shared Drawable sd = sa.wrap!Drawable; 6776 shared const Drawable scd = sa.wrap!Drawable; 6777 immutable Drawable id = ia.wrap!Drawable; 6778 assert( md.draw() == 1); 6779 assert( cd.draw() == 2); 6780 assert( sd.draw() == 3); 6781 assert(scd.draw() == 4); 6782 assert( id.draw() == 5); 6783 } 6784 { 6785 Drawable2 d = ma.wrap!Drawable2; 6786 static assert(!__traits(compiles, d.draw())); 6787 assert(d.draw(10) == 10); 6788 } 6789 } 6790 6791 // https://issues.dlang.org/show_bug.cgi?id=10377 6792 @system unittest 6793 { 6794 import std.range, std.algorithm; 6795 6796 interface MyInputRange(T) 6797 { 6798 @property T front(); 6799 void popFront(); 6800 @property bool empty(); 6801 } 6802 6803 //auto o = iota(0,10,1).inputRangeObject(); 6804 //pragma(msg, __traits(allMembers, typeof(o))); 6805 auto r = iota(0,10,1).inputRangeObject().wrap!(MyInputRange!int)(); 6806 assert(equal(r, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); 6807 } 6808 6809 // https://issues.dlang.org/show_bug.cgi?id=10536 6810 @system unittest 6811 { 6812 interface Interface 6813 { 6814 int foo(); 6815 } 6816 class Pluggable 6817 { 6818 int foo() { return 1; } 6819 @disable void opCast(T, this X)(); // ! 6820 } 6821 6822 Interface i = new Pluggable().wrap!Interface; 6823 assert(i.foo() == 1); 6824 } 6825 @system unittest 6826 { 6827 // Enhancement 10538 6828 interface Interface 6829 { 6830 int foo(); 6831 int bar(int); 6832 } 6833 class Pluggable 6834 { 6835 int opDispatch(string name, A...)(A args) { return 100; } 6836 } 6837 6838 Interface i = wrap!Interface(new Pluggable()); 6839 assert(i.foo() == 100); 6840 assert(i.bar(10) == 100); 6841 } 6842 6843 // https://issues.dlang.org/show_bug.cgi?id=12064 6844 @system unittest 6845 { 6846 interface I 6847 { 6848 int foo(); 6849 final int nvi1(){return foo();} 6850 } 6851 6852 interface J 6853 { 6854 int bar(); 6855 final int nvi2(){return bar();} 6856 } 6857 6858 class Baz 6859 { 6860 int foo() { return 42;} 6861 int bar() { return 12064;} 6862 } 6863 6864 auto baz = new Baz(); 6865 auto foobar = baz.wrap!(I, J)(); 6866 assert(foobar.nvi1 == 42); 6867 assert(foobar.nvi2 == 12064); 6868 } 6869 6870 // Make a tuple of non-static function symbols 6871 package template GetOverloadedMethods(T) 6872 { 6873 import std.meta : Filter; 6874 6875 alias allMembers = __traits(allMembers, T); 6876 template follows(size_t i = 0) 6877 { 6878 static if (i >= allMembers.length) 6879 { 6880 alias follows = AliasSeq!(); 6881 } 6882 else static if (!__traits(compiles, mixin("T."~allMembers[i]))) 6883 { 6884 alias follows = follows!(i + 1); 6885 } 6886 else 6887 { 6888 enum name = allMembers[i]; 6889 6890 template isMethod(alias f) 6891 { 6892 static if (is(typeof(&f) F == F*) && is(F == function)) 6893 enum isMethod = !__traits(isStaticFunction, f); 6894 else 6895 enum isMethod = false; 6896 } 6897 alias follows = AliasSeq!( 6898 Filter!(isMethod, __traits(getOverloads, T, name)), 6899 follows!(i + 1)); 6900 } 6901 } 6902 alias GetOverloadedMethods = follows!(); 6903 } 6904 // find a function from Fs that has same identifier and covariant type with f 6905 private template findCovariantFunction(alias finfo, Source, Fs...) 6906 { 6907 template check(size_t i = 0) 6908 { 6909 static if (i >= Fs.length) 6910 enum ptrdiff_t check = -1; 6911 else 6912 { 6913 enum ptrdiff_t check = 6914 (finfo.name == __traits(identifier, Fs[i])) && 6915 isCovariantWith!(FunctionTypeOf!(Fs[i]), finfo.type) 6916 ? i : check!(i + 1); 6917 } 6918 } 6919 enum x = check!(); 6920 static if (x == -1 && is(typeof(Source.opDispatch))) 6921 { 6922 alias Params = Parameters!(finfo.type); 6923 enum ptrdiff_t findCovariantFunction = 6924 is(typeof(( Source).init.opDispatch!(finfo.name)(Params.init))) || 6925 is(typeof(( const Source).init.opDispatch!(finfo.name)(Params.init))) || 6926 is(typeof(( immutable Source).init.opDispatch!(finfo.name)(Params.init))) || 6927 is(typeof(( shared Source).init.opDispatch!(finfo.name)(Params.init))) || 6928 is(typeof((shared const Source).init.opDispatch!(finfo.name)(Params.init))) 6929 ? ptrdiff_t.max : -1; 6930 } 6931 else 6932 enum ptrdiff_t findCovariantFunction = x; 6933 } 6934 6935 private enum TypeModifier 6936 { 6937 mutable = 0, // type is mutable 6938 const_ = 1, // type is const 6939 immutable_ = 2, // type is immutable 6940 shared_ = 4, // type is shared 6941 inout_ = 8, // type is wild 6942 } 6943 private template TypeMod(T) 6944 { 6945 static if (is(T == immutable)) 6946 { 6947 enum mod1 = TypeModifier.immutable_; 6948 enum mod2 = 0; 6949 } 6950 else 6951 { 6952 enum mod1 = is(T == shared) ? TypeModifier.shared_ : 0; 6953 static if (is(T == const)) 6954 enum mod2 = TypeModifier.const_; 6955 else static if (is(T == inout)) 6956 enum mod2 = TypeModifier.inout_; 6957 else 6958 enum mod2 = TypeModifier.mutable; 6959 } 6960 enum TypeMod = cast(TypeModifier)(mod1 | mod2); 6961 } 6962 6963 @system unittest 6964 { 6965 template UnittestFuncInfo(alias f) 6966 { 6967 enum name = __traits(identifier, f); 6968 alias type = FunctionTypeOf!f; 6969 } 6970 6971 class A 6972 { 6973 int draw() { return 1; } 6974 @property int value() { return 2; } 6975 final int run() { return 3; } 6976 } 6977 alias methods = GetOverloadedMethods!A; 6978 6979 alias int F1(); 6980 alias @property int F2(); 6981 alias string F3(); 6982 alias nothrow @trusted uint F4(); 6983 alias int F5(Object); 6984 alias bool F6(Object); 6985 static assert(methods.length == 3 + 4); 6986 static assert(__traits(identifier, methods[0]) == "draw" && is(typeof(&methods[0]) == F1*)); 6987 static assert(__traits(identifier, methods[1]) == "value" && is(typeof(&methods[1]) == F2*)); 6988 static assert(__traits(identifier, methods[2]) == "run" && is(typeof(&methods[2]) == F1*)); 6989 6990 int draw(); 6991 @property int value(); 6992 void opEquals(); 6993 int nomatch(); 6994 static assert(findCovariantFunction!(UnittestFuncInfo!draw, A, methods) == 0); 6995 static assert(findCovariantFunction!(UnittestFuncInfo!value, A, methods) == 1); 6996 static assert(findCovariantFunction!(UnittestFuncInfo!opEquals, A, methods) == -1); 6997 static assert(findCovariantFunction!(UnittestFuncInfo!nomatch, A, methods) == -1); 6998 6999 // considering opDispatch 7000 class B 7001 { 7002 void opDispatch(string name, A...)(A) {} 7003 } 7004 alias methodsB = GetOverloadedMethods!B; 7005 static assert(findCovariantFunction!(UnittestFuncInfo!draw, B, methodsB) == ptrdiff_t.max); 7006 static assert(findCovariantFunction!(UnittestFuncInfo!value, B, methodsB) == ptrdiff_t.max); 7007 static assert(findCovariantFunction!(UnittestFuncInfo!opEquals, B, methodsB) == ptrdiff_t.max); 7008 static assert(findCovariantFunction!(UnittestFuncInfo!nomatch, B, methodsB) == ptrdiff_t.max); 7009 } 7010 7011 package template DerivedFunctionType(T...) 7012 { 7013 static if (!T.length) 7014 { 7015 alias DerivedFunctionType = void; 7016 } 7017 else static if (T.length == 1) 7018 { 7019 static if (is(T[0] == function)) 7020 { 7021 alias DerivedFunctionType = T[0]; 7022 } 7023 else 7024 { 7025 alias DerivedFunctionType = void; 7026 } 7027 } 7028 else static if (is(T[0] P0 == function) && is(T[1] P1 == function)) 7029 { 7030 alias FA = FunctionAttribute; 7031 7032 alias F0 = T[0], R0 = ReturnType!F0, PSTC0 = ParameterStorageClassTuple!F0; 7033 alias F1 = T[1], R1 = ReturnType!F1, PSTC1 = ParameterStorageClassTuple!F1; 7034 enum FA0 = functionAttributes!F0; 7035 enum FA1 = functionAttributes!F1; 7036 7037 template CheckParams(size_t i = 0) 7038 { 7039 static if (i >= P0.length) 7040 enum CheckParams = true; 7041 else 7042 { 7043 enum CheckParams = (is(P0[i] == P1[i]) && PSTC0[i] == PSTC1[i]) && 7044 CheckParams!(i + 1); 7045 } 7046 } 7047 static if (R0.sizeof == R1.sizeof && !is(CommonType!(R0, R1) == void) && 7048 P0.length == P1.length && CheckParams!() && TypeMod!F0 == TypeMod!F1 && 7049 variadicFunctionStyle!F0 == variadicFunctionStyle!F1 && 7050 functionLinkage!F0 == functionLinkage!F1 && 7051 ((FA0 ^ FA1) & (FA.ref_ | FA.property)) == 0) 7052 { 7053 alias R = Select!(is(R0 : R1), R0, R1); 7054 alias FX = FunctionTypeOf!(R function(P0)); 7055 // @system is default 7056 alias FY = SetFunctionAttributes!(FX, functionLinkage!F0, (FA0 | FA1) & ~FA.system); 7057 alias DerivedFunctionType = DerivedFunctionType!(FY, T[2 .. $]); 7058 } 7059 else 7060 alias DerivedFunctionType = void; 7061 } 7062 else 7063 alias DerivedFunctionType = void; 7064 } 7065 @safe unittest 7066 { 7067 // attribute covariance 7068 alias int F1(); 7069 static assert(is(DerivedFunctionType!(F1, F1) == F1)); 7070 alias int F2() pure nothrow; 7071 static assert(is(DerivedFunctionType!(F1, F2) == F2)); 7072 alias int F3() @safe; 7073 alias int F23() @safe pure nothrow; 7074 static assert(is(DerivedFunctionType!(F2, F3) == F23)); 7075 7076 // return type covariance 7077 alias long F4(); 7078 static assert(is(DerivedFunctionType!(F1, F4) == void)); 7079 class C {} 7080 class D : C {} 7081 alias C F5(); 7082 alias D F6(); 7083 static assert(is(DerivedFunctionType!(F5, F6) == F6)); 7084 alias typeof(null) F7(); 7085 alias int[] F8(); 7086 alias int* F9(); 7087 static assert(is(DerivedFunctionType!(F5, F7) == F7)); 7088 static assert(is(DerivedFunctionType!(F7, F8) == void)); 7089 static assert(is(DerivedFunctionType!(F7, F9) == F7)); 7090 7091 // variadic type equality 7092 alias int F10(int); 7093 alias int F11(int...); 7094 alias int F12(int, ...); 7095 static assert(is(DerivedFunctionType!(F10, F11) == void)); 7096 static assert(is(DerivedFunctionType!(F10, F12) == void)); 7097 static assert(is(DerivedFunctionType!(F11, F12) == void)); 7098 7099 // linkage equality 7100 alias extern(C) int F13(int); 7101 alias extern(D) int F14(int); 7102 alias extern(Windows) int F15(int); 7103 static assert(is(DerivedFunctionType!(F13, F14) == void)); 7104 static assert(is(DerivedFunctionType!(F13, F15) == void)); 7105 static assert(is(DerivedFunctionType!(F14, F15) == void)); 7106 7107 // ref & @property equality 7108 alias int F16(int); 7109 alias ref int F17(int); 7110 alias @property int F18(int); 7111 static assert(is(DerivedFunctionType!(F16, F17) == void)); 7112 static assert(is(DerivedFunctionType!(F16, F18) == void)); 7113 static assert(is(DerivedFunctionType!(F17, F18) == void)); 7114 } 7115 7116 package template Bind(alias Template, args1...) 7117 { 7118 alias Bind(args2...) = Template!(args1, args2); 7119 } 7120 7121 7122 /** 7123 Options regarding auto-initialization of a `SafeRefCounted` object (see 7124 the definition of `SafeRefCounted` below). 7125 */ 7126 enum RefCountedAutoInitialize 7127 { 7128 /// Do not auto-initialize the object 7129 no, 7130 /// Auto-initialize the object 7131 yes, 7132 } 7133 7134 /// 7135 @system unittest 7136 { 7137 import core.exception : AssertError; 7138 import std.exception : assertThrown; 7139 7140 struct Foo 7141 { 7142 int a = 42; 7143 } 7144 7145 SafeRefCounted!(Foo, RefCountedAutoInitialize.yes) rcAuto; 7146 SafeRefCounted!(Foo, RefCountedAutoInitialize.no) rcNoAuto; 7147 7148 assert(rcAuto.refCountedPayload.a == 42); 7149 7150 assertThrown!AssertError(rcNoAuto.refCountedPayload); 7151 rcNoAuto.refCountedStore.ensureInitialized; 7152 assert(rcNoAuto.refCountedPayload.a == 42); 7153 } 7154 7155 // Same the above but for old RefCounted and not documented 7156 @system unittest 7157 { 7158 import core.exception : AssertError; 7159 import std.exception : assertThrown; 7160 7161 struct Foo 7162 { 7163 int a = 42; 7164 } 7165 7166 RefCounted!(Foo, RefCountedAutoInitialize.yes) rcAuto; 7167 RefCounted!(Foo, RefCountedAutoInitialize.no) rcNoAuto; 7168 7169 assert(rcAuto.refCountedPayload.a == 42); 7170 7171 assertThrown!AssertError(rcNoAuto.refCountedPayload); 7172 rcNoAuto.refCountedStore.ensureInitialized; 7173 assert(rcNoAuto.refCountedPayload.a == 42); 7174 } 7175 7176 /** 7177 Defines a reference-counted object containing a `T` value as 7178 payload. 7179 7180 An instance of `SafeRefCounted` is a reference to a structure, 7181 which is referred to as the $(I store), or $(I storage implementation 7182 struct) in this documentation. The store contains a reference count 7183 and the `T` payload. `SafeRefCounted` uses `malloc` to allocate 7184 the store. As instances of `SafeRefCounted` are copied or go out of 7185 scope, they will automatically increment or decrement the reference 7186 count. When the reference count goes down to zero, `SafeRefCounted` 7187 will call `destroy` against the payload and call `free` to 7188 deallocate the store. If the `T` payload contains any references 7189 to GC-allocated memory, then `SafeRefCounted` will add it to the GC memory 7190 that is scanned for pointers, and remove it from GC scanning before 7191 `free` is called on the store. 7192 7193 One important consequence of `destroy` is that it will call the 7194 destructor of the `T` payload. GC-managed references are not 7195 guaranteed to be valid during a destructor call, but other members of 7196 `T`, such as file handles or pointers to `malloc` memory, will 7197 still be valid during the destructor call. This allows the `T` to 7198 deallocate or clean up any non-GC resources immediately after the 7199 reference count has reached zero. 7200 7201 Without -preview=dip1000, `SafeRefCounted` is unsafe and should be 7202 used with care. No references to the payload should be escaped outside 7203 the `SafeRefCounted` object. 7204 7205 With -preview=dip1000, `SafeRefCounted` is safe if it's payload is accessed only 7206 with the $(LREF borrow) function. Scope semantics can also prevent accidental 7207 escaping of `refCountedPayload`, but it's still up to the user to not destroy 7208 the last counted reference while the payload is in use. Due to that, 7209 `refCountedPayload` remains accessible only in `@system` code. 7210 7211 The `autoInit` option makes the object ensure the store is 7212 automatically initialized. Leaving $(D autoInit == 7213 RefCountedAutoInitialize.yes) (the default option) is convenient but 7214 has the cost of a test whenever the payload is accessed. If $(D 7215 autoInit == RefCountedAutoInitialize.no), user code must call either 7216 `refCountedStore.isInitialized` or `refCountedStore.ensureInitialized` 7217 before attempting to access the payload. Not doing so results in null 7218 pointer dereference. 7219 7220 If `T.this()` is annotated with `@disable` then `autoInit` must be 7221 `RefCountedAutoInitialize.no` in order to compile. 7222 7223 See_Also: 7224 $(LREF RefCounted) 7225 */ 7226 struct SafeRefCounted(T, RefCountedAutoInitialize autoInit = 7227 RefCountedAutoInitialize.yes) 7228 if (!is(T == class) && !(is(T == interface))) 7229 { 7230 version (D_BetterC) 7231 { 7232 private enum enableGCScan = false; 7233 } 7234 else 7235 { 7236 private enum enableGCScan = hasIndirections!T; 7237 } 7238 7239 extern(C) private pure nothrow @nogc static 7240 { 7241 pragma(mangle, "free") void pureFree( void *ptr ); 7242 static if (enableGCScan) 7243 import core.memory : GC; 7244 } 7245 7246 pragma(inline, true) private void checkInit()() 7247 if (autoInit == RefCountedAutoInitialize.yes) 7248 { 7249 _refCounted.ensureInitialized(); 7250 } 7251 7252 pragma(inline, true) private void checkInit()() inout 7253 if (autoInit == RefCountedAutoInitialize.no) 7254 { 7255 assert(_refCounted.isInitialized, 7256 "Attempted to use an uninitialized payload."); 7257 } 7258 7259 /// `SafeRefCounted` storage implementation. 7260 struct RefCountedStore 7261 { 7262 private struct Impl 7263 { 7264 T _payload; 7265 size_t _count; 7266 } 7267 7268 private Impl* _store; 7269 7270 private void initialize(A...)(auto ref A args) 7271 { 7272 import core.lifetime : emplace, forward; 7273 7274 allocateStore(); 7275 version (D_Exceptions) scope(failure) () @trusted { deallocateStore(); }(); 7276 emplace(&_store._payload, forward!args); 7277 _store._count = 1; 7278 } 7279 7280 private void move(ref T source) nothrow pure 7281 { 7282 import std.algorithm.mutation : moveEmplace; 7283 7284 allocateStore(); 7285 () @trusted { moveEmplace(source, _store._payload); }(); 7286 _store._count = 1; 7287 } 7288 7289 // 'nothrow': can only generate an Error 7290 private void allocateStore() nothrow pure 7291 { 7292 static if (enableGCScan) 7293 { 7294 import std.internal.memory : enforceCalloc; 7295 auto ptr = enforceCalloc(1, Impl.sizeof); 7296 _store = () @trusted { return cast(Impl*) ptr; }(); 7297 () @trusted { GC.addRange(&_store._payload, T.sizeof); }(); 7298 } 7299 else 7300 { 7301 import std.internal.memory : enforceMalloc; 7302 auto ptr = enforceMalloc(Impl.sizeof); 7303 _store = () @trusted { return cast(Impl*) ptr; }(); 7304 } 7305 } 7306 7307 private void deallocateStore() nothrow pure 7308 { 7309 static if (enableGCScan) 7310 { 7311 GC.removeRange(&this._store._payload); 7312 } 7313 pureFree(_store); 7314 _store = null; 7315 } 7316 7317 /** 7318 Returns `true` if and only if the underlying store has been 7319 allocated and initialized. 7320 */ 7321 @property nothrow @safe pure @nogc 7322 bool isInitialized() const 7323 { 7324 return _store !is null; 7325 } 7326 7327 /** 7328 Returns underlying reference count if it is allocated and initialized 7329 (a positive integer), and `0` otherwise. 7330 */ 7331 @property nothrow @safe pure @nogc 7332 size_t refCount() const 7333 { 7334 return isInitialized ? _store._count : 0; 7335 } 7336 7337 /** 7338 Makes sure the payload was properly initialized. Such a 7339 call is typically inserted before using the payload. 7340 7341 This function is unavailable if `T.this()` is annotated with 7342 `@disable`. 7343 */ 7344 @safe pure nothrow 7345 void ensureInitialized()() 7346 { 7347 // By checking for `@disable this()` and failing early we can 7348 // produce a clearer error message. 7349 static assert(__traits(compiles, { static T t; }), 7350 "Cannot automatically initialize `" ~ fullyQualifiedName!T ~ 7351 "` because `" ~ fullyQualifiedName!T ~ 7352 ".this()` is annotated with `@disable`."); 7353 if (!isInitialized) initialize(); 7354 } 7355 7356 } 7357 RefCountedStore _refCounted; 7358 7359 /// Returns storage implementation struct. 7360 @property nothrow @safe 7361 ref inout(RefCountedStore) refCountedStore() inout 7362 { 7363 return _refCounted; 7364 } 7365 7366 /** 7367 Constructor that initializes the payload. 7368 7369 Postcondition: `refCountedStore.isInitialized` 7370 */ 7371 this(A...)(auto ref A args) if (A.length > 0) 7372 out 7373 { 7374 assert(refCountedStore.isInitialized); 7375 } 7376 do 7377 { 7378 import core.lifetime : forward; 7379 _refCounted.initialize(forward!args); 7380 } 7381 7382 /// Ditto 7383 this(return scope T val) 7384 { 7385 _refCounted.move(val); 7386 } 7387 7388 /** 7389 Constructor that tracks the reference count appropriately. If $(D 7390 !refCountedStore.isInitialized), does nothing. 7391 */ 7392 this(this) @safe pure nothrow @nogc 7393 { 7394 if (!_refCounted.isInitialized) return; 7395 ++_refCounted._store._count; 7396 } 7397 7398 /** 7399 Destructor that tracks the reference count appropriately. If $(D 7400 !refCountedStore.isInitialized), does nothing. When the reference count goes 7401 down to zero, calls `destroy` agaist the payload and calls `free` 7402 to deallocate the corresponding resource. 7403 */ 7404 ~this() 7405 { 7406 import std.traits : dip1000Enabled; 7407 7408 // This prevents the same reference from decrementing the count twice. 7409 scope(exit) _refCounted = _refCounted.init; 7410 7411 if (!_refCounted.isInitialized) return; 7412 assert(_refCounted._store._count > 0); 7413 if (--_refCounted._store._count) return; 7414 // Done, destroy and deallocate 7415 .destroy(_refCounted._store._payload); 7416 7417 static if (dip1000Enabled) 7418 { 7419 () @trusted { _refCounted.deallocateStore(); }(); 7420 } 7421 else _refCounted.deallocateStore(); 7422 } 7423 7424 /** 7425 Assignment operators. 7426 7427 Note: You may not assign a new payload to an uninitialized SafeRefCounted, if 7428 auto initialization is off. Assigning another counted reference is still okay. 7429 */ 7430 void opAssign(typeof(this) rhs) 7431 { 7432 import std.algorithm.mutation : swap; 7433 7434 swap(_refCounted._store, rhs._refCounted._store); 7435 } 7436 7437 /// Ditto 7438 void opAssign(T rhs) 7439 { 7440 import std.algorithm.mutation : move; 7441 7442 checkInit(); 7443 move(rhs, _refCounted._store._payload); 7444 } 7445 7446 //version to have a single properly ddoc'ed function (w/ correct sig) 7447 version (StdDdoc) 7448 { 7449 /** 7450 Returns a reference to the payload. If (autoInit == 7451 RefCountedAutoInitialize.yes), calls $(D 7452 refCountedStore.ensureInitialized). Otherwise, just issues $(D 7453 assert(refCountedStore.isInitialized)). Used with $(D alias 7454 refCountedPayload this;), so callers can just use the `SafeRefCounted` 7455 object as a `T`. 7456 7457 $(BLUE The first overload exists only if $(D autoInit == RefCountedAutoInitialize.yes).) 7458 So if $(D autoInit == RefCountedAutoInitialize.no) 7459 or called for a constant or immutable object, then 7460 `refCountedPayload` will also be qualified as nothrow 7461 (but will still assert if not initialized). 7462 */ 7463 @property @system 7464 ref T refCountedPayload() return; 7465 7466 /// ditto 7467 @property nothrow @system pure @nogc 7468 ref inout(T) refCountedPayload() inout return; 7469 } 7470 else 7471 { 7472 static if (autoInit == RefCountedAutoInitialize.yes) 7473 { 7474 //Can't use inout here because of potential mutation 7475 @property @system 7476 ref T refCountedPayload() return 7477 { 7478 checkInit(); 7479 return _refCounted._store._payload; 7480 } 7481 } 7482 else 7483 { 7484 @property nothrow @system pure @nogc 7485 ref inout(T) refCountedPayload() inout return 7486 { 7487 checkInit(); 7488 return _refCounted._store._payload; 7489 } 7490 } 7491 } 7492 7493 /** 7494 Returns a reference to the payload. If (autoInit == 7495 RefCountedAutoInitialize.yes), calls $(D 7496 refCountedStore.ensureInitialized). Otherwise, just issues $(D 7497 assert(refCountedStore.isInitialized)). 7498 */ 7499 alias refCountedPayload this; 7500 7501 static if (is(T == struct) && !is(typeof((ref T t) => t.toString()))) 7502 { 7503 string toString(this This)() 7504 { 7505 import std.conv : to; 7506 7507 static if (autoInit) 7508 return to!string(refCountedPayload); 7509 else 7510 { 7511 if (!_refCounted.isInitialized) 7512 return This.stringof ~ "(RefCountedStore(null))"; 7513 else 7514 return to!string(_refCounted._store._payload); 7515 } 7516 } 7517 } 7518 } 7519 7520 /// 7521 @betterC pure @system nothrow @nogc unittest 7522 { 7523 // A pair of an `int` and a `size_t` - the latter being the 7524 // reference count - will be dynamically allocated 7525 auto rc1 = SafeRefCounted!int(5); 7526 assert(rc1 == 5); 7527 // No more allocation, add just one extra reference count 7528 auto rc2 = rc1; 7529 // Reference semantics 7530 rc2 = 42; 7531 assert(rc1 == 42); 7532 // the pair will be freed when rc1 and rc2 go out of scope 7533 } 7534 7535 // This test can't be betterC because the test extractor won't see the private 7536 // `initialize` method accessed here 7537 pure @safe nothrow @nogc unittest 7538 { 7539 auto rc1 = SafeRefCounted!(int, RefCountedAutoInitialize.no)(5); 7540 rc1._refCounted.initialize(); 7541 } 7542 7543 pure @system unittest 7544 { 7545 foreach (MyRefCounted; AliasSeq!(SafeRefCounted, RefCounted)) 7546 { 7547 MyRefCounted!int* p; 7548 auto rc1 = MyRefCounted!int(5); 7549 p = &rc1; 7550 assert(rc1 == 5); 7551 assert(rc1._refCounted._store._count == 1); 7552 { 7553 auto rc2 = rc1; 7554 assert(rc1._refCounted._store._count == 2); 7555 // Reference semantics 7556 rc2 = 42; 7557 assert(rc1 == 42); 7558 rc2 = rc2; 7559 assert(rc2._refCounted._store._count == 2); 7560 rc1 = rc2; 7561 assert(rc1._refCounted._store._count == 2); 7562 } 7563 // Artificially end scope of rc1 by calling ~this() explicitly 7564 rc1.__xdtor(); 7565 assert(p._refCounted._store == null); 7566 7567 // [Safe]RefCounted as a member 7568 struct A 7569 { 7570 MyRefCounted!int x; 7571 this(int y) 7572 { 7573 x._refCounted.initialize(y); 7574 } 7575 A copy() 7576 { 7577 auto another = this; 7578 return another; 7579 } 7580 } 7581 auto a = A(4); 7582 auto b = a.copy(); 7583 assert(a.x._refCounted._store._count == 2, 7584 "https://issues.dlang.org/show_bug.cgi?id=4356 still unfixed"); 7585 } 7586 } 7587 7588 @betterC pure @safe nothrow @nogc unittest 7589 { 7590 import std.algorithm.mutation : swap; 7591 7592 SafeRefCounted!int p1, p2; 7593 swap(p1, p2); 7594 } 7595 7596 // Same as above but for old RefCounted and not @safe 7597 @betterC pure @system nothrow @nogc unittest 7598 { 7599 import std.algorithm.mutation : swap; 7600 7601 RefCounted!int p1, p2; 7602 swap(p1, p2); 7603 } 7604 7605 // https://issues.dlang.org/show_bug.cgi?id=6606 7606 @betterC @safe pure nothrow @nogc unittest 7607 { 7608 union U { 7609 size_t i; 7610 void* p; 7611 } 7612 7613 struct S { 7614 U u; 7615 } 7616 7617 alias SRC = SafeRefCounted!S; 7618 } 7619 7620 // Same as above but for old RefCounted and not @safe 7621 @betterC @system pure nothrow @nogc unittest 7622 { 7623 union U { 7624 size_t i; 7625 void* p; 7626 } 7627 7628 struct S { 7629 U u; 7630 } 7631 7632 alias SRC = RefCounted!S; 7633 } 7634 7635 // https://issues.dlang.org/show_bug.cgi?id=6436 7636 @betterC @system pure unittest 7637 { 7638 import std.meta : AliasSeq; 7639 struct S 7640 { 7641 this(int rval) { assert(rval == 1); } 7642 this(ref int lval) { assert(lval == 3); ++lval; } 7643 } 7644 7645 foreach (MyRefCounted; AliasSeq!(SafeRefCounted, RefCounted)) 7646 { 7647 auto s1 = MyRefCounted!S(1); 7648 int lval = 3; 7649 auto s2 = MyRefCounted!S(lval); 7650 assert(lval == 4); 7651 } 7652 } 7653 7654 // gc_addRange coverage 7655 @betterC @safe pure unittest 7656 { 7657 struct S { int* p; } 7658 7659 auto s = SafeRefCounted!S(null); 7660 } 7661 7662 // Same as above but for old RefCounted and not @safe 7663 @betterC @system pure unittest 7664 { 7665 struct S { int* p; } 7666 7667 auto s = RefCounted!S(null); 7668 } 7669 7670 @betterC @system pure nothrow @nogc unittest 7671 { 7672 import std.meta : AliasSeq; 7673 foreach (MyRefCounted; AliasSeq!(SafeRefCounted, RefCounted)) 7674 { 7675 MyRefCounted!int a; 7676 a = 5; //This should not assert 7677 assert(a == 5); 7678 7679 MyRefCounted!int b; 7680 b = a; //This should not assert either 7681 assert(b == 5); 7682 7683 MyRefCounted!(int*) c; 7684 } 7685 } 7686 7687 // https://issues.dlang.org/show_bug.cgi?id=21638 7688 @betterC @system pure nothrow @nogc unittest 7689 { 7690 import std.meta : AliasSeq; 7691 static struct NoDefaultCtor 7692 { 7693 @disable this(); 7694 this(int x) @nogc nothrow pure { this.x = x; } 7695 int x; 7696 } 7697 7698 foreach (MyRefCounted; AliasSeq!(SafeRefCounted, RefCounted)) 7699 { 7700 auto rc = MyRefCounted!(NoDefaultCtor, RefCountedAutoInitialize.no)(5); 7701 assert(rc.x == 5); 7702 } 7703 } 7704 7705 // https://issues.dlang.org/show_bug.cgi?id=20502 7706 @system unittest 7707 { 7708 alias Types = AliasSeq!(SafeRefCounted, RefCounted); 7709 alias funcs = AliasSeq!(safeRefCounted, refCounted); 7710 static foreach (aliasI; 0 .. 2) 7711 {{ 7712 alias MyRefCounted = Types[aliasI]; 7713 alias myRefCounted = funcs[aliasI]; 7714 import std.conv : to; 7715 7716 // Check that string conversion is transparent for refcounted 7717 // structs that do not have either toString or alias this. 7718 static struct A { Object a; } 7719 auto a = A(new Object()); 7720 auto r = myRefCounted(a); 7721 assert(to!string(r) == to!string(a)); 7722 assert(to!string(cast(const) r) == to!string(cast(const) a)); 7723 // Check that string conversion is still transparent for refcounted 7724 // structs that have alias this. 7725 static struct B { int b; alias b this; } 7726 static struct C { B b; alias b this; } 7727 assert(to!string(myRefCounted(C(B(123)))) == to!string(C(B(123)))); 7728 // https://issues.dlang.org/show_bug.cgi?id=22093 7729 // Check that uninitialized refcounted structs that previously could be 7730 // converted to strings still can be. 7731 alias R = typeof(r); 7732 R r2; 7733 cast(void) (((const ref R a) => to!string(a))(r2)); 7734 cast(void) to!string(MyRefCounted!(A, RefCountedAutoInitialize.no).init); 7735 }} 7736 } 7737 7738 // We tried to make `refCountedPayload` `@safe` in 7739 // https://github.com/dlang/phobos/pull/8368 . It proved impossible, but it may 7740 // be possible in the future. This test checks for false `@safe` issues we 7741 // encountered. 7742 @safe unittest 7743 { 7744 struct Container 7745 { 7746 int[] data; 7747 } 7748 7749 int[] getArr1 (scope Container local) 7750 { 7751 // allowed because the argument is inferred as return scope. 7752 return local.data; 7753 } 7754 7755 int[] getArr2 (scope Container local) 7756 { 7757 SafeRefCounted!Container rc = local; 7758 // Escapes a reference to expired reference counted struct 7759 // don't do this! 7760 return rc.refCountedPayload().data; 7761 } 7762 7763 int destroyFirstAndUseLater() 7764 { 7765 auto rc = SafeRefCounted!int(123); 7766 int* ptr = &rc.refCountedPayload(); 7767 destroy(rc); 7768 return *ptr; 7769 } 7770 7771 // This is here mainly to test that safety gets inferred correctly for the 7772 // next tests 7773 static assert(isSafe!getArr1); 7774 // https://github.com/dlang/phobos/pull/8101#issuecomment-843017282 7775 // This got apparently fixed automatically by compiler updates. 7776 static assert(!isSafe!getArr2); 7777 // As of writing, this is the issue that is still preventing payload access 7778 // from being `@safe` 7779 static assert(!isSafe!destroyFirstAndUseLater); 7780 } 7781 7782 /** 7783 Borrows the payload of $(LREF SafeRefCounted) for use in `fun`. Inferred as `@safe` 7784 if `fun` is `@safe` and does not escape a reference to the payload. 7785 The reference count will be incremented for the duration of the operation, 7786 so destroying the last reference will not leave dangling references in 7787 `fun`. 7788 7789 Params: 7790 fun = A callable accepting the payload either by value or by reference. 7791 refCount = The counted reference to the payload. 7792 Returns: 7793 The return value of `fun`, if any. `ref` in the return value will be 7794 forwarded. 7795 Issues: 7796 For yet unknown reason, code that uses this function with UFCS syntax 7797 will not be inferred as `@safe`. It will still compile if the code is 7798 explicitly marked `@safe` and nothing in `fun` prevents that. 7799 */ 7800 template borrow(alias fun) 7801 { 7802 import std.functional : unaryFun; 7803 7804 auto ref borrow(RC)(RC refCount) if 7805 ( 7806 isInstanceOf!(SafeRefCounted, RC) 7807 && is(typeof(unaryFun!fun(refCount.refCountedPayload))) 7808 ) 7809 { 7810 refCount.checkInit(); 7811 7812 // If `fun` escapes a reference to the payload, it will be inferred 7813 // as unsafe due to the scope storage class here. 7814 scope plPtr = &refCount._refCounted._store._payload; 7815 return unaryFun!fun(*plPtr); 7816 7817 // We destroy our copy of the reference here, automatically destroying 7818 // the payload if `fun` destroyed the last reference outside. 7819 } 7820 } 7821 7822 /// This example can be marked `@safe` with `-preview=dip1000`. 7823 @safe pure nothrow unittest 7824 { 7825 auto rcInt = safeRefCounted(5); 7826 assert(rcInt.borrow!(theInt => theInt) == 5); 7827 auto sameInt = rcInt; 7828 assert(sameInt.borrow!"a" == 5); 7829 7830 // using `ref` in the function 7831 auto arr = [0, 1, 2, 3, 4, 5, 6]; 7832 sameInt.borrow!(ref (x) => arr[x]) = 10; 7833 assert(arr == [0, 1, 2, 3, 4, 10, 6]); 7834 7835 // modifying the payload via an alias 7836 sameInt.borrow!"a*=2"; 7837 assert(rcInt.borrow!"a" == 10); 7838 } 7839 7840 // Some memory safety penetration testing. 7841 @system unittest 7842 { 7843 int* globalPtr; 7844 int torpedoesFired = 0; 7845 struct Destroyer { ~this() @safe { torpedoesFired++; } } 7846 7847 alias RcInt = typeof(safeRefCounted(0)); 7848 auto standardUsage(RcInt arg) 7849 { 7850 return borrow!((ref x) => x)(arg); 7851 } 7852 ref harmlessRefReturn(RcInt arg) 7853 { 7854 return borrow!(ref (ref x) => *globalPtr = x)(arg); 7855 } 7856 ref problematicRefReturn(RcInt arg) 7857 { 7858 return borrow!(ref (ref x) => x)(arg); 7859 } 7860 auto sideChannelEscape(RcInt arg) 7861 { 7862 return borrow!((ref x) 7863 { 7864 globalPtr = &x; 7865 return x; 7866 })(arg); 7867 } 7868 auto destroyDuringApply() 7869 { 7870 auto rc = safeRefCounted(Destroyer()); 7871 return borrow!((ref x) 7872 { 7873 // Destroys the last reference to the payload, decrementing it's 7874 // reference count. 7875 rc.__dtor(); 7876 // Destroy again! rc should be set to it's init value so that this 7877 // won't decrement the reference count of the original payload. 7878 rc.__dtor(); 7879 // The internal reference count increment done for duration of 7880 // `apply` should make sure that the payload destructor is not yet 7881 // run, and this value thus not incremented. 7882 return torpedoesFired; 7883 })(rc); 7884 } 7885 7886 // First, let's verify the dangerous functions really do what they are 7887 // supposed to do. 7888 auto testRc = safeRefCounted(42); 7889 assert(sideChannelEscape(testRc) == 42); 7890 assert(&problematicRefReturn(testRc) == globalPtr); 7891 7892 // Now, are the @safe attributes inferred correctly? 7893 assert(isSafe!standardUsage); 7894 assert(isSafe!harmlessRefReturn); 7895 assert(!isSafe!problematicRefReturn); 7896 assert(!isSafe!sideChannelEscape); 7897 assert(isSafe!destroyDuringApply); 7898 7899 // Finally, we test protection against early destruction during `apply`. 7900 auto torpedoesUpToReturn = destroyDuringApply(); 7901 assert(torpedoesFired == torpedoesUpToReturn + 1); 7902 } 7903 7904 /** 7905 * Initializes a `SafeRefCounted` with `val`. The template parameter 7906 * `T` of `SafeRefCounted` is inferred from `val`. 7907 * This function can be used to move non-copyable values to the heap. 7908 * It also disables the `autoInit` option of `SafeRefCounted`. 7909 * 7910 * Params: 7911 * val = The value to be reference counted 7912 * Returns: 7913 * An initialized `SafeRefCounted` containing `val`. 7914 * See_Also: 7915 * $(LREF refCounted) 7916 * $(HTTP en.cppreference.com/w/cpp/memory/shared_ptr/make_shared, C++'s make_shared) 7917 */ 7918 SafeRefCounted!(T, RefCountedAutoInitialize.no) safeRefCounted(T)(T val) 7919 { 7920 typeof(return) res; 7921 res._refCounted.move(val); 7922 return res; 7923 } 7924 7925 /// 7926 @system unittest 7927 { 7928 static struct File 7929 { 7930 static size_t nDestroyed; 7931 string name; 7932 @disable this(this); // not copyable 7933 ~this() { name = null; ++nDestroyed; } 7934 } 7935 7936 auto file = File("name"); 7937 assert(file.name == "name"); 7938 // file cannot be copied and has unique ownership 7939 static assert(!__traits(compiles, {auto file2 = file;})); 7940 7941 assert(File.nDestroyed == 0); 7942 7943 // make the file ref counted to share ownership 7944 // Note: 7945 // We write a compound statement (brace-delimited scope) in which all `SafeRefCounted!File` handles are created and deleted. 7946 // This allows us to see (after the scope) what happens after all handles have been destroyed. 7947 { 7948 // We move the content of `file` to a separate (and heap-allocated) `File` object, 7949 // managed-and-accessed via one-or-multiple (initially: one) `SafeRefCounted!File` objects ("handles"). 7950 // This "moving": 7951 // (1) invokes `file`'s destructor (=> `File.nDestroyed` is incremented from 0 to 1 and `file.name` becomes `null`); 7952 // (2) overwrites `file` with `File.init` (=> `file.name` becomes `null`). 7953 // It appears that writing `name = null;` in the destructor is redundant, 7954 // but please note that (2) is only performed if `File` defines a destructor (or post-blit operator), 7955 // and in the absence of the `nDestroyed` instrumentation there would have been no reason to define a destructor. 7956 import std.algorithm.mutation : move; 7957 auto rcFile = safeRefCounted(move(file)); 7958 assert(rcFile.name == "name"); 7959 assert(File.nDestroyed == 1); 7960 assert(file.name == null); 7961 7962 // We create another `SafeRefCounted!File` handle to the same separate `File` object. 7963 // While any of the handles is still alive, the `File` object is kept alive (=> `File.nDestroyed` is not modified). 7964 auto rcFile2 = rcFile; 7965 assert(rcFile.refCountedStore.refCount == 2); 7966 assert(File.nDestroyed == 1); 7967 } 7968 // The separate `File` object is deleted when the last `SafeRefCounted!File` handle is destroyed 7969 // (i.e. at the closing brace of the compound statement above, which destroys both handles: `rcFile` and `rcFile2`) 7970 // (=> `File.nDestroyed` is incremented again, from 1 to 2): 7971 assert(File.nDestroyed == 2); 7972 } 7973 7974 /** 7975 Creates a proxy for the value `a` that will forward all operations 7976 while disabling implicit conversions. The aliased item `a` must be 7977 an $(B lvalue). This is useful for creating a new type from the 7978 "base" type (though this is $(B not) a subtype-supertype 7979 relationship; the new type is not related to the old type in any way, 7980 by design). 7981 7982 The new type supports all operations that the underlying type does, 7983 including all operators such as `+`, `--`, `<`, `[]`, etc. 7984 7985 Params: 7986 a = The value to act as a proxy for all operations. It must 7987 be an lvalue. 7988 */ 7989 mixin template Proxy(alias a) 7990 { 7991 private alias ValueType = typeof({ return a; }()); 7992 7993 /* Determine if 'T.a' can referenced via a const(T). 7994 * Use T* as the parameter because 'scope' inference needs a fully 7995 * analyzed T, which doesn't work when accessibleFrom() is used in a 7996 * 'static if' in the definition of Proxy or T. 7997 */ 7998 private enum bool accessibleFrom(T) = 7999 is(typeof((T* self){ cast(void) mixin("(*self)."~__traits(identifier, a)); })); 8000 8001 static if (is(typeof(this) == class)) 8002 { 8003 override bool opEquals(Object o) 8004 { 8005 if (auto b = cast(typeof(this))o) 8006 { 8007 return a == mixin("b."~__traits(identifier, a)); 8008 } 8009 return false; 8010 } 8011 8012 bool opEquals(T)(T b) 8013 if (is(ValueType : T) || is(typeof(a.opEquals(b))) || is(typeof(b.opEquals(a)))) 8014 { 8015 static if (is(typeof(a.opEquals(b)))) 8016 return a.opEquals(b); 8017 else static if (is(typeof(b.opEquals(a)))) 8018 return b.opEquals(a); 8019 else 8020 return a == b; 8021 } 8022 8023 override int opCmp(Object o) 8024 { 8025 if (auto b = cast(typeof(this))o) 8026 { 8027 return a < mixin("b."~__traits(identifier, a)) ? -1 8028 : a > mixin("b."~__traits(identifier, a)) ? +1 : 0; 8029 } 8030 static if (is(ValueType == class)) 8031 return a.opCmp(o); 8032 else 8033 throw new Exception("Attempt to compare a "~typeid(this).toString~" and a "~typeid(o).toString); 8034 } 8035 8036 int opCmp(T)(auto ref const T b) 8037 if (is(ValueType : T) || is(typeof(a.opCmp(b))) || is(typeof(b.opCmp(a)))) 8038 { 8039 static if (is(typeof(a.opCmp(b)))) 8040 return a.opCmp(b); 8041 else static if (is(typeof(b.opCmp(a)))) 8042 return -b.opCmp(a); 8043 else 8044 return a < b ? -1 : a > b ? +1 : 0; 8045 } 8046 8047 static if (accessibleFrom!(const typeof(this))) 8048 { 8049 override size_t toHash() const nothrow @safe 8050 { 8051 static if (__traits(compiles, .hashOf(a))) 8052 return .hashOf(a); 8053 else 8054 // Workaround for when .hashOf is not both @safe and nothrow. 8055 { 8056 static if (is(typeof(&a) == ValueType*)) 8057 alias v = a; 8058 else 8059 auto v = a; // if a is (property) function 8060 // BUG: Improperly casts away `shared`! 8061 return typeid(ValueType).getHash((() @trusted => cast(const void*) &v)()); 8062 } 8063 } 8064 } 8065 } 8066 else 8067 { 8068 auto ref opEquals(this X, B)(auto ref B b) 8069 { 8070 static if (is(immutable B == immutable typeof(this))) 8071 { 8072 return a == mixin("b."~__traits(identifier, a)); 8073 } 8074 else 8075 return a == b; 8076 } 8077 8078 auto ref opCmp(this X, B)(auto ref B b) 8079 { 8080 static if (is(typeof(a.opCmp(b)))) 8081 return a.opCmp(b); 8082 else static if (is(typeof(b.opCmp(a)))) 8083 return -b.opCmp(a); 8084 else static if (isFloatingPoint!ValueType || isFloatingPoint!B) 8085 return a < b ? -1 : a > b ? +1 : a == b ? 0 : float.nan; 8086 else 8087 return a < b ? -1 : (a > b); 8088 } 8089 8090 static if (accessibleFrom!(const typeof(this))) 8091 { 8092 size_t toHash() const nothrow @safe 8093 { 8094 static if (__traits(compiles, .hashOf(a))) 8095 return .hashOf(a); 8096 else 8097 // Workaround for when .hashOf is not both @safe and nothrow. 8098 { 8099 static if (is(typeof(&a) == ValueType*)) 8100 alias v = a; 8101 else 8102 auto v = a; // if a is (property) function 8103 // BUG: Improperly casts away `shared`! 8104 return typeid(ValueType).getHash((() @trusted => cast(const void*) &v)()); 8105 } 8106 } 8107 } 8108 } 8109 8110 auto ref opCall(this X, Args...)(auto ref Args args) { return a(args); } 8111 8112 auto ref opCast(T, this X)() { return cast(T) a; } 8113 8114 auto ref opIndex(this X, D...)(auto ref D i) { return a[i]; } 8115 auto ref opSlice(this X )() { return a[]; } 8116 auto ref opSlice(this X, B, E)(auto ref B b, auto ref E e) { return a[b .. e]; } 8117 8118 auto ref opUnary (string op, this X )() { return mixin(op~"a"); } 8119 auto ref opIndexUnary(string op, this X, D...)(auto ref D i) { return mixin(op~"a[i]"); } 8120 auto ref opSliceUnary(string op, this X )() { return mixin(op~"a[]"); } 8121 auto ref opSliceUnary(string op, this X, B, E)(auto ref B b, auto ref E e) { return mixin(op~"a[b .. e]"); } 8122 8123 auto ref opBinary(string op, this X, B)(auto ref B b) 8124 if (op == "in" && is(typeof(a in b)) || op != "in") 8125 { 8126 return mixin("a "~op~" b"); 8127 } 8128 auto ref opBinaryRight(string op, this X, B)(auto ref B b) { return mixin("b "~op~" a"); } 8129 8130 static if (!is(typeof(this) == class)) 8131 { 8132 import std.traits; 8133 static if (isAssignable!ValueType) 8134 { 8135 auto ref opAssign(this X)(auto ref typeof(this) v) 8136 { 8137 a = mixin("v."~__traits(identifier, a)); 8138 return this; 8139 } 8140 } 8141 else 8142 { 8143 @disable void opAssign(this X)(auto ref typeof(this) v); 8144 } 8145 } 8146 8147 auto ref opAssign (this X, V )(auto ref V v) if (!is(V == typeof(this))) { return a = v; } 8148 auto ref opIndexAssign(this X, V, D...)(auto ref V v, auto ref D i) { return a[i] = v; } 8149 auto ref opSliceAssign(this X, V )(auto ref V v) { return a[] = v; } 8150 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; } 8151 8152 auto ref opOpAssign (string op, this X, V )(auto ref V v) 8153 { 8154 return mixin("a = a "~op~" v"); 8155 } 8156 auto ref opIndexOpAssign(string op, this X, V, D...)(auto ref V v, auto ref D i) 8157 { 8158 return mixin("a[i] " ~op~"= v"); 8159 } 8160 auto ref opSliceOpAssign(string op, this X, V )(auto ref V v) 8161 { 8162 return mixin("a[] " ~op~"= v"); 8163 } 8164 auto ref opSliceOpAssign(string op, this X, V, B, E)(auto ref V v, auto ref B b, auto ref E e) 8165 { 8166 return mixin("a[b .. e] "~op~"= v"); 8167 } 8168 8169 template opDispatch(string name) 8170 { 8171 static if (is(typeof(__traits(getMember, a, name)) == function)) 8172 { 8173 // non template function 8174 auto ref opDispatch(this X, Args...)(auto ref Args args) { return mixin("a."~name~"(args)"); } 8175 } 8176 else static if (is(typeof({ enum x = mixin("a."~name); }))) 8177 { 8178 // built-in type field, manifest constant, and static non-mutable field 8179 enum opDispatch = mixin("a."~name); 8180 } 8181 else static if (__traits(isTemplate, mixin("a."~name))) 8182 { 8183 // member template 8184 template opDispatch(T...) 8185 { 8186 enum targs = T.length ? "!T" : ""; 8187 auto ref opDispatch(this X, Args...)(auto ref Args args){ return mixin("a."~name~targs~"(args)"); } 8188 } 8189 } 8190 else 8191 { 8192 // field or property function 8193 @property auto ref opDispatch(this X)() { return mixin("a."~name); } 8194 @property auto ref opDispatch(this X, V)(auto ref V v) { return mixin("a."~name~" = v"); } 8195 } 8196 8197 } 8198 8199 import std.traits : isArray; 8200 8201 static if (isArray!ValueType) 8202 { 8203 auto opDollar() const { return a.length; } 8204 } 8205 else static if (is(typeof(a.opDollar!0))) 8206 { 8207 auto ref opDollar(size_t pos)() { return a.opDollar!pos(); } 8208 } 8209 else static if (is(typeof(a.opDollar) == function)) 8210 { 8211 auto ref opDollar() { return a.opDollar(); } 8212 } 8213 else static if (is(typeof(a.opDollar))) 8214 { 8215 alias opDollar = a.opDollar; 8216 } 8217 } 8218 8219 /// 8220 @safe unittest 8221 { 8222 struct MyInt 8223 { 8224 private int value; 8225 mixin Proxy!value; 8226 8227 this(int n){ value = n; } 8228 } 8229 8230 MyInt n = 10; 8231 8232 // Enable operations that original type has. 8233 ++n; 8234 assert(n == 11); 8235 assert(n * 2 == 22); 8236 8237 void func(int n) { } 8238 8239 // Disable implicit conversions to original type. 8240 //int x = n; 8241 //func(n); 8242 } 8243 8244 ///The proxied value must be an $(B lvalue). 8245 @safe unittest 8246 { 8247 struct NewIntType 8248 { 8249 //Won't work; the literal '1' 8250 //is an rvalue, not an lvalue 8251 //mixin Proxy!1; 8252 8253 //Okay, n is an lvalue 8254 int n; 8255 mixin Proxy!n; 8256 8257 this(int n) { this.n = n; } 8258 } 8259 8260 NewIntType nit = 0; 8261 nit++; 8262 assert(nit == 1); 8263 8264 8265 struct NewObjectType 8266 { 8267 Object obj; 8268 //Ok, obj is an lvalue 8269 mixin Proxy!obj; 8270 8271 this (Object o) { obj = o; } 8272 } 8273 8274 NewObjectType not = new Object(); 8275 assert(__traits(compiles, not.toHash())); 8276 } 8277 8278 /** 8279 There is one exception to the fact that the new type is not related to the 8280 old type. $(DDSUBLINK spec/function,pseudo-member, Pseudo-member) 8281 functions are usable with the new type; they will be forwarded on to the 8282 proxied value. 8283 */ 8284 @safe unittest 8285 { 8286 import std.math.traits : isInfinity; 8287 8288 float f = 1.0; 8289 assert(!f.isInfinity); 8290 8291 struct NewFloat 8292 { 8293 float _; 8294 mixin Proxy!_; 8295 8296 this(float f) { _ = f; } 8297 } 8298 8299 NewFloat nf = 1.0f; 8300 assert(!nf.isInfinity); 8301 } 8302 8303 @safe unittest 8304 { 8305 static struct MyInt 8306 { 8307 private int value; 8308 mixin Proxy!value; 8309 this(int n) inout { value = n; } 8310 8311 enum str = "str"; 8312 static immutable arr = [1,2,3]; 8313 } 8314 8315 static foreach (T; AliasSeq!(MyInt, const MyInt, immutable MyInt)) 8316 {{ 8317 T m = 10; 8318 static assert(!__traits(compiles, { int x = m; })); 8319 static assert(!__traits(compiles, { void func(int n){} func(m); })); 8320 assert(m == 10); 8321 assert(m != 20); 8322 assert(m < 20); 8323 assert(+m == 10); 8324 assert(-m == -10); 8325 assert(cast(double) m == 10.0); 8326 assert(m + 10 == 20); 8327 assert(m - 5 == 5); 8328 assert(m * 20 == 200); 8329 assert(m / 2 == 5); 8330 assert(10 + m == 20); 8331 assert(15 - m == 5); 8332 assert(20 * m == 200); 8333 assert(50 / m == 5); 8334 static if (is(T == MyInt)) // mutable 8335 { 8336 assert(++m == 11); 8337 assert(m++ == 11); assert(m == 12); 8338 assert(--m == 11); 8339 assert(m-- == 11); assert(m == 10); 8340 m = m; 8341 m = 20; assert(m == 20); 8342 } 8343 static assert(T.max == int.max); 8344 static assert(T.min == int.min); 8345 static assert(T.init == int.init); 8346 static assert(T.str == "str"); 8347 static assert(T.arr == [1,2,3]); 8348 }} 8349 } 8350 @system unittest 8351 { 8352 static struct MyArray 8353 { 8354 private int[] value; 8355 mixin Proxy!value; 8356 this(int[] arr) { value = arr; } 8357 this(immutable int[] arr) immutable { value = arr; } 8358 } 8359 8360 static foreach (T; AliasSeq!(MyArray, const MyArray, immutable MyArray)) 8361 {{ 8362 static if (is(T == immutable) && !is(typeof({ T a = [1,2,3,4]; }))) 8363 T a = [1,2,3,4].idup; // workaround until qualified ctor is properly supported 8364 else 8365 T a = [1,2,3,4]; 8366 assert(a == [1,2,3,4]); 8367 assert(a != [5,6,7,8]); 8368 assert(+a[0] == 1); 8369 version (LittleEndian) 8370 assert(cast(ulong[]) a == [0x0000_0002_0000_0001, 0x0000_0004_0000_0003]); 8371 else 8372 assert(cast(ulong[]) a == [0x0000_0001_0000_0002, 0x0000_0003_0000_0004]); 8373 assert(a ~ [10,11] == [1,2,3,4,10,11]); 8374 assert(a[0] == 1); 8375 assert(a[] == [1,2,3,4]); 8376 assert(a[2 .. 4] == [3,4]); 8377 static if (is(T == MyArray)) // mutable 8378 { 8379 a = a; 8380 a = [5,6,7,8]; assert(a == [5,6,7,8]); 8381 a[0] = 0; assert(a == [0,6,7,8]); 8382 a[] = 1; assert(a == [1,1,1,1]); 8383 a[0 .. 3] = 2; assert(a == [2,2,2,1]); 8384 a[0] += 2; assert(a == [4,2,2,1]); 8385 a[] *= 2; assert(a == [8,4,4,2]); 8386 a[0 .. 2] /= 2; assert(a == [4,2,4,2]); 8387 } 8388 }} 8389 } 8390 @system unittest 8391 { 8392 class Foo 8393 { 8394 int field; 8395 8396 @property int val1() const { return field; } 8397 @property void val1(int n) { field = n; } 8398 8399 @property ref int val2() { return field; } 8400 8401 int func(int x, int y) const { return x; } 8402 void func1(ref int a) { a = 9; } 8403 8404 T ifti1(T)(T t) { return t; } 8405 void ifti2(Args...)(Args args) { } 8406 void ifti3(T, Args...)(Args args) { } 8407 8408 T opCast(T)(){ return T.init; } 8409 8410 T tempfunc(T)() { return T.init; } 8411 } 8412 class Hoge 8413 { 8414 Foo foo; 8415 mixin Proxy!foo; 8416 this(Foo f) { foo = f; } 8417 } 8418 8419 auto h = new Hoge(new Foo()); 8420 int n; 8421 8422 static assert(!__traits(compiles, { Foo f = h; })); 8423 8424 // field 8425 h.field = 1; // lhs of assign 8426 n = h.field; // rhs of assign 8427 assert(h.field == 1); // lhs of BinExp 8428 assert(1 == h.field); // rhs of BinExp 8429 assert(n == 1); 8430 8431 // getter/setter property function 8432 h.val1 = 4; 8433 n = h.val1; 8434 assert(h.val1 == 4); 8435 assert(4 == h.val1); 8436 assert(n == 4); 8437 8438 // ref getter property function 8439 h.val2 = 8; 8440 n = h.val2; 8441 assert(h.val2 == 8); 8442 assert(8 == h.val2); 8443 assert(n == 8); 8444 8445 // member function 8446 assert(h.func(2,4) == 2); 8447 h.func1(n); 8448 assert(n == 9); 8449 8450 // IFTI 8451 assert(h.ifti1(4) == 4); 8452 h.ifti2(4); 8453 h.ifti3!int(4, 3); 8454 8455 // https://issues.dlang.org/show_bug.cgi?id=5896 test 8456 assert(h.opCast!int() == 0); 8457 assert(cast(int) h == 0); 8458 const ih = new const Hoge(new Foo()); 8459 static assert(!__traits(compiles, ih.opCast!int())); 8460 static assert(!__traits(compiles, cast(int) ih)); 8461 8462 // template member function 8463 assert(h.tempfunc!int() == 0); 8464 } 8465 8466 @system unittest // about Proxy inside a class 8467 { 8468 class MyClass 8469 { 8470 int payload; 8471 mixin Proxy!payload; 8472 this(int i){ payload = i; } 8473 string opCall(string msg){ return msg; } 8474 int pow(int i){ return payload ^^ i; } 8475 } 8476 8477 class MyClass2 8478 { 8479 MyClass payload; 8480 mixin Proxy!payload; 8481 this(int i){ payload = new MyClass(i); } 8482 } 8483 8484 class MyClass3 8485 { 8486 int payload; 8487 mixin Proxy!payload; 8488 this(int i){ payload = i; } 8489 } 8490 8491 // opEquals 8492 Object a = new MyClass(5); 8493 Object b = new MyClass(5); 8494 Object c = new MyClass2(5); 8495 Object d = new MyClass3(5); 8496 assert(a == b); 8497 assert((cast(MyClass) a) == 5); 8498 assert(5 == (cast(MyClass) b)); 8499 assert(5 == cast(MyClass2) c); 8500 assert(a != d); 8501 8502 assert(c != a); 8503 // oops! above line is unexpected, isn't it? 8504 // the reason is below. 8505 // MyClass2.opEquals knows MyClass but, 8506 // MyClass.opEquals doesn't know MyClass2. 8507 // so, c.opEquals(a) is true, but a.opEquals(c) is false. 8508 // furthermore, opEquals(T) couldn't be invoked. 8509 assert((cast(MyClass2) c) != (cast(MyClass) a)); 8510 8511 // opCmp 8512 Object e = new MyClass2(7); 8513 assert(a < cast(MyClass2) e); // OK. and 8514 assert(e > a); // OK, but... 8515 // assert(a < e); // RUNTIME ERROR! 8516 // assert((cast(MyClass) a) < e); // RUNTIME ERROR! 8517 assert(3 < cast(MyClass) a); 8518 assert((cast(MyClass2) e) < 11); 8519 8520 // opCall 8521 assert((cast(MyClass2) e)("hello") == "hello"); 8522 8523 // opCast 8524 assert((cast(MyClass)(cast(MyClass2) c)) == a); 8525 assert((cast(int)(cast(MyClass2) c)) == 5); 8526 8527 // opIndex 8528 class MyClass4 8529 { 8530 string payload; 8531 mixin Proxy!payload; 8532 this(string s){ payload = s; } 8533 } 8534 class MyClass5 8535 { 8536 MyClass4 payload; 8537 mixin Proxy!payload; 8538 this(string s){ payload = new MyClass4(s); } 8539 } 8540 auto f = new MyClass4("hello"); 8541 assert(f[1] == 'e'); 8542 auto g = new MyClass5("hello"); 8543 assert(f[1] == 'e'); 8544 8545 // opSlice 8546 assert(f[2 .. 4] == "ll"); 8547 8548 // opUnary 8549 assert(-(cast(MyClass2) c) == -5); 8550 8551 // opBinary 8552 assert((cast(MyClass) a) + (cast(MyClass2) c) == 10); 8553 assert(5 + cast(MyClass) a == 10); 8554 8555 // opAssign 8556 (cast(MyClass2) c) = 11; 8557 assert((cast(MyClass2) c) == 11); 8558 (cast(MyClass2) c) = new MyClass(13); 8559 assert((cast(MyClass2) c) == 13); 8560 8561 // opOpAssign 8562 assert((cast(MyClass2) c) += 4); 8563 assert((cast(MyClass2) c) == 17); 8564 8565 // opDispatch 8566 assert((cast(MyClass2) c).pow(2) == 289); 8567 8568 // opDollar 8569 assert(f[2..$-1] == "ll"); 8570 8571 // toHash 8572 int[Object] hash; 8573 hash[a] = 19; 8574 hash[c] = 21; 8575 assert(hash[b] == 19); 8576 assert(hash[c] == 21); 8577 } 8578 8579 @safe unittest 8580 { 8581 struct MyInt 8582 { 8583 int payload; 8584 8585 mixin Proxy!payload; 8586 } 8587 8588 MyInt v; 8589 v = v; 8590 8591 struct Foo 8592 { 8593 @disable void opAssign(typeof(this)); 8594 } 8595 struct MyFoo 8596 { 8597 Foo payload; 8598 8599 mixin Proxy!payload; 8600 } 8601 MyFoo f; 8602 static assert(!__traits(compiles, f = f)); 8603 8604 struct MyFoo2 8605 { 8606 Foo payload; 8607 8608 mixin Proxy!payload; 8609 8610 // override default Proxy behavior 8611 void opAssign(typeof(this) rhs){} 8612 } 8613 MyFoo2 f2; 8614 f2 = f2; 8615 } 8616 8617 // https://issues.dlang.org/show_bug.cgi?id=8613 8618 @safe unittest 8619 { 8620 static struct Name 8621 { 8622 mixin Proxy!val; 8623 private string val; 8624 this(string s) { val = s; } 8625 } 8626 8627 bool[Name] names; 8628 names[Name("a")] = true; 8629 bool* b = Name("a") in names; 8630 } 8631 8632 // workaround for https://issues.dlang.org/show_bug.cgi?id=19669 8633 private enum isDIP1000 = __traits(compiles, () @safe { 8634 int x; 8635 int* p; 8636 p = &x; 8637 }); 8638 // excludes struct S; it's 'mixin Proxy!foo' doesn't compile with -dip1000 8639 static if (isDIP1000) {} else 8640 @system unittest 8641 { 8642 // https://issues.dlang.org/show_bug.cgi?id=14213 8643 // using function for the payload 8644 static struct S 8645 { 8646 int foo() { return 12; } 8647 mixin Proxy!foo; 8648 } 8649 S s; 8650 assert(s + 1 == 13); 8651 assert(s * 2 == 24); 8652 } 8653 8654 @system unittest 8655 { 8656 static class C 8657 { 8658 int foo() { return 12; } 8659 mixin Proxy!foo; 8660 } 8661 C c = new C(); 8662 } 8663 8664 // Check all floating point comparisons for both Proxy and Typedef, 8665 // also against int and a Typedef!int, to be as regression-proof 8666 // as possible. https://issues.dlang.org/show_bug.cgi?id=15561 8667 @safe unittest 8668 { 8669 static struct MyFloatImpl 8670 { 8671 float value; 8672 mixin Proxy!value; 8673 } 8674 static void allFail(T0, T1)(T0 a, T1 b) 8675 { 8676 assert(!(a == b)); 8677 assert(!(a<b)); 8678 assert(!(a <= b)); 8679 assert(!(a>b)); 8680 assert(!(a >= b)); 8681 } 8682 static foreach (T1; AliasSeq!(MyFloatImpl, Typedef!float, Typedef!double, 8683 float, real, Typedef!int, int)) 8684 { 8685 static foreach (T2; AliasSeq!(MyFloatImpl, Typedef!float)) 8686 {{ 8687 T1 a; 8688 T2 b; 8689 8690 static if (isFloatingPoint!T1 || isFloatingPoint!(TypedefType!T1)) 8691 allFail(a, b); 8692 a = 3; 8693 allFail(a, b); 8694 8695 b = 4; 8696 assert(a != b); 8697 assert(a<b); 8698 assert(a <= b); 8699 assert(!(a>b)); 8700 assert(!(a >= b)); 8701 8702 a = 4; 8703 assert(a == b); 8704 assert(!(a<b)); 8705 assert(a <= b); 8706 assert(!(a>b)); 8707 assert(a >= b); 8708 }} 8709 } 8710 } 8711 8712 /** 8713 $(B Typedef) allows the creation of a unique type which is 8714 based on an existing type. Unlike the `alias` feature, 8715 $(B Typedef) ensures the two types are not considered as equals. 8716 8717 Params: 8718 8719 init = Optional initial value for the new type. 8720 cookie = Optional, used to create multiple unique types which are 8721 based on the same origin type `T` 8722 8723 Note: If a library routine cannot handle the Typedef type, 8724 you can use the `TypedefType` template to extract the 8725 type which the Typedef wraps. 8726 */ 8727 struct Typedef(T, T init = T.init, string cookie=null) 8728 { 8729 private T Typedef_payload = init; 8730 8731 // https://issues.dlang.org/show_bug.cgi?id=18415 8732 // prevent default construction if original type does too. 8733 static if ((is(T == struct) || is(T == union)) && !is(typeof({T t;}))) 8734 { 8735 @disable this(); 8736 } 8737 8738 this(T init) 8739 { 8740 Typedef_payload = init; 8741 } 8742 8743 this(Typedef tdef) 8744 { 8745 this(tdef.Typedef_payload); 8746 } 8747 8748 // We need to add special overload for cast(Typedef!X) exp, 8749 // thus we can't simply inherit Proxy!Typedef_payload 8750 T2 opCast(T2 : Typedef!(T, Unused), this X, T, Unused...)() 8751 { 8752 return T2(cast(T) Typedef_payload); 8753 } 8754 8755 auto ref opCast(T2, this X)() 8756 { 8757 return cast(T2) Typedef_payload; 8758 } 8759 8760 mixin Proxy!Typedef_payload; 8761 8762 pure nothrow @nogc @safe @property 8763 { 8764 alias TD = typeof(this); 8765 static if (isIntegral!T) 8766 { 8767 static TD min() {return TD(T.min);} 8768 static TD max() {return TD(T.max);} 8769 } 8770 else static if (isFloatingPoint!T) 8771 { 8772 static TD infinity() {return TD(T.infinity);} 8773 static TD nan() {return TD(T.nan);} 8774 static TD dig() {return TD(T.dig);} 8775 static TD epsilon() {return TD(T.epsilon);} 8776 static TD mant_dig() {return TD(T.mant_dig);} 8777 static TD max_10_exp() {return TD(T.max_10_exp);} 8778 static TD max_exp() {return TD(T.max_exp);} 8779 static TD min_10_exp() {return TD(T.min_10_exp);} 8780 static TD min_exp() {return TD(T.min_exp);} 8781 static TD max() {return TD(T.max);} 8782 static TD min_normal() {return TD(T.min_normal);} 8783 TD re() {return TD(Typedef_payload.re);} 8784 TD im() {return TD(Typedef_payload.im);} 8785 } 8786 } 8787 8788 /** 8789 * Convert wrapped value to a human readable string 8790 */ 8791 string toString(this T)() 8792 { 8793 import std.array : appender; 8794 auto app = appender!string(); 8795 auto spec = singleSpec("%s"); 8796 toString(app, spec); 8797 return app.data; 8798 } 8799 8800 /// ditto 8801 void toString(this T, W)(ref W writer, scope const ref FormatSpec!char fmt) 8802 if (isOutputRange!(W, char)) 8803 { 8804 formatValue(writer, Typedef_payload, fmt); 8805 } 8806 8807 /// 8808 @safe unittest 8809 { 8810 import std.conv : to; 8811 8812 int i = 123; 8813 auto td = Typedef!int(i); 8814 assert(i.to!string == td.to!string); 8815 } 8816 } 8817 8818 /// 8819 @safe unittest 8820 { 8821 alias MyInt = Typedef!int; 8822 MyInt foo = 10; 8823 foo++; 8824 assert(foo == 11); 8825 } 8826 8827 /// custom initialization values 8828 @safe unittest 8829 { 8830 alias MyIntInit = Typedef!(int, 42); 8831 static assert(is(TypedefType!MyIntInit == int)); 8832 static assert(MyIntInit() == 42); 8833 } 8834 8835 /// Typedef creates a new type 8836 @safe unittest 8837 { 8838 alias MyInt = Typedef!int; 8839 static void takeInt(int) {} 8840 static void takeMyInt(MyInt) {} 8841 8842 int i; 8843 takeInt(i); // ok 8844 static assert(!__traits(compiles, takeMyInt(i))); 8845 8846 MyInt myInt; 8847 static assert(!__traits(compiles, takeInt(myInt))); 8848 takeMyInt(myInt); // ok 8849 } 8850 8851 /// Use the optional `cookie` argument to create different types of the same base type 8852 @safe unittest 8853 { 8854 alias TypeInt1 = Typedef!int; 8855 alias TypeInt2 = Typedef!int; 8856 8857 // The two Typedefs are the same type. 8858 static assert(is(TypeInt1 == TypeInt2)); 8859 8860 alias MoneyEuros = Typedef!(float, float.init, "euros"); 8861 alias MoneyDollars = Typedef!(float, float.init, "dollars"); 8862 8863 // The two Typedefs are _not_ the same type. 8864 static assert(!is(MoneyEuros == MoneyDollars)); 8865 } 8866 8867 // https://issues.dlang.org/show_bug.cgi?id=12461 8868 @safe unittest 8869 { 8870 alias Int = Typedef!int; 8871 8872 Int a, b; 8873 a += b; 8874 assert(a == 0); 8875 } 8876 8877 /** 8878 Get the underlying type which a `Typedef` wraps. 8879 If `T` is not a `Typedef` it will alias itself to `T`. 8880 */ 8881 template TypedefType(T) 8882 { 8883 static if (is(T : Typedef!Arg, Arg)) 8884 alias TypedefType = Arg; 8885 else 8886 alias TypedefType = T; 8887 } 8888 8889 /// 8890 @safe unittest 8891 { 8892 import std.conv : to; 8893 8894 alias MyInt = Typedef!int; 8895 static assert(is(TypedefType!MyInt == int)); 8896 8897 /// Instantiating with a non-Typedef will return that type 8898 static assert(is(TypedefType!int == int)); 8899 8900 string num = "5"; 8901 8902 // extract the needed type 8903 MyInt myInt = MyInt( num.to!(TypedefType!MyInt) ); 8904 assert(myInt == 5); 8905 8906 // cast to the underlying type to get the value that's being wrapped 8907 int x = cast(TypedefType!MyInt) myInt; 8908 8909 alias MyIntInit = Typedef!(int, 42); 8910 static assert(is(TypedefType!MyIntInit == int)); 8911 static assert(MyIntInit() == 42); 8912 } 8913 8914 @safe unittest 8915 { 8916 Typedef!int x = 10; 8917 static assert(!__traits(compiles, { int y = x; })); 8918 static assert(!__traits(compiles, { long z = x; })); 8919 8920 Typedef!int y = 10; 8921 assert(x == y); 8922 8923 static assert(Typedef!int.init == int.init); 8924 8925 Typedef!(float, 1.0) z; // specifies the init 8926 assert(z == 1.0); 8927 8928 static assert(typeof(z).init == 1.0); 8929 8930 alias Dollar = Typedef!(int, 0, "dollar"); 8931 alias Yen = Typedef!(int, 0, "yen"); 8932 static assert(!is(Dollar == Yen)); 8933 8934 Typedef!(int[3]) sa; 8935 static assert(sa.length == 3); 8936 static assert(typeof(sa).length == 3); 8937 8938 Typedef!(int[3]) dollar1; 8939 assert(dollar1[0..$] is dollar1[0 .. 3]); 8940 8941 Typedef!(int[]) dollar2; 8942 dollar2.length = 3; 8943 assert(dollar2[0..$] is dollar2[0 .. 3]); 8944 8945 static struct Dollar1 8946 { 8947 static struct DollarToken {} 8948 enum opDollar = DollarToken.init; 8949 auto opSlice(size_t, DollarToken) { return 1; } 8950 auto opSlice(size_t, size_t) { return 2; } 8951 } 8952 8953 Typedef!Dollar1 drange1; 8954 assert(drange1[0..$] == 1); 8955 assert(drange1[0 .. 1] == 2); 8956 8957 static struct Dollar2 8958 { 8959 size_t opDollar(size_t pos)() { return pos == 0 ? 1 : 100; } 8960 size_t opIndex(size_t i, size_t j) { return i + j; } 8961 } 8962 8963 Typedef!Dollar2 drange2; 8964 assert(drange2[$, $] == 101); 8965 8966 static struct Dollar3 8967 { 8968 size_t opDollar() { return 123; } 8969 size_t opIndex(size_t i) { return i; } 8970 } 8971 8972 Typedef!Dollar3 drange3; 8973 assert(drange3[$] == 123); 8974 } 8975 8976 // https://issues.dlang.org/show_bug.cgi?id=18415 8977 @safe @nogc pure nothrow unittest 8978 { 8979 struct NoDefCtorS{@disable this();} 8980 union NoDefCtorU{@disable this();} 8981 static assert(!is(typeof({Typedef!NoDefCtorS s;}))); 8982 static assert(!is(typeof({Typedef!NoDefCtorU u;}))); 8983 } 8984 8985 // https://issues.dlang.org/show_bug.cgi?id=11703 8986 @safe @nogc pure nothrow unittest 8987 { 8988 alias I = Typedef!int; 8989 static assert(is(typeof(I.min) == I)); 8990 static assert(is(typeof(I.max) == I)); 8991 8992 alias F = Typedef!double; 8993 static assert(is(typeof(F.infinity) == F)); 8994 static assert(is(typeof(F.epsilon) == F)); 8995 8996 F f; 8997 assert(!is(typeof(F.re).stringof == double)); 8998 assert(!is(typeof(F.im).stringof == double)); 8999 } 9000 9001 @safe unittest 9002 { 9003 // https://issues.dlang.org/show_bug.cgi?id=8655 9004 import std.typecons; 9005 import std.bitmanip; 9006 static import core.stdc.config; 9007 9008 alias c_ulong = Typedef!(core.stdc.config.c_ulong); 9009 9010 static struct Foo 9011 { 9012 mixin(bitfields!( 9013 c_ulong, "NameOffset", 31, 9014 c_ulong, "NameIsString", 1 9015 )); 9016 } 9017 } 9018 9019 // https://issues.dlang.org/show_bug.cgi?id=12596 9020 @safe unittest 9021 { 9022 import std.typecons; 9023 alias TD = Typedef!int; 9024 TD x = TD(1); 9025 TD y = TD(x); 9026 assert(x == y); 9027 } 9028 9029 @safe unittest // about toHash 9030 { 9031 import std.typecons; 9032 { 9033 alias TD = Typedef!int; 9034 int[TD] td; 9035 td[TD(1)] = 1; 9036 assert(td[TD(1)] == 1); 9037 } 9038 9039 { 9040 alias TD = Typedef!(int[]); 9041 int[TD] td; 9042 td[TD([1,2,3,4])] = 2; 9043 assert(td[TD([1,2,3,4])] == 2); 9044 } 9045 9046 { 9047 alias TD = Typedef!(int[][]); 9048 int[TD] td; 9049 td[TD([[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]])] = 3; 9050 assert(td[TD([[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]])] == 3); 9051 } 9052 9053 { 9054 struct MyStruct{ int x; } 9055 alias TD = Typedef!MyStruct; 9056 int[TD] td; 9057 td[TD(MyStruct(10))] = 4; 9058 assert(TD(MyStruct(20)) !in td); 9059 assert(td[TD(MyStruct(10))] == 4); 9060 } 9061 9062 { 9063 static struct MyStruct2 9064 { 9065 int x; 9066 size_t toHash() const nothrow @safe { return x; } 9067 bool opEquals(ref const MyStruct2 r) const { return r.x == x; } 9068 } 9069 9070 alias TD = Typedef!MyStruct2; 9071 int[TD] td; 9072 td[TD(MyStruct2(50))] = 5; 9073 assert(td[TD(MyStruct2(50))] == 5); 9074 } 9075 9076 { 9077 class MyClass{} 9078 alias TD = Typedef!MyClass; 9079 int[TD] td; 9080 auto c = new MyClass; 9081 td[TD(c)] = 6; 9082 assert(TD(new MyClass) !in td); 9083 assert(td[TD(c)] == 6); 9084 } 9085 } 9086 9087 @system unittest 9088 { 9089 alias String = Typedef!(char[]); 9090 alias CString = Typedef!(const(char)[]); 9091 CString cs = "fubar"; 9092 String s = cast(String) cs; 9093 assert(cs == s); 9094 char[] s2 = cast(char[]) cs; 9095 const(char)[] cs2 = cast(const(char)[])s; 9096 assert(s2 == cs2); 9097 } 9098 9099 @system unittest // toString 9100 { 9101 import std.meta : AliasSeq; 9102 import std.conv : to; 9103 9104 struct TestS {} 9105 class TestC {} 9106 9107 static foreach (T; AliasSeq!(int, bool, float, double, real, 9108 char, dchar, wchar, 9109 TestS, TestC, 9110 int*, int[], int[2], int[int])) 9111 {{ 9112 T t; 9113 9114 Typedef!T td; 9115 Typedef!(const T) ctd; 9116 Typedef!(immutable T) itd; 9117 9118 assert(t.to!string() == td.to!string()); 9119 9120 static if (!(is(T == TestS) || is(T == TestC))) 9121 { 9122 assert(t.to!string() == ctd.to!string()); 9123 assert(t.to!string() == itd.to!string()); 9124 } 9125 }} 9126 } 9127 9128 @safe @nogc unittest // typedef'ed type with custom operators 9129 { 9130 static struct MyInt 9131 { 9132 int value; 9133 int opCmp(MyInt other) 9134 { 9135 if (value < other.value) 9136 return -1; 9137 return !(value == other.value); 9138 } 9139 } 9140 9141 auto m1 = Typedef!MyInt(MyInt(1)); 9142 auto m2 = Typedef!MyInt(MyInt(2)); 9143 assert(m1 < m2); 9144 } 9145 9146 /** 9147 Allocates a `class` object right inside the current scope, 9148 therefore avoiding the overhead of `new`. This facility is unsafe; 9149 it is the responsibility of the user to not escape a reference to the 9150 object outside the scope. 9151 9152 The class destructor will be called when the result of `scoped()` is 9153 itself destroyed. 9154 9155 Scoped class instances can be embedded in a parent `class` or `struct`, 9156 just like a child struct instance. Scoped member variables must have 9157 type `typeof(scoped!Class(args))`, and be initialized with a call to 9158 scoped. See below for an example. 9159 9160 Note: 9161 It's illegal to move a class instance even if you are sure there 9162 are no pointers to it. As such, it is illegal to move a scoped object. 9163 */ 9164 template scoped(T) 9165 if (is(T == class)) 9166 { 9167 // _d_newclass now use default GC alignment (looks like (void*).sizeof * 2 for 9168 // small objects). We will just use the maximum of filed alignments. 9169 enum alignment = __traits(classInstanceAlignment, T); 9170 alias aligned = _alignUp!alignment; 9171 9172 static struct Scoped 9173 { 9174 // Addition of `alignment` is required as `Scoped_store` can be misaligned in memory. 9175 private void[aligned(__traits(classInstanceSize, T) + size_t.sizeof) + alignment] Scoped_store = void; 9176 9177 @property inout(T) Scoped_payload() inout 9178 { 9179 void* alignedStore = cast(void*) aligned(cast(size_t) Scoped_store.ptr); 9180 // As `Scoped` can be unaligned moved in memory class instance should be moved accordingly. 9181 immutable size_t d = alignedStore - Scoped_store.ptr; 9182 size_t* currD = cast(size_t*) &Scoped_store[$ - size_t.sizeof]; 9183 if (d != *currD) 9184 { 9185 import core.stdc.string : memmove; 9186 memmove(alignedStore, Scoped_store.ptr + *currD, __traits(classInstanceSize, T)); 9187 *currD = d; 9188 } 9189 return cast(inout(T)) alignedStore; 9190 } 9191 alias Scoped_payload this; 9192 9193 @disable this(); 9194 @disable this(this); 9195 9196 ~this() 9197 { 9198 // `destroy` will also write .init but we have no functions in druntime 9199 // for deterministic finalization and memory releasing for now. 9200 .destroy(Scoped_payload); 9201 } 9202 } 9203 9204 /** Returns the _scoped object. 9205 Params: args = Arguments to pass to `T`'s constructor. 9206 */ 9207 @system auto scoped(Args...)(auto ref Args args) 9208 { 9209 import core.lifetime : emplace, forward; 9210 9211 Scoped result = void; 9212 void* alignedStore = cast(void*) aligned(cast(size_t) result.Scoped_store.ptr); 9213 immutable size_t d = alignedStore - result.Scoped_store.ptr; 9214 *cast(size_t*) &result.Scoped_store[$ - size_t.sizeof] = d; 9215 emplace!(Unqual!T)(result.Scoped_store[d .. $ - size_t.sizeof], forward!args); 9216 return result; 9217 } 9218 } 9219 9220 /// 9221 @system unittest 9222 { 9223 class A 9224 { 9225 int x; 9226 this() {x = 0;} 9227 this(int i){x = i;} 9228 ~this() {} 9229 } 9230 9231 // Standard usage, constructing A on the stack 9232 auto a1 = scoped!A(); 9233 a1.x = 42; 9234 9235 // Result of `scoped` call implicitly converts to a class reference 9236 A aRef = a1; 9237 assert(aRef.x == 42); 9238 9239 // Scoped destruction 9240 { 9241 auto a2 = scoped!A(1); 9242 assert(a2.x == 1); 9243 aRef = a2; 9244 // a2 is destroyed here, calling A's destructor 9245 } 9246 // aRef is now an invalid reference 9247 9248 // Here the temporary scoped A is immediately destroyed. 9249 // This means the reference is then invalid. 9250 version (Bug) 9251 { 9252 // Wrong, should use `auto` 9253 A invalid = scoped!A(); 9254 } 9255 9256 // Restrictions 9257 version (Bug) 9258 { 9259 import std.algorithm.mutation : move; 9260 auto invalid = a1.move; // illegal, scoped objects can't be moved 9261 } 9262 static assert(!is(typeof({ 9263 auto e1 = a1; // illegal, scoped objects can't be copied 9264 assert([a1][0].x == 42); // ditto 9265 }))); 9266 static assert(!is(typeof({ 9267 alias ScopedObject = typeof(a1); 9268 auto e2 = ScopedObject(); // illegal, must be built via scoped!A 9269 auto e3 = ScopedObject(1); // ditto 9270 }))); 9271 9272 // Use with alias 9273 alias makeScopedA = scoped!A; 9274 auto a3 = makeScopedA(); 9275 auto a4 = makeScopedA(1); 9276 9277 // Use as member variable 9278 struct B 9279 { 9280 typeof(scoped!A()) a; // note the trailing parentheses 9281 9282 this(int i) 9283 { 9284 // construct member 9285 a = scoped!A(i); 9286 } 9287 } 9288 9289 // Stack-allocate 9290 auto b1 = B(5); 9291 aRef = b1.a; 9292 assert(aRef.x == 5); 9293 destroy(b1); // calls A's destructor for b1.a 9294 // aRef is now an invalid reference 9295 9296 // Heap-allocate 9297 auto b2 = new B(6); 9298 assert(b2.a.x == 6); 9299 destroy(*b2); // calls A's destructor for b2.a 9300 } 9301 9302 private size_t _alignUp(size_t alignment)(size_t n) 9303 if (alignment > 0 && !((alignment - 1) & alignment)) 9304 { 9305 enum badEnd = alignment - 1; // 0b11, 0b111, ... 9306 return (n + badEnd) & ~badEnd; 9307 } 9308 9309 // https://issues.dlang.org/show_bug.cgi?id=6580 testcase 9310 @system unittest 9311 { 9312 enum alignment = (void*).alignof; 9313 9314 static class C0 { } 9315 static class C1 { byte b; } 9316 static class C2 { byte[2] b; } 9317 static class C3 { byte[3] b; } 9318 static class C7 { byte[7] b; } 9319 static assert(scoped!C0().sizeof % alignment == 0); 9320 static assert(scoped!C1().sizeof % alignment == 0); 9321 static assert(scoped!C2().sizeof % alignment == 0); 9322 static assert(scoped!C3().sizeof % alignment == 0); 9323 static assert(scoped!C7().sizeof % alignment == 0); 9324 9325 enum longAlignment = long.alignof; 9326 static class C1long 9327 { 9328 long long_; byte byte_ = 4; 9329 this() { } 9330 this(long _long, ref int i) { long_ = _long; ++i; } 9331 } 9332 static class C2long { byte[2] byte_ = [5, 6]; long long_ = 7; } 9333 static assert(scoped!C1long().sizeof % longAlignment == 0); 9334 static assert(scoped!C2long().sizeof % longAlignment == 0); 9335 9336 void alignmentTest() 9337 { 9338 int var = 5; 9339 auto c1long = scoped!C1long(3, var); 9340 assert(var == 6); 9341 auto c2long = scoped!C2long(); 9342 assert(cast(uint)&c1long.long_ % longAlignment == 0); 9343 assert(cast(uint)&c2long.long_ % longAlignment == 0); 9344 assert(c1long.long_ == 3 && c1long.byte_ == 4); 9345 assert(c2long.byte_ == [5, 6] && c2long.long_ == 7); 9346 } 9347 9348 alignmentTest(); 9349 9350 version (DigitalMars) 9351 { 9352 void test(size_t size) 9353 { 9354 import core.stdc.stdlib : alloca; 9355 cast(void) alloca(size); 9356 alignmentTest(); 9357 } 9358 foreach (i; 0 .. 10) 9359 test(i); 9360 } 9361 else 9362 { 9363 void test(size_t size)() 9364 { 9365 byte[size] arr; 9366 alignmentTest(); 9367 } 9368 static foreach (i; 0 .. 11) 9369 test!i(); 9370 } 9371 } 9372 9373 // Original https://issues.dlang.org/show_bug.cgi?id=6580 testcase 9374 @system unittest 9375 { 9376 class C { int i; byte b; } 9377 9378 auto sa = [scoped!C(), scoped!C()]; 9379 assert(cast(uint)&sa[0].i % int.alignof == 0); 9380 assert(cast(uint)&sa[1].i % int.alignof == 0); // fails 9381 } 9382 9383 @system unittest 9384 { 9385 class A { int x = 1; } 9386 auto a1 = scoped!A(); 9387 assert(a1.x == 1); 9388 auto a2 = scoped!A(); 9389 a1.x = 42; 9390 a2.x = 53; 9391 assert(a1.x == 42); 9392 } 9393 9394 @system unittest 9395 { 9396 class A { int x = 1; this() { x = 2; } } 9397 auto a1 = scoped!A(); 9398 assert(a1.x == 2); 9399 auto a2 = scoped!A(); 9400 a1.x = 42; 9401 a2.x = 53; 9402 assert(a1.x == 42); 9403 } 9404 9405 @system unittest 9406 { 9407 class A { int x = 1; this(int y) { x = y; } ~this() {} } 9408 auto a1 = scoped!A(5); 9409 assert(a1.x == 5); 9410 auto a2 = scoped!A(42); 9411 a1.x = 42; 9412 a2.x = 53; 9413 assert(a1.x == 42); 9414 } 9415 9416 @system unittest 9417 { 9418 class A { static bool dead; ~this() { dead = true; } } 9419 class B : A { static bool dead; ~this() { dead = true; } } 9420 { 9421 auto b = scoped!B(); 9422 } 9423 assert(B.dead, "asdasd"); 9424 assert(A.dead, "asdasd"); 9425 } 9426 9427 // https://issues.dlang.org/show_bug.cgi?id=8039 testcase 9428 @system unittest 9429 { 9430 static int dels; 9431 static struct S { ~this(){ ++dels; } } 9432 9433 static class A { S s; } 9434 dels = 0; { scoped!A(); } 9435 assert(dels == 1); 9436 9437 static class B { S[2] s; } 9438 dels = 0; { scoped!B(); } 9439 assert(dels == 2); 9440 9441 static struct S2 { S[3] s; } 9442 static class C { S2[2] s; } 9443 dels = 0; { scoped!C(); } 9444 assert(dels == 6); 9445 9446 static class D: A { S2[2] s; } 9447 dels = 0; { scoped!D(); } 9448 assert(dels == 1+6); 9449 } 9450 9451 @system unittest 9452 { 9453 // https://issues.dlang.org/show_bug.cgi?id=4500 9454 class A 9455 { 9456 this() { a = this; } 9457 this(int i) { a = this; } 9458 A a; 9459 bool check() { return this is a; } 9460 } 9461 9462 auto a1 = scoped!A(); 9463 assert(a1.check()); 9464 9465 auto a2 = scoped!A(1); 9466 assert(a2.check()); 9467 9468 a1.a = a1; 9469 assert(a1.check()); 9470 } 9471 9472 @system unittest 9473 { 9474 static class A 9475 { 9476 static int sdtor; 9477 9478 this() { ++sdtor; assert(sdtor == 1); } 9479 ~this() { assert(sdtor == 1); --sdtor; } 9480 } 9481 9482 interface Bob {} 9483 9484 static class ABob : A, Bob 9485 { 9486 this() { ++sdtor; assert(sdtor == 2); } 9487 ~this() { assert(sdtor == 2); --sdtor; } 9488 } 9489 9490 A.sdtor = 0; 9491 scope(exit) assert(A.sdtor == 0); 9492 auto abob = scoped!ABob(); 9493 } 9494 9495 @safe unittest 9496 { 9497 static class A { this(int) {} } 9498 static assert(!__traits(compiles, scoped!A())); 9499 } 9500 9501 @system unittest 9502 { 9503 static class A { @property inout(int) foo() inout { return 1; } } 9504 9505 auto a1 = scoped!A(); 9506 assert(a1.foo == 1); 9507 static assert(is(typeof(a1.foo) == int)); 9508 9509 auto a2 = scoped!(const(A))(); 9510 assert(a2.foo == 1); 9511 static assert(is(typeof(a2.foo) == const(int))); 9512 9513 auto a3 = scoped!(immutable(A))(); 9514 assert(a3.foo == 1); 9515 static assert(is(typeof(a3.foo) == immutable(int))); 9516 9517 const c1 = scoped!A(); 9518 assert(c1.foo == 1); 9519 static assert(is(typeof(c1.foo) == const(int))); 9520 9521 const c2 = scoped!(const(A))(); 9522 assert(c2.foo == 1); 9523 static assert(is(typeof(c2.foo) == const(int))); 9524 9525 const c3 = scoped!(immutable(A))(); 9526 assert(c3.foo == 1); 9527 static assert(is(typeof(c3.foo) == immutable(int))); 9528 } 9529 9530 @system unittest 9531 { 9532 class C 9533 { 9534 this(int rval) { assert(rval == 1); } 9535 this(ref int lval) { assert(lval == 3); ++lval; } 9536 } 9537 9538 auto c1 = scoped!C(1); 9539 int lval = 3; 9540 auto c2 = scoped!C(lval); 9541 assert(lval == 4); 9542 } 9543 9544 @system unittest 9545 { 9546 class C 9547 { 9548 this(){} 9549 this(int){} 9550 this(int, int){} 9551 } 9552 alias makeScopedC = scoped!C; 9553 9554 auto a = makeScopedC(); 9555 auto b = makeScopedC(1); 9556 auto c = makeScopedC(1, 1); 9557 9558 static assert(is(typeof(a) == typeof(b))); 9559 static assert(is(typeof(b) == typeof(c))); 9560 } 9561 9562 /** 9563 Defines a simple, self-documenting yes/no flag. This makes it easy for 9564 APIs to define functions accepting flags without resorting to $(D 9565 bool), which is opaque in calls, and without needing to define an 9566 enumerated type separately. Using `Flag!"Name"` instead of $(D 9567 bool) makes the flag's meaning visible in calls. Each yes/no flag has 9568 its own type, which makes confusions and mix-ups impossible. 9569 9570 Example: 9571 9572 Code calling `getLine` (usually far away from its definition) can't be 9573 understood without looking at the documentation, even by users familiar with 9574 the API: 9575 ---- 9576 string getLine(bool keepTerminator) 9577 { 9578 ... 9579 if (keepTerminator) ... 9580 ... 9581 } 9582 ... 9583 auto line = getLine(false); 9584 ---- 9585 9586 Assuming the reverse meaning (i.e. "ignoreTerminator") and inserting the wrong 9587 code compiles and runs with erroneous results. 9588 9589 After replacing the boolean parameter with an instantiation of `Flag`, code 9590 calling `getLine` can be easily read and understood even by people not 9591 fluent with the API: 9592 9593 ---- 9594 string getLine(Flag!"keepTerminator" keepTerminator) 9595 { 9596 ... 9597 if (keepTerminator) ... 9598 ... 9599 } 9600 ... 9601 auto line = getLine(Yes.keepTerminator); 9602 ---- 9603 9604 The structs `Yes` and `No` are provided as shorthand for 9605 `Flag!"Name".yes` and `Flag!"Name".no` and are preferred for brevity and 9606 readability. These convenience structs mean it is usually unnecessary and 9607 counterproductive to create an alias of a `Flag` as a way of avoiding typing 9608 out the full type while specifying the affirmative or negative options. 9609 9610 Passing categorical data by means of unstructured `bool` 9611 parameters is classified under "simple-data coupling" by Steve 9612 McConnell in the $(LUCKY Code Complete) book, along with three other 9613 kinds of coupling. The author argues citing several studies that 9614 coupling has a negative effect on code quality. `Flag` offers a 9615 simple structuring method for passing yes/no flags to APIs. 9616 */ 9617 template Flag(string name) { 9618 /// 9619 enum Flag : bool 9620 { 9621 /** 9622 When creating a value of type `Flag!"Name"`, use $(D 9623 Flag!"Name".no) for the negative option. When using a value 9624 of type `Flag!"Name"`, compare it against $(D 9625 Flag!"Name".no) or just `false` or `0`. */ 9626 no = false, 9627 9628 /** When creating a value of type `Flag!"Name"`, use $(D 9629 Flag!"Name".yes) for the affirmative option. When using a 9630 value of type `Flag!"Name"`, compare it against $(D 9631 Flag!"Name".yes). 9632 */ 9633 yes = true 9634 } 9635 } 9636 9637 /// 9638 @safe unittest 9639 { 9640 Flag!"abc" flag; 9641 9642 assert(flag == Flag!"abc".no); 9643 assert(flag == No.abc); 9644 assert(!flag); 9645 if (flag) assert(0); 9646 } 9647 9648 /// 9649 @safe unittest 9650 { 9651 auto flag = Yes.abc; 9652 9653 assert(flag); 9654 assert(flag == Yes.abc); 9655 if (!flag) assert(0); 9656 if (flag) {} else assert(0); 9657 } 9658 9659 /** 9660 Convenience names that allow using e.g. `Yes.encryption` instead of 9661 `Flag!"encryption".yes` and `No.encryption` instead of $(D 9662 Flag!"encryption".no). 9663 */ 9664 struct Yes 9665 { 9666 template opDispatch(string name) 9667 { 9668 enum opDispatch = Flag!name.yes; 9669 } 9670 } 9671 //template yes(string name) { enum Flag!name yes = Flag!name.yes; } 9672 9673 /// Ditto 9674 struct No 9675 { 9676 template opDispatch(string name) 9677 { 9678 enum opDispatch = Flag!name.no; 9679 } 9680 } 9681 9682 /// 9683 @safe unittest 9684 { 9685 Flag!"abc" flag; 9686 9687 assert(flag == Flag!"abc".no); 9688 assert(flag == No.abc); 9689 assert(!flag); 9690 if (flag) assert(0); 9691 } 9692 9693 /// 9694 @safe unittest 9695 { 9696 auto flag = Yes.abc; 9697 9698 assert(flag); 9699 assert(flag == Yes.abc); 9700 if (!flag) assert(0); 9701 if (flag) {} else assert(0); 9702 } 9703 9704 /** 9705 Detect whether an enum is of integral type and has only "flag" values 9706 (i.e. values with a bit count of exactly 1). 9707 Additionally, a zero value is allowed for compatibility with enums including 9708 a "None" value. 9709 */ 9710 template isBitFlagEnum(E) 9711 { 9712 static if (is(E Base == enum) && isIntegral!Base) 9713 { 9714 enum isBitFlagEnum = (E.min >= 0) && 9715 { 9716 static foreach (immutable flag; EnumMembers!E) 9717 {{ 9718 Base value = flag; 9719 value &= value - 1; 9720 if (value != 0) return false; 9721 }} 9722 return true; 9723 }(); 9724 } 9725 else 9726 { 9727 enum isBitFlagEnum = false; 9728 } 9729 } 9730 9731 /// 9732 @safe pure nothrow unittest 9733 { 9734 enum A 9735 { 9736 None, 9737 A = 1 << 0, 9738 B = 1 << 1, 9739 C = 1 << 2, 9740 D = 1 << 3, 9741 } 9742 9743 static assert(isBitFlagEnum!A); 9744 } 9745 9746 /// Test an enum with default (consecutive) values 9747 @safe pure nothrow unittest 9748 { 9749 enum B 9750 { 9751 A, 9752 B, 9753 C, 9754 D // D == 3 9755 } 9756 9757 static assert(!isBitFlagEnum!B); 9758 } 9759 9760 /// Test an enum with non-integral values 9761 @safe pure nothrow unittest 9762 { 9763 enum C: double 9764 { 9765 A = 1 << 0, 9766 B = 1 << 1 9767 } 9768 9769 static assert(!isBitFlagEnum!C); 9770 } 9771 9772 /** 9773 A typesafe structure for storing combinations of enum values. 9774 9775 This template defines a simple struct to represent bitwise OR combinations of 9776 enum values. It can be used if all the enum values are integral constants with 9777 a bit count of at most 1, or if the `unsafe` parameter is explicitly set to 9778 Yes. 9779 This is much safer than using the enum itself to store 9780 the OR combination, which can produce surprising effects like this: 9781 ---- 9782 enum E 9783 { 9784 A = 1 << 0, 9785 B = 1 << 1 9786 } 9787 E e = E.A | E.B; 9788 // will throw SwitchError 9789 final switch (e) 9790 { 9791 case E.A: 9792 return; 9793 case E.B: 9794 return; 9795 } 9796 ---- 9797 */ 9798 struct BitFlags(E, Flag!"unsafe" unsafe = No.unsafe) 9799 if (unsafe || isBitFlagEnum!(E)) 9800 { 9801 @safe @nogc pure nothrow: 9802 private: 9803 enum isBaseEnumType(T) = is(E == T); 9804 alias Base = OriginalType!E; 9805 Base mValue; 9806 9807 public: 9808 this(E flag) 9809 { 9810 this = flag; 9811 } 9812 9813 this(T...)(T flags) 9814 if (allSatisfy!(isBaseEnumType, T)) 9815 { 9816 this = flags; 9817 } 9818 9819 bool opCast(B: bool)() const 9820 { 9821 return mValue != 0; 9822 } 9823 9824 Base opCast(B)() const 9825 if (is(Base : B)) 9826 { 9827 return mValue; 9828 } 9829 9830 auto opUnary(string op)() const 9831 if (op == "~") 9832 { 9833 return BitFlags(cast(E) cast(Base) ~mValue); 9834 } 9835 9836 auto ref opAssign(T...)(T flags) 9837 if (allSatisfy!(isBaseEnumType, T)) 9838 { 9839 mValue = 0; 9840 foreach (E flag; flags) 9841 { 9842 mValue |= flag; 9843 } 9844 return this; 9845 } 9846 9847 auto ref opAssign(E flag) 9848 { 9849 mValue = flag; 9850 return this; 9851 } 9852 9853 auto ref opOpAssign(string op: "|")(BitFlags flags) 9854 { 9855 mValue |= flags.mValue; 9856 return this; 9857 } 9858 9859 auto ref opOpAssign(string op: "&")(BitFlags flags) 9860 { 9861 mValue &= flags.mValue; 9862 return this; 9863 } 9864 9865 auto ref opOpAssign(string op: "|")(E flag) 9866 { 9867 mValue |= flag; 9868 return this; 9869 } 9870 9871 auto ref opOpAssign(string op: "&")(E flag) 9872 { 9873 mValue &= flag; 9874 return this; 9875 } 9876 9877 auto opBinary(string op)(BitFlags flags) const 9878 if (op == "|" || op == "&") 9879 { 9880 BitFlags result = this; 9881 result.opOpAssign!op(flags); 9882 return result; 9883 } 9884 9885 auto opBinary(string op)(E flag) const 9886 if (op == "|" || op == "&") 9887 { 9888 BitFlags result = this; 9889 result.opOpAssign!op(flag); 9890 return result; 9891 } 9892 9893 auto opBinaryRight(string op)(E flag) const 9894 if (op == "|" || op == "&") 9895 { 9896 return opBinary!op(flag); 9897 } 9898 9899 bool opDispatch(string name)() const 9900 if (__traits(hasMember, E, name)) 9901 { 9902 enum e = __traits(getMember, E, name); 9903 return (mValue & e) == e; 9904 } 9905 9906 void opDispatch(string name)(bool set) 9907 if (__traits(hasMember, E, name)) 9908 { 9909 enum e = __traits(getMember, E, name); 9910 if (set) 9911 mValue |= e; 9912 else 9913 mValue &= ~e; 9914 } 9915 } 9916 9917 /// Set values with the | operator and test with & 9918 @safe @nogc pure nothrow unittest 9919 { 9920 enum Enum 9921 { 9922 A = 1 << 0, 9923 } 9924 9925 // A default constructed BitFlags has no value set 9926 immutable BitFlags!Enum flags_empty; 9927 assert(!flags_empty.A); 9928 9929 // Value can be set with the | operator 9930 immutable flags_A = flags_empty | Enum.A; 9931 9932 // and tested using property access 9933 assert(flags_A.A); 9934 9935 // or the & operator 9936 assert(flags_A & Enum.A); 9937 // which commutes. 9938 assert(Enum.A & flags_A); 9939 } 9940 9941 /// A default constructed BitFlags has no value set 9942 @safe @nogc pure nothrow unittest 9943 { 9944 enum Enum 9945 { 9946 None, 9947 A = 1 << 0, 9948 B = 1 << 1, 9949 C = 1 << 2 9950 } 9951 9952 immutable BitFlags!Enum flags_empty; 9953 assert(!(flags_empty & (Enum.A | Enum.B | Enum.C))); 9954 assert(!(flags_empty & Enum.A) && !(flags_empty & Enum.B) && !(flags_empty & Enum.C)); 9955 } 9956 9957 // BitFlags can be variadically initialized 9958 @safe @nogc pure nothrow unittest 9959 { 9960 import std.traits : EnumMembers; 9961 9962 enum Enum 9963 { 9964 A = 1 << 0, 9965 B = 1 << 1, 9966 C = 1 << 2 9967 } 9968 9969 // Values can also be set using property access 9970 BitFlags!Enum flags; 9971 flags.A = true; 9972 assert(flags & Enum.A); 9973 flags.A = false; 9974 assert(!(flags & Enum.A)); 9975 9976 // BitFlags can be variadically initialized 9977 immutable BitFlags!Enum flags_AB = BitFlags!Enum(Enum.A, Enum.B); 9978 assert(flags_AB.A && flags_AB.B && !flags_AB.C); 9979 9980 // You can use the EnumMembers template to set all flags 9981 immutable BitFlags!Enum flags_all = EnumMembers!Enum; 9982 assert(flags_all.A && flags_all.B && flags_all.C); 9983 } 9984 9985 /// Binary operations: subtracting and intersecting flags 9986 @safe @nogc pure nothrow unittest 9987 { 9988 enum Enum 9989 { 9990 A = 1 << 0, 9991 B = 1 << 1, 9992 C = 1 << 2, 9993 } 9994 immutable BitFlags!Enum flags_AB = BitFlags!Enum(Enum.A, Enum.B); 9995 immutable BitFlags!Enum flags_BC = BitFlags!Enum(Enum.B, Enum.C); 9996 9997 // Use the ~ operator for subtracting flags 9998 immutable BitFlags!Enum flags_B = flags_AB & ~BitFlags!Enum(Enum.A); 9999 assert(!flags_B.A && flags_B.B && !flags_B.C); 10000 10001 // use & between BitFlags for intersection 10002 assert(flags_B == (flags_BC & flags_AB)); 10003 } 10004 10005 /// All the binary operators work in their assignment version 10006 @safe @nogc pure nothrow unittest 10007 { 10008 enum Enum 10009 { 10010 A = 1 << 0, 10011 B = 1 << 1, 10012 } 10013 10014 BitFlags!Enum flags_empty, temp, flags_AB; 10015 flags_AB = Enum.A | Enum.B; 10016 10017 temp |= flags_AB; 10018 assert(temp == (flags_empty | flags_AB)); 10019 10020 temp = flags_empty; 10021 temp |= Enum.B; 10022 assert(temp == (flags_empty | Enum.B)); 10023 10024 temp = flags_empty; 10025 temp &= flags_AB; 10026 assert(temp == (flags_empty & flags_AB)); 10027 10028 temp = flags_empty; 10029 temp &= Enum.A; 10030 assert(temp == (flags_empty & Enum.A)); 10031 } 10032 10033 /// Conversion to bool and int 10034 @safe @nogc pure nothrow unittest 10035 { 10036 enum Enum 10037 { 10038 A = 1 << 0, 10039 B = 1 << 1, 10040 } 10041 10042 BitFlags!Enum flags; 10043 10044 // BitFlags with no value set evaluate to false 10045 assert(!flags); 10046 10047 // BitFlags with at least one value set evaluate to true 10048 flags |= Enum.A; 10049 assert(flags); 10050 10051 // This can be useful to check intersection between BitFlags 10052 BitFlags!Enum flags_AB = Enum.A | Enum.B; 10053 assert(flags & flags_AB); 10054 assert(flags & Enum.A); 10055 10056 // You can of course get you raw value out of flags 10057 auto value = cast(int) flags; 10058 assert(value == Enum.A); 10059 } 10060 10061 /// You need to specify the `unsafe` parameter for enums with custom values 10062 @safe @nogc pure nothrow unittest 10063 { 10064 enum UnsafeEnum 10065 { 10066 A = 1, 10067 B = 2, 10068 C = 4, 10069 BC = B|C 10070 } 10071 static assert(!__traits(compiles, { BitFlags!UnsafeEnum flags; })); 10072 BitFlags!(UnsafeEnum, Yes.unsafe) flags; 10073 10074 // property access tests for exact match of unsafe enums 10075 flags.B = true; 10076 assert(!flags.BC); // only B 10077 flags.C = true; 10078 assert(flags.BC); // both B and C 10079 flags.B = false; 10080 assert(!flags.BC); // only C 10081 10082 // property access sets all bits of unsafe enum group 10083 flags = flags.init; 10084 flags.BC = true; 10085 assert(!flags.A && flags.B && flags.C); 10086 flags.A = true; 10087 flags.BC = false; 10088 assert(flags.A && !flags.B && !flags.C); 10089 } 10090 10091 // Negation of BitFlags should work with any base type. 10092 // Double-negation of BitFlags should work. 10093 @safe @nogc pure nothrow unittest 10094 { 10095 static foreach (alias Base; AliasSeq!( 10096 byte, 10097 ubyte, 10098 short, 10099 ushort, 10100 int, 10101 uint, 10102 long, 10103 ulong, 10104 )) 10105 {{ 10106 enum Enum : Base 10107 { 10108 A = 1 << 0, 10109 B = 1 << 1, 10110 C = 1 << 2, 10111 } 10112 10113 auto flags = BitFlags!Enum(Enum.A); 10114 10115 assert(flags == ~~flags); 10116 }} 10117 } 10118 10119 private enum false_(T) = false; 10120 10121 // ReplaceType 10122 /** 10123 Replaces all occurrences of `From` into `To`, in one or more types `T`. For 10124 example, `ReplaceType!(int, uint, Tuple!(int, float)[string])` yields 10125 `Tuple!(uint, float)[string]`. The types in which replacement is performed 10126 may be arbitrarily complex, including qualifiers, built-in type constructors 10127 (pointers, arrays, associative arrays, functions, and delegates), and template 10128 instantiations; replacement proceeds transitively through the type definition. 10129 However, member types in `struct`s or `class`es are not replaced because there 10130 are no ways to express the types resulting after replacement. 10131 10132 This is an advanced type manipulation necessary e.g. for replacing the 10133 placeholder type `This` in $(REF Algebraic, std,variant). 10134 10135 Returns: `ReplaceType` aliases itself to the type(s) that result after 10136 replacement. 10137 */ 10138 alias ReplaceType(From, To, T...) = ReplaceTypeUnless!(false_, From, To, T); 10139 10140 /// 10141 @safe unittest 10142 { 10143 static assert( 10144 is(ReplaceType!(int, string, int[]) == string[]) && 10145 is(ReplaceType!(int, string, int[int]) == string[string]) && 10146 is(ReplaceType!(int, string, const(int)[]) == const(string)[]) && 10147 is(ReplaceType!(int, string, Tuple!(int[], float)) 10148 == Tuple!(string[], float)) 10149 ); 10150 } 10151 10152 /** 10153 Like $(LREF ReplaceType), but does not perform replacement in types for which 10154 `pred` evaluates to `true`. 10155 */ 10156 template ReplaceTypeUnless(alias pred, From, To, T...) 10157 { 10158 import std.meta; 10159 10160 static if (T.length == 1) 10161 { 10162 static if (pred!(T[0])) 10163 alias ReplaceTypeUnless = T[0]; 10164 else static if (is(T[0] == From)) 10165 alias ReplaceTypeUnless = To; 10166 else static if (is(T[0] == const(U), U)) 10167 alias ReplaceTypeUnless = const(ReplaceTypeUnless!(pred, From, To, U)); 10168 else static if (is(T[0] == immutable(U), U)) 10169 alias ReplaceTypeUnless = immutable(ReplaceTypeUnless!(pred, From, To, U)); 10170 else static if (is(T[0] == shared(U), U)) 10171 alias ReplaceTypeUnless = shared(ReplaceTypeUnless!(pred, From, To, U)); 10172 else static if (is(T[0] == U*, U)) 10173 { 10174 static if (is(U == function)) 10175 alias ReplaceTypeUnless = replaceTypeInFunctionTypeUnless!(pred, From, To, T[0]); 10176 else 10177 alias ReplaceTypeUnless = ReplaceTypeUnless!(pred, From, To, U)*; 10178 } 10179 else static if (is(T[0] == delegate)) 10180 { 10181 alias ReplaceTypeUnless = replaceTypeInFunctionTypeUnless!(pred, From, To, T[0]); 10182 } 10183 else static if (is(T[0] == function)) 10184 { 10185 static assert(0, "Function types not supported," ~ 10186 " use a function pointer type instead of " ~ T[0].stringof); 10187 } 10188 else static if (is(T[0] == U!V, alias U, V...)) 10189 { 10190 template replaceTemplateArgs(T...) 10191 { 10192 static if (is(typeof(T[0]))) { // template argument is value or symbol 10193 static if (__traits(compiles, { alias _ = T[0]; })) 10194 // it's a symbol 10195 alias replaceTemplateArgs = T[0]; 10196 else 10197 // it's a value 10198 enum replaceTemplateArgs = T[0]; 10199 } else 10200 alias replaceTemplateArgs = ReplaceTypeUnless!(pred, From, To, T[0]); 10201 } 10202 alias ReplaceTypeUnless = U!(staticMap!(replaceTemplateArgs, V)); 10203 } 10204 else static if (is(T[0] == struct)) 10205 // don't match with alias this struct below 10206 // https://issues.dlang.org/show_bug.cgi?id=15168 10207 alias ReplaceTypeUnless = T[0]; 10208 else static if (is(T[0] == U[], U)) 10209 alias ReplaceTypeUnless = ReplaceTypeUnless!(pred, From, To, U)[]; 10210 else static if (is(T[0] == U[n], U, size_t n)) 10211 alias ReplaceTypeUnless = ReplaceTypeUnless!(pred, From, To, U)[n]; 10212 else static if (is(T[0] == U[V], U, V)) 10213 alias ReplaceTypeUnless = 10214 ReplaceTypeUnless!(pred, From, To, U)[ReplaceTypeUnless!(pred, From, To, V)]; 10215 else 10216 alias ReplaceTypeUnless = T[0]; 10217 } 10218 else static if (T.length > 1) 10219 { 10220 alias ReplaceTypeUnless = AliasSeq!(ReplaceTypeUnless!(pred, From, To, T[0]), 10221 ReplaceTypeUnless!(pred, From, To, T[1 .. $])); 10222 } 10223 else 10224 { 10225 alias ReplaceTypeUnless = AliasSeq!(); 10226 } 10227 } 10228 10229 /// 10230 @safe unittest 10231 { 10232 import std.traits : isArray; 10233 10234 static assert( 10235 is(ReplaceTypeUnless!(isArray, int, string, int*) == string*) && 10236 is(ReplaceTypeUnless!(isArray, int, string, int[]) == int[]) && 10237 is(ReplaceTypeUnless!(isArray, int, string, Tuple!(int, int[])) 10238 == Tuple!(string, int[])) 10239 ); 10240 } 10241 10242 private template replaceTypeInFunctionTypeUnless(alias pred, From, To, fun) 10243 { 10244 alias RX = ReplaceTypeUnless!(pred, From, To, ReturnType!fun); 10245 alias PX = AliasSeq!(ReplaceTypeUnless!(pred, From, To, Parameters!fun)); 10246 // Wrapping with AliasSeq is neccesary because ReplaceType doesn't return 10247 // tuple if Parameters!fun.length == 1 10248 10249 string gen() 10250 { 10251 enum linkage = functionLinkage!fun; 10252 alias attributes = functionAttributes!fun; 10253 enum variadicStyle = variadicFunctionStyle!fun; 10254 alias storageClasses = ParameterStorageClassTuple!fun; 10255 10256 string result; 10257 10258 result ~= "extern(" ~ linkage ~ ") "; 10259 static if (attributes & FunctionAttribute.ref_) 10260 { 10261 result ~= "ref "; 10262 } 10263 10264 result ~= "RX"; 10265 static if (is(fun == delegate)) 10266 result ~= " delegate"; 10267 else 10268 result ~= " function"; 10269 10270 result ~= "("; 10271 static foreach (i; 0 .. PX.length) 10272 { 10273 if (i) 10274 result ~= ", "; 10275 if (storageClasses[i] & ParameterStorageClass.scope_) 10276 result ~= "scope "; 10277 if (storageClasses[i] & ParameterStorageClass.in_) 10278 result ~= "in "; 10279 if (storageClasses[i] & ParameterStorageClass.out_) 10280 result ~= "out "; 10281 if (storageClasses[i] & ParameterStorageClass.ref_) 10282 result ~= "ref "; 10283 if (storageClasses[i] & ParameterStorageClass.lazy_) 10284 result ~= "lazy "; 10285 if (storageClasses[i] & ParameterStorageClass.return_) 10286 result ~= "return "; 10287 10288 result ~= "PX[" ~ i.stringof ~ "]"; 10289 } 10290 static if (variadicStyle == Variadic.typesafe) 10291 result ~= " ..."; 10292 else static if (variadicStyle != Variadic.no) 10293 result ~= ", ..."; 10294 result ~= ")"; 10295 10296 static if (attributes & FunctionAttribute.pure_) 10297 result ~= " pure"; 10298 static if (attributes & FunctionAttribute.nothrow_) 10299 result ~= " nothrow"; 10300 static if (attributes & FunctionAttribute.property) 10301 result ~= " @property"; 10302 static if (attributes & FunctionAttribute.trusted) 10303 result ~= " @trusted"; 10304 static if (attributes & FunctionAttribute.safe) 10305 result ~= " @safe"; 10306 static if (attributes & FunctionAttribute.nogc) 10307 result ~= " @nogc"; 10308 static if (attributes & FunctionAttribute.system) 10309 result ~= " @system"; 10310 static if (attributes & FunctionAttribute.const_) 10311 result ~= " const"; 10312 static if (attributes & FunctionAttribute.immutable_) 10313 result ~= " immutable"; 10314 static if (attributes & FunctionAttribute.inout_) 10315 result ~= " inout"; 10316 static if (attributes & FunctionAttribute.shared_) 10317 result ~= " shared"; 10318 static if (attributes & FunctionAttribute.return_) 10319 result ~= " return"; 10320 static if (attributes & FunctionAttribute.live) 10321 result ~= " @live"; 10322 10323 return result; 10324 } 10325 10326 mixin("alias replaceTypeInFunctionTypeUnless = " ~ gen() ~ ";"); 10327 } 10328 10329 @safe unittest 10330 { 10331 template Test(Ts...) 10332 { 10333 static if (Ts.length) 10334 { 10335 //pragma(msg, "Testing: ReplaceType!("~Ts[0].stringof~", " 10336 // ~Ts[1].stringof~", "~Ts[2].stringof~")"); 10337 static assert(is(ReplaceType!(Ts[0], Ts[1], Ts[2]) == Ts[3]), 10338 "ReplaceType!("~Ts[0].stringof~", "~Ts[1].stringof~", " 10339 ~Ts[2].stringof~") == " 10340 ~ReplaceType!(Ts[0], Ts[1], Ts[2]).stringof); 10341 alias Test = Test!(Ts[4 .. $]); 10342 } 10343 else alias Test = void; 10344 } 10345 10346 //import core.stdc.stdio; 10347 alias RefFun1 = ref int function(float, long); 10348 alias RefFun2 = ref float function(float, long); 10349 extern(C) int printf(const char*, ...) nothrow @nogc @system; 10350 extern(C) float floatPrintf(const char*, ...) nothrow @nogc @system; 10351 int func(float); 10352 10353 int x; 10354 struct S1 { void foo() { x = 1; } } 10355 struct S2 { void bar() { x = 2; } } 10356 10357 alias Pass = Test!( 10358 int, float, typeof(&func), float delegate(float), 10359 int, float, typeof(&printf), typeof(&floatPrintf), 10360 int, float, int function(out long, ...), 10361 float function(out long, ...), 10362 int, float, int function(ref float, long), 10363 float function(ref float, long), 10364 int, float, int function(ref int, long), 10365 float function(ref float, long), 10366 int, float, int function(out int, long), 10367 float function(out float, long), 10368 int, float, int function(lazy int, long), 10369 float function(lazy float, long), 10370 int, float, int function(out long, ref const int), 10371 float function(out long, ref const float), 10372 int, float, int function(in long, ref const int), 10373 float function(in long, ref const float), 10374 int, float, int function(long, in int), 10375 float function(long, in float), 10376 int, int, int, int, 10377 int, float, int, float, 10378 int, float, const int, const float, 10379 int, float, immutable int, immutable float, 10380 int, float, shared int, shared float, 10381 int, float, int*, float*, 10382 int, float, const(int)*, const(float)*, 10383 int, float, const(int*), const(float*), 10384 const(int)*, float, const(int*), const(float), 10385 int*, float, const(int)*, const(int)*, 10386 int, float, int[], float[], 10387 int, float, int[42], float[42], 10388 int, float, const(int)[42], const(float)[42], 10389 int, float, const(int[42]), const(float[42]), 10390 int, float, int[int], float[float], 10391 int, float, int[double], float[double], 10392 int, float, double[int], double[float], 10393 int, float, int function(float, long), float function(float, long), 10394 int, float, int function(float), float function(float), 10395 int, float, int function(float, int), float function(float, float), 10396 int, float, int delegate(float, long), float delegate(float, long), 10397 int, float, int delegate(float), float delegate(float), 10398 int, float, int delegate(float, int), float delegate(float, float), 10399 int, float, Unique!int, Unique!float, 10400 int, float, Tuple!(float, int), Tuple!(float, float), 10401 int, float, RefFun1, RefFun2, 10402 S1, S2, 10403 S1[1][][S1]* function(), 10404 S2[1][][S2]* function(), 10405 int, string, 10406 int[3] function( int[] arr, int[2] ...) pure @trusted, 10407 string[3] function(string[] arr, string[2] ...) pure @trusted, 10408 ); 10409 10410 // https://issues.dlang.org/show_bug.cgi?id=15168 10411 static struct T1 { string s; alias s this; } 10412 static struct T2 { char[10] s; alias s this; } 10413 static struct T3 { string[string] s; alias s this; } 10414 alias Pass2 = Test!( 10415 ubyte, ubyte, T1, T1, 10416 ubyte, ubyte, T2, T2, 10417 ubyte, ubyte, T3, T3, 10418 ); 10419 } 10420 10421 // https://issues.dlang.org/show_bug.cgi?id=17116 10422 @safe unittest 10423 { 10424 alias ConstDg = void delegate(float) const; 10425 alias B = void delegate(int) const; 10426 alias A = ReplaceType!(float, int, ConstDg); 10427 static assert(is(B == A)); 10428 } 10429 10430 // https://issues.dlang.org/show_bug.cgi?id=19696 10431 @safe unittest 10432 { 10433 static struct T(U) {} 10434 static struct S { T!int t; alias t this; } 10435 static assert(is(ReplaceType!(float, float, S) == S)); 10436 } 10437 10438 // https://issues.dlang.org/show_bug.cgi?id=19697 10439 @safe unittest 10440 { 10441 class D(T) {} 10442 class C : D!C {} 10443 static assert(is(ReplaceType!(float, float, C))); 10444 } 10445 10446 // https://issues.dlang.org/show_bug.cgi?id=16132 10447 @safe unittest 10448 { 10449 interface I(T) {} 10450 class C : I!int {} 10451 static assert(is(ReplaceType!(int, string, C) == C)); 10452 } 10453 10454 // https://issues.dlang.org/show_bug.cgi?id=22325 10455 @safe unittest 10456 { 10457 static struct Foo(alias f) {} 10458 static void bar() {} 10459 alias _ = ReplaceType!(int, int, Foo!bar); 10460 } 10461 10462 /** 10463 Ternary type with three truth values: 10464 10465 $(UL 10466 $(LI `Ternary.yes` for `true`) 10467 $(LI `Ternary.no` for `false`) 10468 $(LI `Ternary.unknown` as an unknown state) 10469 ) 10470 10471 Also known as trinary, trivalent, or trilean. 10472 10473 See_Also: 10474 $(HTTP en.wikipedia.org/wiki/Three-valued_logic, 10475 Three Valued Logic on Wikipedia) 10476 */ 10477 struct Ternary 10478 { 10479 @safe @nogc nothrow pure: 10480 10481 private ubyte value = 6; 10482 private static Ternary make(ubyte b) 10483 { 10484 Ternary r = void; 10485 r.value = b; 10486 return r; 10487 } 10488 10489 /** 10490 The possible states of the `Ternary` 10491 */ 10492 enum no = make(0); 10493 /// ditto 10494 enum yes = make(2); 10495 /// ditto 10496 enum unknown = make(6); 10497 10498 /** 10499 Construct and assign from a `bool`, receiving `no` for `false` and `yes` 10500 for `true`. 10501 */ 10502 this(bool b) { value = b << 1; } 10503 10504 /// ditto 10505 void opAssign(bool b) { value = b << 1; } 10506 10507 /** 10508 Construct a ternary value from another ternary value 10509 */ 10510 this(const Ternary b) { value = b.value; } 10511 10512 /** 10513 $(TABLE Truth table for logical operations, 10514 $(TR $(TH `a`) $(TH `b`) $(TH `$(TILDE)a`) $(TH `a | b`) $(TH `a & b`) $(TH `a ^ b`)) 10515 $(TR $(TD `no`) $(TD `no`) $(TD `yes`) $(TD `no`) $(TD `no`) $(TD `no`)) 10516 $(TR $(TD `no`) $(TD `yes`) $(TD) $(TD `yes`) $(TD `no`) $(TD `yes`)) 10517 $(TR $(TD `no`) $(TD `unknown`) $(TD) $(TD `unknown`) $(TD `no`) $(TD `unknown`)) 10518 $(TR $(TD `yes`) $(TD `no`) $(TD `no`) $(TD `yes`) $(TD `no`) $(TD `yes`)) 10519 $(TR $(TD `yes`) $(TD `yes`) $(TD) $(TD `yes`) $(TD `yes`) $(TD `no`)) 10520 $(TR $(TD `yes`) $(TD `unknown`) $(TD) $(TD `yes`) $(TD `unknown`) $(TD `unknown`)) 10521 $(TR $(TD `unknown`) $(TD `no`) $(TD `unknown`) $(TD `unknown`) $(TD `no`) $(TD `unknown`)) 10522 $(TR $(TD `unknown`) $(TD `yes`) $(TD) $(TD `yes`) $(TD `unknown`) $(TD `unknown`)) 10523 $(TR $(TD `unknown`) $(TD `unknown`) $(TD) $(TD `unknown`) $(TD `unknown`) $(TD `unknown`)) 10524 ) 10525 */ 10526 Ternary opUnary(string s)() if (s == "~") 10527 { 10528 return make((386 >> value) & 6); 10529 } 10530 10531 /// ditto 10532 Ternary opBinary(string s)(Ternary rhs) if (s == "|") 10533 { 10534 return make((25_512 >> (value + rhs.value)) & 6); 10535 } 10536 10537 /// ditto 10538 Ternary opBinary(string s)(Ternary rhs) if (s == "&") 10539 { 10540 return make((26_144 >> (value + rhs.value)) & 6); 10541 } 10542 10543 /// ditto 10544 Ternary opBinary(string s)(Ternary rhs) if (s == "^") 10545 { 10546 return make((26_504 >> (value + rhs.value)) & 6); 10547 } 10548 10549 /// ditto 10550 Ternary opBinary(string s)(bool rhs) 10551 if (s == "|" || s == "&" || s == "^") 10552 { 10553 return this.opBinary!s(Ternary(rhs)); 10554 } 10555 } 10556 10557 /// 10558 @safe @nogc nothrow pure 10559 unittest 10560 { 10561 Ternary a; 10562 assert(a == Ternary.unknown); 10563 10564 assert(~Ternary.yes == Ternary.no); 10565 assert(~Ternary.no == Ternary.yes); 10566 assert(~Ternary.unknown == Ternary.unknown); 10567 } 10568 10569 @safe @nogc nothrow pure 10570 unittest 10571 { 10572 alias f = Ternary.no, t = Ternary.yes, u = Ternary.unknown; 10573 Ternary[27] truthTableAnd = 10574 [ 10575 t, t, t, 10576 t, u, u, 10577 t, f, f, 10578 u, t, u, 10579 u, u, u, 10580 u, f, f, 10581 f, t, f, 10582 f, u, f, 10583 f, f, f, 10584 ]; 10585 10586 Ternary[27] truthTableOr = 10587 [ 10588 t, t, t, 10589 t, u, t, 10590 t, f, t, 10591 u, t, t, 10592 u, u, u, 10593 u, f, u, 10594 f, t, t, 10595 f, u, u, 10596 f, f, f, 10597 ]; 10598 10599 Ternary[27] truthTableXor = 10600 [ 10601 t, t, f, 10602 t, u, u, 10603 t, f, t, 10604 u, t, u, 10605 u, u, u, 10606 u, f, u, 10607 f, t, t, 10608 f, u, u, 10609 f, f, f, 10610 ]; 10611 10612 for (auto i = 0; i != truthTableAnd.length; i += 3) 10613 { 10614 assert((truthTableAnd[i] & truthTableAnd[i + 1]) 10615 == truthTableAnd[i + 2]); 10616 assert((truthTableOr[i] | truthTableOr[i + 1]) 10617 == truthTableOr[i + 2]); 10618 assert((truthTableXor[i] ^ truthTableXor[i + 1]) 10619 == truthTableXor[i + 2]); 10620 } 10621 10622 Ternary a; 10623 assert(a == Ternary.unknown); 10624 static assert(!is(typeof({ if (a) {} }))); 10625 assert(!is(typeof({ auto b = Ternary(3); }))); 10626 a = true; 10627 assert(a == Ternary.yes); 10628 a = false; 10629 assert(a == Ternary.no); 10630 a = Ternary.unknown; 10631 assert(a == Ternary.unknown); 10632 Ternary b; 10633 b = a; 10634 assert(b == a); 10635 assert(~Ternary.yes == Ternary.no); 10636 assert(~Ternary.no == Ternary.yes); 10637 assert(~Ternary.unknown == Ternary.unknown); 10638 } 10639 10640 @safe @nogc nothrow pure 10641 unittest 10642 { 10643 Ternary a = Ternary(true); 10644 assert(a == Ternary.yes); 10645 assert((a & false) == Ternary.no); 10646 assert((a | false) == Ternary.yes); 10647 assert((a ^ true) == Ternary.no); 10648 assert((a ^ false) == Ternary.yes); 10649 } 10650 10651 // https://issues.dlang.org/show_bug.cgi?id=22511 10652 @safe unittest 10653 { 10654 static struct S 10655 { 10656 int b; 10657 @disable this(this); 10658 this(ref return scope inout S rhs) inout 10659 { 10660 this.b = rhs.b + 1; 10661 } 10662 } 10663 10664 Nullable!S s1 = S(1); 10665 assert(s1.get().b == 2); 10666 Nullable!S s2 = s1; 10667 assert(s2.get().b == 3); 10668 } 10669 10670 @safe unittest 10671 { 10672 static struct S 10673 { 10674 int b; 10675 this(this) { ++b; } 10676 } 10677 10678 Nullable!S s1 = S(1); 10679 assert(s1.get().b == 2); 10680 Nullable!S s2 = s1; 10681 assert(s2.get().b == 3); 10682 } 10683 10684 // https://issues.dlang.org/show_bug.cgi?id=24318 10685 @system unittest 10686 { 10687 static struct S 10688 { 10689 @disable this(this); 10690 int i; 10691 } 10692 10693 Nullable!S s = S(1); 10694 assert(s.get().i == 1); 10695 s = S(2); 10696 assert(s.get().i == 2); 10697 } 10698 10699 /// The old version of $(LREF SafeRefCounted), before $(LREF borrow) existed. 10700 /// Old code may be relying on `@safe`ty of some of the member functions which 10701 /// cannot be safe in the new scheme, and 10702 /// can avoid breakage by continuing to use this. `SafeRefCounted` should be 10703 /// preferred, as this type is outdated and unrecommended for new code. 10704 struct RefCounted(T, RefCountedAutoInitialize autoInit = 10705 RefCountedAutoInitialize.yes) 10706 { 10707 version (D_BetterC) 10708 { 10709 private enum enableGCScan = false; 10710 } 10711 else 10712 { 10713 private enum enableGCScan = hasIndirections!T; 10714 } 10715 10716 extern(C) private pure nothrow @nogc static 10717 { 10718 pragma(mangle, "free") void pureFree( void *ptr ); 10719 static if (enableGCScan) 10720 import core.memory : GC; 10721 } 10722 10723 struct RefCountedStore 10724 { 10725 private struct Impl 10726 { 10727 T _payload; 10728 size_t _count; 10729 } 10730 10731 private Impl* _store; 10732 10733 private void initialize(A...)(auto ref A args) 10734 { 10735 import core.lifetime : emplace, forward; 10736 10737 allocateStore(); 10738 version (D_Exceptions) scope(failure) deallocateStore(); 10739 emplace(&_store._payload, forward!args); 10740 _store._count = 1; 10741 } 10742 10743 private void move(ref T source) nothrow pure 10744 { 10745 import std.algorithm.mutation : moveEmplace; 10746 10747 allocateStore(); 10748 moveEmplace(source, _store._payload); 10749 _store._count = 1; 10750 } 10751 10752 // 'nothrow': can only generate an Error 10753 private void allocateStore() nothrow pure 10754 { 10755 static if (enableGCScan) 10756 { 10757 import std.internal.memory : enforceCalloc; 10758 _store = cast(Impl*) enforceCalloc(1, Impl.sizeof); 10759 GC.addRange(&_store._payload, T.sizeof); 10760 } 10761 else 10762 { 10763 import std.internal.memory : enforceMalloc; 10764 _store = cast(Impl*) enforceMalloc(Impl.sizeof); 10765 } 10766 } 10767 10768 private void deallocateStore() nothrow pure 10769 { 10770 static if (enableGCScan) 10771 { 10772 GC.removeRange(&this._store._payload); 10773 } 10774 pureFree(_store); 10775 _store = null; 10776 } 10777 10778 @property nothrow @safe pure @nogc 10779 bool isInitialized() const 10780 { 10781 return _store !is null; 10782 } 10783 10784 @property nothrow @safe pure @nogc 10785 size_t refCount() const 10786 { 10787 return isInitialized ? _store._count : 0; 10788 } 10789 10790 void ensureInitialized()() 10791 { 10792 // By checking for `@disable this()` and failing early we can 10793 // produce a clearer error message. 10794 static assert(__traits(compiles, { static T t; }), 10795 "Cannot automatically initialize `" ~ fullyQualifiedName!T ~ 10796 "` because `" ~ fullyQualifiedName!T ~ 10797 ".this()` is annotated with `@disable`."); 10798 if (!isInitialized) initialize(); 10799 } 10800 10801 } 10802 RefCountedStore _refCounted; 10803 10804 @property nothrow @safe 10805 ref inout(RefCountedStore) refCountedStore() inout 10806 { 10807 return _refCounted; 10808 } 10809 10810 this(A...)(auto ref A args) if (A.length > 0) 10811 out 10812 { 10813 assert(refCountedStore.isInitialized); 10814 } 10815 do 10816 { 10817 import core.lifetime : forward; 10818 _refCounted.initialize(forward!args); 10819 } 10820 10821 this(T val) 10822 { 10823 _refCounted.move(val); 10824 } 10825 10826 this(this) @safe pure nothrow @nogc 10827 { 10828 if (!_refCounted.isInitialized) return; 10829 ++_refCounted._store._count; 10830 } 10831 10832 ~this() 10833 { 10834 if (!_refCounted.isInitialized) return; 10835 assert(_refCounted._store._count > 0); 10836 if (--_refCounted._store._count) 10837 return; 10838 // Done, destroy and deallocate 10839 .destroy(_refCounted._store._payload); 10840 _refCounted.deallocateStore(); 10841 } 10842 10843 void opAssign(typeof(this) rhs) 10844 { 10845 import std.algorithm.mutation : swap; 10846 10847 swap(_refCounted._store, rhs._refCounted._store); 10848 } 10849 10850 void opAssign(T rhs) 10851 { 10852 import std.algorithm.mutation : move; 10853 10854 static if (autoInit == RefCountedAutoInitialize.yes) 10855 { 10856 _refCounted.ensureInitialized(); 10857 } 10858 else 10859 { 10860 assert(_refCounted.isInitialized); 10861 } 10862 move(rhs, _refCounted._store._payload); 10863 } 10864 10865 static if (autoInit == RefCountedAutoInitialize.yes) 10866 { 10867 //Can't use inout here because of potential mutation 10868 @property 10869 ref T refCountedPayload() return 10870 { 10871 _refCounted.ensureInitialized(); 10872 return _refCounted._store._payload; 10873 } 10874 } 10875 10876 @property nothrow @safe pure @nogc 10877 ref inout(T) refCountedPayload() inout return 10878 { 10879 assert(_refCounted.isInitialized, "Attempted to access an uninitialized payload."); 10880 return _refCounted._store._payload; 10881 } 10882 10883 alias refCountedPayload this; 10884 10885 static if (is(T == struct) && !is(typeof((ref T t) => t.toString()))) 10886 { 10887 string toString(this This)() 10888 { 10889 import std.conv : to; 10890 10891 static if (autoInit) 10892 return to!string(refCountedPayload); 10893 else 10894 { 10895 if (!_refCounted.isInitialized) 10896 return This.stringof ~ "(RefCountedStore(null))"; 10897 else 10898 return to!string(_refCounted._store._payload); 10899 } 10900 } 10901 } 10902 } 10903 10904 /// 10905 @betterC pure @system nothrow @nogc unittest 10906 { 10907 auto rc1 = RefCounted!int(5); 10908 assert(rc1 == 5); 10909 auto rc2 = rc1; 10910 rc2 = 42; 10911 assert(rc1 == 42); 10912 } 10913 10914 // More unit tests below SafeRefCounted 10915 10916 /** 10917 * Like $(LREF safeRefCounted) but used to initialize $(LREF RefCounted) 10918 * instead. Intended for backwards compatibility, otherwise it is preferable 10919 * to use `safeRefCounted`. 10920 */ 10921 RefCounted!(T, RefCountedAutoInitialize.no) refCounted(T)(T val) 10922 { 10923 typeof(return) res; 10924 res._refCounted.move(val); 10925 return res; 10926 } 10927 10928 /// 10929 @system unittest 10930 { 10931 static struct File 10932 { 10933 static size_t nDestroyed; 10934 string name; 10935 @disable this(this); // not copyable 10936 ~this() { name = null; ++nDestroyed; } 10937 } 10938 10939 auto file = File("name"); 10940 assert(file.name == "name"); 10941 static assert(!__traits(compiles, {auto file2 = file;})); 10942 assert(File.nDestroyed == 0); 10943 10944 { 10945 import std.algorithm.mutation : move; 10946 auto rcFile = refCounted(move(file)); 10947 assert(rcFile.name == "name"); 10948 assert(File.nDestroyed == 1); 10949 assert(file.name == null); 10950 10951 auto rcFile2 = rcFile; 10952 assert(rcFile.refCountedStore.refCount == 2); 10953 assert(File.nDestroyed == 1); 10954 } 10955 10956 assert(File.nDestroyed == 2); 10957 } 10958 10959 // More unit tests below safeRefCounted