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