IntrusivePtr

Implementation of a ref counted pointer that points to an object with an embedded reference counter btl.autoptr.common.ControlBlock.

IntrusivePtr retains shared ownership of an object through a pointer.

Several ref counted pointer objects may own the same object.

The object is destroyed and its memory deallocated when either of the following happens:

1. the last remaining ref counted pointer owning the object is destroyed.

2. the last remaining ref counted pointer owning the object is assigned another pointer via various methods like opAssign and store.

The object is destroyed using destructor of type _Type.

A IntrusivePtr can not share ownership of an object while storing a pointer to another object (use SharedPtr for that).

A IntrusivePtr may also own no objects, in which case it is called empty.

_Type must contain one property of type ControlBlock (this property contains ref counting). If this property is shared then ref counting is atomic.

If _Type is const/immutable then ControlBlock cannot be modified => ref counting doesn't work and IntrusivePtr can be only moved.

If multiple threads of execution access the same IntrusivePtr (shared IntrusivePtr) then only some methods can be called (load, store, exchange, compareExchange, useCount).

Template parameters:

_Type type of managed object

_weakPtr if true then IntrusivePtr represent weak ptr

  1. template IntrusivePtr(_Type, bool _weakPtr = false)
    template IntrusivePtr (
    _Type
    bool _weakPtr = false
    ) {}
  2. template IntrusivePtr(_Type, _DestructorType, _ControlType = IntrusiveControlBlock!_Type, bool _weakPtr = false)
  3. template IntrusivePtr(_Type, _ControlType, _DestructorType, bool _weakPtr = false)

Members

Aliases

_ControlType
alias _ControlType = IntrusiveControlBlock!_Type
Undocumented in source.

Imports

AliasSeq (from std.meta)
public import std.meta : AliasSeq;
Undocumented in source.
CopyConstness (from std.traits)
public import std.traits : Unqual, Unconst, CopyTypeQualifiers, CopyConstness, PointerTarget, hasIndirections, hasElaborateDestructor, isMutable, isAbstractClass, isDynamicArray, isStaticArray, isCallable, Select, isArray;
Undocumented in source.
CopyTypeQualifiers (from std.traits)
public import std.traits : Unqual, Unconst, CopyTypeQualifiers, CopyConstness, PointerTarget, hasIndirections, hasElaborateDestructor, isMutable, isAbstractClass, isDynamicArray, isStaticArray, isCallable, Select, isArray;
Undocumented in source.
ElementEncodingType (from std.range)
public import std.range : ElementEncodingType;
Undocumented in source.
MemoryOrder (from core.atomic)
public import core.atomic : MemoryOrder;
Undocumented in source.
PointerTarget (from std.traits)
public import std.traits : Unqual, Unconst, CopyTypeQualifiers, CopyConstness, PointerTarget, hasIndirections, hasElaborateDestructor, isMutable, isAbstractClass, isDynamicArray, isStaticArray, isCallable, Select, isArray;
Undocumented in source.
Select (from std.traits)
public import std.traits : Unqual, Unconst, CopyTypeQualifiers, CopyConstness, PointerTarget, hasIndirections, hasElaborateDestructor, isMutable, isAbstractClass, isDynamicArray, isStaticArray, isCallable, Select, isArray;
Undocumented in source.
Unconst (from std.traits)
public import std.traits : Unqual, Unconst, CopyTypeQualifiers, CopyConstness, PointerTarget, hasIndirections, hasElaborateDestructor, isMutable, isAbstractClass, isDynamicArray, isStaticArray, isCallable, Select, isArray;
Undocumented in source.
Unqual (from std.traits)
public import std.traits : Unqual, Unconst, CopyTypeQualifiers, CopyConstness, PointerTarget, hasIndirections, hasElaborateDestructor, isMutable, isAbstractClass, isDynamicArray, isStaticArray, isCallable, Select, isArray;
Undocumented in source.
forward (from core.lifetime)
public import core.lifetime : forward;
Undocumented in source.
hasElaborateDestructor (from std.traits)
public import std.traits : Unqual, Unconst, CopyTypeQualifiers, CopyConstness, PointerTarget, hasIndirections, hasElaborateDestructor, isMutable, isAbstractClass, isDynamicArray, isStaticArray, isCallable, Select, isArray;
Undocumented in source.
hasIndirections (from std.traits)
public import std.traits : Unqual, Unconst, CopyTypeQualifiers, CopyConstness, PointerTarget, hasIndirections, hasElaborateDestructor, isMutable, isAbstractClass, isDynamicArray, isStaticArray, isCallable, Select, isArray;
Undocumented in source.
isAbstractClass (from std.traits)
public import std.traits : Unqual, Unconst, CopyTypeQualifiers, CopyConstness, PointerTarget, hasIndirections, hasElaborateDestructor, isMutable, isAbstractClass, isDynamicArray, isStaticArray, isCallable, Select, isArray;
Undocumented in source.
isArray (from std.traits)
public import std.traits : Unqual, Unconst, CopyTypeQualifiers, CopyConstness, PointerTarget, hasIndirections, hasElaborateDestructor, isMutable, isAbstractClass, isDynamicArray, isStaticArray, isCallable, Select, isArray;
Undocumented in source.
isCallable (from std.traits)
public import std.traits : Unqual, Unconst, CopyTypeQualifiers, CopyConstness, PointerTarget, hasIndirections, hasElaborateDestructor, isMutable, isAbstractClass, isDynamicArray, isStaticArray, isCallable, Select, isArray;
Undocumented in source.
isDynamicArray (from std.traits)
public import std.traits : Unqual, Unconst, CopyTypeQualifiers, CopyConstness, PointerTarget, hasIndirections, hasElaborateDestructor, isMutable, isAbstractClass, isDynamicArray, isStaticArray, isCallable, Select, isArray;
Undocumented in source.
isMutable (from std.traits)
public import std.traits : Unqual, Unconst, CopyTypeQualifiers, CopyConstness, PointerTarget, hasIndirections, hasElaborateDestructor, isMutable, isAbstractClass, isDynamicArray, isStaticArray, isCallable, Select, isArray;
Undocumented in source.
isStaticArray (from std.traits)
public import std.traits : Unqual, Unconst, CopyTypeQualifiers, CopyConstness, PointerTarget, hasIndirections, hasElaborateDestructor, isMutable, isAbstractClass, isDynamicArray, isStaticArray, isCallable, Select, isArray;
Undocumented in source.

