]> git.sesse.net Git - casparcg/blob - common/memory/safe_ptr.h
29df7f990aa623c6e9d3e1c18179790f080a24e8
[casparcg] / common / memory / safe_ptr.h
1 #pragma once\r
2 \r
3 #include <memory>\r
4 #include <stdexcept>\r
5 #include <type_traits>\r
6 \r
7 namespace caspar\r
8 {\r
9 \r
10 template<typename T>\r
11 class safe_ptr\r
12 {   \r
13     template <typename> friend class safe_ptr;\r
14 public:\r
15     typedef T  element_type;\r
16 \r
17     safe_ptr(); // will construct new T object using make_safe<T>()\r
18 \r
19     safe_ptr(const safe_ptr& other) \r
20         : p_(other.p_)\r
21     {\r
22     }\r
23 \r
24     template<typename U>\r
25     safe_ptr(const safe_ptr<U>& other, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) \r
26         : p_(other.p_)\r
27     {\r
28     }\r
29 \r
30     safe_ptr(safe_ptr&& other) \r
31         : p_(other.p_)\r
32     {\r
33     }\r
34 \r
35     template<typename U>\r
36     safe_ptr(safe_ptr<U>&& other, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) \r
37         : p_(other.p_)\r
38     {\r
39     }\r
40         \r
41     template<typename U>    \r
42     explicit safe_ptr(const std::shared_ptr<U>& p, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) \r
43         : p_(p)\r
44     {\r
45         if(!p)\r
46             throw std::invalid_argument("p");\r
47     }\r
48 \r
49     template<typename U>    \r
50     explicit safe_ptr(std::shared_ptr<U>&& p, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) \r
51         : p_(std::move(p))\r
52     {\r
53         if(!p_)\r
54             throw std::invalid_argument("p");\r
55     }\r
56 \r
57     template<typename U>    \r
58     explicit safe_ptr(U* p, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) \r
59         : p_(p)\r
60     {\r
61         if(!p)\r
62             throw std::invalid_argument("p");\r
63     }\r
64 \r
65     template<typename U, typename D>    \r
66     explicit safe_ptr(U* p, D d, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) \r
67         : p_(p, d)\r
68     {\r
69         if(!p)\r
70             throw std::invalid_argument("p");\r
71     }\r
72     \r
73     template<typename U>\r
74     typename std::enable_if<std::is_convertible<U*, T*>::value, safe_ptr&>::type\r
75     operator=(const safe_ptr<U>& other)\r
76     {\r
77         safe_ptr(other).swap(*this);\r
78         return *this;\r
79     }\r
80 \r
81     template<typename U>\r
82     typename std::enable_if<std::is_convertible<U*, T*>::value, safe_ptr&>::type\r
83     operator=(safe_ptr<U>&& other)\r
84     {\r
85         safe_ptr<T>(std::move(other)).swap(*this);\r
86         return *this;\r
87     }\r
88         \r
89     T& operator*() const \r
90     { \r
91         return *p_.get();\r
92     }\r
93 \r
94     T* operator->() const \r
95     { \r
96         return p_.get();\r
97     }\r
98 \r
99     T* get() const \r
100     { \r
101         return p_.get();\r
102     }\r
103 \r
104     bool unique() const \r
105     { \r
106         return p_.unique();\r
107     }\r
108 \r
109     long use_count() const \r
110     {\r
111         return p_.use_count();\r
112     }\r
113 \r
114     void swap(safe_ptr& other) \r
115     { \r
116         p_.swap(other.p_); \r
117     } \r
118 \r
119     operator std::shared_ptr<T>() const \r
120     { \r
121         return p_;\r
122     }\r
123 \r
124     operator std::weak_ptr<T>() const \r
125     { \r
126         return std::weak_ptr<T>(p_);\r
127     }\r
128     \r
129     template<class U>\r
130     bool owner_before(const safe_ptr& ptr)\r
131     { \r
132         return p_.owner_before(ptr.p_); \r
133     }\r
134 \r
135     template<class U>\r
136     bool owner_before(const std::shared_ptr<U>& ptr)\r
137     { \r
138         return p_.owner_before(ptr); \r
139     }\r
140 \r
141     template<class D, class U> \r
142     D* get_deleter(safe_ptr<U> const& ptr) \r
143     { \r
144         return p_.get_deleter(); \r
145     }\r
146 \r
147 private:    \r
148     std::shared_ptr<T> p_;\r
149 };\r
150 \r
151 template<class T, class U>\r
152 bool operator==(const safe_ptr<T>& a, const safe_ptr<U>& b)\r
153 {\r
154     return a.get() == b.get();\r
155 }\r
156 \r
157 template<class T, class U>\r
158 bool operator==(const std::shared_ptr<T>& a, const safe_ptr<U>& b)\r
159 {\r
160     return a.get() == b.get();\r
161 }\r
162 \r
163 template<class T, class U>\r
164 bool operator==(const safe_ptr<T>& a, const std::shared_ptr<U>& b)\r
165 {\r
166     return a.get() == b.get();\r
167 }\r
168 \r
169 template<class T, class U>\r
170 bool operator!=(const safe_ptr<T>& a, const safe_ptr<U>& b)\r
171 {\r
172     return a.get() != b.get();\r
173 }\r
174 \r
175 template<class T, class U>\r
176 bool operator!=(const std::shared_ptr<T>& a, const safe_ptr<U>& b)\r
177 {\r
178     return a.get() != b.get();\r
179 }\r
180 \r
181 template<class T, class U>\r
182 bool operator!=(const safe_ptr<T>& a, const std::shared_ptr<U>& b)\r
183 {\r
184     return a.get() != b.get();\r
185 }\r
186 \r
187 template<class T, class U>\r
188 bool operator<(const safe_ptr<T>& a, const safe_ptr<U>& b)\r
189 {\r
190     return a.get() < b.get();\r
191 }\r
192 \r
193 template<class T, class U>\r
194 bool operator<(const std::shared_ptr<T>& a, const safe_ptr<U>& b)\r
195 {\r
196     return a.get() < b.get();\r
197 }\r
198 \r
199 template<class T, class U>\r
200 bool operator<(const safe_ptr<T>& a, const std::shared_ptr<U>& b)\r
201 {\r
202     return a.get() < b.get();\r
203 }\r
204 \r
205 template<class T, class U>\r
206 bool operator>(const safe_ptr<T>& a, const safe_ptr<U>& b)\r
207 {\r
208     return a.get() > b.get();\r
209 }\r
210 \r
211 template<class T, class U>\r
212 bool operator>(const std::shared_ptr<T>& a, const safe_ptr<U>& b)\r
213 {\r
214     return a.get() > b.get();\r
215 }\r
216 \r
217 template<class T, class U>\r
218 bool operator>(const safe_ptr<T>& a, const std::shared_ptr<U>& b)\r
219 {\r
220     return a.get() > b.get();\r
221 }\r
222 \r
223 template<class T, class U>\r
224 bool operator>=(const safe_ptr<T>& a, const safe_ptr<U>& b)\r
225 {\r
226     return a.get() >= b.get();\r
227 }\r
228 \r
229 template<class T, class U>\r
230 bool operator>=(const std::shared_ptr<T>& a, const safe_ptr<U>& b)\r
231 {\r
232     return a.get() >= b.get();\r
233 }\r
234 \r
235 template<class T, class U>\r
236 bool operator>=(const safe_ptr<T>& a, const std::shared_ptr<U>& b)\r
237 {\r
238     return a.get() >= b.get();\r
239 }\r
240 \r
241 template<class T, class U>\r
242 bool operator<=(const safe_ptr<T>& a, const safe_ptr<U>& b)\r
243 {\r
244     return a.get() <= b.get();\r
245 }\r
246 \r
247 template<class T, class U>\r
248 bool operator<=(const std::shared_ptr<T>& a, const safe_ptr<U>& b)\r
249 {\r
250     return a.get() <= b.get();\r
251 }\r
252 \r
253 template<class T, class U>\r
254 bool operator<=(const safe_ptr<T>& a, const std::shared_ptr<U>& b)\r
255 {\r
256     return a.get() <= b.get();\r
257 }\r
258 \r
259 template<class E, class T, class U>\r
260 std::basic_ostream<E, T>& operator<<(std::basic_ostream<E, T>& out, const safe_ptr<U>& p)\r
261 {\r
262     return out << p.get();\r
263 }\r
264 \r
265 template<class T> \r
266 void swap(safe_ptr<T>& a, safe_ptr<T>& b)\r
267 {\r
268     a.swap(b);\r
269 }\r
270 \r
271 template<class T> \r
272 T* get_pointer(safe_ptr<T> const& p)\r
273 {\r
274     return p.get();\r
275 }\r
276 \r
277 template <class T, class U>\r
278 safe_ptr<T> static_pointer_cast(const safe_ptr<U>& p)\r
279 {\r
280     return safe_ptr<T>(std::static_pointer_cast<T>(std::shared_ptr<U>(p)));\r
281 }\r
282 \r
283 template <class T, class U>\r
284 safe_ptr<T> const_pointer_cast(const safe_ptr<U>& p)\r
285 {\r
286     return safe_ptr<T>(std::const_pointer_cast<T>(std::shared_ptr<U>(p)));\r
287 }\r
288 \r
289 template <class T, class U>\r
290 safe_ptr<T> dynamic_pointer_cast(const safe_ptr<U>& p)\r
291 {\r
292     auto temp = std::dynamic_pointer_cast<T>(std::shared_ptr<U>(p));\r
293     if(!temp)\r
294         throw std::bad_cast();\r
295     return safe_ptr<T>(std::move(temp));\r
296 }\r
297 \r
298 //\r
299 // enable_safe_this \r
300 //\r
301 // A safe_ptr version of enable_shared_from_this.\r
302 // So that an object may get safe_ptr objects to itself.\r
303 //\r
304 \r
305 template<class T>\r
306 class enable_safe_from_this : public std::enable_shared_from_this<T>\r
307 {\r
308 public:\r
309     safe_ptr<T> safe_from_this() \r
310     {\r
311         return safe_ptr<T>(this->shared_from_this());\r
312     }\r
313 \r
314     safe_ptr<T const> safe_from_this() const \r
315     {\r
316         return safe_ptr<T const>(this->shared_from_this());\r
317     }\r
318 protected:\r
319     enable_safe_from_this()\r
320     {\r
321     }\r
322     \r
323     enable_safe_from_this(const enable_safe_from_this&)\r
324     {\r
325     }\r
326     \r
327     enable_safe_from_this& operator=(const enable_safe_from_this&)\r
328     {        \r
329         return *this;\r
330     }\r
331     \r
332     ~enable_safe_from_this ()\r
333     {\r
334     }\r
335 };\r
336 \r
337 //\r
338 // make_safe\r
339 //\r
340 // safe_ptr equivalents to make_shared\r
341 //\r
342 \r
343 template<typename T>\r
344 safe_ptr<T> make_safe_ptr(const std::shared_ptr<T>& ptr)\r
345 {\r
346         return safe_ptr<T>(ptr);\r
347 }\r
348 \r
349 template<typename T>\r
350 safe_ptr<T> make_safe_ptr(std::shared_ptr<T>&& ptr)\r
351 {\r
352         return safe_ptr<T>(ptr);\r
353 }\r
354 \r
355 template<typename T>\r
356 safe_ptr<T> make_safe()\r
357 {\r
358     return safe_ptr<T>(std::make_shared<T>());\r
359 }\r
360 \r
361 template<typename T, typename P0>\r
362 safe_ptr<T> make_safe(P0&& p0)\r
363 {\r
364     return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0)));\r
365 }\r
366 \r
367 template<typename T, typename P0, typename P1>\r
368 safe_ptr<T> make_safe(P0&& p0, P1&& p1)\r
369 {\r
370     return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1)));\r
371 }\r
372 \r
373 template<typename T, typename P0, typename P1, typename P2>\r
374 safe_ptr<T> make_safe(P0&& p0, P1&& p1, P2&& p2)\r
375 {\r
376     return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2)));\r
377 }\r
378 \r
379 template<typename T, typename P0, typename P1, typename P2, typename P3>\r
380 safe_ptr<T> make_safe(P0&& p0, P1&& p1, P2&& p2, P3&& p3)\r
381 {\r
382     return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3)));\r
383 }\r
384 \r
385 template<typename T, typename P0, typename P1, typename P2, typename P3, typename P4>\r
386 safe_ptr<T> make_safe(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4)\r
387 {\r
388     return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3), std::forward<P4>(p4)));\r
389 }\r
390 \r
391 template<typename T, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5>\r
392 safe_ptr<T> make_safe(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4, P5&& p5)\r
393 {\r
394     return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2), std::forward<P3>(p3), std::forward<P4>(p4), std::forward<P5>(p5)));\r
395 }\r
396 \r
397 template<typename T>\r
398 safe_ptr<T>::safe_ptr() \r
399     : p_(make_safe<T>())\r
400 {\r
401\r
402 \r
403 } // namespace\r