1 /** Functions for user-defined _lifetime implementation. 2 3 Copyright: Denis Shelomovskij 2012-2014 4 5 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). 6 7 Authors: Denis Shelomovskij 8 */ 9 module unstd.lifetime; 10 11 import unstd.array; 12 import unstd.casts; 13 import unstd.traits; 14 import unstd.generictuple; 15 import std.exception; 16 17 18 /** 19 Moves $(D source) into $(D target). 20 21 Specifically: 22 $(UL 23 $(LI Does nothing if $(D &source is &target) (for the first overload only). 24 ) 25 $(LI Destroys $(D target) if needed (for the first overload only, see 26 $(STDREF traits, hasElaborateDestructor)) 27 ) 28 $(LI Bitwise copies $(D source) into $(D target). 29 ) 30 $(LI If $(D hasElaborateCopyConstructor!T || hasElaborateDestructor!T) 31 is $(D true) (see $(STDREF traits, hasElaborateCopyConstructor)), 32 then sets $(D source) to $(D T.init). 33 ) 34 ) 35 See also $(STDREF exception, doesPointTo). 36 37 Preconditions: 38 $(D &source == &target || !doesPointTo(source, source)) 39 */ 40 void move(T)(ref T source, ref T target) 41 in { assert(&source == &target || !doesPointTo(source, source)); } 42 body 43 { 44 // Performance optimization: 45 // Do not compare addresses if we don't have side effects, 46 // T is assignable, and T fits in register. 47 static if(hasElaborateCopyConstructor!T || hasElaborateDestructor!T || 48 !isAssignable!T || hasElaborateAssign!T || 49 T.sizeof > size_t.sizeof) 50 if (&source == &target) return; 51 52 static if(hasElaborateDestructor!T) 53 destruct(target, false); 54 55 static if(!isAssignable!T || hasElaborateAssign!T) 56 rawCopy(source._unqual, target._unqual); 57 else 58 target = source; 59 60 static if(hasElaborateCopyConstructor!T || hasElaborateDestructor!T) 61 setToInitialState(source); 62 } 63 64 unittest 65 { 66 Object obj1 = new Object; 67 Object obj2 = obj1; 68 Object obj3; 69 move(obj2, obj3); 70 assert(obj3 is obj1); 71 72 static struct S1 { int a = 1, b = 2; } 73 S1 s11 = { 10, 11 }; 74 S1 s12; 75 move(s11, s12); 76 assert(s11.a == 10 && s11.b == 11 && s12.a == 10 && s12.b == 11); 77 78 shared S1 sharedS11, sharedS12; 79 move(sharedS11, sharedS12); 80 81 const int constI11, constI12; 82 void constTest(in int ci1) { const ci2 = move(ci1); } 83 84 static struct S2 { int a = 1; int * b; } 85 S2 s21 = { 10, null }; 86 s21.b = new int; 87 S2 s22; 88 move(s21, s22); 89 assert(s21 == s22); 90 91 // Issue 5661 test(1) 92 static struct S3 93 { 94 static struct X { int n = 0; ~this(){n = 0;} } 95 X x; 96 } 97 static assert(hasElaborateDestructor!S3); 98 S3 s31, s32; 99 s31.x.n = 1; 100 move(s31, s32); 101 assert(s31.x.n == 0); 102 assert(s32.x.n == 1); 103 104 // Issue 5661 test(2) 105 static struct S4 106 { 107 static struct X { int n = 0; this(this){n = 0;} } 108 X x; 109 } 110 static assert(hasElaborateCopyConstructor!S4); 111 S4 s41, s42; 112 s41.x.n = 1; 113 move(s41, s42); 114 assert(s41.x.n == 0); 115 assert(s42.x.n == 1); 116 } 117 118 /// Ditto 119 T move(T)(ref T source) 120 { 121 // Can avoid to check aliasing here. 122 123 static if(hasElaborateCopyConstructor!T || hasElaborateDestructor!T) 124 { 125 T result = void; 126 rawCopy(source, result); 127 setToInitialState(source); 128 return result; 129 } 130 else 131 { 132 return source; 133 } 134 } 135 136 unittest 137 { 138 Object obj1 = new Object; 139 Object obj2 = obj1; 140 Object obj3 = move(obj2); 141 assert(obj3 is obj1); 142 143 static struct S1 { int a = 1, b = 2; } 144 S1 s11 = { 10, 11 }; 145 S1 s12 = move(s11); 146 assert(s11.a == 10 && s11.b == 11 && s12.a == 10 && s12.b == 11); 147 148 shared S1 sharedS11, sharedS12 = move(sharedS11); 149 void constTest(in int ci1, in int ci2) { move(ci1, ci2); } 150 151 static struct S2 { int a = 1; int * b; } 152 S2 s21 = { 10, null }; 153 s21.b = new int; 154 S2 s22 = move(s21); 155 assert(s21 == s22); 156 157 // Issue 5661 test(1) 158 static struct S3 159 { 160 static struct X { int n = 0; ~this(){n = 0;} } 161 X x; 162 } 163 static assert(hasElaborateDestructor!S3); 164 S3 s31; 165 s31.x.n = 1; 166 S3 s32 = move(s31); 167 assert(s31.x.n == 0); 168 assert(s32.x.n == 1); 169 170 // Issue 5661 test(2) 171 static struct S4 172 { 173 static struct X { int n = 0; this(this){n = 0;} } 174 X x; 175 } 176 static assert(hasElaborateCopyConstructor!S4); 177 S4 s41; 178 s41.x.n = 1; 179 S4 s42 = move(s41); 180 assert(s41.x.n == 0); 181 assert(s42.x.n == 1); 182 } 183 184 unittest//Issue 6217 185 { 186 import std.algorithm; 187 auto x = map!"a"([1,2,3]); 188 x = move(x); 189 } 190 191 unittest// Issue 8055 192 { 193 static struct S 194 { 195 int x; 196 ~this() { assert(x == 0); } 197 } 198 S foo(S s) { return move(s); } 199 S a; 200 a.x = 0; 201 auto b = foo(a); 202 assert(b.x == 0); 203 } 204 205 unittest// Issue 8057 206 { 207 int n = 10; 208 struct S 209 { 210 int x; 211 ~this() 212 { 213 // Struct always can equal to its `init` 214 if(this == S.init) return; 215 // Access to enclosing scope 216 assert(n == 10); 217 } 218 } 219 S foo(S s) 220 { 221 // Move nested struct 222 return move(s); 223 } 224 S a; 225 a.x = 1; 226 auto b = foo(a); 227 assert(b.x == 1); 228 229 // Regression 8171 230 static struct Array(T) 231 { 232 // nested struct has no member 233 struct Payload 234 { 235 ~this() {} 236 } 237 } 238 Array!int.Payload x = void; 239 static assert(__traits(compiles, move(x) )); 240 static assert(__traits(compiles, move(x, x) )); 241 } 242 243 244 /** 245 Forwards function arguments with saving ref-ness. 246 247 Example: 248 --- 249 int foo(int n) { return 1; } 250 int foo(ref int n) { return 2; } 251 int bar()(auto ref int x) { return foo(forward!x); } 252 253 assert(bar(1) == 1); 254 int i; 255 assert(bar(i) == 2); 256 --- 257 258 --- 259 void foo(int n, ref string s) { s = null; foreach (i; 0..n) s ~= "Hello"; } 260 261 // forwards all arguments which are bound to parameter tuple 262 void bar(Args...)(auto ref Args args) { return foo(forward!args); } 263 264 // forwards all arguments with swapping order 265 void baz(Args...)(auto ref Args args) { return foo(forward!args[$/2..$], forward!args[0..$/2]); } 266 267 string s; 268 bar(1, s); 269 assert(s == "Hello"); 270 baz(s, 2); 271 assert(s == "HelloHello"); 272 --- 273 274 Note: 275 This is just a copy of $(STDREF algorithm, _forward) 276 implementation except it uses fixed $(D move). 277 */ 278 template forward(args...) 279 { 280 static if (args.length) 281 { 282 alias arg = args[0]; 283 static if (__traits(isRef, arg)) 284 alias fwd = arg; 285 else 286 @property fwd()() { return move(arg); } 287 alias forward = expressionTuple!(fwd, forward!(args[1 .. $])); 288 } 289 else 290 alias forward = expressionTuple!(); 291 } 292 293 // Note: unittest can't be used as an example here as there is no way to place it before `Note` section. 294 295 unittest 296 { 297 class C 298 { 299 static int foo(int n) { return 1; } 300 static int foo(ref int n) { return 2; } 301 } 302 int bar()(auto ref int x) { return C.foo(forward!x); } 303 304 assert(bar(1) == 1); 305 int i; 306 assert(bar(i) == 2); 307 } 308 309 unittest 310 { 311 void foo(int n, ref string s) { s = null; foreach (i; 0..n) s ~= "Hello"; } 312 313 void bar(Args...)(auto ref Args args) { return foo(forward!args); } 314 315 void baz(Args...)(auto ref Args args) { return foo(forward!args[$/2..$], forward!args[0..$/2]); } 316 317 string s; 318 bar(1, s); 319 assert(s == "Hello"); 320 baz(s, 2); 321 assert(s == "HelloHello"); 322 } 323 324 unittest 325 { 326 auto foo(TL...)(auto ref TL args) 327 { 328 string result = ""; 329 foreach (i, _; args) 330 { 331 //pragma(msg, "[",i,"] ", __traits(isRef, args[i]) ? "L" : "R"); 332 result ~= __traits(isRef, args[i]) ? "L" : "R"; 333 } 334 return result; 335 } 336 337 string bar(TL...)(auto ref TL args) 338 { 339 return foo(forward!args); 340 } 341 string baz(TL...)(auto ref TL args) 342 { 343 int x; 344 return foo(forward!args[3], forward!args[2], 1, forward!args[1], forward!args[0], x); 345 } 346 347 struct S {} 348 S makeS(){ return S(); } 349 int n; 350 string s; 351 assert(bar(S(), makeS(), n, s) == "RRLL"); 352 assert(baz(S(), makeS(), n, s) == "LLRRRL"); 353 } 354 355 unittest 356 { 357 ref int foo(ref int a) { return a; } 358 ref int bar(Args)(auto ref Args args) 359 { 360 return foo(forward!args); 361 } 362 static assert(!__traits(compiles, { auto x1 = bar(3); })); // case of NG 363 int value = 3; 364 auto x2 = bar(value); // case of OK 365 } 366 367 368 // Used in `_initializeFromImplicitlyConvertible` and `constructFrom` overload for static arrays. 369 private template _implicitlyConvertibleDim(From, To) 370 { 371 template impl(To, From, size_t dim) 372 { 373 static if(isImplicitlyConvertible!(From, To)) 374 enum impl = dim; 375 else static if(isStaticArray!To) 376 enum impl = impl!(ArrayElementType!To, From, dim + 1); 377 else 378 enum impl = -1; 379 } 380 381 enum _implicitlyConvertibleDim = impl!(To, From, 0); 382 } 383 384 unittest 385 { 386 alias dim = _implicitlyConvertibleDim; 387 388 static assert(dim!(int, int) == 0); 389 static assert(dim!(int, int[1][1]) == 2); 390 static assert(dim!(int[1], int[1][1]) == 1); 391 static assert(dim!(int[1], int) == -1); 392 static assert(dim!(int, long) == 0); 393 static assert(dim!(int, long[1][1]) == 2); 394 static assert(dim!(long, int) == -1); 395 } 396 397 398 // Used in `constructFrom` and `constructFromLiteral`. 399 private void _initializeFromImplicitlyConvertible(D, S)(ref D dest, ref S src) 400 if(__traits(compiles, { D d = S.init; })) 401 { 402 enum dim = _implicitlyConvertibleDim!(S, Unqual!D); 403 static assert(dim != -1); // should never fail 404 foreach(ref element; asFlatStaticArray!dim(dest)) 405 { 406 static if(is(S == struct)) 407 { 408 // Argument is implicitly convertible to `D` or to it's element type. 409 // As we are dealing with structs here, this means both types are 410 // the same type with, possibly, different qualifiers. 411 static assert(is(Unqual!(typeof(element)) == Unqual!S)); // should never fail 412 413 rawCopy(src._unqual, element._unqual); 414 callPostblits(element); 415 } 416 else static if(isAssignable!D) 417 { 418 element = src; 419 } 420 else 421 { 422 element._unqual = src; 423 } 424 } 425 } 426 427 unittest 428 { 429 alias init = _initializeFromImplicitlyConvertible; 430 431 static assert( __traits(compiles, init!(int, int))); 432 static assert( __traits(compiles, init!(long, int))); 433 static assert(!__traits(compiles, init!(int, long))); 434 static assert( __traits(compiles, init!(const int*, int*))); 435 static assert( __traits(compiles, init!(const int*, immutable int*))); 436 static assert(!__traits(compiles, init!(immutable int*, const int*))); 437 static assert( __traits(compiles, init!(shared int*, shared int*))); 438 static assert( __traits(compiles, init!(const shared int*, shared int*))); 439 440 { 441 int src = 1, dest; 442 init(dest, src); 443 assert(dest == 1); 444 } 445 { 446 int src = 1; 447 long dest; 448 init(dest, src); 449 assert(dest == 1); 450 } 451 { 452 int src = 1; 453 long[2][1] dest; 454 init(dest, src); 455 assert(dest == [[1, 1]]); 456 } 457 { 458 int* src = cast(int*) 1; 459 const(int*)[2][1] dest; 460 init(dest, src); 461 assert(dest == [[cast(int*) 1, cast(int*) 1]]); 462 } 463 { 464 static struct S 465 { int* p; } 466 467 S src = S(cast(int*) 1); 468 const S dest; 469 init(dest, src); 470 assert(cast(int) dest.p == 1); 471 } 472 } 473 474 475 /** 476 Constructs an object of type $(D T) in given chunk of uninitialized memory 477 just like $(D T t = arg;). 478 */ 479 void constructFrom(T, Arg)(ref T chunk, auto ref Arg arg) 480 { 481 static if(is(T == struct)) 482 { 483 static if(is(Unqual!T == Unqual!Arg)) 484 { 485 // Initializing struct with the same type 486 487 static if(isImplicitlyConvertible!(Arg, T)) 488 { 489 _initializeFromImplicitlyConvertible(chunk, arg); 490 } 491 else 492 { 493 static assert(0, "Can't implicitly convert expression of type " 494 ~ Arg.stringof ~ " to " ~ T.stringof); 495 } 496 } 497 else 498 { 499 constructFromLiteral(chunk, forward!arg); 500 } 501 } 502 else static if(__traits(compiles, { T t = arg; })) 503 { 504 _initializeFromImplicitlyConvertible(chunk, arg); 505 } 506 else 507 { 508 static assert(0, "`" ~ T.stringof ~ " t = " ~ Arg.stringof 509 ~ ";` doesn't compile."); 510 } 511 } 512 513 // Test copying from same struct branch 514 515 unittest 516 { 517 static struct S 518 { 519 int i = 1; 520 this(int _i) inout { i = _i; } 521 this(const S); 522 } 523 524 // Initializing struct with the same type doesn't call constructor. 525 S s = void; 526 constructFrom(s, S(2)); 527 assert(s.i == 2); 528 constructFrom(s, immutable S(3)); 529 assert(s.i == 3); 530 } 531 532 unittest 533 { 534 static struct S 535 { 536 int* p; 537 this(const S); 538 } 539 540 // Initializing struct with the same type requires implicit cast. 541 S s = void; 542 static assert(!__traits(compiles, constructFrom(s, immutable S()))); 543 } 544 545 // Test redirection to `constructFromLiteral` branch 546 547 pure nothrow unittest // constructors 548 { 549 static struct S 550 { 551 pure nothrow: 552 this(int n) { assert(n == 2); } 553 this(ref int n) { assert(n == 3); } 554 } 555 556 S s; 557 short sh = 2; 558 int i = 3; 559 560 constructFrom(s, 2); // calls this(int n) 561 constructFrom(s, sh); // calls this(int n) 562 constructFrom(s, i); // calls this(ref int n) 563 } 564 565 // Test non-struct branches 566 567 unittest 568 { 569 { 570 uint i = void; 571 572 constructFrom(i, 3); 573 assert(cast(int) i == 3); 574 575 constructFrom(i, 4U); 576 assert(cast(int) i == 4); 577 578 static assert(!__traits(compiles, constructFrom(i, 0L))); 579 static assert(!__traits(compiles, constructFrom(i, 0UL))); 580 } 581 582 { 583 void* p = void; 584 585 constructFrom(p, cast(void*) 3); 586 assert(cast(int) p == 3); 587 588 static assert(!__traits(compiles, constructFrom(p, 0))); 589 static assert(!__traits(compiles, constructFrom(p, 0, 0))); 590 static assert(!__traits(compiles, constructFrom(p, (const void*).init))); 591 static assert(!__traits(compiles, constructFrom(p, (shared void*).init))); 592 } 593 594 // shared 595 { 596 shared void* p; 597 constructFrom(p, cast(shared void*) 3); 598 assert(cast(int) p == 3); 599 600 static assert(!__traits(compiles, constructFrom(p, (const void*).init))); 601 static assert(!__traits(compiles, constructFrom(p, (void*).init))); 602 } 603 604 // const 605 { 606 foreach(T; TypeTuple!(immutable void, const void, void)) 607 { 608 void* p = void; 609 constructFrom(cast(const) p, cast(T*) 1); 610 assert(cast(int) p == 1); 611 } 612 613 void* p = void; 614 static assert(!__traits(compiles, constructFrom(cast(const) p, (shared void*).init))); 615 } 616 } 617 618 619 /* 620 Constructs an object of type $(D T) at given chunk of uninitialized memory 621 just like $(D T t = arg;). 622 623 The function is $(D @safe) iff copy construction is $(D @safe). 624 */ 625 package void _assumeSafeCopyConstructFrom(T, U)(ref T chunk, ref U from) 626 if(__traits(compiles, { T t = rvalueOf!U; }) && is(Unqual!T == Unqual!U)) 627 { 628 static if(is(T == struct) || is(T == union)) 629 { 630 () @trusted { rawCopy(from._unqual, chunk._unqual); } (); 631 callPostblits(chunk); 632 } 633 else static if(isAssignable!T) 634 { 635 chunk = from; 636 } 637 else 638 { 639 () @trusted { chunk._unqual = from; } (); 640 } 641 } 642 643 @safe pure nothrow @nogc unittest 644 { 645 static struct S { } 646 S s, s0; 647 _assumeSafeCopyConstructFrom(s, s0); 648 649 int i = 0, j = 1; 650 _assumeSafeCopyConstructFrom(i, j); 651 assert(i == 1); 652 j = 2; 653 (ref const a) { _assumeSafeCopyConstructFrom(a, j); } (i); 654 assert(i == 2); 655 } 656 657 658 /** 659 Constructs an object of $(D struct) type $(D S) in given chunk of uninitialized memory 660 just like $(D auto s = S(args);). 661 */ 662 void constructFromLiteral(S, Args...)(ref S chunk, auto ref Args args) 663 if(is(S == struct)) 664 { 665 static if(hasMember!(S, "__ctor")) 666 { 667 // `S` defines a constructor. 668 669 static assert(!isNested!S, "Can't initialize nested struct " 670 ~ S.stringof ~ " with context pointer using constructor."); 671 672 // Let's initialize `chunk` and call the constructor! 673 setToInitialState(chunk); 674 675 chunk.__ctor(forward!args); 676 } 677 else static if(hasMember!(S, "opCall")) 678 { 679 static assert(0, "Can't initialize struct " ~ S.stringof ~ " using `opCall`." ~ 680 " Use `constructFrom(chunk, " ~ S.stringof ~ "(...))` instead."); 681 } 682 else static if(__traits(compiles, { auto t = S(args); })) 683 { 684 // Struct without constructor that has one matching field for 685 // each argument (i.e. each field is initializable from the 686 // corresponding argument). 687 688 static assert(!anyTuple!(hasNested, FieldTypeTuple!S[Args.length .. $]), 689 "To initialize struct " ~ S.stringof ~ " using static initialization" ~ 690 " you must explicitly pass arguments for all fields with context pointers."); 691 692 // If struct fields doesn't have copy constructors 693 // and every field has corresponding argument, 694 // we still need to initialize the struct 695 // because of possible padding holes. 696 setToInitialState(chunk); 697 698 foreach(i, ref field; chunk.tupleof[0 .. Args.length]) 699 _initializeFromImplicitlyConvertible(field, args[i]); 700 } 701 else 702 { 703 static assert(0, "`auto t = "~ S.stringof 704 ~ "(" ~ Args.stringof ~ ");` doesn't compile."); 705 } 706 } 707 708 // Test constructor branch 709 710 unittest // copying from same struct 711 { 712 static struct S 713 { 714 int i = 1; 715 this(int _i) inout { i = _i; } 716 this(const S s) { i = 10 + s.i; } 717 } 718 719 // Call constructor even if copying from same struct. 720 S s = void; 721 constructFromLiteral(s, S(2)); 722 assert(s.i == 12); 723 constructFromLiteral(s, immutable S(3)); 724 assert(s.i == 13); 725 } 726 727 unittest // copying from same struct if implicit cast isn't allowed 728 { 729 static struct S 730 { 731 int i = 1; 732 void* p = cast(void*) 7; 733 this(const S) { i = 2; } 734 } 735 736 S s = void; 737 constructFromLiteral(s, immutable S()); 738 assert(s.i == 2); 739 } 740 741 unittest // context pointer 742 { 743 int i; 744 struct S { this(int) { ++i; } } 745 S s = void; 746 static assert(!__traits(compiles, constructFromLiteral(s, 0))); 747 748 static int si = 0; 749 static struct S3 { S s; this(int) { s = S.init; ++si; } } 750 S3 s3 = void; 751 constructFromLiteral(s3, 0); 752 assert(si == 1); 753 } 754 755 unittest // constructors 756 { 757 758 static void* p; 759 static int i = 2, j = 2; 760 static struct S 761 { 762 int[2] arr = 1; 763 this(int n1, int n2, ref int _i, out int _j) 764 { 765 assert(&this == p && arr == [1, 1]); 766 assert(n1 == 1 && n2 == 2); 767 assert(&_i == &i && &_j == &j); 768 assert(_i++ == 2 && _j++ == 0); 769 } 770 771 this(int n) 772 { assert(n == 2); } 773 774 this(ref int n) 775 { assert(n == 3); } 776 } 777 S s; p = &s; 778 short sh = 2; 779 constructFromLiteral(s, 1, sh, i, j); 780 assert(i == 3 && j == 1); 781 782 static assert(!__traits(compiles, constructFromLiteral(s, 1, 1, 0, j))); 783 static assert(!__traits(compiles, constructFromLiteral(s, 1, 1, i, 0))); 784 static assert(!__traits(compiles, constructFromLiteral(s, 1, 1, sh, j))); 785 static assert(!__traits(compiles, constructFromLiteral(s, 1, 1, i, sh))); 786 787 constructFromLiteral(s, 2); // calls this(int n) 788 constructFromLiteral(s, sh); // calls this(int n) 789 constructFromLiteral(s, i); // calls this(ref int n) 790 } 791 792 unittest // templated constructors 793 { 794 static void* p; 795 static int i = 0; 796 static struct S 797 { 798 int[2] arr = 1; 799 this(T)(auto ref T t) 800 { 801 assert(&this == p && arr == [1, 1]); 802 assert(i++ == __traits(isRef, t)); 803 } 804 } 805 S s; p = &s; 806 constructFromLiteral(s, 1); // calls this(int t) 807 assert(i == 1); 808 short sh = 1; 809 constructFromLiteral(s, sh); // calls this(ref int t) 810 assert(i == 2); 811 } 812 813 // Test opCall branch 814 815 unittest // opCall 816 { 817 int i; 818 struct S 819 { 820 int i; 821 static S opCall(int); 822 } 823 S s = void; 824 static assert(!__traits(compiles, constructFromLiteral(s, 0))); 825 } 826 827 // Test matching fields branch 828 829 unittest 830 { 831 struct S { int a, b; this(int) {} } 832 S s; 833 static assert(!__traits(compiles, constructFromLiteral(s, 0, 0))); 834 } 835 836 unittest // context pointer 837 { 838 int i; 839 struct S { this(int) { ++i; } } 840 S s = void; 841 842 static struct S2 { int i; S s; } 843 S2 s2 = void; 844 static assert(!__traits(compiles, constructFromLiteral(s2, 0))); 845 constructFromLiteral(s2, 0, S(0)); 846 assert(i == 1); 847 } 848 849 unittest // qualifiers 850 { 851 static struct S 852 { uint a = 1; void* b = null; } 853 854 { 855 S s; 856 857 constructFromLiteral(s, 2U); 858 assert(s.a == 2 && !s.b); 859 860 constructFromLiteral(s, 3); 861 assert(s.a == 3 && !s.b); 862 863 immutable int immutableI = 4; 864 constructFromLiteral(s, immutableI); 865 assert(s.a == 4 && !s.b); 866 867 constructFromLiteral(s, 0, cast(void*) 3); 868 assert(!s.a && cast(int) s.b == 3); 869 870 // Note: S(0L) compiles because compiler knows constan value. 871 static assert(!__traits(compiles, constructFromLiteral(s, 0L))); 872 static assert(!__traits(compiles, constructFromLiteral(s, 0, 0))); 873 static assert(!__traits(compiles, constructFromLiteral(s, 0, 0, 0))); 874 static assert(!__traits(compiles, constructFromLiteral(s, 0, (const void*).init))); 875 static assert(!__traits(compiles, constructFromLiteral(s, 0, (shared void*).init))); 876 } 877 878 // shared 879 { 880 shared S s; 881 constructFromLiteral(s, 0, cast(shared void*) 3); 882 assert(!s.a && cast(int) s.b == 3); 883 884 static assert(!__traits(compiles, constructFromLiteral(s, 0, (const void*).init))); 885 static assert(!__traits(compiles, constructFromLiteral(s, 0, (void*).init))); 886 } 887 888 // const 889 { 890 foreach(T; TypeTuple!(immutable void, const void, void)) 891 { 892 S s = void; 893 constructFromLiteral(*cast(const) &s, 0, cast(T*) 1); 894 assert(!s.a && cast(int) s.b == 1); 895 } 896 897 S s = void; 898 static assert(!__traits(compiles, constructFromLiteral(*cast(const) &s, 0, (shared void*).init))); 899 } 900 } 901 902 unittest // static array 903 { 904 static struct S 905 { int[2][1] sarr; } 906 907 { 908 S s = void; 909 constructFromLiteral(s, 2); 910 assert(s.sarr[0] == [2, 2]); 911 } 912 { 913 S s = void; 914 static assert(!__traits(compiles, constructFromLiteral(s, (int[1]).init))); 915 // Note: S([3, 4]) compiles without cast because compiler knows array literal value. 916 constructFromLiteral(s, cast(int[2]) [3, 4]); 917 assert(s.sarr[0] == [3, 4]); 918 } 919 } 920 921 922 /** 923 Constructs an object of $(D class) type $(D C) at given reference to uninitialized memory 924 just like $(D auto c = new C(args);) except given memory is used instead of allocating. 925 */ 926 void initializeClassInstance(C, Args...)(C chunk, auto ref Args args) 927 if(is(C == class)) 928 { 929 static assert(!isNested!C, "Can't initialize nested class " ~ C.stringof); 930 931 chunk.viewAs!(byte*)[0 .. __traits(classInstanceSize, C)] = typeid(Unqual!C).init[]; 932 933 static if(hasMember!(C, "__ctor")) 934 { 935 chunk.__ctor(forward!args); 936 } 937 else static if(Args.length) 938 { 939 static assert(0, "No constructor for class " ~ C.stringof); 940 } 941 else 942 { 943 static assert(!anyTuple!(hasNested, FieldTypeTuple!C), 944 "Can't initialize class " ~ C.stringof 945 ~ " without constructor but with nested fields."); 946 } 947 } 948 949 // Test context pointer check 950 951 unittest 952 { 953 int i; 954 { 955 class C { void f() { ++i; } } 956 C c; 957 static assert(!__traits(compiles, initializeClassInstance(c))); 958 } 959 960 { 961 struct S { void f() { ++i; } } 962 static int si = 0; 963 static class C2 { S s; this(int) { s = S.init; ++si; } } 964 965 void[__traits(classInstanceSize, C2)] buff = void; 966 auto c2 = cast(C2) buff.ptr; 967 initializeClassInstance(c2, 0); 968 assert(si == 1); 969 } 970 } 971 972 // Test constructor branch 973 974 unittest 975 { 976 static void* p; 977 static int i = 2, j = 2; 978 static class C 979 { 980 int[2] arr = 1; 981 this(int n1, int n2, ref int _i, out int _j) 982 { 983 assert(cast(void*) this == p && arr == [1, 1]); 984 assert(n1 == 1 && n2 == 2); 985 assert(&_i == &i && &_j == &j); 986 assert(_i++ == 2 && _j++ == 0); 987 } 988 989 this(int n) 990 { assert(n == 2); } 991 992 this(ref int n) 993 { assert(n == 3); } 994 } 995 996 void[__traits(classInstanceSize, C)] buff = void; 997 auto c = cast(C) (p = buff.ptr); 998 short sh = 2; 999 initializeClassInstance(c, 1, sh, i, j); 1000 assert(i == 3 && j == 1); 1001 1002 static assert(!__traits(compiles, initializeClassInstance(c, 1, 1, 0, j))); 1003 static assert(!__traits(compiles, initializeClassInstance(c, 1, 1, i, 0))); 1004 static assert(!__traits(compiles, initializeClassInstance(c, 1, 1, sh, j))); 1005 static assert(!__traits(compiles, initializeClassInstance(c, 1, 1, i, sh))); 1006 1007 initializeClassInstance(c, 2); // calls this(int n) 1008 initializeClassInstance(c, sh); // calls this(int n) 1009 initializeClassInstance(c, i); // calls this(ref int n) 1010 } 1011 1012 // Test no-constructor branches 1013 1014 unittest 1015 { 1016 static class C { int i = -1; } 1017 1018 void[__traits(classInstanceSize, C)] buff = void; 1019 auto c = cast(C) buff.ptr; 1020 initializeClassInstance(c); 1021 assert(c.i == -1); 1022 1023 static assert(!__traits(compiles, initializeClassInstance(c, 0))); 1024 } 1025 1026 unittest 1027 { 1028 int i; 1029 struct S 1030 { int i = -1; void f() { ++i; } } 1031 1032 static class C1 { S s; } 1033 C1 c1; 1034 static assert(!__traits(compiles, initializeClassInstance(c1))); 1035 1036 static class C2 1037 { S s; this() { s = S.init; } } 1038 void[__traits(classInstanceSize, C2)] buff2 = void; 1039 auto c2 = cast(C2) buff2.ptr; 1040 initializeClassInstance(c2); 1041 assert(c2.s.i == -1); 1042 } 1043 1044 1045 private extern (C) void rt_finalize2(void* p, bool det, bool resetMemory); 1046 1047 /** 1048 Destroys the given class instance and puts it in an invalid state. It's used 1049 to destroy an object so that any cleanup which its destructor or finalizer 1050 does is done. 1051 It does $(I not) initiate a GC cycle or free any GC memory. 1052 It $(I always) zero class instance $(D __vptr). 1053 If $(D resetMemory) is $(D true) it will also set class instance memory to 1054 its initial state so that it no longer references any other objects. 1055 */ 1056 void finalizeClassInstance(T)(T t, bool resetMemory = true) 1057 { 1058 static assert(is(T == class) || is(T == interface), "Can only finalize class or interface, not " ~ T.stringof); 1059 rt_finalize2(t.toRawPtr, true, resetMemory); 1060 } 1061 1062 unittest 1063 { 1064 interface I { } 1065 static bool destroyed = false; 1066 static class A: I 1067 { 1068 int n = -1; 1069 this() {} 1070 ~this() { destroyed = true; } 1071 } 1072 1073 auto a = new A, b = new A; 1074 a.n = b.n = 2; 1075 finalizeClassInstance(a); 1076 assert(destroyed); 1077 assert(a.n == -1); 1078 1079 destroyed = false; 1080 I i = b; 1081 finalizeClassInstance(i); 1082 assert(destroyed); 1083 assert(b.n == -1); 1084 } 1085 1086 /** 1087 Determines whether class instance $(D t) is finalized. 1088 1089 Also returns $(D true) if $(D t)'s memory is zero-filled. 1090 1091 $(D T) must be either $(D class) or $(D interface). 1092 */ 1093 bool isFinalized(T)(in T t) 1094 { 1095 static if(is(T == class)) 1096 { 1097 alias obj = t; 1098 } 1099 else static if(is(T == interface)) 1100 { 1101 const ppi = *t.viewAs!(const Interface***); 1102 if(!ppi) 1103 return true; 1104 auto obj = cast(Object) (t.viewAs!(void*) - (*ppi).offset); 1105 } 1106 else 1107 static assert(0, "Can only check class or interface to be finalized, not " ~ T.stringof); 1108 1109 return !obj.__vptr; 1110 } 1111 1112 /// ditto 1113 @property bool finalized(T)(in T t) 1114 { return isFinalized(t); } 1115 1116 unittest 1117 { 1118 interface I { } 1119 static class A: I 1120 { 1121 int n = -1; 1122 this() { n = 2; } 1123 } 1124 1125 { 1126 // Object reference 1127 1128 auto a1 = new A, a2 = new A; 1129 const ca1 = a1; 1130 assert(!a1.finalized && !isFinalized(a2)); 1131 assert(!ca1.finalized); 1132 finalizeClassInstance(a1); 1133 finalizeClassInstance(a2, false); 1134 assert(a1.finalized && isFinalized(a2)); 1135 assert(ca1.finalized); 1136 } 1137 1138 { 1139 // Interface reference 1140 1141 I ia1 = new A, ia2 = new A; 1142 const cia1 = ia1, cia2 = ia2; 1143 assert(!ia1.finalized && !isFinalized(ia2)); 1144 assert(!cia1.finalized); 1145 finalizeClassInstance(ia1); 1146 finalizeClassInstance(ia2, !false); 1147 assert(ia1.finalized && isFinalized(ia2)); 1148 assert(cia1.finalized); 1149 } 1150 1151 { 1152 // Zero-filled memory 1153 1154 const size_t buff = 0; 1155 assert((cast(const A) &buff).finalized); 1156 assert((cast(const I) &buff).finalized); 1157 } 1158 1159 { 1160 int i; 1161 assert(!__traits(compiles, i.finalized)); 1162 assert(!__traits(compiles, isFinalized(i))); 1163 struct S { } 1164 assert(!__traits(compiles, S().finalized)); 1165 } 1166 } 1167 1168 1169 /** 1170 Destructs $(D t) exactly the same way a compiler does in a case it goes out of scope. 1171 Also puts destructed object in its $(D init) state if $(D resetInitialState) 1172 is $(D true), otherwise object state will be undefined (i.e. possibly invalid). 1173 */ 1174 void destruct(T)(ref T t, bool resetInitialState = true) 1175 { 1176 callDestructors(t); 1177 if(resetInitialState) 1178 setToInitialState(t); 1179 } 1180 1181 unittest 1182 { 1183 int i = -1; 1184 destruct(i, false); 1185 assert(i == -1); 1186 destruct(i); 1187 assert(i == 0); 1188 1189 static assert(!__traits(compiles, destruct(5))); // doesn't accept rvalue 1190 } 1191 1192 unittest 1193 { 1194 static int n = 0; 1195 static struct S 1196 { 1197 int i = -1; 1198 ~this() { ++n; } 1199 } 1200 1201 auto s = S(1); 1202 destruct(s, false); 1203 assert(s.i == 1 && n == 1); 1204 destruct(s); 1205 assert(s.i == -1 && n == 2); 1206 } 1207 1208 1209 /** 1210 Sets the passed object to its `init` state. 1211 1212 Use this function instead of dealing with tricky $(D typeid(T).init()). 1213 */ 1214 void setToInitialState(T)(ref T t) 1215 { 1216 alias U = Unqual!T; 1217 1218 static if((!isAssignable!T || hasElaborateAssign!T) && (!isAssignable!U || hasElaborateAssign!U)) 1219 { 1220 import core.stdc..string; 1221 1222 // `typeid(T)` will also work but will cost a virtual call per each array 1223 // dimension. We will not be here for [static arrays of] classes so 1224 // there is no problems with `TypeInfo_Class.init` field name clash. 1225 if(const p = typeid(MultidimStaticArrayElementType!U).init().ptr) 1226 foreach(ref el; asFlatStaticArray(t._unqual)) 1227 memcpy(&el, p, typeof(el).sizeof); 1228 else 1229 memset(cast(void*) &t, 0, T.sizeof); 1230 } 1231 else static if(!isAssignable!T || hasElaborateAssign!T) 1232 { 1233 t._unqual = U.init; 1234 } 1235 else 1236 { 1237 t = T.init; 1238 } 1239 } 1240 1241 unittest 1242 { 1243 int i = -1; 1244 setToInitialState(i); 1245 assert(i == 0); 1246 1247 static assert(!__traits(compiles, setToInitialState(5))); // doesn't accept rvalue 1248 1249 static bool exited = false; 1250 1251 static struct S(int def) 1252 { 1253 int i = def; 1254 @disable this(); 1255 this(this) { assert(0); } 1256 ~this() { assert(exited); } 1257 } 1258 1259 S!0 s0 = void; s0.i = -1; 1260 setToInitialState(s0); 1261 assert(s0.i == 0); 1262 1263 S!1 s1 = void; s1.i = -1; 1264 setToInitialState(s1); 1265 assert(s1.i == 1); 1266 1267 S!1[2][1] sArr = void; 1268 foreach(ref el; sArr[0]) 1269 el.i = -1; 1270 setToInitialState(sArr); 1271 assert(sArr == (S!1[2][1]).init); 1272 1273 exited = true; 1274 } 1275 1276 unittest // const 1277 { 1278 static struct Int1 1279 { int i = 1; } 1280 1281 static struct S 1282 { const Int1 i; } 1283 1284 int i = 0; 1285 static assert(S.sizeof == i.sizeof); 1286 setToInitialState(i.viewAs!S); 1287 assert(i == 1); i = 0; 1288 1289 setToInitialState(i.viewAs!(const S)); 1290 assert(i == 1); i = 0; 1291 } 1292 1293 1294 /** 1295 Sets all elements of the passed dynamic array to its `init` state. 1296 1297 Use this function for better performance instead of calling 1298 $(MREF setToInitialState) on each element. 1299 */ 1300 void setElementsToInitialState(T)(T[] arr) 1301 { 1302 alias U = Unqual!T; 1303 1304 // This is just a copy of `setToInitialState` implementation. 1305 1306 static if((!isAssignable!T || hasElaborateAssign!T) && (!isAssignable!U || hasElaborateAssign!U)) 1307 { 1308 import core.stdc..string; 1309 1310 static if(is(U == void)) 1311 memset(cast(void*) arr.ptr, 0, arr.length); 1312 else if(const p = typeid(MultidimStaticArrayElementType!U).init().ptr) 1313 foreach(ref t; arr) 1314 foreach(ref el; asFlatStaticArray(t._unqual)) 1315 memcpy(&el, p, typeof(el).sizeof); 1316 else 1317 memset(cast(void*) arr.ptr, 0, T.sizeof * arr.length); 1318 } 1319 else static if(!isAssignable!T || hasElaborateAssign!T) 1320 { 1321 (cast(U[]) arr)[] = U.init; 1322 } 1323 else 1324 { 1325 arr[] = T.init; 1326 } 1327 } 1328 1329 unittest 1330 { 1331 int[] i = new int[3]; 1332 i[] = -1; 1333 setElementsToInitialState(i); 1334 assert(i == [0, 0, 0]); 1335 1336 static bool exited = false; 1337 1338 static struct S(int def) 1339 { 1340 int i = def; 1341 @disable this(); 1342 this(this) { assert(0); } 1343 ~this() { assert(exited); } 1344 } 1345 1346 auto s0 = [S!0.init, S!0.init]; s0[0].i = s0[1].i = -1; 1347 setElementsToInitialState(s0); 1348 assert(s0[0].i == 0 && s0[1].i == 0); 1349 1350 auto s1 = [S!1.init, S!1.init]; s1[0].i = s1[1].i = -1; 1351 setElementsToInitialState(s1); 1352 assert(s1[0].i == 1 && s1[1].i == 1); 1353 1354 auto sArr = [(S!1[2][1]).init]; 1355 foreach(ref el; sArr[0][0]) 1356 el.i = -1; 1357 setElementsToInitialState(sArr); 1358 assert(sArr[0] == (S!1[2][1]).init); 1359 1360 exited = true; 1361 1362 byte[2] bArr = -1; 1363 setElementsToInitialState(cast(const void[]) bArr); 1364 assert(bArr == [0, 0]); 1365 } 1366 1367 unittest // const 1368 { 1369 static struct Int1 1370 { int i = 1; } 1371 1372 static struct S 1373 { const Int1 i; } 1374 1375 int i = 0; 1376 static assert(S.sizeof == i.sizeof); 1377 setElementsToInitialState((cast(S*) &i)[0 .. 1]); 1378 assert(i == 1); i = 0; 1379 1380 setElementsToInitialState((cast(const S*) &i)[0 .. 1]); 1381 assert(i == 1); i = 0; 1382 } 1383 1384 1385 /** Calls the postblit of the given object, if any. 1386 1387 Faster and convenient replacement for $(D typeid(T).postblit(&t)). 1388 */ 1389 void callPostblits(T)(ref T t) 1390 { 1391 static if(hasElaborateCopyConstructor!T) 1392 { 1393 foreach(ref el; asFlatStaticArray(t)) 1394 { 1395 foreach(ref field; el.tupleof) 1396 static if(hasElaborateCopyConstructor!(typeof(field))) 1397 callPostblits(field); 1398 1399 static if(hasMember!(typeof(el), "__postblit")) 1400 el.__postblit(); 1401 } 1402 } 1403 } 1404 1405 unittest 1406 { 1407 int i = -1; 1408 callPostblits(i); // no-op for non-elaborate types 1409 1410 static assert(!__traits(compiles, callPostblits(5))); // doesn't accept rvalue 1411 1412 static int[] log; 1413 static void checkLog(int[] arr...) 1414 { assert(log == arr); log = null; } 1415 1416 static bool exited = false; 1417 1418 static struct S 1419 { 1420 int i; 1421 @disable this(); 1422 this(this) { log ~= i; } 1423 ~this() { assert(exited); } 1424 } 1425 1426 S s = void; s.i = -1; 1427 callPostblits(s); 1428 checkLog(-1); 1429 1430 S[3][2][1] sArr = void; 1431 foreach(uint j, ref el; sArr.viewAs!(S[6])) 1432 el.i = j; 1433 callPostblits(sArr); 1434 checkLog(0, 1, 2, 3, 4, 5); 1435 1436 static struct S2 1437 { 1438 S s; 1439 S[2] sArr; 1440 1441 @disable this(); 1442 this(this) { log ~= -1; } 1443 ~this() { assert(exited); } 1444 } 1445 1446 S2 s2 = void; 1447 foreach(uint j, ref el; s2.viewAs!(S[3])) 1448 el.i = j; 1449 callPostblits(s2); 1450 checkLog(0, 1, 2, -1); 1451 1452 exited = true; 1453 } 1454 1455 1456 /** Calls the destructor of the given object, if any. 1457 1458 Faster and convenient replacement for $(D typeid(T).destroy(&t)). 1459 */ 1460 void callDestructors(T)(ref T t) 1461 { 1462 static if(hasElaborateDestructor!T) 1463 { 1464 foreach_reverse(ref el; asFlatStaticArray(t)) 1465 { 1466 static if(hasMember!(typeof(el), "__dtor")) 1467 el.__dtor(); 1468 1469 foreach_reverse(ref field; el.tupleof) 1470 static if(hasElaborateDestructor!(typeof(field))) 1471 callDestructors(field); 1472 } 1473 } 1474 } 1475 1476 unittest 1477 { 1478 int i = -1; 1479 callDestructors(i); // no-op for non-elaborate types 1480 1481 static assert(!__traits(compiles, callDestructors(5))); // doesn't accept rvalue 1482 1483 static int[] log; 1484 static void checkLog(int[] arr...) 1485 { assert(log == arr); log = null; } 1486 1487 static bool exited = false; 1488 1489 static struct S 1490 { 1491 int i; 1492 @disable this(); 1493 this(this) { assert(exited); } 1494 ~this() { log ~= i; } 1495 } 1496 1497 S s = void; s.i = -1; 1498 callDestructors(s); 1499 checkLog(-1); 1500 1501 S[3][2][1] sArr = void; 1502 foreach(uint j, ref el; sArr.viewAs!(S[6])) 1503 el.i = j; 1504 callDestructors(sArr); 1505 checkLog(5, 4, 3, 2, 1, 0); 1506 1507 static struct S2 1508 { 1509 S s; 1510 S[2] sArr; 1511 1512 @disable this(); 1513 this(this) { assert(exited); } 1514 ~this() { log ~= -1; } 1515 } 1516 1517 S2 s2 = void; 1518 foreach(uint j, ref el; s2.viewAs!(S[3])) 1519 el.i = j; 1520 callDestructors(s2); 1521 checkLog(-1, 2, 1, 0); 1522 1523 exited = true; 1524 } 1525 1526 1527 // Utility function to unqualify a value. 1528 package @property ref _unqual(T)(ref T val) @system 1529 { 1530 return *cast(Unqual!T*) &val; 1531 } 1532 1533 @trusted unittest 1534 { 1535 static assert(!__traits(compiles, 1._unqual)); 1536 1537 int i = 0; 1538 (ref const a) { ++a._unqual; } (i); 1539 assert(i == 1); 1540 }