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