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 }