Structs

IntrusivePtr
struct IntrusivePtr
Undocumented in source.

Variables

_isLockFree
enum bool _isLockFree;
Undocumented in source.
hasSharedCounter
enum bool hasSharedCounter;
Undocumented in source.
hasWeakCounter
enum bool hasWeakCounter;
Undocumented in source.

Examples

1 static struct Struct{
2     ControlBlock!(int, int) control;
3     int i;
4 
5     this(int i)pure nothrow @safe @nogc{
6         this.i = i;
7     }
8 }
9 
10 static class Base{
11     int i;
12     ControlBlock!(int, int) control;
13 
14     this(int i)pure nothrow @safe @nogc{
15         this.i = i;
16     }
17 }
18 static class Derived : Base{
19     double d;
20 
21     this(int i, double d)pure nothrow @safe @nogc{
22         super(i);
23         this.d = d;
24     }
25 }
26 static class Class : Derived{
27     bool b;
28     this(int i, double d, bool b)pure nothrow @safe @nogc{
29         super(i, d);
30         this.b = b;
31     }
32 }
33 
34 ///simple:
35 {
36     IntrusivePtr!Struct a = IntrusivePtr!Struct.make(42);
37     assert(a.useCount == 1);
38 
39     IntrusivePtr!(const Struct) b = a;
40     assert(a.useCount == 2);
41 
42     IntrusivePtr!Struct.WeakType w = a.weak;
43     assert(a.useCount == 2);
44     assert(a.weakCount == 1);
45 
46     IntrusivePtr!Struct c = w.lock;
47     assert(a.useCount == 3);
48     assert(a.weakCount == 1);
49 
50     assert(c.get.i == 42);
51 }
52 
53 ///polymorphism and aliasing:
54 {
55     ///create IntrusivePtr
56     IntrusivePtr!Base foo = IntrusivePtr!Derived.make(42, 3.14);
57     IntrusivePtr!Class zee = IntrusivePtr!Class.make(42, 3.14, false);
58 
59     ///dynamic cast:
60     IntrusivePtr!Derived bar = dynCast!Derived(foo);
61     assert(bar != null);
62     assert(foo.useCount == 2);
63 
64     ///this doesnt work because Foo destructor attributes are more restrictive then Class's:
65     //IntrusivePtr!Class x = zee;
66 
67     ///this does work:
68     IntrusivePtr!Base x = zee;
69     assert(zee.useCount == 2);
70 }
71 
72 
73 ///multi threading:
74 {
75     ///create IntrusivePtr with atomic ref counting
76     IntrusivePtr!(shared Base) foo = IntrusivePtr!(shared Derived).make(42, 3.14);
77 
78     ///this doesnt work:
79     //foo.get.i += 1;
80 
81     import core.atomic : atomicFetchAdd;
82     atomicFetchAdd(foo.get.i, 1);
83     assert(foo.get.i == 43);
84 
85 
86     ///creating `shared(IntrusivePtr)`:
87     shared IntrusivePtr!(shared Derived) bar = share(dynCast!Derived(foo));
88 
89     ///`shared(IntrusivePtr)` is lock free (except `load` and `useCount`/`weakCount`).
90     static assert(typeof(bar).isLockFree == true);
91 
92     ///multi thread operations (`load`, `store`, `exchange` and `compareExchange`):
93     IntrusivePtr!(shared Derived) bar2 = bar.load();
94     assert(bar2 != null);
95     assert(bar2.useCount == 3);
96 
97     IntrusivePtr!(shared Derived) bar3 = bar.exchange(null);
98     assert(bar3 != null);
99     assert(bar3.useCount == 3);
100 }
//make IntrusivePtr object
static struct Foo{
    ControlBlock!(int, int) c;
    int i;

    this(int i)pure nothrow @safe @nogc{
        this.i = i;
    }
}

{
    auto foo = IntrusivePtr!Foo.make(42);
    auto foo2 = IntrusivePtr!Foo.make!Mallocator(42);  //explicit stateless allocator
}
import std.experimental.allocator : make, dispose, allocatorObject;

static struct Foo{
    ControlBlock!(int, int) c;
    int i;

    this(int i)pure nothrow @safe @nogc{
        this.i = i;
    }

    ~this(){
        if(false)
            auto allocator = allocatorObject(Mallocator.instance);
    }
}

//alloc IntrusivePtr object

auto allocator = allocatorObject(Mallocator.instance);

{
    auto x = IntrusivePtr!Foo.alloc(allocator, 42);
}

Meta