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