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