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