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 }