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