1 /* 2 ******************************************************************************************* 3 * Dgame (a D game framework) - Copyright (c) Randy Schütt 4 * 5 * This software is provided 'as-is', without any express or implied warranty. 6 * In no event will the authors be held liable for any damages arising from 7 * the use of this software. 8 * 9 * Permission is granted to anyone to use this software for any purpose, 10 * including commercial applications, and to alter it and redistribute it 11 * freely, subject to the following restrictions: 12 * 13 * 1. The origin of this software must not be misrepresented; you must not claim 14 * that you wrote the original software. If you use this software in a product, 15 * an acknowledgment in the product documentation would be appreciated but is 16 * not required. 17 * 18 * 2. Altered source versions must be plainly marked as such, and must not be 19 * misrepresented as being the original software. 20 * 21 * 3. This notice may not be removed or altered from any source distribution. 22 ******************************************************************************************* 23 */ 24 module Dgame.Internal.Unique; 25 26 debug import std.stdio; 27 private import Dgame.Internal.Allocator; 28 private import cstd = core.stdc.stdlib; 29 30 @property 31 string idOf(T)() { 32 static if (__traits(compiles, { string s = T.stringof; })) 33 return T.stringof; 34 else 35 return __traits(identifier, T); 36 } 37 38 void _def_del(T = void)(T* p) { 39 cstd.free(p); 40 } 41 42 struct unique_ptr(T) { 43 T* ptr; 44 void function(T*) del_func; 45 46 this(T* p, void function(T*) df = &_def_del!(T)) { 47 this.ptr = p; 48 this.del_func = df; 49 } 50 51 this(ref T* p, void function(T*) df = &_def_del!(T)) { 52 this.ptr = p; 53 this.del_func = df; 54 55 p = null; 56 } 57 58 @disable 59 this(this); 60 61 ~this() { 62 if (this.del_func is null || this.ptr is null) { 63 return; 64 } 65 66 debug writeln("Terminate unique ", idOf!(T)); 67 68 this.del_func(this.ptr); 69 } 70 71 T* release() pure nothrow { 72 scope(exit) this.ptr = null; 73 return this.ptr; 74 } 75 76 bool isValid() const pure nothrow { 77 return this.ptr !is null; 78 } 79 80 alias ptr this; 81 } 82 83 unique_ptr!(T) move(T)(ref unique_ptr!(T) uniq) { 84 return unique_ptr!(T)(uniq.release(), uniq.del_func); 85 } 86 87 unique_ptr!(T) make_unique(T)(auto ref T value, void function(T*) df = &_def_del!(T)) if (!is(T : U*, U)) { 88 T* p; 89 make(value, p); 90 91 return make_unique(p, df); 92 } 93 94 unique_ptr!(T) make_unique(T, Args...)(void function(T*) df, Args args) { 95 import std.conv : emplace; 96 97 T* p = alloc_new!(T)(1); 98 emplace(p, args); 99 100 return make_unique(p, df); 101 } 102 103 unique_ptr!(T) make_unique(T, Args...)(Args args) { 104 import std.conv : emplace; 105 106 T* p = alloc_new!(T)(1); 107 emplace(p, args); 108 109 return make_unique(p); 110 } 111 112 unique_ptr!(T) make_unique(T)(auto ref T* p, void function(T*) df = &_def_del!(T)) { 113 return unique_ptr!(T)(p, df); 114 } 115 116 unique_ptr!(T) allocate_unique(T)(size_t count, void function(T*) df = &_def_del!(T)) { 117 T* p = alloc_new!(T)(count); 118 119 return make_unique(p, df); 120 } 121 122 unittest { 123 struct A { 124 int id; 125 } 126 127 unique_ptr!(A) test(unique_ptr!(A) rhs) { 128 assert(rhs.isValid()); 129 assert(rhs.id == 42); 130 131 return move(rhs); 132 } 133 134 unique_ptr!(A) as = new A(42); 135 136 assert(as.isValid()); 137 assert(as.id == 42); 138 139 unique_ptr!(A) as2 = move(as); 140 141 assert(!as.isValid()); 142 assert(as2.isValid()); 143 assert(as2.id == 42); 144 145 unique_ptr!(A) as3 = test(move(as2)); 146 147 assert(!as2.isValid()); 148 assert(as3.isValid()); 149 assert(as3.id == 42); 150 }