1 /** 2 Taken from Phobos, tweaked for convenience 3 4 Copyright: Copyright the respective authors, 2008- 5 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 6 Authors: $(WEB erdani.org, Andrei Alexandrescu), 7 $(WEB bartoszmilewski.wordpress.com, Bartosz Milewski), 8 Don Clugston, 9 Shin Fujishiro, 10 Kenji Hara 11 */ 12 13 module memutils.unique; 14 15 import memutils.allocators; 16 import memutils.constants; 17 import memutils.utils; 18 19 import memutils.helpers; 20 21 22 // TODO: Move release() into Embed!, and add a releaseCheck() for refCounted (cannot release > 1 reference) 23 struct Unique(T, ALLOC = ThreadMem) 24 { 25 nothrow: 26 @trusted: 27 alias TR = RefTypeOf!T; 28 private TR m_object; 29 30 mixin Embed!(m_object, false); 31 enum NOGC = true; 32 enum isRefCounted = false; 33 enum isUnique = true; 34 35 enum ElemSize = AllocSize!T; 36 37 public: 38 /** 39 Constructor that takes an rvalue. 40 It will ensure uniqueness, as long as the rvalue 41 isn't just a view on an lvalue (e.g., a cast). 42 Typical usage: 43 ---- 44 Unique!Foo f = new Foo; 45 ---- 46 */ 47 this(inout TR p) 48 { 49 opAssign(cast(TR)p); 50 } 51 /** 52 Constructor that takes an lvalue. It nulls its source. 53 The nulling will ensure uniqueness as long as there 54 are no previous aliases to the source. 55 */ 56 this(ref TR p) 57 { 58 opAssign(p); 59 } 60 61 /** 62 Constructor that takes a $(D Unique) of a type that is convertible to our type. 63 64 Typically used to transfer a $(D Unique) rvalue of derived type to 65 a $(D Unique) of base type. 66 Example: 67 --- 68 class C : Object {} 69 70 Unique!C uc = new C; 71 Unique!Object uo = uc.release; 72 --- 73 */ 74 this(U)(Unique!U u) 75 if (is(u.TR:TR)) 76 { 77 // logTrace("Unique constructor converting from ", U.stringof); 78 opAssign(u.m_object); 79 u.m_object = null; 80 } 81 82 void free() 83 { 84 TR p = null; 85 opAssign(p); 86 } 87 88 void opAssign()(auto ref TR p) 89 { 90 if (m_object) destructRecurse(this); 91 if (!p) return; 92 //logTrace("Unique ctor of ", T.stringof, " : ", ptr.to!string); 93 m_object = p; 94 p = null; 95 } 96 /* 97 void opAssign(U)(in Unique!U p) 98 { 99 debug(Unique) logTrace("Unique opAssign converting from ", U.stringof); 100 // first delete any resource we own 101 destroy(this); 102 m_object = cast(TR)u.m_object; 103 cast(TR)u.m_object = null; 104 }*/ 105 106 /// Transfer ownership from a $(D Unique) of a type that is convertible to our type. 107 void opAssign(U)(Unique!U u) 108 if (is(u.TR:TR)) 109 { 110 opAssign(u.m_object); 111 u.m_object = null; 112 } 113 114 ~this() 115 { 116 //logDebug("Unique destructor of ", T.stringof, " : ", ptr); 117 118 119 static if (ALLOC.stringof != "void") { 120 if (m_object) { 121 //logTrace("ptr in ptree: ", ptr in ptree); 122 123 124 ObjectAllocator!(T, ALLOC).free(m_object); 125 126 //static if (HasDebugAllocations && DebugUnique) 127 // debug memset(ptr, 0, AllocSize!T); 128 } 129 } 130 } 131 /** Returns whether the resource exists. */ 132 @property bool isEmpty() const 133 { 134 return m_object is null; 135 } 136 137 /** Transfer ownership to a $(D Unique) rvalue. Nullifies the current contents. */ 138 TR release() 139 { 140 //logTrace("Release"); 141 if (!m_object) return null; 142 auto ret = m_object; 143 drop(); 144 return ret; 145 } 146 147 void drop() 148 { 149 //logTrace("Drop"); 150 if (!m_object) return; 151 m_object = null; 152 } 153 154 TR opUnary(string op)() if (op == "*") { return m_object; } 155 const(TR) opUnary(string op)() const if (op == "*") { return m_object; } 156 157 TR get() { return m_object; } 158 159 bool opCast(U : bool)() const { 160 return !isEmpty; 161 } 162 163 U opCast(U)() const nothrow 164 if (__traits(hasMember, U, "isUnique")) 165 { 166 if (!m_object) return Unique!(T, ALLOC)(); 167 return Unique!(U, ALLOC)(cast(U)this.m_object.release()); 168 } 169 170 U opCast(U)() const nothrow 171 if (!__traits(hasMember, U, "isUnique")) 172 { 173 if (!m_object) return cast(U)typeof(m_object).init; 174 return cast(U)this.m_object; 175 } 176 177 /** 178 Postblit operator is undefined to prevent the cloning of $(D Unique) objects. 179 */ 180 @disable this(this); 181 182 private: 183 184 @property void* ptr() const { 185 return cast(void*)m_object; 186 } 187 188 } 189 190 auto unique(T)(T obj) { 191 return Unique!T(obj); 192 }