1 module m3.SmartPointer;
2 
3 private:
4 
5 static import m3.m3;
6 
7 debug(m3) {
8     static import core.stdc.stdio;
9     alias printf = core.stdc.stdio.printf;
10 }
11 
12 static import std.traits;
13 alias isArray = std.traits.isArray;
14 
15 public:
16 
17 /* Unique Ptr */
18 
19 struct UniquePtr(T) {
20     static assert(!isArray!(T), "Arrays aren't allowed for UniquePtr");
21 
22     alias Type = m3.m3.TypeOf!(T);
23     alias Deleter = void function(Type) @nogc;
24 
25 private:
26     Type _data;
27     Deleter _deleter;
28 
29 public:
30     @nogc
31     this(Type data, Deleter deleter = &m3.m3.destruct!(T)) nothrow {
32         _data = data;
33         _deleter = deleter;
34     }
35 
36     @disable
37     this(this);
38 
39     @nogc
40     ~this() {
41         if (_data)
42             _deleter(_data);
43     }
44 
45     @nogc
46     Type release() pure nothrow {
47         scope(exit) _data = null;
48         return _data;
49     }
50 
51     @nogc
52     @property
53     inout(Type) get() inout pure nothrow {
54         return _data;
55     }
56 
57     alias get this;
58 }
59 
60 @nogc
61 UniquePtr!(T) makeUnique(T)(T* data) {
62     return UniquePtr!(T)(data);
63 }
64 
65 @nogc
66 UniquePtr!(T) makeUnique(T)(T* data, UniquePtr!(T).Deleter deleter) {
67     return UniquePtr!(T)(data, deleter);
68 }
69 
70 @nogc
71 UniquePtr!(T) makeUnique(T)(T data) if (is(T == class)) {
72     return UniquePtr!(T)(data);
73 }
74 
75 @nogc
76 UniquePtr!(T) makeUnique(T)(T data, UniquePtr!(T).Deleter deleter) if (is(T == class)) {
77     return UniquePtr!(T)(data, deleter);
78 }
79 
80 @nogc
81 UniquePtr!(T) makeUnique(T, Args...)(auto ref Args args) {
82     return UniquePtr!(T)(m3.m3.make!(T)(args));
83 }
84 
85 @nogc
86 UniquePtr!(T) makeUnique(T, Args...)(UniquePtr!(T).Deleter deleter, auto ref Args args) {
87     return UniquePtr!(T)(m3.m3.make!(T)(args), deleter);
88 }
89 
90 /* Shared Ptr */
91 
92 struct SharedPtr(T) {
93     static assert(!isArray!(T), "Arrays aren't allowed for SharedPtr");
94 
95     alias Type = m3.m3.TypeOf!(T);
96     alias Deleter = void function(Type) @nogc;
97 
98 private:
99     Type _data;
100     Deleter _deleter;
101     int* _useCounter;
102 
103 public:
104     @nogc
105     this(Type data, Deleter deleter = &m3.m3.destruct!(T)) nothrow {
106         _data = data;
107         _deleter = deleter;
108         _useCounter = m3.m3.make!(int)(1);
109     }
110 
111     @nogc
112     this(this) {
113         if (_useCounter)
114             (*_useCounter)++;
115     }
116 
117     @nogc
118     ~this() {
119         if (_useCounter) {
120             (*_useCounter)--;
121             
122             if (*_useCounter <= 0) {
123                 if (_data)
124                     _deleter(_data);
125                 m3.m3.destruct(_useCounter);
126             }
127         }
128     }
129 
130     @nogc
131     Type release() pure nothrow {
132         scope(exit) _data = null;
133         return _data;
134     }
135 
136     @nogc
137     @property
138     int useCount() const pure nothrow {
139         return _useCounter ? *_useCounter : 0;
140     }
141 
142     @nogc
143     @property
144     inout(Type) get() inout pure nothrow {
145         return _data;
146     }
147 
148     alias get this;
149 }
150 
151 @nogc
152 SharedPtr!(T) makeShared(T)(T* data) {
153     return SharedPtr!(T)(data);
154 }
155 
156 @nogc
157 SharedPtr!(T) makeShared(T)(T* data, SharedPtr!(T).Deleter deleter) {
158     return SharedPtr!(T)(data, deleter);
159 }
160 
161 @nogc
162 SharedPtr!(T) makeShared(T)(T data) if (is(T == class)) {
163     return SharedPtr!(T)(data);
164 }
165 
166 @nogc
167 SharedPtr!(T) makeShared(T)(T data, SharedPtr!(T).Deleter deleter) if (is(T == class)) {
168     return SharedPtr!(T)(data, deleter);
169 }
170 
171 @nogc
172 SharedPtr!(T) makeShared(T, Args...)(auto ref Args args) {
173     return SharedPtr!(T)(m3.m3.make!(T)(args));
174 }
175 
176 @nogc
177 SharedPtr!(T) makeShared(T, Args...)(SharedPtr!(T).Deleter deleter, auto ref Args args) {
178     return SharedPtr!(T)(m3.m3.make!(T)(args), deleter);
179 }
180 
181 version (unittest) {
182     class A {
183     @nogc:
184 
185         int id;
186 
187         this(int i) {
188             this.id = i;
189         }
190         
191         ~this() {
192             debug(m3) printf("DTor A\n");
193         }
194         
195         int getId() const {
196             return this.id;
197         }
198     }
199 
200     class B : A {
201     @nogc:
202 
203         this(int i) {
204             super(i);
205         }
206         
207         ~this() {
208             debug(m3) printf("DTor B\n");
209         }
210     }
211 
212     struct C {
213     @nogc:
214 
215         int id;
216         
217         this(int i) {
218             this.id = i;
219         }
220 
221         ~this() {
222             debug(m3) printf("DTor C\n");
223         }
224         
225         int getId() const {
226             return this.id;
227         }
228     }
229 
230     __gshared int sdl_deleter = 0;
231 
232     struct _SDL_Surface { }
233 
234     @nogc
235     void _SDL_FreeSurface(_SDL_Surface*) {
236         sdl_deleter++;
237     }
238 }
239 
240 @nogc
241 unittest {
242     debug(m3) printf("\n ---- UniquePtr Test started ---- \n");
243 
244     UniquePtr!(C) uc = makeUnique!(C)(42);
245     assert(uc.id == 42 && uc.getId() == 42);
246 
247     UniquePtr!(A) uc2 = makeUnique(m3.m3.make!(A)(23));
248     assert(uc2.id == 23 && uc2.getId() == 23);
249 
250     UniquePtr!(A) uc3 = makeUnique!(A)(42);
251     assert(uc3.id == 42 && uc3.getId() == 42);
252 
253     assert(!__traits(compiles, { auto uc4 = uc3; }));
254 
255     C* c = m3.m3.make!(C)(23);
256     assert(c.id == 23 && c.getId() == 23);
257 
258     UniquePtr!(C) uc4 = makeUnique(c);
259     assert(c == uc4.get);
260     assert(uc4.id == c.id && uc4.getId() == c.getId());
261 
262     int[] arr = m3.m3.make!(int[])(42);
263     UniquePtr!(int) uc5 = makeUnique(arr.ptr);
264     assert(uc5.get == arr.ptr);
265 
266     {
267         _SDL_Surface* sdl_srfc = m3.m3.make!(_SDL_Surface);
268         //UniquePtr!(_SDL_Surface).Deleter sdl_del = (_SDL_Surface* p) @nogc { _SDL_FreeSurface(p); p = null; };
269         UniquePtr!(_SDL_Surface) srfc = makeUnique!(_SDL_Surface)(sdl_srfc, function(_SDL_Surface* p) { _SDL_FreeSurface(p); p = null; debug(m3)printf("UniquePtr: _SDL_FreeSurface\n"); });
270     }
271 
272     assert(sdl_deleter == 1);
273 
274     debug(m3) printf("\n ---- UniquePtr Test ended ---- \n");
275 }
276 
277 @nogc
278 unittest {
279     debug(m3) printf("\n ---- SharedPtr Test started ---- \n");
280 
281     SharedPtr!(C) sc = makeShared!(C)(42);
282     assert(sc.id == 42 && sc.getId() == 42);
283     assert(sc.useCount == 1);
284 
285     SharedPtr!(A) sc2 = makeShared(m3.m3.make!(A)(23));
286     assert(sc2.id == 23 && sc2.getId() == 23);
287     assert(sc2.useCount == 1);
288 
289     SharedPtr!(A) sc3 = makeShared!(A)(42);
290     assert(sc3.id == 42 && sc3.getId() == 42);
291     assert(sc3.useCount == 1);
292 
293     {
294         SharedPtr!(A) sc4 = sc3;
295         assert(sc4.id == 42 && sc3.getId() == 42);
296         assert(sc4.id == sc3.id && sc3.getId() == sc3.getId());
297         assert(sc3.useCount == 2);
298         assert(sc4.useCount == 2);
299     }
300 
301     assert(sc3.useCount == 1);
302 
303     C* c = m3.m3.make!(C)(23);
304     SharedPtr!(C) sc5 = makeShared(c);
305     assert(c == sc5.get);
306     assert(sc5.id == c.id && sc5.getId() == c.getId());
307 
308     int[] arr = m3.m3.make!(int[])(42);
309     SharedPtr!(int) sc6 = makeShared(arr.ptr);
310     assert(sc6.get == arr.ptr);
311 
312     {
313         SharedPtr!(_SDL_Surface) srfc1;
314         assert(srfc1.useCount == 0);
315 
316         {
317             _SDL_Surface* sdl_srfc = m3.m3.make!(_SDL_Surface);
318             //SharedPtr!(_SDL_Surface).Deleter sdl_del = (_SDL_Surface* p) @nogc { _SDL_FreeSurface(p); p = null; };
319             SharedPtr!(_SDL_Surface) srfc2 = makeShared!(_SDL_Surface)(sdl_srfc, function(_SDL_Surface* p) { _SDL_FreeSurface(p); p = null; debug(m3) printf("SharedPtr: _SDL_FreeSurface\n"); });
320 
321             assert(srfc1.useCount == 0);
322             assert(srfc2.useCount == 1);
323             
324             srfc1 = srfc2;
325 
326             assert(srfc1.useCount == 2);
327             assert(srfc2.useCount == 2);
328         }
329 
330         assert(srfc1.useCount == 1);
331         assert(sdl_deleter == 1);
332     }
333 
334     assert(sdl_deleter == 2);
335     
336     debug(m3) printf("\n ---- SharedPtr Test ended ---- \n");
337 }