1 module btl.autoptr.generational_ptr;
2 
3 import btl.internal.allocator;
4 import btl.internal.traits;
5 import btl.internal.gc;
6 
7 import btl.autoptr.common;
8 
9 
10 ///TODO:
11 template GenerationalPtr(
12     _Type,
13     _DestructorType = DestructorType!_Type,
14     bool _weakPtr = false
15 )if(isDestructorType!_DestructorType){
16 
17     static if (is(_Type == class) || is(_Type == interface) || is(_Type == struct) || is(_Type == union))
18         static assert(!__traits(isNested, _Type),
19             "SharedPtr does not support nested types."
20         );
21 
22     static assert(is(DestructorType!void : _DestructorType),
23         _Type.stringof ~ " wrong DestructorType " ~ DestructorType!void.stringof ~
24         " : " ~ _DestructorType.stringof
25     );
26 
27     void check_dtor()(){
28         static assert(is(DestructorType!_Type : _DestructorType),
29             "destructor of type '" ~ _Type.stringof ~
30             "' doesn't support specified finalizer " ~ _DestructorType.stringof
31         );
32     }
33 
34     import std.meta : AliasSeq;
35     import std.range : ElementEncodingType;
36     import std.traits: Unqual, Unconst, CopyTypeQualifiers, CopyConstness,
37         hasIndirections, hasElaborateDestructor,
38         isMutable, isAbstractClass, isDynamicArray, isStaticArray, isCallable, Select, isArray;
39 
40     import core.atomic : MemoryOrder;
41     import core.lifetime : forward;
42 
43     enum bool referenceElementType = isClassOrInterface!_Type || isDynamicArray!_Type;
44 
45     static if(isDynamicArray!_Type)
46         alias ElementDestructorType() = .DestructorType!void;
47     else
48         alias ElementDestructorType() = .DestructorType!_Type;
49 
50 
51     enum bool _isLockFree = false;
52 
53     struct GenerationalPtr{
54 
55         /**
56             Type of element managed by `SharedPtr`.
57         */
58         public alias ElementType = _Type;
59 
60 
61         /**
62             Type of destructor (`void function(void*)@attributes`).
63         */
64         public alias DestructorType = _DestructorType;
65 
66 
67         /**
68             Type of control block.
69         */
70         public alias ControlType = ControlBlock!void;
71 
72 
73         /**
74             `true` if `SharedPtr` is weak ptr.
75         */
76         public alias isWeak = _weakPtr;
77 
78 
79         /**
80             Same as `ElementType*` or `ElementType` if is class/interface/slice.
81         */
82         public alias ElementReferenceType = ElementReferenceTypeImpl!ElementType;
83 
84 
85         /**
86             Weak pointer
87 
88             `SharedPtr.WeakType` is a smart pointer that holds a non-owning ("weak") reference to an object that is managed by `SharedPtr`.
89             It must be converted to `SharedPtr` in order to access the referenced object.
90 
91             `SharedPtr.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,
92             `SharedPtr.WeakType` is used to track the object, and it is converted to `SharedPtr` to assume temporary ownership.
93             If the original `SharedPtr` is destroyed at this time, the object's lifetime is extended until the temporary `SharedPtr` is destroyed as well.
94 
95             Another use for `SharedPtr.WeakType` is to break reference cycles formed by objects managed by `SharedPtr`.
96             If such cycle is orphaned (i,e. there are no outside shared pointers into the cycle), the `SharedPtr` reference counts cannot reach zero and the memory is leaked.
97             To prevent this, one of the pointers in the cycle can be made weak.
98         */
99         static if(hasWeakCounter)
100             public alias WeakType = GenerationalPtr!(
101                 _Type,
102                 _DestructorType,
103                 true
104             );
105         else
106             public alias WeakType = void;
107 
108 
109         /**
110             Type of non weak ptr.
111         */
112         public alias OwningType = GenerationalPtr!(
113             _Type,
114             _DestructorType,
115             false
116         );
117 
118 
119 
120         /**
121             `true` if shared `SharedPtr` has lock free operations `store`, `load`, `exchange`, `compareExchange`, otherwise 'false'
122         */
123         public alias isLockFree = _isLockFree;
124 
125 
126 
127         private ElementReferenceType _element;
128 
129         static if(isWeak)
130             private size_t _generation;
131 
132         private void _set_element(ElementReferenceType e)pure nothrow @system @nogc{
133             static if(isMutable!ElementReferenceType)
134                 this._element = e;
135             else
136                 (*cast(Unqual!ElementReferenceType*)&this._element) = cast(Unqual!ElementReferenceType)e;
137         }
138 
139         private void _const_set_element(ElementReferenceType e)const pure nothrow @system @nogc{
140             auto self = cast(Unqual!(typeof(this))*)&this;
141 
142             static if(isMutable!ElementReferenceType)
143                 self._element = e;
144             else
145                 (*cast(Unqual!ElementReferenceType*)&self._element) = cast(Unqual!ElementReferenceType)e;
146         }
147 
148         private void _release()scope{
149             if(false){
150                 DestructorType dt;
151                 dt(null);
152             }
153 
154             import std.traits : hasIndirections;
155             import core.memory : GC;
156 
157             if(this._control !is null)
158                 this._control.release!isWeak;
159         }
160 
161         private void _reset()scope pure nothrow @system @nogc{
162             this._control = null;
163             this._set_element(null);
164         }
165 
166         private void _const_reset()scope const pure nothrow @system @nogc{
167             this._const_set_counter(null);
168             this._const_set_element(null);
169         }
170 
171         package auto _move()@trusted{
172             auto e = this._element;
173             auto c = this._control;
174             this._const_reset();
175 
176             return typeof(this)(c, e);
177         }
178     }
179 }