1 /** 2 Implementation of non aliasable reference counted pointer `RcPtr` (similar to c++ `std::shared_ptr` without aliasing). 3 4 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 5 Authors: Adam Búš 6 */ 7 module btl.autoptr.rc_ptr; 8 9 import btl.traits.common; 10 11 import btl.internal.allocator; 12 import btl.internal.traits; 13 import btl.internal.gc; 14 15 import btl.autoptr.common; 16 17 18 /** 19 Check if type `T` is `RcPtr`. 20 */ 21 public template isRcPtr(T){ 22 import std.traits : isInstanceOf; 23 24 enum bool isRcPtr = isInstanceOf!(RcPtr, T); 25 } 26 27 /// 28 unittest{ 29 static assert(!isRcPtr!long); 30 static assert(!isRcPtr!(void*)); 31 32 static assert(isRcPtr!(RcPtr!long)); 33 static assert(isRcPtr!(RcPtr!long.WeakType)); 34 } 35 36 37 38 /** 39 Implementation of a ref counted pointer without support for aliasing (smaller size of pointer). 40 41 `RcPtr` retains shared ownership of an object through a pointer. 42 43 Several ref counted pointer objects may own the same object. 44 45 The object is destroyed and its memory deallocated when either of the following happens: 46 47 1. the last remaining ref counted pointer owning the object is destroyed. 48 49 2. the last remaining ref counted pointer owning the object is assigned another pointer via various methods like `opAssign` and `store`. 50 51 The object is destroyed using destructor of type `_Type`. 52 53 A `RcPtr` can not share ownership of an object while storing a pointer to another object (use `SharedPtr` for that). 54 The stored pointer is the one accessed by `get()`, the dereference and the comparison operators. 55 56 A `RcPtr` may also own no objects, in which case it is called empty. 57 58 If template parameter `_ControlType` is `shared` then all member functions (including copy constructor and copy assignment) 59 can be called by multiple threads on different instances of `RcPtr` without additional synchronization even if these instances are copies and share ownership of the same object. 60 61 If multiple threads of execution access the same `RcPtr` (`shared RcPtr`) then only some methods can be called (`load`, `store`, `exchange`, `compareExchange`, `useCount`). 62 63 Template parameters: 64 65 `_Type` type of managed object 66 67 `_DestructorType` function pointer with attributes of destructor, to get attributes of destructor from type use `btl.autoptr.common.DestructorType!T`. Destructor of type `_Type` must be compatible with `_DestructorType` 68 69 `_ControlType` represent type of counter, must by of type `btl.autoptr.common.ControlBlock`. if is shared then ref counting is atomic. 70 71 `_weakPtr` if `true` then `RcPtr` represent weak ptr 72 73 */ 74 public template RcPtr( 75 _Type, 76 _DestructorType = DestructorType!_Type, 77 _ControlType = ControlBlockDeduction!(_Type, SharedControlBlock), 78 bool _weakPtr = false 79 ) 80 if(isControlBlock!_ControlType && isDestructorType!_DestructorType){ 81 82 static assert(_ControlType.hasSharedCounter || is(_ControlType == immutable), 83 "_ControlType must be `ControlBlock` with shared counter or `btl.autoptr.common.ControlBlock` must be immutable." 84 ); 85 86 static assert(!_weakPtr || _ControlType.hasWeakCounter, 87 "weak pointer must have control block with weak counter" 88 ); 89 90 static if (is(_Type == class) || is(_Type == interface) || is(_Type == struct) || is(_Type == union)) 91 static assert(!__traits(isNested, _Type), 92 "RcPtr does not support nested types." 93 ); 94 95 static assert(is(DestructorType!void : _DestructorType), 96 _Type.stringof ~ " wrong DestructorType " ~ DestructorType!void.stringof ~ 97 " : " ~ _DestructorType.stringof 98 ); 99 100 /* 101 static assert(is(DestructorType!_Type : _DestructorType), 102 "destructor of type '" ~ _Type.stringof ~ 103 "' doesn't support specified finalizer " ~ _DestructorType.stringof 104 ); 105 */ 106 107 void check_dtor()(){ 108 static assert(!isIntrusive!_Type); 109 110 static assert(is(DestructorType!_Type : _DestructorType), 111 "destructor of type '" ~ _Type.stringof ~ 112 "' doesn't support specified finalizer " ~ _DestructorType.stringof 113 ); 114 } 115 116 import std.meta : AliasSeq; 117 import std.range : ElementEncodingType; 118 import std.traits: Unqual, Unconst, CopyTypeQualifiers, CopyConstness, 119 hasIndirections, hasElaborateDestructor, 120 isMutable, isAbstractClass, isDynamicArray, isStaticArray, isCallable, Select, isArray; 121 122 import core.atomic : MemoryOrder; 123 import core.lifetime : forward; 124 125 126 enum bool hasWeakCounter = _ControlType.hasWeakCounter; 127 128 enum bool hasSharedCounter = _ControlType.hasSharedCounter; 129 130 enum bool referenceElementType = isClassOrInterface!_Type || isDynamicArray!_Type; 131 132 133 enum bool _isLockFree = !isDynamicArray!_Type; 134 135 struct RcPtr{ 136 137 /** 138 Type of element managed by `RcPtr`. 139 */ 140 public alias ElementType = _Type; 141 142 143 /** 144 Type of destructor (`void function(void*)@attributes`). 145 */ 146 public alias DestructorType = _DestructorType; 147 148 149 /** 150 Type of control block. 151 */ 152 public alias ControlType = _ControlType; 153 154 155 /** 156 `true` if `RcPtr` is weak ptr. 157 */ 158 public alias isWeak = _weakPtr; 159 160 161 /** 162 Same as `ElementType*` or `ElementType` if is class/interface/slice. 163 */ 164 public alias ElementReferenceType = ElementReferenceTypeImpl!ElementType; 165 166 167 /** 168 Weak pointer 169 170 `RcPtr.WeakType` is a smart pointer that holds a non-owning ("weak") reference to an object that is managed by `RcPtr`. 171 It must be converted to `RcPtr` in order to access the referenced object. 172 173 `RcPtr.WeakType` models temporary ownership: when an object needs to be accessed only if it exists, and it may be deleted at any time by someone else, 174 `RcPtr.WeakType` is used to track the object, and it is converted to `RcPtr` to assume temporary ownership. 175 If the original `RcPtr` is destroyed at this time, the object's lifetime is extended until the temporary `RcPtr` is destroyed as well. 176 177 Another use for `RcPtr.WeakType` is to break reference cycles formed by objects managed by `RcPtr`. 178 If such cycle is orphaned (i,e. there are no outside shared pointers into the cycle), the `RcPtr` reference counts cannot reach zero and the memory is leaked. 179 To prevent this, one of the pointers in the cycle can be made weak. 180 */ 181 static if(hasWeakCounter) 182 public alias WeakType = RcPtr!( 183 _Type, 184 _DestructorType, 185 _ControlType, 186 true 187 ); 188 else 189 public alias WeakType = void; 190 191 192 /** 193 Type of non weak ptr. 194 */ 195 public alias SharedType = RcPtr!( 196 _Type, 197 _DestructorType, 198 _ControlType, 199 false 200 ); 201 202 203 /** 204 `true` if shared `RcPtr` has lock free operations `store`, `load`, `exchange`, `compareExchange`, otherwise 'false' 205 */ 206 public alias isLockFree = _isLockFree; 207 208 static if(isLockFree) 209 static assert(ElementReferenceType.sizeof == size_t.sizeof); 210 211 212 213 /** 214 Destructor 215 216 If `this` owns an object and it is the last `RcPtr` owning it, the object is destroyed. 217 After the destruction, the smart pointers that shared ownership with `this`, if any, will report a `useCount()` that is one less than its previous value. 218 */ 219 public ~this(){ 220 this._release(); 221 } 222 223 224 //necesary for btl.autoptr.unique_ptr.sharedPtr 225 package this(Elm, this This)(Elm element, Forward)pure nothrow @safe @nogc 226 if(true 227 && is(Elm : GetElementReferenceType!This) 228 && !is(Unqual!Elm == typeof(null)) 229 ){ 230 this._element = element; 231 } 232 233 // 234 package this(C, Elm, this This)(C* control, Elm element)pure nothrow @safe @nogc 235 if(true 236 && is(Elm : GetElementReferenceType!This) 237 && is(C : GetControlType!This) 238 && !is(Unqual!Elm == typeof(null)) 239 ){ 240 assert(control !is null); 241 assert((control is null) == (element is null)); 242 243 this(element, Forward.init); 244 control.add!isWeak; 245 } 246 247 248 /** 249 Forward constructor (merge move and copy constructor). 250 */ 251 public this(Rhs, this This)(scope auto ref Rhs rhs, Forward)@trusted 252 if(isRcPtr!Rhs && !is(Rhs == shared)){ 253 //error: 254 static if(!isConstructable!(rhs, This)){ 255 this.construct_error(forward!rhs); 256 } 257 //lock (copy): 258 else static if(weakLock!(Rhs, This)){ 259 if(rhs._element !is null && rhs._control.add_shared_if_exists()) 260 this._element = rhs._element; 261 /+else 262 this._element = null;+/ 263 } 264 //copy 265 else static if(isRef!rhs){ 266 static assert(isCopyConstructable!(Rhs, This)); 267 268 if(rhs._element is null) 269 this(null); 270 else 271 this(rhs._control, rhs._element); 272 } 273 //move 274 else{ 275 static assert(isMoveConstructable!(Rhs, This)); 276 277 this._element = rhs._element; 278 279 static if(isWeak && !Rhs.isWeak){ 280 if(this._element !is null) 281 this._control.add!isWeak; 282 } 283 else{ 284 rhs._const_reset(); 285 } 286 } 287 } 288 289 // 290 private void construct_error(Rhs, this This)(scope auto ref Rhs rhs) 291 if(isRcPtr!Rhs && !isConstructable!(rhs, This)){ 292 static if(isRef!rhs){ 293 import std.traits : isMutable; 294 295 static assert(isMutable!Rhs, 296 "rhs must be mutable." 297 ); 298 static assert(isMutable!(Rhs.ControlType), 299 "control type of rhs must be mutable." 300 ); 301 } 302 303 static assert(is(GetElementReferenceType!Rhs : GetElementReferenceType!This), 304 "element type '" ~ GetElementReferenceType!Rhs.stringof ~ "' is not compatible with '" ~ GetElementReferenceType!This.stringof ~ "'." 305 ); 306 static assert(is(Rhs.DestructorType : This.DestructorType), 307 "destructor attributes '" ~ Rhs.DestructorType.stringof ~ "' are not compatible with '" ~ This.DestructorType.stringof ~ "'." 308 ); 309 static assert(is(GetControlType!Rhs* : GetControlType!This*), 310 "control type " ~ GetControlType!Rhs.stringof ~ " is not compatible with '" ~ GetControlType!This.stringof ~ "'." 311 ); 312 313 static assert(0, "RcPtr canno't be constructed from rhs of type " ~ Rhs.stringof); 314 } 315 316 317 /** 318 Constructs a `RcPtr` without managed object. Same as `RcPtr.init` 319 320 Examples: 321 -------------------- 322 RcPtr!long x = null; 323 324 assert(x == null); 325 assert(x == RcPtr!long.init); 326 -------------------- 327 */ 328 public this(this This)(typeof(null) nil, Forward = Forward.init)pure nothrow @safe @nogc{ 329 } 330 331 332 333 /** 334 Constructs a `RcPtr` which shares ownership of the object managed by `rhs`. 335 336 If rhs manages no object, this manages no object too. 337 If rhs if rvalue then ownership is moved. 338 The template overload doesn't participate in overload resolution if ElementType of `typeof(rhs)` is not implicitly convertible to `ElementType`. 339 If rhs if `WeakType` then this ctor is equivalent to `this(rhs.lock())`. 340 341 Examples: 342 -------------------- 343 { 344 RcPtr!long x = RcPtr!long.make(123); 345 assert(x.useCount == 1); 346 347 RcPtr!long a = x; //lvalue copy ctor 348 assert(a == x); 349 350 const RcPtr!long b = x; //lvalue copy ctor 351 assert(b == x); 352 353 RcPtr!(const long) c = x; //lvalue ctor 354 assert(c == x); 355 356 const RcPtr!long d = b; //lvalue ctor 357 assert(d == x); 358 359 assert(x.useCount == 5); 360 } 361 362 { 363 import core.lifetime : move; 364 RcPtr!long x = RcPtr!long.make(123); 365 assert(x.useCount == 1); 366 367 RcPtr!long a = move(x); //rvalue copy ctor 368 assert(a.useCount == 1); 369 370 const RcPtr!long b = move(a); //rvalue copy ctor 371 assert(b.useCount == 1); 372 373 RcPtr!(const long) c = b.load; //rvalue ctor 374 assert(c.useCount == 2); 375 376 const RcPtr!long d = move(c); //rvalue ctor 377 assert(d.useCount == 2); 378 } 379 380 { 381 import core.lifetime : move; 382 auto u = UniquePtr!(long, SharedControlBlock).make(123); 383 384 RcPtr!long s = move(u); //rvalue copy ctor 385 assert(s != null); 386 assert(s.useCount == 1); 387 388 RcPtr!long s2 = UniquePtr!(long, SharedControlBlock).init; 389 assert(s2 == null); 390 } 391 -------------------- 392 */ 393 public this(Rhs, this This)(scope auto ref Rhs rhs)@trusted 394 if(isRcPtr!Rhs && !is(Rhs == shared) && !isMoveCtor!(This, rhs)){ 395 //static assert(isConstructable!(rhs, This)); 396 this(forward!rhs, Forward.init); 397 } 398 399 400 401 //copy ctors: 402 static if(isCopyConstructable!(typeof(this), typeof(this))) 403 this(ref scope typeof(this) rhs)@safe{this(rhs, Forward.init);} 404 else 405 @disable this(ref scope typeof(this) rhs)@safe; 406 407 static if(isCopyConstructable!(typeof(this), const typeof(this))) 408 this(ref scope typeof(this) rhs)const @safe{this(rhs, Forward.init);} 409 else 410 @disable this(ref scope typeof(this) rhs)const @safe; 411 412 static if(isCopyConstructable!(typeof(this), immutable typeof(this))) 413 this(ref scope typeof(this) rhs)immutable @safe{this(rhs, Forward.init);} 414 else 415 @disable this(ref scope typeof(this) rhs)immutable @safe; 416 417 static if(isCopyConstructable!(typeof(this), shared typeof(this))) 418 this(ref scope typeof(this) rhs)shared @safe{this(rhs, Forward.init);} 419 else 420 @disable this(ref scope typeof(this) rhs)shared @safe; 421 422 static if(isCopyConstructable!(typeof(this), const shared typeof(this))) 423 this(ref scope typeof(this) rhs)const shared @safe{this(rhs, Forward.init);} 424 else 425 @disable this(ref scope typeof(this) rhs)const shared @safe; 426 427 428 /+ 429 //Not neccesary: 430 static foreach(alias From; AliasSeq!( 431 const typeof(this), 432 immutable typeof(this), 433 shared typeof(this), 434 const shared typeof(this) 435 )){ 436 @disable this(ref scope From rhs)@safe; 437 @disable this(ref scope From rhs)const @safe; 438 @disable this(ref scope From rhs)immutable @safe; 439 @disable this(ref scope From rhs)shared @safe; 440 @disable this(ref scope From rhs)const shared @safe; 441 //@disable this(ref scope From rhs)pure nothrow @safe @nogc; 442 } 443 +/ 444 445 446 447 /** 448 Releases the ownership of the managed object, if any. 449 450 After the call, this manages no object. 451 452 Examples: 453 -------------------- 454 { 455 RcPtr!long x = RcPtr!long.make(1); 456 457 assert(x.useCount == 1); 458 x = null; 459 assert(x.useCount == 0); 460 assert(x == null); 461 } 462 463 { 464 RcPtr!(shared long) x = RcPtr!(shared long).make(1); 465 466 assert(x.useCount == 1); 467 x = null; 468 assert(x.useCount == 0); 469 assert(x == null); 470 } 471 472 { 473 shared RcPtr!(long) x = RcPtr!(shared long).make(1); 474 475 assert(x.useCount == 1); 476 x = null; 477 assert(x.useCount == 0); 478 assert(x == null); 479 } 480 -------------------- 481 */ 482 public void opAssign(MemoryOrder order = MemoryOrder.seq, this This)(typeof(null) nil)scope 483 if(isMutable!This){ 484 static if(is(This == shared)){ 485 static if(isLockFree){ 486 import core.atomic : atomicExchange; 487 488 ()@trusted{ 489 UnqualSmartPtr!This tmp; 490 tmp._set_element(cast(typeof(this._element))atomicExchange!order( 491 cast(Unqual!(This.ElementReferenceType)*)&this._element, 492 null 493 )); 494 }(); 495 } 496 else{ 497 return this.lockSmartPtr!( 498 (ref scope self) => self.opAssign!order(null) 499 )(); 500 } 501 } 502 else{ 503 this._release(); 504 ()@trusted{ 505 this._reset(); 506 }(); 507 } 508 } 509 510 /** 511 Shares ownership of the object managed by `rhs`. 512 513 If `rhs` manages no object, `this` manages no object too. 514 If `rhs` is rvalue then move-assigns a `RcPtr` from `rhs` 515 516 Examples: 517 -------------------- 518 { 519 RcPtr!long px1 = RcPtr!long.make(1); 520 RcPtr!long px2 = RcPtr!long.make(2); 521 522 assert(px2.useCount == 1); 523 px1 = px2; 524 assert(*px1 == 2); 525 assert(px2.useCount == 2); 526 } 527 528 529 { 530 RcPtr!long px = RcPtr!long.make(1); 531 RcPtr!(const long) pcx = RcPtr!long.make(2); 532 533 assert(px.useCount == 1); 534 pcx = px; 535 assert(*pcx == 1); 536 assert(pcx.useCount == 2); 537 538 } 539 540 541 { 542 const RcPtr!long cpx = RcPtr!long.make(1); 543 RcPtr!(const long) pcx = RcPtr!long.make(2); 544 545 assert(pcx.useCount == 1); 546 pcx = cpx; 547 assert(*pcx == 1); 548 assert(pcx.useCount == 2); 549 550 } 551 552 { 553 RcPtr!(immutable long) pix = RcPtr!(immutable long).make(123); 554 RcPtr!(const long) pcx = RcPtr!long.make(2); 555 556 assert(pix.useCount == 1); 557 pcx = pix; 558 assert(*pcx == 123); 559 assert(pcx.useCount == 2); 560 561 } 562 -------------------- 563 */ 564 public void opAssign(MemoryOrder order = MemoryOrder.seq, Rhs, this This)(scope auto ref Rhs desired)scope 565 if(isRcPtr!Rhs && !is(Rhs == shared)){ 566 //error 567 static if(!isAssignable!(desired, This)){ 568 this.assign_error(forward!desired); 569 } 570 // shared assign: 571 else static if(is(This == shared)){ 572 static if(isLockFree){ 573 import core.atomic : atomicExchange; 574 575 static if(isRef!desired && (This.isWeak == Rhs.isWeak)){ 576 if((()@trusted => cast(const void*)&desired is cast(const void*)&this)()) 577 return; 578 } 579 580 ()@trusted{ 581 UnqualSmartPtr!This tmp_desired = forward!desired; 582 //desired._control.add!(This.isWeak); 583 584 UnqualSmartPtr!This tmp; 585 GetElementReferenceType!This source = tmp_desired._element; //interface/class cast 586 587 tmp._set_element(cast(typeof(this._element))atomicExchange!order( 588 cast(Unqual!(This.ElementReferenceType)*)&this._element, 589 cast(Unqual!(This.ElementReferenceType))source 590 )); 591 592 tmp_desired._const_reset(); 593 }(); 594 } 595 else{ 596 this.lockSmartPtr!( 597 (ref scope self, scope auto ref Rhs x) => self.opAssign!order(forward!x) 598 )(forward!desired); 599 } 600 } 601 // copy assign or non identity move assign: 602 else static if(isRef!desired || !is(This == Rhs)){ 603 604 static if(isRef!desired && (This.isWeak == Rhs.isWeak)){ 605 if((()@trusted => cast(const void*)&desired is cast(const void*)&this)()) 606 return; 607 } 608 609 this._release(); 610 611 auto tmp = This(forward!desired); 612 613 ()@trusted{ 614 this._set_element(tmp._element); 615 tmp._const_reset(); 616 }(); 617 } 618 //identity move assign: //separate case for core.lifetime.move 619 else{ 620 static assert(isMoveAssignable!(Rhs, This)); 621 static assert(!isRef!desired); 622 623 this._release(); 624 625 ()@trusted{ 626 this._set_element(desired._element); 627 desired._const_reset(); 628 }(); 629 630 } 631 } 632 633 // 634 private void assign_error(Rhs, this This)(scope auto ref Rhs desired) 635 if(isRcPtr!Rhs && !isAssignable!(desired, This)){ 636 import std.traits : isMutable; 637 638 static assert(!weakLock!(Rhs, This), 639 "weak error" 640 ); 641 static assert(isMutable!This, "assign must have mutable this"); 642 643 644 this.construct_error(forward!desired); 645 } 646 647 648 649 /** 650 Constructs an object of type `ElementType` and wraps it in a `RcPtr` using args as the parameter list for the constructor of `ElementType`. 651 652 The object is constructed as if by the expression `emplace!ElementType(_payload, forward!args)`, where _payload is an internal pointer to storage suitable to hold an object of type `ElementType`. 653 The storage is typically larger than `ElementType.sizeof` in order to use one allocation for both the control block and the `ElementType` object. 654 655 Examples: 656 -------------------- 657 { 658 RcPtr!long a = RcPtr!long.make(); 659 assert(a.get == 0); 660 661 RcPtr!(const long) b = RcPtr!long.make(2); 662 assert(b.get == 2); 663 } 664 665 { 666 static struct Struct{ 667 int i = 7; 668 669 this(int i)pure nothrow @safe @nogc{ 670 this.i = i; 671 } 672 } 673 674 RcPtr!Struct s1 = RcPtr!Struct.make(); 675 assert(s1.get.i == 7); 676 677 RcPtr!Struct s2 = RcPtr!Struct.make(123); 678 assert(s2.get.i == 123); 679 } 680 681 { 682 static interface Interface{ 683 } 684 static class Class : Interface{ 685 int i; 686 687 this(int i)pure nothrow @safe @nogc{ 688 this.i = i; 689 } 690 } 691 692 RcPtr!Interface x = RcPtr!Class.make(3); 693 //assert(x.dynTo!Class.get.i == 3); 694 } 695 -------------------- 696 */ 697 public static auto make(AllocatorType = DefaultAllocator, bool supportGC = platformSupportGC, Args...)(auto ref Args args) 698 if(!isDynamicArray!ElementType){ 699 check_dtor(); 700 701 alias ReturnType = RcPtr!( 702 ElementType, 703 .DestructorType!( 704 .DestructorType!ElementType, 705 DestructorType, 706 DestructorAllocatorType!AllocatorType 707 ), 708 ControlType 709 ); 710 711 auto m = ReturnType.MakeEmplace!(AllocatorType, supportGC).make(AllocatorType.init, forward!(args)); 712 713 return (m is null) 714 ? ReturnType.init 715 : ReturnType(m.get, Forward.init); 716 } 717 718 719 /** 720 Constructs an object of array type `ElementType` including its array elements and wraps it in a `RcPtr`. 721 722 Parameters: 723 n = Array length 724 725 args = parameters for constructor for each array element. 726 727 The array elements are constructed as if by the expression `emplace!ElementType(_payload, args)`, where _payload is an internal pointer to storage suitable to hold an object of type `ElementType`. 728 The storage is typically larger than `ElementType.sizeof * n` in order to use one allocation for both the control block and the each array element. 729 730 Examples: 731 -------------------- 732 auto arr = RcPtr!(long[]).make(6, -1); 733 assert(arr.length == 6); 734 assert(arr.get.length == 6); 735 736 import std.algorithm : all; 737 assert(arr.get.all!(x => x == -1)); 738 739 for(int i = 0; i < 6; ++i) 740 arr.get[i] = i; 741 742 assert(arr.get == [0, 1, 2, 3, 4, 5]); 743 -------------------- 744 */ 745 public static auto make(AllocatorType = DefaultAllocator, bool supportGC = platformSupportGC, Args...)(const size_t n, auto ref Args args) 746 if(isDynamicArray!ElementType){ 747 check_dtor(); 748 749 alias ReturnType = RcPtr!( 750 ElementType, 751 .DestructorType!( 752 .DestructorType!ElementType, 753 DestructorType, 754 DestructorAllocatorType!AllocatorType 755 ), 756 ControlType 757 ); 758 759 auto m = ReturnType.MakeDynamicArray!(AllocatorType, supportGC).make(AllocatorType.init, n, forward!(args)); 760 761 return (m is null) 762 ? ReturnType.init 763 : ReturnType(m.get, Forward.init); 764 } 765 766 767 768 /** 769 Constructs an object of type `ElementType` and wraps it in a `RcPtr` using args as the parameter list for the constructor of `ElementType`. 770 771 The object is constructed as if by the expression `emplace!ElementType(_payload, forward!args)`, where _payload is an internal pointer to storage suitable to hold an object of type `ElementType`. 772 The storage is typically larger than `ElementType.sizeof` in order to use one allocation for both the control block and the `ElementType` object. 773 774 Examples: 775 -------------------- 776 auto a = allocatorObject(Mallocator.instance); 777 { 778 auto a = RcPtr!long.alloc(a); 779 assert(a.get == 0); 780 781 auto b = RcPtr!(const long).alloc(a, 2); 782 assert(b.get == 2); 783 } 784 785 { 786 static struct Struct{ 787 int i = 7; 788 789 this(int i)pure nothrow @safe @nogc{ 790 this.i = i; 791 } 792 } 793 794 auto s1 = RcPtr!Struct.alloc(a); 795 assert(s1.get.i == 7); 796 797 auto s2 = RcPtr!Struct.alloc(a, 123); 798 assert(s2.get.i == 123); 799 } 800 801 { 802 static interface Interface{ 803 } 804 static class Class : Interface{ 805 int i; 806 807 this(int i)pure nothrow @safe @nogc{ 808 this.i = i; 809 } 810 } 811 812 RcPtr!Interface x = RcPtr!Class.alloc(a, 3); 813 //assert(x.dynTo!Class.get.i == 3); 814 } 815 -------------------- 816 */ 817 public static auto alloc(bool supportGC = platformSupportGC, AllocatorType, Args...)(AllocatorType a, auto ref Args args) 818 if(!isDynamicArray!ElementType){ 819 check_dtor(); 820 821 alias ReturnType = RcPtr!( 822 ElementType, 823 .DestructorType!( 824 .DestructorType!ElementType, 825 DestructorType, 826 DestructorAllocatorType!AllocatorType 827 ), 828 ControlType 829 ); 830 auto m = ReturnType.MakeEmplace!(AllocatorType, supportGC).make(forward!(a, args)); 831 832 return (m is null) 833 ? ReturnType.init 834 : ReturnType(m.get, Forward.init); 835 } 836 837 838 839 /** 840 Constructs an object of array type `ElementType` including its array elements and wraps it in a `RcPtr`. 841 842 Parameters: 843 n = Array length 844 845 args = parameters for constructor for each array element. 846 847 The array elements are constructed as if by the expression `emplace!ElementType(_payload, args)`, where _payload is an internal pointer to storage suitable to hold an object of type `ElementType`. 848 The storage is typically larger than `ElementType.sizeof * n` in order to use one allocation for both the control block and the each array element. 849 850 Examples: 851 -------------------- 852 auto a = allocatorObject(Mallocator.instance); 853 auto arr = RcPtr!(long[], DestructorType!(typeof(a))).alloc(a, 6, -1); 854 assert(arr.length == 6); 855 assert(arr.get.length == 6); 856 857 import std.algorithm : all; 858 assert(arr.get.all!(x => x == -1)); 859 860 for(int i = 0; i < 6; ++i) 861 arr.get[i] = i; 862 863 assert(arr.get == [0, 1, 2, 3, 4, 5]); 864 -------------------- 865 */ 866 public static auto alloc(bool supportGC = platformSupportGC, AllocatorType, Args...)(AllocatorType a, const size_t n, auto ref Args args) 867 if(isDynamicArray!ElementType){ 868 check_dtor(); 869 870 alias ReturnType = RcPtr!( 871 ElementType, 872 .DestructorType!( 873 .DestructorType!ElementType, 874 DestructorType, 875 DestructorAllocatorType!AllocatorType 876 ), 877 ControlType 878 ); 879 880 auto m = ReturnType.MakeDynamicArray!(AllocatorType, supportGC).make(forward!(a, n, args)); 881 882 return (m is null) 883 ? ReturnType.init 884 : ReturnType(m.get, Forward.init); 885 } 886 887 888 889 /** 890 Returns the number of different `RcPtr` instances 891 892 Returns the number of different `RcPtr` instances (`this` included) managing the current object or `0` if there is no managed object. 893 894 Examples: 895 -------------------- 896 RcPtr!long x = null; 897 898 assert(x.useCount == 0); 899 900 x = RcPtr!long.make(123); 901 assert(x.useCount == 1); 902 903 auto y = x; 904 assert(x.useCount == 2); 905 906 auto w1 = x.weak; //weak ptr 907 assert(x.useCount == 2); 908 909 RcPtr!long.WeakType w2 = x; //weak ptr 910 assert(x.useCount == 2); 911 912 y = null; 913 assert(x.useCount == 1); 914 915 x = null; 916 assert(x.useCount == 0); 917 assert(w1.useCount == 0); 918 -------------------- 919 */ 920 public @property ControlType.Shared useCount(this This)()const scope nothrow @trusted @nogc{ 921 922 static if(is(ControlType.Shared == void)) 923 return; 924 925 else static if(is(This == shared)) 926 return this.lockSmartPtr!( 927 (ref scope self) => self.useCount() 928 )(); 929 930 else 931 return (this._element is null) 932 ? 0 933 : this._control.count!false + 1; 934 935 936 } 937 938 939 /** 940 Returns the number of different `RcPtr.WeakType` instances 941 942 Returns the number of different `RcPtr.WeakType` instances (`this` included) managing the current object or `0` if there is no managed object. 943 944 Examples: 945 -------------------- 946 RcPtr!long x = null; 947 assert(x.useCount == 0); 948 assert(x.weakCount == 0); 949 950 x = RcPtr!long.make(123); 951 assert(x.useCount == 1); 952 assert(x.weakCount == 0); 953 954 auto w = x.weak(); 955 assert(x.useCount == 1); 956 assert(x.weakCount == 1); 957 -------------------- 958 */ 959 public @property ControlType.Weak weakCount(this This)()const scope nothrow @safe @nogc{ 960 961 static if(is(ControlType.Weak == void)) 962 return; 963 964 else static if(is(This == shared)) 965 return this.lockSharedPtr!( 966 (ref scope self) => self.weakCount() 967 )(); 968 969 else 970 return (this._element is null) 971 ? 0 972 : this._control.count!true; 973 974 975 } 976 977 978 979 /** 980 Swap `this` with `rhs` 981 982 Examples: 983 -------------------- 984 { 985 RcPtr!long a = RcPtr!long.make(1); 986 RcPtr!long b = RcPtr!long.make(2); 987 a.proxySwap(b); 988 assert(*a == 2); 989 assert(*b == 1); 990 import std.algorithm : swap; 991 swap(a, b); 992 assert(*a == 1); 993 assert(*b == 2); 994 assert(a.useCount == 1); 995 assert(b.useCount == 1); 996 } 997 -------------------- 998 */ 999 public void proxySwap(ref scope typeof(this) rhs)scope @trusted pure nothrow @nogc{ 1000 auto element = this._element; 1001 this._set_element(rhs._element); 1002 rhs._set_element(element); 1003 } 1004 1005 1006 1007 /** 1008 Returns the non `shared` `RcPtr` pointer pointed-to by `shared` `this`. 1009 1010 Examples: 1011 -------------------- 1012 shared RcPtr!(long) x = RcPtr!(shared long).make(123); 1013 1014 { 1015 RcPtr!(shared long) y = x.load(); 1016 assert(y.useCount == 2); 1017 1018 assert(y.get == 123); 1019 } 1020 -------------------- 1021 */ 1022 public UnqualSmartPtr!This load(MemoryOrder order = MemoryOrder.seq, this This)()scope{ 1023 1024 static if(is(This == shared)) 1025 return this.lockSmartPtr!( 1026 (ref scope self) => self.load!order() 1027 )(); 1028 1029 else 1030 return typeof(return)(this); 1031 1032 } 1033 1034 1035 1036 /** 1037 Stores the non `shared` `RcPtr` parameter `ptr` to `this`. 1038 1039 If `this` is shared then operation is atomic or guarded by mutex. 1040 1041 Template parameter `order` has type `core.atomic.MemoryOrder`. 1042 1043 Examples: 1044 -------------------- 1045 //null store: 1046 { 1047 shared x = RcPtr!(shared long).make(123); 1048 assert(x.load.get == 123); 1049 1050 x.store(null); 1051 assert(x.useCount == 0); 1052 assert(x.load == null); 1053 } 1054 1055 //rvalue store: 1056 { 1057 shared x = RcPtr!(shared long).make(123); 1058 assert(x.load.get == 123); 1059 1060 x.store(RcPtr!(shared long).make(42)); 1061 assert(x.load.get == 42); 1062 } 1063 1064 //lvalue store: 1065 { 1066 shared x = RcPtr!(shared long).make(123); 1067 auto y = RcPtr!(shared long).make(42); 1068 1069 assert(x.load.get == 123); 1070 assert(y.load.get == 42); 1071 1072 x.store(y); 1073 assert(x.load.get == 42); 1074 assert(x.useCount == 2); 1075 } 1076 -------------------- 1077 */ 1078 public alias store = opAssign; 1079 1080 1081 1082 /** 1083 Stores the non `shared` `RcPtr` pointer ptr in the `shared(RcPtr)` pointed to by `this` and returns the value formerly pointed-to by this, atomically or with mutex. 1084 1085 Examples: 1086 -------------------- 1087 //lvalue exchange 1088 { 1089 shared x = RcPtr!(shared long).make(123); 1090 auto y = RcPtr!(shared long).make(42); 1091 1092 auto z = x.exchange(y); 1093 1094 assert(x.load.get == 42); 1095 assert(y.get == 42); 1096 assert(z.get == 123); 1097 } 1098 1099 //rvalue exchange 1100 { 1101 shared x = RcPtr!(shared long).make(123); 1102 auto y = RcPtr!(shared long).make(42); 1103 1104 import core.lifetime : move; 1105 auto z = x.exchange(move(y)); 1106 1107 assert(x.load.get == 42); 1108 assert(y == null); 1109 assert(z.get == 123); 1110 } 1111 1112 //null exchange (same as move) 1113 { 1114 shared x = RcPtr!(shared long).make(123); 1115 1116 auto z = x.exchange(null); 1117 1118 assert(x.load == null); 1119 assert(z.get == 123); 1120 } 1121 1122 //swap: 1123 { 1124 shared x = RcPtr!(shared long).make(123); 1125 auto y = RcPtr!(shared long).make(42); 1126 1127 import core.lifetime : move; 1128 //opAssign is same as store 1129 y = x.exchange(move(y)); 1130 1131 assert(x.load.get == 42); 1132 assert(y.get == 123); 1133 } 1134 -------------------- 1135 */ 1136 public RcPtr exchange(MemoryOrder order = MemoryOrder.seq, this This)(typeof(null))scope 1137 if(isMutable!This){ 1138 1139 static if(is(This == shared)){ 1140 static if(isLockFree){ 1141 import core.atomic : atomicExchange; 1142 1143 return()@trusted{ 1144 UnqualSmartPtr!This result; 1145 result._set_element(cast(typeof(this._element))atomicExchange!order( 1146 cast(Unqual!(This.ElementReferenceType)*)&this._element, 1147 null 1148 )); 1149 1150 return result._move; 1151 }(); 1152 } 1153 else{ 1154 return this.lockSmartPtr!( 1155 (ref scope self) => self.exchange!order(null) 1156 )(); 1157 } 1158 } 1159 else{ 1160 return this._move; 1161 } 1162 } 1163 1164 /// ditto 1165 public RcPtr exchange(MemoryOrder order = MemoryOrder.seq, Rhs, this This)(scope Rhs rhs)scope 1166 if( isRcPtr!Rhs 1167 && isMoveAssignable!(Rhs, This) 1168 && !is(Rhs == shared) 1169 ){ 1170 static if(is(This == shared)){ 1171 1172 static if(isLockFree){ 1173 import core.atomic : atomicExchange; 1174 1175 return()@trusted{ 1176 UnqualSmartPtr!This result; 1177 GetElementReferenceType!This source = rhs._element; //interface/class cast 1178 1179 result._set_element(cast(typeof(this._element))atomicExchange!order( 1180 cast(Unqual!(This.ElementReferenceType)*)&this._element, 1181 cast(Unqual!(This.ElementReferenceType))source 1182 )); 1183 rhs._const_reset(); 1184 1185 return result._move; 1186 }(); 1187 } 1188 else{ 1189 return this.lockSmartPtr!( 1190 (ref scope self, Rhs x) => self.exchange!order(x._move) 1191 )(rhs._move); 1192 } 1193 } 1194 else{ 1195 auto result = this._move; 1196 1197 return()@trusted{ 1198 this = rhs._move; 1199 return result._move; 1200 }(); 1201 } 1202 } 1203 1204 1205 /** 1206 Compares the `RcPtr` pointers pointed-to by `this` and `expected`. 1207 1208 If they are equivalent (store the same pointer value, and either share ownership of the same object or are both empty), assigns `desired` into `this` using the memory ordering constraints specified by `success` and returns `true`. 1209 If they are not equivalent, assigns `this` into `expected` using the memory ordering constraints specified by `failure` and returns `false`. 1210 1211 More info in c++ std::atomic<std::shared_ptr>. 1212 1213 1214 Examples: 1215 -------------------- 1216 static foreach(enum bool weak; [true, false]){ 1217 //fail 1218 { 1219 RcPtr!long a = RcPtr!long.make(123); 1220 RcPtr!long b = RcPtr!long.make(42); 1221 RcPtr!long c = RcPtr!long.make(666); 1222 1223 static if(weak)a.compareExchangeWeak(b, c); 1224 else a.compareExchangeStrong(b, c); 1225 1226 assert(*a == 123); 1227 assert(*b == 123); 1228 assert(*c == 666); 1229 1230 } 1231 1232 //success 1233 { 1234 RcPtr!long a = RcPtr!long.make(123); 1235 RcPtr!long b = a; 1236 RcPtr!long c = RcPtr!long.make(666); 1237 1238 static if(weak)a.compareExchangeWeak(b, c); 1239 else a.compareExchangeStrong(b, c); 1240 1241 assert(*a == 666); 1242 assert(*b == 123); 1243 assert(*c == 666); 1244 } 1245 1246 //shared fail 1247 { 1248 shared RcPtr!(shared long) a = RcPtr!(shared long).make(123); 1249 RcPtr!(shared long) b = RcPtr!(shared long).make(42); 1250 RcPtr!(shared long) c = RcPtr!(shared long).make(666); 1251 1252 static if(weak)a.compareExchangeWeak(b, c); 1253 else a.compareExchangeStrong(b, c); 1254 1255 auto tmp = a.exchange(null); 1256 assert(*tmp == 123); 1257 assert(*b == 123); 1258 assert(*c == 666); 1259 } 1260 1261 //shared success 1262 { 1263 RcPtr!(shared long) b = RcPtr!(shared long).make(123); 1264 shared RcPtr!(shared long) a = b; 1265 RcPtr!(shared long) c = RcPtr!(shared long).make(666); 1266 1267 static if(weak)a.compareExchangeWeak(b, c); 1268 else a.compareExchangeStrong(b, c); 1269 1270 auto tmp = a.exchange(null); 1271 assert(*tmp == 666); 1272 assert(*b == 123); 1273 assert(*c == 666); 1274 } 1275 } 1276 -------------------- 1277 */ 1278 public bool compareExchangeStrong 1279 (MemoryOrder success = MemoryOrder.seq, MemoryOrder failure = success, E, D, this This) 1280 (ref scope E expected, scope D desired)scope 1281 if( isRcPtr!E && !is(E == shared) 1282 && isRcPtr!D && !is(D == shared) 1283 && isMoveAssignable!(D, This) 1284 && isCopyAssignable!(This, E) 1285 && (This.isWeak == D.isWeak) 1286 && (This.isWeak == E.isWeak) 1287 ){ 1288 return this.compareExchangeImpl!(false, success, failure)(expected, desired._move); 1289 } 1290 1291 1292 1293 /** 1294 Same as `compareExchangeStrong` but may fail spuriously. 1295 1296 More info in c++ `std::atomic<std::shared_ptr>`. 1297 */ 1298 public bool compareExchangeWeak 1299 (MemoryOrder success = MemoryOrder.seq, MemoryOrder failure = success, E, D, this This) 1300 (ref scope E expected, scope D desired)scope 1301 if( isRcPtr!E && !is(E == shared) 1302 && isRcPtr!D && !is(D == shared) 1303 && isMoveAssignable!(D, This) 1304 && isCopyAssignable!(This, E) 1305 && (This.isWeak == D.isWeak) 1306 && (This.isWeak == E.isWeak) 1307 ){ 1308 return this.compareExchangeImpl!(true, success, failure)(expected, desired._move); 1309 } 1310 1311 1312 private bool compareExchangeImpl 1313 (bool weak, MemoryOrder success, MemoryOrder failure, E, D, this This) 1314 (ref scope E expected, scope D desired)scope @trusted 1315 if( isRcPtr!E && !is(E == shared) 1316 && isRcPtr!D && !is(D == shared) 1317 && isMoveAssignable!(D, This) 1318 && isCopyAssignable!(This, E) 1319 && (This.isWeak == D.isWeak) 1320 && (This.isWeak == E.isWeak) 1321 ){ 1322 static if(is(This == shared)){ 1323 static if(isLockFree){ 1324 import core.atomic : cas, casWeak; 1325 static if(weak) 1326 alias casImpl = casWeak; 1327 else 1328 alias casImpl = cas; 1329 1330 1331 return ()@trusted{ 1332 GetElementReferenceType!This source_desired = desired._element; //interface/class cast 1333 GetElementReferenceType!This source_expected = expected._element; //interface/class cast 1334 1335 const bool store_occurred = casImpl!(success, failure)( 1336 cast(Unqual!(This.ElementReferenceType)*)&this._element, 1337 cast(Unqual!(This.ElementReferenceType)*)&source_expected, 1338 cast(Unqual!(This.ElementReferenceType))source_desired 1339 ); 1340 1341 if(store_occurred){ 1342 desired._const_reset(); 1343 if(expected._element !is null) 1344 expected._control.release!(This.isWeak); 1345 } 1346 else{ 1347 expected = null; 1348 expected._set_element(source_expected); 1349 } 1350 1351 return store_occurred; 1352 }(); 1353 } 1354 else{ 1355 static assert(!isLockFree); 1356 shared mutex = getMutex(this); 1357 1358 mutex.lock(); 1359 1360 alias Self = UnqualSmartPtr!This; 1361 1362 static assert(!is(Self == shared)); 1363 1364 Self* self = cast(Self*)&this; 1365 1366 if(*self == expected){ 1367 auto tmp = self._move; //destructor is called after mutex.unlock(); 1368 *self = desired._move; 1369 1370 mutex.unlock(); 1371 return true; 1372 } 1373 1374 auto tmp = expected._move; //destructor is called after mutex.unlock(); 1375 expected = *self; 1376 1377 mutex.unlock(); 1378 return false; 1379 } 1380 } 1381 else{ 1382 if(this == expected){ 1383 this = desired._move; 1384 return true; 1385 } 1386 expected = this; 1387 1388 return false; 1389 } 1390 } 1391 1392 1393 1394 /** 1395 Creates a new non weak `RcPtr` that shares ownership of the managed object (must be `RcPtr.WeakType`). 1396 1397 If there is no managed object, i.e. this is empty or this is `expired`, then the returned `RcPtr` is empty. 1398 Method exists only if `RcPtr` is `isWeak` 1399 1400 Examples: 1401 -------------------- 1402 { 1403 RcPtr!long x = RcPtr!long.make(123); 1404 1405 auto w = x.weak; //weak ptr 1406 1407 RcPtr!long y = w.lock; 1408 1409 assert(x == y); 1410 assert(x.useCount == 2); 1411 assert(y.get == 123); 1412 } 1413 1414 { 1415 RcPtr!long x = RcPtr!long.make(123); 1416 1417 auto w = x.weak; //weak ptr 1418 1419 assert(w.expired == false); 1420 1421 x = RcPtr!long.make(321); 1422 1423 assert(w.expired == true); 1424 1425 RcPtr!long y = w.lock; 1426 1427 assert(y == null); 1428 } 1429 -------------------- 1430 */ 1431 public SharedType lock()()scope 1432 if(isCopyConstructable!(typeof(this), SharedType)){ 1433 return typeof(return)(this); 1434 } 1435 1436 1437 1438 /** 1439 Equivalent to `useCount() == 0` (must be `RcPtr.WeakType`). 1440 1441 Method exists only if `RcPtr` is `isWeak` 1442 1443 Examples: 1444 -------------------- 1445 { 1446 RcPtr!long x = RcPtr!long.make(123); 1447 1448 auto wx = x.weak; //weak pointer 1449 1450 assert(wx.expired == false); 1451 1452 x = null; 1453 1454 assert(wx.expired == true); 1455 } 1456 -------------------- 1457 */ 1458 public @property bool expired(this This)()scope const nothrow @safe @nogc{ 1459 return (this.useCount == 0); 1460 } 1461 1462 1463 1464 static if(!isWeak){ 1465 /** 1466 Operator *, same as method 'get'. 1467 1468 Examples: 1469 -------------------- 1470 RcPtr!long x = RcPtr!long.make(123); 1471 assert(*x == 123); 1472 (*x = 321); 1473 assert(*x == 321); 1474 const y = x; 1475 assert(*y == 321); 1476 assert(*x == 321); 1477 static assert(is(typeof(*y) == const long)); 1478 -------------------- 1479 */ 1480 public template opUnary(string op : "*") 1481 if(op == "*"){ //doc 1482 alias opUnary = get; 1483 } 1484 1485 1486 1487 /** 1488 Get reference to managed object of `ElementType` or value if `ElementType` is reference type (class or interface) or dynamic array. 1489 1490 Examples: 1491 -------------------- 1492 RcPtr!long x = RcPtr!long.make(123); 1493 assert(x.get == 123); 1494 x.get = 321; 1495 assert(x.get == 321); 1496 const y = x; 1497 assert(y.get == 321); 1498 assert(x.get == 321); 1499 static assert(is(typeof(y.get) == const long)); 1500 -------------------- 1501 */ 1502 static if(referenceElementType){ 1503 public @property inout(ElementType) get()inout return pure nothrow @safe @nogc{ 1504 return this._element; 1505 } 1506 } 1507 else static if(is(Unqual!ElementType == void)){ 1508 /// ditto 1509 public @property inout(ElementType) get()inout scope pure nothrow @safe @nogc{ 1510 } 1511 } 1512 else{ 1513 /// ditto 1514 public @property ref inout(ElementType) get()inout return pure nothrow @system @nogc{ 1515 return *cast(inout(ElementType)*)this._element; 1516 } 1517 } 1518 1519 } 1520 1521 1522 1523 /** 1524 Get pointer to managed object of `ElementType` or reference if `ElementType` is reference type (class or interface) or dynamic array. 1525 1526 If `this` is weak expired pointer then return null. 1527 1528 Doesn't increment useCount, is inherently unsafe. 1529 1530 Examples: 1531 -------------------- 1532 { 1533 RcPtr!long x = RcPtr!long.make(123); 1534 assert(*x.element == 123); 1535 1536 x.get = 321; 1537 assert(*x.element == 321); 1538 1539 const y = x; 1540 assert(*y.element == 321); 1541 assert(*x.element == 321); 1542 1543 static assert(is(typeof(y.element) == const(long)*)); 1544 } 1545 1546 { 1547 auto x = RcPtr!(long[]).make(6, 42); 1548 assert(x.element[0] == 42); 1549 static assert(is(typeof(x.element) == long[])); 1550 } 1551 1552 { 1553 auto s = RcPtr!long.make(42); 1554 const w = s.weak; 1555 1556 assert(*w.element == 42); 1557 1558 s = null; 1559 assert(w.element is null); 1560 } 1561 1562 { 1563 auto s = RcPtr!long.make(42); 1564 auto w = s.weak; 1565 1566 scope const p = w.element; 1567 1568 s = null; 1569 assert(w.element is null); 1570 1571 assert(p !is null); //p is dangling pointer! 1572 } 1573 -------------------- 1574 */ 1575 public @property ElementReferenceTypeImpl!(GetElementType!This) element(this This)()return pure nothrow @system @nogc 1576 if(!is(This == shared)){ 1577 static if(isWeak) 1578 return (cast(const)this).expired 1579 ? null 1580 : this._element; 1581 else 1582 return this._element; 1583 } 1584 1585 1586 1587 /** 1588 Get pointer to managed object of `ElementType` or reference if `ElementType` is reference type (class or interface) or pointer to first dynamic array element. 1589 1590 If `this` is weak expired pointer then return null. 1591 1592 Doesn't increment useCount, is inherently unsafe. 1593 1594 Examples: 1595 -------------------- 1596 { 1597 RcPtr!long x = RcPtr!long.make(123); 1598 assert(*x.ptr == 123); 1599 1600 x.get = 321; 1601 assert(*x.ptr == 321); 1602 1603 const y = x; 1604 assert(*y.ptr == 321); 1605 assert(*x.ptr == 321); 1606 1607 static assert(is(typeof(y.ptr) == const(long)*)); 1608 } 1609 1610 { 1611 auto x = RcPtr!(long[]).make(6, 42); 1612 assert(*x.ptr == 42); 1613 static assert(is(typeof(x.ptr) == long*)); 1614 } 1615 1616 { 1617 auto s = RcPtr!long.make(42); 1618 const w = s.weak; 1619 1620 assert(*w.ptr == 42); 1621 1622 s = null; 1623 assert(w.ptr is null); 1624 } 1625 1626 { 1627 auto s = RcPtr!long.make(42); 1628 auto w = s.weak; 1629 1630 scope const p = w.ptr; 1631 1632 s = null; 1633 assert(w.ptr is null); 1634 1635 assert(p !is null); //p is dangling pointer! 1636 } 1637 -------------------- 1638 */ 1639 public @property ElementPointerTypeImpl!(GetElementType!This) ptr(this This)()return pure nothrow @system @nogc 1640 if(!is(This == shared)){ 1641 auto get_ptr(){ 1642 static if(isDynamicArray!ElementType) 1643 return this._element.ptr; 1644 else 1645 return this._element; 1646 } 1647 1648 1649 1650 static if(isWeak) 1651 return (cast(const)this).expired 1652 ? null 1653 : get_ptr(); 1654 else 1655 return get_ptr(); 1656 } 1657 1658 1659 1660 /** 1661 Returns length of dynamic array (isDynamicArray!ElementType == true). 1662 1663 Examples: 1664 -------------------- 1665 auto x = RcPtr!(int[]).make(10, -1); 1666 assert(x.length == 10); 1667 assert(x.get.length == 10); 1668 1669 import std.algorithm : all; 1670 assert(x.get.all!(i => i == -1)); 1671 -------------------- 1672 */ 1673 static if(isDynamicArray!ElementType) 1674 public @property size_t length()const scope pure nothrow @safe @nogc{ 1675 return this._element.length; 1676 } 1677 1678 1679 /** 1680 Returns weak pointer (must have weak counter). 1681 1682 Examples: 1683 -------------------- 1684 RcPtr!long x = RcPtr!long.make(123); 1685 assert(x.useCount == 1); 1686 1687 auto wx = x.weak; //weak pointer 1688 assert(wx.expired == false); 1689 assert(wx.lock.get == 123); 1690 assert(wx.useCount == 1); 1691 1692 x = null; 1693 assert(wx.expired == true); 1694 assert(wx.useCount == 0); 1695 -------------------- 1696 */ 1697 public WeakType weak()()scope 1698 if(isCopyConstructable!(typeof(this), WeakType)){ 1699 static if(hasWeakCounter){ 1700 return typeof(return)(this); 1701 } 1702 } 1703 1704 1705 1706 /** 1707 Checks if `this` stores a non-null pointer, i.e. whether `this != null`. 1708 1709 Examples: 1710 -------------------- 1711 RcPtr!long x = RcPtr!long.make(123); 1712 assert(cast(bool)x); //explicit cast 1713 assert(x); //implicit cast 1714 x = null; 1715 assert(!cast(bool)x); //explicit cast 1716 assert(!x); //implicit cast 1717 -------------------- 1718 */ 1719 public bool opCast(To : bool)()const scope pure nothrow @safe @nogc 1720 if(is(To : bool)){ //docs 1721 return (this != null); 1722 } 1723 1724 1725 1726 /** 1727 Support for quelifier cast. 1728 */ 1729 public ref To opCast(To, this This)()return scope pure nothrow @nogc 1730 if(is(immutable To : immutable typeof(this))){ 1731 static if(is(This : To)){ 1732 return *(()@trusted => cast(To*)&this )(); 1733 } 1734 else{ 1735 return *(()@system => cast(To*)&this )(); 1736 } 1737 } 1738 1739 1740 1741 /** 1742 Cast `this` to different type `To` when `isRcPtr!To`. 1743 1744 BUG: qualfied variable of struct with dtor cannot be inside other struct (generated dtor will use opCast to mutable before dtor call ). opCast is renamed to opCastImpl 1745 1746 Examples: 1747 -------------------- 1748 RcPtr!long x = RcPtr!long.make(123); 1749 auto y = cast(RcPtr!(const long))x; 1750 auto z = cast(const RcPtr!long)x; 1751 auto u = cast(const RcPtr!(const long))x; 1752 assert(x.useCount == 4); 1753 -------------------- 1754 */ 1755 public To opCastImpl(To, this This)()scope 1756 if(isRcPtr!To && !is(This == shared)){ 1757 return To(this); 1758 } 1759 1760 1761 /** 1762 Operator == and != . 1763 Compare pointers. 1764 1765 Examples: 1766 -------------------- 1767 { 1768 RcPtr!long x = RcPtr!long.make(0); 1769 assert(x != null); 1770 x = null; 1771 assert(x == null); 1772 } 1773 1774 { 1775 RcPtr!long x = RcPtr!long.make(123); 1776 RcPtr!long y = RcPtr!long.make(123); 1777 assert(x == x); 1778 assert(y == y); 1779 assert(x != y); 1780 } 1781 1782 { 1783 RcPtr!long x; 1784 RcPtr!(const long) y; 1785 assert(x == x); 1786 assert(y == y); 1787 assert(x == y); 1788 } 1789 1790 { 1791 RcPtr!long x = RcPtr!long.make(123); 1792 RcPtr!long y = RcPtr!long.make(123); 1793 assert(x == x.element); 1794 assert(y.element == y); 1795 assert(x != y.element); 1796 } 1797 -------------------- 1798 */ 1799 public bool opEquals(typeof(null) nil)const @safe scope pure nothrow @nogc{ 1800 static if(isDynamicArray!ElementType) 1801 return (this._element.length == 0); 1802 else 1803 return (this._element is null); 1804 } 1805 1806 /// ditto 1807 public bool opEquals(Rhs)(scope auto ref const Rhs rhs)const @safe scope pure nothrow @nogc 1808 if(isRcPtr!Rhs && !is(Rhs == shared)){ 1809 return this.opEquals(rhs._element); 1810 } 1811 1812 /// ditto 1813 public bool opEquals(Elm)(scope const Elm elm)const @safe scope pure nothrow @nogc 1814 if(is(Elm : GetElementReferenceType!(typeof(this)))){ 1815 static if(isDynamicArray!ElementType){ 1816 static assert(isDynamicArray!Elm); 1817 1818 if(this._element.length != elm.length) 1819 return false; 1820 1821 if(this._element.ptr is elm.ptr) 1822 return true; 1823 1824 return (this._element.length == 0); 1825 } 1826 else{ 1827 return (this._element is elm); 1828 } 1829 } 1830 1831 1832 1833 /** 1834 Operators <, <=, >, >= for `RcPtr`. 1835 1836 Compare address of payload. 1837 1838 Examples: 1839 -------------------- 1840 { 1841 const a = RcPtr!long.make(42); 1842 const b = RcPtr!long.make(123); 1843 const n = RcPtr!long.init; 1844 1845 assert(a <= a); 1846 assert(a >= a); 1847 1848 assert((a < b) == !(a >= b)); 1849 assert((a > b) == !(a <= b)); 1850 1851 assert(a > n); 1852 assert(a > null); 1853 1854 assert(n < a); 1855 assert(null < a); 1856 } 1857 1858 { 1859 const a = RcPtr!long.make(42); 1860 const b = RcPtr!long.make(123); 1861 1862 assert(a <= a.element); 1863 assert(a.element >= a); 1864 1865 assert((a < b.element) == !(a.element >= b)); 1866 assert((a > b.element) == !(a.element <= b)); 1867 } 1868 -------------------- 1869 */ 1870 public sizediff_t opCmp(typeof(null) nil)const @trusted scope pure nothrow @nogc{ 1871 static if(isDynamicArray!ElementType){ 1872 return this._element.length; 1873 } 1874 else{ 1875 return (cast(const void*)this._element) - (cast(const void*)null); 1876 } 1877 1878 } 1879 1880 /// ditto 1881 public sizediff_t opCmp(Elm)(scope const Elm elm)const @trusted scope pure nothrow @nogc 1882 if(is(Elm : GetElementReferenceType!(typeof(this)))){ 1883 static if(isDynamicArray!ElementType){ 1884 const void* lhs = cast(const void*)(this._element.ptr + this._element.length); 1885 const void* rhs = cast(const void*)(elm.ptr + elm.length); 1886 1887 return lhs - rhs; 1888 } 1889 else{ 1890 return (cast(const void*)this._element) - (cast(const void*)elm); 1891 } 1892 } 1893 1894 /// ditto 1895 public sizediff_t opCmp(Rhs)(scope auto ref const Rhs rhs)const @trusted scope pure nothrow @nogc 1896 if(isRcPtr!Rhs && !is(Rhs == shared)){ 1897 return this.opCmp(rhs._element); 1898 } 1899 1900 1901 1902 /** 1903 Generate hash 1904 1905 Return: 1906 Address of payload as `size_t` 1907 1908 Examples: 1909 -------------------- 1910 { 1911 RcPtr!long x = RcPtr!long.make(123); 1912 RcPtr!long y = RcPtr!long.make(123); 1913 assert(x.toHash == x.toHash); 1914 assert(y.toHash == y.toHash); 1915 assert(x.toHash != y.toHash); 1916 RcPtr!(const long) z = x; 1917 assert(x.toHash == z.toHash); 1918 } 1919 { 1920 RcPtr!long x; 1921 RcPtr!(const long) y; 1922 assert(x.toHash == x.toHash); 1923 assert(y.toHash == y.toHash); 1924 assert(x.toHash == y.toHash); 1925 } 1926 -------------------- 1927 */ 1928 public @property size_t toHash()@trusted scope const pure nothrow @nogc { 1929 static if(isDynamicArray!ElementType) 1930 return cast(size_t)cast(void*)(this._element.ptr + this._element.length); 1931 else 1932 return cast(size_t)cast(void*)this._element; 1933 } 1934 1935 1936 1937 package ElementReferenceType _element; 1938 1939 private void _release()scope{ 1940 if(false){ 1941 DestructorType dt; 1942 dt(null); 1943 } 1944 1945 if(this._element !is null) 1946 this._control.release!isWeak; 1947 } 1948 1949 package GetControlType!This* _control(this This)()pure nothrow @trusted @nogc 1950 in(this._element !is null){ 1951 static if(isDynamicArray!ElementType){ 1952 return cast(typeof(return))((cast(void*)this._element.ptr) - ControlType.sizeof); 1953 } 1954 else static if(is(ElementType == interface)){ 1955 static assert(__traits(getLinkage, ElementType) == "D"); 1956 return cast(typeof(return))((cast(void*)cast(Object)cast(Unqual!ElementType)this._element) - ControlType.sizeof); 1957 } 1958 else{ 1959 return cast(typeof(return))((cast(void*)this._element) - ControlType.sizeof); 1960 } 1961 } 1962 1963 private void _reset()scope pure nothrow @system @nogc{ 1964 this._set_element(null); 1965 } 1966 1967 package void _const_reset()scope const pure nothrow @system @nogc{ 1968 auto self = cast(Unqual!(typeof(this))*)&this; 1969 1970 self._reset(); 1971 } 1972 1973 private void _set_element(ElementReferenceType e)pure nothrow @system @nogc{ 1974 (*cast(Unqual!ElementReferenceType*)&this._element) = cast(Unqual!ElementReferenceType)e; 1975 } 1976 1977 private void _const_set_element(ElementReferenceType e)const pure nothrow @system @nogc{ 1978 auto self = cast(Unqual!(typeof(this))*)&this; 1979 1980 static if(isMutable!ElementReferenceType) 1981 self._element = e; 1982 else 1983 (*cast(Unqual!ElementReferenceType*)&self._element) = cast(Unqual!ElementReferenceType)e; 1984 } 1985 1986 package auto _move()@trusted{ 1987 auto e = this._element; 1988 this._const_reset(); 1989 1990 return typeof(this)(e, Forward.init); 1991 } 1992 1993 private alias MakeEmplace(AllocatorType, bool supportGC) = .MakeEmplace!( 1994 _Type, 1995 _DestructorType, 1996 _ControlType, 1997 AllocatorType, 1998 supportGC 1999 ); 2000 2001 private alias MakeDynamicArray(AllocatorType, bool supportGC) = .MakeDynamicArray!( 2002 _Type, 2003 _DestructorType, 2004 _ControlType, 2005 AllocatorType, 2006 supportGC 2007 ); 2008 2009 package alias SmartPtr = .SmartPtr; 2010 2011 /**/ 2012 package alias ChangeElementType(T) = RcPtr!( 2013 CopyTypeQualifiers!(ElementType, T), 2014 DestructorType, 2015 ControlType, 2016 isWeak 2017 ); 2018 } 2019 2020 } 2021 2022 2023 2024 /// Alias to `RcPtr` with different order of template parameters 2025 public template RcPtr( 2026 _Type, 2027 _ControlType, 2028 _DestructorType = DestructorType!_Type 2029 ) 2030 if(isControlBlock!_ControlType && isDestructorType!_DestructorType){ 2031 alias RcPtr = .RcPtr!(_Type, _DestructorType, _ControlType, false); 2032 } 2033 2034 /// 2035 unittest{ 2036 static class Foo{ 2037 int i; 2038 2039 this(int i)pure nothrow @safe @nogc{ 2040 this.i = i; 2041 } 2042 } 2043 2044 static class Bar : Foo{ 2045 double d; 2046 2047 this(int i, double d)pure nothrow @safe @nogc{ 2048 super(i); 2049 this.d = d; 2050 } 2051 } 2052 2053 static class Zee : Bar{ 2054 bool b; 2055 2056 this(int i, double d, bool b)pure nothrow @safe @nogc{ 2057 super(i, d); 2058 this.b = b; 2059 } 2060 2061 ~this()nothrow @system{ 2062 } 2063 } 2064 2065 ///simple: 2066 { 2067 RcPtr!long a = RcPtr!long.make(42); 2068 assert(a.useCount == 1); 2069 2070 RcPtr!(const long) b = a; 2071 assert(a.useCount == 2); 2072 2073 RcPtr!long.WeakType w = a.weak; //or WeakRcPtr!long 2074 assert(a.useCount == 2); 2075 assert(a.weakCount == 1); 2076 2077 RcPtr!long c = w.lock; 2078 assert(a.useCount == 3); 2079 assert(a.weakCount == 1); 2080 2081 assert(*c == 42); 2082 assert(c.get == 42); 2083 } 2084 2085 ///polymorphism and aliasing: 2086 { 2087 ///create RcPtr 2088 RcPtr!Foo foo = RcPtr!Bar.make(42, 3.14); 2089 RcPtr!Zee zee = RcPtr!Zee.make(42, 3.14, false); 2090 2091 ///dynamic cast: 2092 RcPtr!Bar bar = dynCast!Bar(foo); 2093 assert(bar != null); 2094 assert(foo.useCount == 2); 2095 2096 ///this doesnt work because Foo destructor attributes are more restrictive then Zee's: 2097 //RcPtr!Foo x = zee; 2098 2099 ///this does work: 2100 RcPtr!(Foo, DestructorType!(Foo, Zee)) x = zee; 2101 assert(zee.useCount == 2); 2102 } 2103 2104 2105 ///multi threading: 2106 { 2107 ///create RcPtr with atomic ref counting 2108 RcPtr!(shared Foo) foo = RcPtr!(shared Bar).make(42, 3.14); 2109 2110 ///this doesnt work: 2111 //foo.get.i += 1; 2112 2113 import core.atomic : atomicFetchAdd; 2114 atomicFetchAdd(foo.get.i, 1); 2115 assert(foo.get.i == 43); 2116 2117 2118 ///creating `shared(RcPtr)`: 2119 shared RcPtr!(shared Bar) bar = share(dynCast!Bar(foo)); 2120 2121 ///`shared(RcPtr)` is lock free (except `load` and `useCount`/`weakCount`). 2122 static assert(typeof(bar).isLockFree == true); 2123 2124 ///multi thread operations (`load`, `store`, `exchange` and `compareExchange`): 2125 RcPtr!(shared Bar) bar2 = bar.load(); 2126 assert(bar2 != null); 2127 assert(bar2.useCount == 3); 2128 2129 RcPtr!(shared Bar) bar3 = bar.exchange(null); 2130 assert(bar3 != null); 2131 assert(bar3.useCount == 3); 2132 } 2133 2134 ///dynamic array: 2135 { 2136 import std.algorithm : all, equal; 2137 2138 RcPtr!(long[]) a = RcPtr!(long[]).make(10, -1); 2139 assert(a.length == 10); 2140 assert(a.get.length == 10); 2141 assert(a.get.all!(x => x == -1)); 2142 2143 for(int i = 0; i < a.length; ++i){ 2144 a.get[i] = i; 2145 } 2146 assert(a.get[] == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); 2147 } 2148 } 2149 2150 //old: 2151 pure nothrow @nogc unittest{ 2152 2153 static class Foo{ 2154 int i; 2155 2156 this(int i)pure nothrow @safe @nogc{ 2157 this.i = i; 2158 } 2159 } 2160 2161 static class Bar : Foo{ 2162 double d; 2163 2164 this(int i, double d)pure nothrow @safe @nogc{ 2165 super(i); 2166 this.d = d; 2167 } 2168 } 2169 2170 //implicit qualifier cast 2171 { 2172 RcPtr!(const Foo) foo = RcPtr!Foo.make(42); 2173 assert(foo.get.i == 42); 2174 assert(foo.useCount == 1); 2175 2176 const RcPtr!Foo foo2 = foo; 2177 assert(foo2.get.i == 42); 2178 assert(foo.useCount == 2); 2179 2180 } 2181 2182 //polymorphic classes: 2183 { 2184 RcPtr!Foo foo = RcPtr!Bar.make(42, 3.14); 2185 assert(foo != null); 2186 assert(foo.useCount == 1); 2187 assert(foo.get.i == 42); 2188 2189 //dynamic cast: 2190 { 2191 RcPtr!Bar bar = dynCast!Bar(foo); 2192 assert(foo.useCount == 2); 2193 2194 assert(bar.get.i == 42); 2195 assert(bar.get.d == 3.14); 2196 } 2197 2198 } 2199 2200 //weak references: 2201 { 2202 2203 auto x = RcPtr!double.make(3.14); 2204 assert(x.useCount == 1); 2205 assert(x.weakCount == 0); 2206 2207 auto w = x.weak(); //weak pointer 2208 assert(x.useCount == 1); 2209 assert(x.weakCount == 1); 2210 assert(*w.lock == 3.14); 2211 2212 RcPtr!double.WeakType w2 = x; 2213 assert(x.useCount == 1); 2214 assert(x.weakCount == 2); 2215 2216 assert(w2.expired == false); 2217 x = null; 2218 assert(w2.expired == true); 2219 } 2220 2221 //dynamic array 2222 { 2223 import std.algorithm : all; 2224 2225 { 2226 auto arr = RcPtr!(long[]).make(10, -1); 2227 2228 assert(arr.length == 10); 2229 assert(arr.get.all!(x => x == -1)); 2230 } 2231 2232 { 2233 auto arr = RcPtr!(long[]).make(8); 2234 assert(arr.length == 8); 2235 assert(arr.get.all!(x => x == long.init)); 2236 } 2237 } 2238 2239 //static array 2240 { 2241 import std.algorithm : all; 2242 2243 { 2244 auto arr = RcPtr!(long[4]).make(-1); 2245 assert(arr.get[].all!(x => x == -1)); 2246 2247 } 2248 2249 { 2250 long[4] tmp = [0, 1, 2, 3]; 2251 auto arr = RcPtr!(long[4]).make(tmp); 2252 assert(arr.get[] == tmp[]); 2253 } 2254 } 2255 2256 } 2257 2258 /// 2259 pure nothrow @safe @nogc unittest{ 2260 //make RcPtr object 2261 static struct Foo{ 2262 int i; 2263 2264 this(int i)pure nothrow @safe @nogc{ 2265 this.i = i; 2266 } 2267 } 2268 2269 { 2270 auto foo = RcPtr!Foo.make(42); 2271 auto foo2 = RcPtr!Foo.make!Mallocator(42); //explicit stateless allocator 2272 } 2273 2274 { 2275 auto arr = RcPtr!(long[]).make(10); //dynamic array with length 10 2276 assert(arr.length == 10); 2277 } 2278 } 2279 2280 /// 2281 nothrow unittest{ 2282 //alloc RcPtr object 2283 import std.experimental.allocator : make, dispose, allocatorObject; 2284 2285 auto allocator = allocatorObject(Mallocator.instance); 2286 2287 { 2288 auto x = RcPtr!(long).alloc(allocator, 42); 2289 } 2290 2291 { 2292 import btl.internal.traits; 2293 static assert(isMoveConstructableElement!(typeof(allocator))); 2294 auto arr = RcPtr!(long[]).alloc(allocator, 10); //dynamic array with length 10 2295 assert(arr.length == 10); 2296 } 2297 2298 } 2299 2300 2301 //make: 2302 pure nothrow @safe @nogc unittest{ 2303 import std.experimental.allocator : allocatorObject; 2304 2305 enum bool supportGC = true; 2306 2307 // 2308 { 2309 auto s = RcPtr!long.make(42); 2310 } 2311 2312 { 2313 auto s = RcPtr!long.make!(DefaultAllocator, supportGC)(42); 2314 } 2315 2316 { 2317 auto s = RcPtr!(long, shared(SharedControlBlock)).make!(DefaultAllocator, supportGC)(42); 2318 } 2319 2320 2321 // dynamic array: 2322 { 2323 auto s = RcPtr!(long[]).make(10, 42); 2324 assert(s.length == 10); 2325 } 2326 2327 { 2328 auto s = RcPtr!(long[]).make!(DefaultAllocator, supportGC)(10, 42); 2329 assert(s.length == 10); 2330 } 2331 2332 { 2333 auto s = RcPtr!(long[], shared(SharedControlBlock)).make!(DefaultAllocator, supportGC)(10, 42); 2334 assert(s.length == 10); 2335 } 2336 } 2337 2338 //alloc: 2339 nothrow unittest{ 2340 import std.experimental.allocator : allocatorObject; 2341 2342 auto a = allocatorObject(Mallocator.instance); 2343 enum bool supportGC = true; 2344 2345 // 2346 { 2347 auto s = RcPtr!long.alloc(a, 42); 2348 } 2349 2350 { 2351 auto s = RcPtr!long.alloc!supportGC(a, 42); 2352 } 2353 2354 { 2355 auto s = RcPtr!(long, shared(SharedControlBlock)).alloc!supportGC(a, 42); 2356 } 2357 2358 2359 // dynamic array: 2360 { 2361 auto s = RcPtr!(long[]).alloc(a, 10, 42); 2362 assert(s.length == 10); 2363 } 2364 2365 { 2366 auto s = RcPtr!(long[]).alloc!supportGC(a, 10, 42); 2367 assert(s.length == 10); 2368 } 2369 2370 { 2371 auto s = RcPtr!(long[], shared(SharedControlBlock)).alloc!supportGC(a, 10, 42); 2372 assert(s.length == 10); 2373 } 2374 } 2375 2376 2377 2378 /** 2379 Dynamic cast for shared pointers if `ElementType` is class with D linkage. 2380 2381 Creates a new instance of `RcPtr` whose stored pointer is obtained from `ptr`'s stored pointer using a dynaic cast expression. 2382 2383 If `ptr` is null or dynamic cast fail then result `RcPtr` is null. 2384 Otherwise, the new `RcPtr` will share ownership with the initial value of `ptr`. 2385 */ 2386 public UnqualSmartPtr!Ptr.ChangeElementType!T dynCast(T, Ptr)(scope auto ref Ptr ptr) 2387 if( isRcPtr!Ptr && !is(Ptr == shared) && !Ptr.isWeak 2388 && isClassOrInterface!T && __traits(getLinkage, T) == "D" 2389 && isClassOrInterface!(Ptr.ElementType) && __traits(getLinkage, Ptr.ElementType) == "D" 2390 ){ 2391 static if(isRef!ptr){ 2392 if(auto element = dynCastElement!T(ptr._element)){ 2393 return typeof(return)(ptr._control, element); 2394 } 2395 2396 return typeof(return).init; 2397 } 2398 else{ 2399 return dynCastMove!T(ptr); 2400 } 2401 } 2402 2403 /// ditto 2404 public UnqualSmartPtr!Ptr.ChangeElementType!T dynCastMove(T, Ptr)(scope auto ref Ptr ptr) 2405 if( isRcPtr!Ptr && !is(Ptr == shared) && !Ptr.isWeak 2406 && isClassOrInterface!T && __traits(getLinkage, T) == "D" 2407 && isClassOrInterface!(Ptr.ElementType) && __traits(getLinkage, Ptr.ElementType) == "D" 2408 ){ 2409 if(auto element = dynCastElement!T(ptr._element)){ 2410 ()@trusted{ 2411 ptr._const_reset(); 2412 }(); 2413 return typeof(return)(element, Forward.init); 2414 } 2415 2416 return typeof(return).init; 2417 } 2418 2419 2420 /// 2421 unittest{ 2422 static class Foo{ 2423 int i; 2424 2425 this(int i)pure nothrow @safe @nogc{ 2426 this.i = i; 2427 } 2428 } 2429 2430 static class Bar : Foo{ 2431 double d; 2432 2433 this(int i, double d)pure nothrow @safe @nogc{ 2434 super(i); 2435 this.d = d; 2436 } 2437 } 2438 2439 static class Zee{ 2440 } 2441 2442 { 2443 RcPtr!(const Foo) foo = RcPtr!Bar.make(42, 3.14); 2444 assert(foo.get.i == 42); 2445 2446 auto bar = dynCast!Bar(foo); 2447 assert(bar != null); 2448 assert(bar.get.d == 3.14); 2449 static assert(is(typeof(bar) == RcPtr!(const Bar))); 2450 2451 auto zee = dynCast!Zee(foo); 2452 assert(zee == null); 2453 static assert(is(typeof(zee) == RcPtr!(const Zee))); 2454 } 2455 2456 { 2457 RcPtr!(const Foo) foo = RcPtr!Bar.make(42, 3.14); 2458 assert(foo.get.i == 42); 2459 2460 import core.lifetime : move; 2461 auto bar = dynCast!Bar(foo.move); 2462 assert(bar != null); 2463 assert(bar.get.d == 3.14); 2464 static assert(is(typeof(bar) == RcPtr!(const Bar))); 2465 } 2466 2467 { 2468 RcPtr!(const Foo) foo = RcPtr!Bar.make(42, 3.14); 2469 assert(foo.get.i == 42); 2470 2471 auto bar = dynCastMove!Bar(foo); 2472 assert(foo == null); 2473 assert(bar != null); 2474 assert(bar.get.d == 3.14); 2475 static assert(is(typeof(bar) == RcPtr!(const Bar))); 2476 } 2477 } 2478 2479 2480 2481 2482 2483 2484 /** 2485 Return `shared RcPtr` pointing to same managed object like parameter `ptr`. 2486 2487 Type of parameter `ptr` must be `RcPtr` with `shared(ControlType)` and `shared`/`immutable` `ElementType` . 2488 */ 2489 public shared(Ptr) share(Ptr)(scope auto ref Ptr ptr) 2490 if(isRcPtr!Ptr){ 2491 import core.lifetime : forward; 2492 static if(is(Ptr == shared)){ 2493 return forward!ptr; 2494 } 2495 else{ 2496 static assert(is(GetControlType!Ptr == shared) || is(GetControlType!Ptr == immutable), 2497 "`RcPtr` has not shared ref counter `ControlType`." 2498 ); 2499 2500 static assert(is(GetElementType!Ptr == shared) || is(GetElementType!Ptr == immutable), 2501 "`RcPtr` has not shared/immutable `ElementType`." 2502 ); 2503 2504 return typeof(return)(forward!ptr, Forward.init); 2505 } 2506 } 2507 2508 /// 2509 nothrow @nogc unittest{ 2510 { 2511 auto x = RcPtr!(shared long).make(123); 2512 assert(x.useCount == 1); 2513 2514 shared s1 = share(x); 2515 assert(x.useCount == 2); 2516 2517 2518 import core.lifetime : move; 2519 shared s2 = share(x.move); 2520 assert(x == null); 2521 assert(s2.useCount == 2); 2522 assert(s2.load.get == 123); 2523 2524 } 2525 2526 { 2527 auto x = RcPtr!(long).make(123); 2528 assert(x.useCount == 1); 2529 2530 ///error `shared RcPtr` need shared `ControlType` and shared `ElementType`. 2531 //shared s1 = share(x); 2532 2533 } 2534 2535 } 2536 2537 2538 2539 /** 2540 Return `RcPtr` pointing to first element of dynamic array managed by rc pointer `ptr`. 2541 */ 2542 public auto first(Ptr)(scope ref Ptr ptr)@trusted 2543 if(isRcPtr!Ptr && is(Ptr.ElementType : T[], T)){ 2544 import std.traits : isDynamicArray, isStaticArray; 2545 import std.range : ElementEncodingType; 2546 2547 alias Result = UnqualSmartPtr!Ptr.ChangeElementType!( 2548 ElementEncodingType!(Ptr.ElementType) 2549 ); 2550 2551 if(ptr == null) 2552 return Result.init; 2553 2554 static if(isDynamicArray!(Ptr.ElementType) || isStaticArray!(Ptr.ElementType)){ 2555 return Result(ptr._control, ptr._element.ptr); 2556 } 2557 else static assert(0, "no impl"); 2558 } 2559 2560 /// ditto 2561 public auto first(Ptr)(scope Ptr ptr)@trusted 2562 if(isRcPtr!Ptr && is(Ptr.ElementType : T[], T)){ 2563 import std.traits : isDynamicArray, isStaticArray; 2564 import std.range : ElementEncodingType; 2565 2566 alias Result = UnqualSmartPtr!Ptr.ChangeElementType!( 2567 ElementEncodingType!(Ptr.ElementType) 2568 ); 2569 2570 if(ptr == null) 2571 return Result.init; 2572 2573 static if(isDynamicArray!(Ptr.ElementType) || isStaticArray!(Ptr.ElementType)){ 2574 auto ptr_element = ptr._element.ptr; 2575 ptr._const_reset(); 2576 return Result(ptr_element, Forward.init); 2577 } 2578 else static assert(0, "no impl"); 2579 } 2580 2581 /// 2582 pure nothrow @nogc unittest{ 2583 //copy 2584 { 2585 auto x = RcPtr!(long[]).make(10, -1); 2586 assert(x.length == 10); 2587 2588 auto y = first(x); 2589 static assert(is(typeof(y) == RcPtr!long)); 2590 assert(*y == -1); 2591 assert(x.useCount == 2); 2592 } 2593 2594 { 2595 auto x = RcPtr!(long[10]).make(-1); 2596 assert(x.get.length == 10); 2597 2598 auto y = first(x); 2599 static assert(is(typeof(y) == RcPtr!long)); 2600 assert(*y == -1); 2601 assert(x.useCount == 2); 2602 } 2603 2604 //move 2605 import core.lifetime : move; 2606 { 2607 auto x = RcPtr!(long[]).make(10, -1); 2608 assert(x.length == 10); 2609 2610 auto y = first(x.move); 2611 static assert(is(typeof(y) == RcPtr!long)); 2612 assert(*y == -1); 2613 } 2614 2615 { 2616 auto x = RcPtr!(long[10]).make(-1); 2617 assert(x.get.length == 10); 2618 2619 auto y = first(x.move); 2620 static assert(is(typeof(y) == RcPtr!long)); 2621 assert(*y == -1); 2622 } 2623 } 2624 2625 2626 2627 //local traits: 2628 private{ 2629 2630 //Constructable: 2631 template isMoveConstructable(From, To){ 2632 import std.traits : Unqual, CopyTypeQualifiers; 2633 2634 static if(is(Unqual!(From.ElementType) == Unqual!(To.ElementType))) 2635 enum bool overlapable = true; 2636 2637 else static if(isClassOrInterface!(From.ElementType) && isClassOrInterface!(To.ElementType)) 2638 enum bool overlapable = true 2639 && (__traits(getLinkage, From.ElementType) == "D") 2640 && (__traits(getLinkage, To.ElementType) == "D"); 2641 else 2642 enum bool overlapable = false; 2643 2644 2645 enum bool isMoveConstructable = true 2646 && overlapable //isOverlapable!(From.ElementType, To.ElementType) //&& is(Unqual!(From.ElementType) == Unqual!(To.ElementType)) 2647 && is(GetElementReferenceType!From : GetElementReferenceType!To) 2648 && is(From.DestructorType : To.DestructorType) 2649 && is(GetControlType!From* : GetControlType!To*); 2650 } 2651 template isCopyConstructable(From, To){ 2652 import std.traits : isMutable; 2653 2654 enum bool isCopyConstructable = true 2655 && isMoveConstructable!(From, To) 2656 && isMutable!From 2657 && isMutable!(From.ControlType); 2658 } 2659 template isConstructable(alias from, To){ 2660 enum bool isConstructable = isRef!from 2661 ? isCopyConstructable!(typeof(from), To) 2662 : isMoveConstructable!(typeof(from), To); 2663 } 2664 2665 //Assignable: 2666 template isMoveAssignable(From, To){ 2667 import std.traits : isMutable; 2668 2669 enum bool isMoveAssignable = true 2670 && isMoveConstructable!(From, To) 2671 && !weakLock!(From, To) 2672 && isMutable!To; 2673 } 2674 template isCopyAssignable(From, To){ 2675 import std.traits : isMutable; 2676 2677 enum bool isCopyAssignable = true 2678 && isCopyConstructable!(From, To) 2679 && !weakLock!(From, To) 2680 && isMutable!To; 2681 } 2682 template isAssignable(alias from, To){ 2683 enum bool isAssignable = isRef!from 2684 ? isCopyAssignable!(typeof(from), To) 2685 : isMoveAssignable!(typeof(from), To); 2686 } 2687 } 2688 2689 2690 version(unittest){ 2691 import btl.internal.test_allocator; 2692 2693 //copy ctor 2694 pure nothrow @nogc unittest{ 2695 2696 2697 static struct Test{} 2698 2699 import std.meta : AliasSeq; 2700 //alias Test = long; 2701 static foreach(alias ControlType; AliasSeq!(SharedControlBlock, shared SharedControlBlock)){{ 2702 alias SPtr(T) = RcPtr!(T, DestructorType!T, ControlType); 2703 2704 //mutable: 2705 { 2706 alias Ptr = SPtr!(Test); 2707 Ptr ptr; 2708 static assert(__traits(compiles, Ptr(ptr))); 2709 static assert(__traits(compiles, const(Ptr)(ptr))); 2710 static assert(!__traits(compiles, immutable(Ptr)(ptr))); 2711 static assert(!__traits(compiles, shared(Ptr)(ptr))); 2712 static assert(!__traits(compiles, const(shared(Ptr))(ptr))); 2713 } 2714 2715 //const: 2716 { 2717 alias Ptr = SPtr!(const Test); 2718 Ptr ptr; 2719 static assert(__traits(compiles, Ptr(ptr))); 2720 static assert(__traits(compiles, const(Ptr)(ptr))); 2721 static assert(!__traits(compiles, immutable(Ptr)(ptr))); 2722 static assert(!__traits(compiles, shared(Ptr)(ptr))); 2723 static assert(!__traits(compiles, const(shared(Ptr))(ptr))); 2724 } 2725 2726 //immutable: 2727 { 2728 alias Ptr = SPtr!(immutable Test); 2729 Ptr ptr; 2730 static assert(__traits(compiles, Ptr(ptr))); 2731 static assert(__traits(compiles, const(Ptr)(ptr))); 2732 static assert(!__traits(compiles, immutable(Ptr)(ptr))); 2733 static assert(__traits(compiles, shared(Ptr)(ptr)) == is(ControlType == shared)); 2734 static assert(__traits(compiles, const(shared(Ptr))(ptr)) == is(ControlType == shared)); 2735 } 2736 2737 2738 //shared: 2739 { 2740 alias Ptr = SPtr!(shared Test); 2741 Ptr ptr; 2742 static assert(__traits(compiles, Ptr(ptr))); 2743 static assert(__traits(compiles, const(Ptr)(ptr))); 2744 static assert(!__traits(compiles, immutable(Ptr)(ptr))); 2745 static assert(__traits(compiles, shared(Ptr)(ptr)) == is(ControlType == shared)); 2746 static assert(__traits(compiles, const(shared(Ptr))(ptr)) == is(ControlType == shared)); 2747 } 2748 2749 2750 //const shared: 2751 { 2752 alias Ptr = SPtr!(const shared Test); 2753 Ptr ptr; 2754 static assert(__traits(compiles, Ptr(ptr))); 2755 static assert(__traits(compiles, const(Ptr)(ptr))); 2756 static assert(!__traits(compiles, immutable(Ptr)(ptr))); 2757 static assert(__traits(compiles, shared(Ptr)(ptr)) == is(ControlType == shared)); 2758 static assert(__traits(compiles, const(shared(Ptr))(ptr)) == is(ControlType == shared)); 2759 } 2760 2761 static foreach(alias T; AliasSeq!( 2762 Test, 2763 const Test, 2764 shared Test, 2765 const shared Test, 2766 immutable Test, 2767 )){{ 2768 alias Ptr = SPtr!T; 2769 2770 const(Ptr) cptr; 2771 static assert(!__traits(compiles, Ptr(cptr))); 2772 static assert(!__traits(compiles, const(Ptr)(cptr))); 2773 static assert(!__traits(compiles, immutable(Ptr)(cptr))); 2774 static assert(!__traits(compiles, shared(Ptr)(cptr))); 2775 static assert(!__traits(compiles, const(shared(Ptr))(cptr))); 2776 2777 immutable(Ptr) iptr; 2778 static assert(!__traits(compiles, Ptr(iptr))); 2779 static assert(!__traits(compiles, const(Ptr)(iptr))); 2780 static assert(!__traits(compiles, immutable(Ptr)(iptr))); 2781 static assert(!__traits(compiles, shared(Ptr)(iptr))); 2782 static assert(!__traits(compiles, const(shared(Ptr))(iptr))); 2783 2784 shared(Ptr) sptr; 2785 static assert(!__traits(compiles, Ptr(sptr))); 2786 static assert(!__traits(compiles, const(Ptr)(sptr))); 2787 static assert(!__traits(compiles, immutable(Ptr)(sptr))); 2788 static assert(!__traits(compiles, shared(Ptr)(sptr))); //need load 2789 static assert(!__traits(compiles, const shared Ptr(sptr))); //need load 2790 2791 shared(const(Ptr)) scptr; 2792 static assert(!__traits(compiles, Ptr(scptr))); 2793 static assert(!__traits(compiles, const(Ptr)(scptr))); 2794 static assert(!__traits(compiles, immutable(Ptr)(scptr))); 2795 static assert(!__traits(compiles, shared(Ptr)(scptr))); //need load 2796 static assert(!__traits(compiles, const(shared(Ptr))(scptr))); //need load 2797 2798 }} 2799 2800 }} 2801 } 2802 2803 //this(typeof(null)) 2804 pure nothrow @safe @nogc unittest{ 2805 RcPtr!long x = null; 2806 2807 assert(x == null); 2808 assert(x == RcPtr!long.init); 2809 2810 } 2811 2812 2813 //opAssign(RcPtr) 2814 pure nothrow @nogc unittest{ 2815 2816 { 2817 RcPtr!long px1 = RcPtr!long.make(1); 2818 RcPtr!long px2 = RcPtr!long.make(2); 2819 2820 assert(px2.useCount == 1); 2821 px1 = px2; 2822 assert(px1.get == 2); 2823 assert(px2.useCount == 2); 2824 } 2825 2826 2827 2828 { 2829 RcPtr!long px = RcPtr!long.make(1); 2830 RcPtr!(const long) pcx = RcPtr!long.make(2); 2831 2832 assert(px.useCount == 1); 2833 pcx = px; 2834 assert(pcx.get == 1); 2835 assert(pcx.useCount == 2); 2836 2837 } 2838 2839 2840 /+{ 2841 const RcPtr!long cpx = RcPtr!long.make(1); 2842 RcPtr!(const long) pcx = RcPtr!long.make(2); 2843 2844 assert(pcx.useCount == 1); 2845 pcx = cpx; 2846 assert(pcx.get == 1); 2847 assert(pcx.useCount == 2); 2848 2849 }+/ 2850 2851 { 2852 RcPtr!(immutable long) pix = RcPtr!(immutable long).make(123); 2853 RcPtr!(const long) pcx = RcPtr!long.make(2); 2854 2855 assert(pix.useCount == 1); 2856 pcx = pix; 2857 assert(pcx.get == 123); 2858 assert(pcx.useCount == 2); 2859 2860 } 2861 } 2862 2863 //opAssign(null) 2864 nothrow @safe @nogc unittest{ 2865 { 2866 RcPtr!long x = RcPtr!long.make(1); 2867 2868 assert(x.useCount == 1); 2869 x = null; 2870 assert(x.useCount == 0); 2871 assert(x == null); 2872 } 2873 2874 { 2875 RcPtr!(shared long) x = RcPtr!(shared long).make(1); 2876 2877 assert(x.useCount == 1); 2878 x = null; 2879 assert(x.useCount == 0); 2880 assert(x == null); 2881 } 2882 2883 import btl.internal.mutex : supportMutex; 2884 static if(supportMutex){ 2885 shared RcPtr!(long) x = RcPtr!(shared long).make(1); 2886 2887 assert(x.useCount == 1); 2888 x = null; 2889 assert(x.useCount == 0); 2890 assert(x.load == null); 2891 } 2892 } 2893 2894 //useCount 2895 pure nothrow @safe @nogc unittest{ 2896 RcPtr!long x = null; 2897 2898 assert(x.useCount == 0); 2899 2900 x = RcPtr!long.make(123); 2901 assert(x.useCount == 1); 2902 2903 auto y = x; 2904 assert(x.useCount == 2); 2905 2906 auto w1 = x.weak; //weak ptr 2907 assert(x.useCount == 2); 2908 2909 RcPtr!long.WeakType w2 = x; //weak ptr 2910 assert(x.useCount == 2); 2911 2912 y = null; 2913 assert(x.useCount == 1); 2914 2915 x = null; 2916 assert(x.useCount == 0); 2917 assert(w1.useCount == 0); 2918 } 2919 2920 //weakCount 2921 pure nothrow @safe @nogc unittest{ 2922 2923 RcPtr!long x = null; 2924 assert(x.useCount == 0); 2925 assert(x.weakCount == 0); 2926 2927 x = RcPtr!long.make(123); 2928 assert(x.useCount == 1); 2929 assert(x.weakCount == 0); 2930 2931 auto w = x.weak(); 2932 assert(x.useCount == 1); 2933 assert(x.weakCount == 1); 2934 } 2935 2936 // store: 2937 nothrow @nogc unittest{ 2938 2939 //null store: 2940 { 2941 shared x = RcPtr!(shared long).make(123); 2942 assert(x.load.get == 123); 2943 2944 x.store(null); 2945 assert(x.useCount == 0); 2946 assert(x.load == null); 2947 } 2948 2949 //rvalue store: 2950 { 2951 shared x = RcPtr!(shared long).make(123); 2952 assert(x.load.get == 123); 2953 2954 x.store(RcPtr!(shared long).make(42)); 2955 assert(x.load.get == 42); 2956 } 2957 2958 //lvalue store: 2959 { 2960 shared x = RcPtr!(shared long).make(123); 2961 auto y = RcPtr!(shared long).make(42); 2962 2963 assert(x.load.get == 123); 2964 assert(y.load.get == 42); 2965 assert(x.useCount == 1); 2966 2967 x.store(y); 2968 assert(x.load.get == 42); 2969 assert(x.useCount == 2); 2970 } 2971 } 2972 2973 //load: 2974 nothrow @nogc unittest{ 2975 2976 shared RcPtr!(long) x = RcPtr!(shared long).make(123); 2977 2978 import btl.internal.mutex : supportMutex; 2979 static if(supportMutex){ 2980 RcPtr!(shared long) y = x.load(); 2981 assert(y.useCount == 2); 2982 2983 assert(y.get == 123); 2984 } 2985 2986 } 2987 2988 //exchange 2989 nothrow @nogc unittest{ 2990 2991 //lvalue exchange 2992 { 2993 shared x = RcPtr!(shared long).make(123); 2994 auto y = RcPtr!(shared long).make(42); 2995 2996 auto z = x.exchange(y); 2997 2998 assert(x.load.get == 42); 2999 assert(y.get == 42); 3000 assert(z.get == 123); 3001 } 3002 3003 //rvalue exchange 3004 { 3005 shared x = RcPtr!(shared long).make(123); 3006 auto y = RcPtr!(shared long).make(42); 3007 3008 import core.lifetime : move; 3009 auto z = x.exchange(y.move); 3010 3011 assert(x.load.get == 42); 3012 assert(y == null); 3013 assert(z.get == 123); 3014 } 3015 3016 //null exchange (same as move) 3017 { 3018 shared x = RcPtr!(shared long).make(123); 3019 3020 auto z = x.exchange(null); 3021 3022 assert(x.load == null); 3023 assert(z.get == 123); 3024 } 3025 3026 //swap: 3027 { 3028 shared x = RcPtr!(shared long).make(123); 3029 auto y = RcPtr!(shared long).make(42); 3030 3031 //opAssign is same as store 3032 import core.lifetime : move; 3033 y = x.exchange(y.move); 3034 3035 assert(x.load.get == 42); 3036 assert(y.get == 123); 3037 } 3038 3039 } 3040 3041 3042 //compareExchange 3043 pure nothrow @nogc unittest{ 3044 static class Foo{ 3045 long i; 3046 this(long i)pure nothrow @safe @nogc{ 3047 this.i = i; 3048 } 3049 3050 bool opEquals(this This)(long i)const @trusted{ 3051 import std.traits : Unqual; 3052 auto self = cast(Unqual!This)this; 3053 return (self.i == i); 3054 } 3055 3056 3057 } 3058 alias Type = const Foo; 3059 static foreach(enum bool weak; [true, false]){ 3060 //fail 3061 { 3062 RcPtr!Type a = RcPtr!Type.make(123); 3063 RcPtr!Type b = RcPtr!Type.make(42); 3064 RcPtr!Type c = RcPtr!Type.make(666); 3065 3066 static if(weak)a.compareExchangeWeak(b, c); 3067 else a.compareExchangeStrong(b, c); 3068 3069 assert(*a == 123); 3070 assert(*b == 123); 3071 assert(*c == 666); 3072 3073 } 3074 3075 //success 3076 { 3077 RcPtr!Type a = RcPtr!Type.make(123); 3078 RcPtr!Type b = a; 3079 RcPtr!Type c = RcPtr!Type.make(666); 3080 3081 static if(weak)a.compareExchangeWeak(b, c); 3082 else a.compareExchangeStrong(b, c); 3083 3084 assert(*a == 666); 3085 assert(*b == 123); 3086 assert(*c == 666); 3087 } 3088 3089 //shared fail 3090 { 3091 shared RcPtr!(shared Type) a = RcPtr!(shared Type).make(123); 3092 RcPtr!(shared Type) b = RcPtr!(shared Type).make(42); 3093 RcPtr!(shared Type) c = RcPtr!(shared Type).make(666); 3094 3095 static if(weak)a.compareExchangeWeak(b, c); 3096 else a.compareExchangeStrong(b, c); 3097 3098 auto tmp = a.exchange(null); 3099 assert(*tmp == 123); 3100 assert(*b == 123); 3101 assert(*c == 666); 3102 } 3103 3104 //shared success 3105 { 3106 RcPtr!(shared Type) b = RcPtr!(shared Type).make(123); 3107 shared RcPtr!(shared Type) a = b; 3108 RcPtr!(shared Type) c = RcPtr!(shared Type).make(666); 3109 3110 static if(weak)a.compareExchangeWeak(b, c); 3111 else a.compareExchangeStrong(b, c); 3112 3113 auto tmp = a.exchange(null); 3114 assert(*tmp == 666); 3115 assert(*b == 123); 3116 assert(*c == 666); 3117 } 3118 } 3119 3120 } 3121 3122 //lock 3123 nothrow @nogc unittest{ 3124 { 3125 RcPtr!long x = RcPtr!long.make(123); 3126 3127 auto w = x.weak; //weak ptr 3128 3129 RcPtr!long y = w.lock; 3130 3131 assert(x == y); 3132 assert(x.useCount == 2); 3133 assert(y.get == 123); 3134 } 3135 3136 { 3137 RcPtr!long x = RcPtr!long.make(123); 3138 3139 auto w = x.weak; //weak ptr 3140 3141 assert(w.expired == false); 3142 3143 x = RcPtr!long.make(321); 3144 3145 assert(w.expired == true); 3146 3147 RcPtr!long y = w.lock; 3148 3149 assert(y == null); 3150 } 3151 { 3152 shared RcPtr!(shared long) x = RcPtr!(shared long).make(123); 3153 3154 shared RcPtr!(shared long).WeakType w = x.load.weak; //weak ptr 3155 3156 assert(w.expired == false); 3157 3158 x = RcPtr!(shared long).make(321); 3159 3160 assert(w.expired == true); 3161 3162 RcPtr!(shared long) y = w.load.lock; 3163 3164 assert(y == null); 3165 } 3166 } 3167 3168 //expired 3169 nothrow @nogc unittest{ 3170 { 3171 RcPtr!long x = RcPtr!long.make(123); 3172 3173 auto wx = x.weak; //weak pointer 3174 3175 assert(wx.expired == false); 3176 3177 x = null; 3178 3179 assert(wx.expired == true); 3180 } 3181 } 3182 3183 //make 3184 pure nothrow @nogc unittest{ 3185 { 3186 RcPtr!long a = RcPtr!long.make(); 3187 assert(a.get == 0); 3188 3189 RcPtr!(const long) b = RcPtr!long.make(2); 3190 assert(b.get == 2); 3191 } 3192 3193 { 3194 static struct Struct{ 3195 int i = 7; 3196 3197 this(int i)pure nothrow @safe @nogc{ 3198 this.i = i; 3199 } 3200 } 3201 3202 RcPtr!Struct s1 = RcPtr!Struct.make(); 3203 assert(s1.get.i == 7); 3204 3205 RcPtr!Struct s2 = RcPtr!Struct.make(123); 3206 assert(s2.get.i == 123); 3207 } 3208 3209 static interface Interface{ 3210 } 3211 static class Class : Interface{ 3212 int i; 3213 3214 this(int i)pure nothrow @safe @nogc{ 3215 this.i = i; 3216 } 3217 } 3218 3219 { 3220 3221 RcPtr!Interface x = RcPtr!Class.make(3); 3222 //assert(x.dynTo!Class.get.i == 3); 3223 } 3224 3225 3226 } 3227 3228 //make dynamic array 3229 pure nothrow @nogc unittest{ 3230 { 3231 auto arr = RcPtr!(long[]).make(6, -1); 3232 assert(arr.length == 6); 3233 assert(arr.get.length == 6); 3234 3235 import std.algorithm : all; 3236 assert(arr.get.all!(x => x == -1)); 3237 3238 for(int i = 0; i < 6; ++i) 3239 arr.get[i] = i; 3240 3241 assert(arr.get == [0, 1, 2, 3, 4, 5]); 3242 } 3243 3244 { 3245 static struct Struct{ 3246 int i; 3247 double d; 3248 } 3249 3250 { 3251 auto a = RcPtr!(Struct[]).make(6, 42, 3.14); 3252 assert(a.length == 6); 3253 assert(a.get.length == 6); 3254 3255 import std.algorithm : all; 3256 assert(a.get[].all!(x => (x.i == 42 && x.d == 3.14))); 3257 } 3258 3259 { 3260 auto a = RcPtr!(Struct[]).make(6); 3261 assert(a.length == 6); 3262 3263 import std.algorithm : all; 3264 assert(a.get[].all!(x => (x.i == int.init))); 3265 } 3266 } 3267 3268 { 3269 static class Class{ 3270 int i; 3271 double d; 3272 3273 this(int i, double d){ 3274 this.i = i; 3275 this.d = d; 3276 } 3277 } 3278 3279 { 3280 auto a = RcPtr!(Class[]).make(6, null); 3281 assert(a.length == 6); 3282 3283 import std.algorithm : all; 3284 assert(a.get[].all!(x => x is null)); 3285 } 3286 3287 { 3288 auto a = RcPtr!(Class[]).make(6); 3289 assert(a.length == 6); 3290 3291 import std.algorithm : all; 3292 assert(a.get[].all!(x => x is null)); 3293 } 3294 3295 3296 } 3297 } 3298 3299 //make static array 3300 pure nothrow @nogc unittest{ 3301 import std.algorithm : all; 3302 { 3303 RcPtr!(long[6]) a = RcPtr!(long[6]).make(); 3304 assert(a.get.length == 6); 3305 assert(a.get[].all!(x => x == long.init)); 3306 } 3307 { 3308 RcPtr!(long[6]) a = RcPtr!(long[6]).make(-1); 3309 assert(a.get.length == 6); 3310 assert(a.get[].all!(x => x == -1)); 3311 } 3312 { 3313 long[6] tmp = [1, 2, 3, 4, 5, 6]; 3314 3315 RcPtr!(const(long)[6]) a = RcPtr!(long[6]).make(tmp); 3316 assert(a.get.length == 6); 3317 assert(a.get[]== tmp); 3318 } 3319 { 3320 static struct Struct{ 3321 int i; 3322 double d; 3323 } 3324 3325 auto a = RcPtr!(Struct[6]).make(42, 3.14); 3326 assert(a.get.length == 6); 3327 3328 import std.algorithm : all; 3329 assert(a.get[].all!(x => (x.i == 42 && x.d == 3.14))); 3330 3331 3332 } 3333 } 3334 3335 //alloc 3336 pure nothrow @nogc unittest{ 3337 { 3338 TestAllocator allocator; 3339 3340 { 3341 RcPtr!long a = RcPtr!long.alloc(&allocator); 3342 assert(a.get == 0); 3343 3344 RcPtr!(const long) b = RcPtr!long.alloc(&allocator, 2); 3345 assert(b.get == 2); 3346 } 3347 3348 { 3349 static struct Struct{ 3350 int i = 7; 3351 3352 this(int i)pure nothrow @safe @nogc{ 3353 this.i = i; 3354 } 3355 } 3356 3357 RcPtr!Struct s1 = RcPtr!Struct.alloc(allocator); 3358 assert(s1.get.i == 7); 3359 3360 RcPtr!Struct s2 = RcPtr!Struct.alloc(allocator, 123); 3361 assert(s2.get.i == 123); 3362 } 3363 3364 static interface Interface{ 3365 } 3366 static class Class : Interface{ 3367 int i; 3368 3369 this(int i)pure nothrow @safe @nogc{ 3370 this.i = i; 3371 } 3372 } 3373 3374 { 3375 3376 3377 RcPtr!Interface x = RcPtr!Class.alloc(&allocator, 3); 3378 assert(x.useCount == 1); 3379 //assert(x.dynTo!Class.get.i == 3); 3380 } 3381 } 3382 } 3383 3384 //alloc 3385 unittest{ 3386 3387 { 3388 import std.experimental.allocator : allocatorObject; 3389 3390 auto a = allocatorObject(Mallocator.instance); 3391 { 3392 auto x = RcPtr!long.alloc(a); 3393 assert(x.get == 0); 3394 3395 auto y = RcPtr!long.alloc(a, 2); 3396 assert(y.get == 2); 3397 } 3398 3399 { 3400 static struct Struct{ 3401 int i = 7; 3402 3403 this(int i)pure nothrow @safe @nogc{ 3404 this.i = i; 3405 } 3406 } 3407 3408 auto s1 = RcPtr!Struct.alloc(a); 3409 assert(s1.get.i == 7); 3410 3411 auto s2 = RcPtr!Struct.alloc(a, 123); 3412 assert(s2.get.i == 123); 3413 } 3414 3415 { 3416 static interface Interface{ 3417 } 3418 static class Class : Interface{ 3419 int i; 3420 3421 this(int i)pure nothrow @safe @nogc{ 3422 this.i = i; 3423 } 3424 } 3425 3426 RcPtr!(Interface, DestructorAllocatorType!(typeof(a))) x = RcPtr!Class.alloc(a, 3); 3427 //assert(x.dynTo!Class.get.i == 3); 3428 } 3429 3430 } 3431 } 3432 3433 //alloc array 3434 nothrow unittest{ 3435 { 3436 import std.experimental.allocator : allocatorObject; 3437 3438 auto a = allocatorObject(Mallocator.instance); 3439 auto arr = RcPtr!(long[], DestructorAllocatorType!(typeof(a))).alloc(a, 6, -1); 3440 assert(arr.length == 6); 3441 assert(arr.get.length == 6); 3442 3443 import std.algorithm : all; 3444 assert(arr.get.all!(x => x == -1)); 3445 3446 for(int i = 0; i < 6; ++i) 3447 arr.get[i] = i; 3448 3449 assert(arr.get == [0, 1, 2, 3, 4, 5]); 3450 } 3451 } 3452 3453 //ctor 3454 pure nothrow @nogc @safe unittest{ 3455 3456 { 3457 RcPtr!long x = RcPtr!long.make(123); 3458 assert(x.useCount == 1); 3459 3460 RcPtr!long a = x; //lvalue copy ctor 3461 assert(a == x); 3462 3463 const RcPtr!long b = x; //lvalue copy ctor 3464 assert(b == x); 3465 3466 RcPtr!(const long) c = x; //lvalue ctor 3467 assert(c == x); 3468 3469 const RcPtr!long d = a; //lvalue ctor 3470 assert(d == x); 3471 3472 assert(x.useCount == 5); 3473 } 3474 3475 { 3476 import core.lifetime : move; 3477 RcPtr!long x = RcPtr!long.make(123); 3478 assert(x.useCount == 1); 3479 3480 RcPtr!long a = move(x); //rvalue copy ctor 3481 assert(a.useCount == 1); 3482 3483 const RcPtr!long b = move(a); //rvalue copy ctor 3484 assert(b.useCount == 1); 3485 3486 /+RcPtr!(const long) c = b.load; //rvalue ctor 3487 assert(c.useCount == 2); 3488 3489 const RcPtr!long d = move(c); //rvalue ctor 3490 assert(d.useCount == 2);+/ 3491 } 3492 3493 /+{ 3494 import core.lifetime : move; 3495 auto u = UniquePtr!(long, SharedControlBlock).make(123); 3496 3497 RcPtr!long s = move(u); //rvalue copy ctor 3498 assert(s != null); 3499 assert(s.useCount == 1); 3500 3501 RcPtr!long s2 = UniquePtr!(long, SharedControlBlock).init; 3502 assert(s2 == null); 3503 3504 }+/ 3505 3506 } 3507 3508 //weak 3509 pure nothrow @nogc unittest{ 3510 RcPtr!long x = RcPtr!long.make(123); 3511 assert(x.useCount == 1); 3512 auto wx = x.weak; //weak pointer 3513 assert(wx.expired == false); 3514 assert(wx.lock.get == 123); 3515 assert(wx.useCount == 1); 3516 x = null; 3517 assert(wx.expired == true); 3518 assert(wx.useCount == 0); 3519 3520 } 3521 3522 //operator * 3523 pure nothrow @nogc unittest{ 3524 3525 RcPtr!long x = RcPtr!long.make(123); 3526 assert(*x == 123); 3527 (*x = 321); 3528 assert(*x == 321); 3529 const y = x; 3530 assert(*y == 321); 3531 assert(*x == 321); 3532 static assert(is(typeof(*y) == const long)); 3533 } 3534 3535 //get 3536 pure nothrow @nogc unittest{ 3537 RcPtr!long x = RcPtr!long.make(123); 3538 assert(x.get == 123); 3539 x.get = 321; 3540 assert(x.get == 321); 3541 const y = x; 3542 assert(y.get == 321); 3543 assert(x.get == 321); 3544 static assert(is(typeof(y.get) == const long)); 3545 } 3546 3547 //element 3548 pure nothrow @nogc unittest{ 3549 { 3550 RcPtr!long x = RcPtr!long.make(123); 3551 assert(*x.element == 123); 3552 3553 x.get = 321; 3554 assert(*x.element == 321); 3555 3556 const y = x; 3557 assert(*y.element == 321); 3558 assert(*x.element == 321); 3559 3560 static assert(is(typeof(y.element) == const(long)*)); 3561 } 3562 3563 { 3564 auto x = RcPtr!(long[]).make(6, 42); 3565 assert(x.element[0] == 42); 3566 static assert(is(typeof(x.element) == long[])); 3567 } 3568 3569 { 3570 auto s = RcPtr!long.make(42); 3571 const w = s.weak; 3572 3573 assert(*w.element == 42); 3574 3575 s = null; 3576 assert(w.element is null); 3577 } 3578 3579 { 3580 auto s = RcPtr!long.make(42); 3581 auto w = s.weak; 3582 3583 scope const p = w.element; 3584 3585 s = null; 3586 assert(w.element is null); 3587 3588 assert(p !is null); //p is dangling pointer! 3589 } 3590 } 3591 3592 //ptr 3593 pure nothrow @nogc unittest{ 3594 { 3595 RcPtr!long x = RcPtr!long.make(123); 3596 assert(*x.ptr == 123); 3597 3598 x.get = 321; 3599 assert(*x.ptr == 321); 3600 3601 const y = x; 3602 assert(*y.ptr == 321); 3603 assert(*x.ptr == 321); 3604 3605 static assert(is(typeof(y.ptr) == const(long)*)); 3606 } 3607 3608 { 3609 auto x = RcPtr!(long[]).make(6, 42); 3610 assert(*x.ptr == 42); 3611 static assert(is(typeof(x.ptr) == long*)); 3612 } 3613 3614 { 3615 auto s = RcPtr!long.make(42); 3616 const w = s.weak; 3617 3618 assert(*w.ptr == 42); 3619 3620 s = null; 3621 assert(w.ptr is null); 3622 } 3623 3624 { 3625 auto s = RcPtr!long.make(42); 3626 auto w = s.weak; 3627 3628 scope const p = w.ptr; 3629 3630 s = null; 3631 assert(w.ptr is null); 3632 3633 assert(p !is null); //p is dangling pointer! 3634 } 3635 } 3636 3637 //opCast bool 3638 @safe pure nothrow @nogc unittest{ 3639 RcPtr!long x = RcPtr!long.make(123); 3640 assert(cast(bool)x); //explicit cast 3641 assert(x); //implicit cast 3642 x = null; 3643 assert(!cast(bool)x); //explicit cast 3644 assert(!x); //implicit cast 3645 } 3646 3647 //opCast RcPtr 3648 /+TODO 3649 @safe pure nothrow @nogc unittest{ 3650 RcPtr!long x = RcPtr!long.make(123); 3651 auto y = cast(RcPtr!(const long))x; 3652 auto z = cast(const RcPtr!long)x; 3653 auto u = cast(const RcPtr!(const long))x; 3654 assert(x.useCount == 4); 3655 } 3656 +/ 3657 3658 //opEquals RcPtr 3659 pure @safe nothrow @nogc unittest{ 3660 { 3661 RcPtr!long x = RcPtr!long.make(0); 3662 assert(x != null); 3663 x = null; 3664 assert(x == null); 3665 } 3666 3667 { 3668 RcPtr!long x = RcPtr!long.make(123); 3669 RcPtr!long y = RcPtr!long.make(123); 3670 assert(x == x); 3671 assert(y == y); 3672 assert(x != y); 3673 } 3674 3675 { 3676 RcPtr!long x; 3677 RcPtr!(const long) y; 3678 assert(x == x); 3679 assert(y == y); 3680 assert(x == y); 3681 } 3682 } 3683 3684 //opEquals RcPtr 3685 pure nothrow @nogc unittest{ 3686 { 3687 RcPtr!long x = RcPtr!long.make(123); 3688 RcPtr!long y = RcPtr!long.make(123); 3689 assert(x == x.element); 3690 assert(y.element == y); 3691 assert(x != y.element); 3692 } 3693 } 3694 3695 //opCmp 3696 pure nothrow @safe @nogc unittest{ 3697 { 3698 const a = RcPtr!long.make(42); 3699 const b = RcPtr!long.make(123); 3700 const n = RcPtr!long.init; 3701 3702 assert(a <= a); 3703 assert(a >= a); 3704 3705 assert((a < b) == !(a >= b)); 3706 assert((a > b) == !(a <= b)); 3707 3708 assert(a > n); 3709 assert(a > null); 3710 3711 assert(n < a); 3712 assert(null < a); 3713 } 3714 } 3715 3716 //opCmp 3717 pure nothrow @nogc unittest{ 3718 { 3719 const a = RcPtr!long.make(42); 3720 const b = RcPtr!long.make(123); 3721 3722 assert(a <= a.element); 3723 assert(a.element >= a); 3724 3725 assert((a < b.element) == !(a.element >= b)); 3726 assert((a > b.element) == !(a.element <= b)); 3727 } 3728 } 3729 3730 //toHash 3731 pure nothrow @safe @nogc unittest{ 3732 { 3733 RcPtr!long x = RcPtr!long.make(123); 3734 RcPtr!long y = RcPtr!long.make(123); 3735 assert(x.toHash == x.toHash); 3736 assert(y.toHash == y.toHash); 3737 assert(x.toHash != y.toHash); 3738 RcPtr!(const long) z = x; 3739 assert(x.toHash == z.toHash); 3740 } 3741 { 3742 RcPtr!long x; 3743 RcPtr!(const long) y; 3744 assert(x.toHash == x.toHash); 3745 assert(y.toHash == y.toHash); 3746 assert(x.toHash == y.toHash); 3747 } 3748 } 3749 3750 //proxySwap 3751 pure nothrow @nogc unittest{ 3752 { 3753 RcPtr!long a = RcPtr!long.make(1); 3754 RcPtr!long b = RcPtr!long.make(2); 3755 a.proxySwap(b); 3756 assert(*a == 2); 3757 assert(*b == 1); 3758 import std.algorithm : swap; 3759 swap(a, b); 3760 assert(*a == 1); 3761 assert(*b == 2); 3762 assert(a.useCount == 1); 3763 assert(b.useCount == 1); 3764 } 3765 } 3766 3767 //length 3768 pure nothrow @nogc unittest{ 3769 auto x = RcPtr!(int[]).make(10, -1); 3770 assert(x.length == 10); 3771 assert(x.get.length == 10); 3772 3773 import std.algorithm : all; 3774 assert(x.get.all!(i => i == -1)); 3775 } 3776 3777 } 3778 3779 pure nothrow @safe @nogc unittest{ 3780 RcPtr!void u = RcPtr!void.make(); 3781 } 3782 3783 3784 version(unittest){ 3785 struct Foo{ 3786 RcPtr!int i; 3787 } 3788 } 3789 3790 3791 3792 //test strong ptr -> weak ptr move ctor 3793 unittest{ 3794 { 3795 import core.lifetime : move; 3796 3797 auto a = RcPtr!int.make(1); 3798 auto b = a; 3799 assert(a.useCount == 2); 3800 assert(a.weakCount == 0); 3801 3802 RcPtr!int.WeakType x = move(a); 3803 assert(b.useCount == 1); 3804 assert(b.weakCount == 1); 3805 } 3806 } 3807 3808 //test strong ptr -> weak ptr assign 3809 unittest{ 3810 { 3811 import core.lifetime : move; 3812 3813 auto a = RcPtr!int.make(1); 3814 auto b = RcPtr!int.make(2); 3815 3816 { 3817 RcPtr!int.WeakType x = RcPtr!int(a); 3818 assert(a.useCount == 1); 3819 assert(a.weakCount == 1); 3820 3821 x = RcPtr!int(b); 3822 assert(a.useCount == 1); 3823 assert(a.weakCount == 0); 3824 3825 assert(b.useCount == 1); 3826 assert(b.weakCount == 1); 3827 } 3828 { 3829 RcPtr!int.WeakType x = a; 3830 assert(a.useCount == 1); 3831 assert(a.weakCount == 1); 3832 3833 RcPtr!int.WeakType y = b; 3834 assert(b.useCount == 1); 3835 assert(b.weakCount == 1); 3836 3837 x = y; 3838 assert(a.useCount == 1); 3839 assert(a.weakCount == 0); 3840 3841 assert(b.useCount == 1); 3842 assert(b.weakCount == 2); 3843 3844 3845 } 3846 } 3847 } 3848 3849 //compare strong and weak ptr 3850 unittest{ 3851 auto a = RcPtr!int.make(1); 3852 auto b = a.weak; 3853 assert(a == b); 3854 } 3855 3856 //self opAssign 3857 unittest{ 3858 auto a = RcPtr!long.make(1); 3859 a = a; 3860 } 3861 3862 version(unittest){ 3863 //debug{ 3864 private struct Cycle{ 3865 3866 RcPtr!(Cycle, DestructorType!void, SharedControlBlock) cycle; 3867 3868 ~this()pure nothrow @safe @nogc{} 3869 } 3870 }