]> git.sesse.net Git - casparcg/blob - common/utility/safe_ptr.h
2.0.0.2:
[casparcg] / common / utility / safe_ptr.h
1 #pragma once\r
2 \r
3 #include "../exception/exceptions.h"\r
4 \r
5 #include <memory>\r
6 #include <vector>\r
7 #include <type_traits>\r
8 \r
9 namespace caspar {\r
10         \r
11 template<typename T>\r
12 class safe_ptr\r
13 {       \r
14         template <typename> friend class safe_ptr;\r
15 public:\r
16         typedef T element_type;\r
17         \r
18         safe_ptr() : impl_(std::make_shared<T>()){static_assert(!std::is_abstract<T>::value, "Cannot construct abstract class.");}      \r
19         \r
20         safe_ptr(const safe_ptr<T>& other) : impl_(other.impl_){}\r
21         \r
22         template<typename Y>\r
23         safe_ptr(const safe_ptr<Y>& other, typename std::enable_if<std::is_convertible<Y*, T*>::value, void*>::type = 0) : impl_(other.impl_){}\r
24                 \r
25         template<typename Y>    \r
26         safe_ptr(const Y& impl, typename std::enable_if<std::is_convertible<typename std::add_pointer<Y>::type, typename std::add_pointer<T>::type>::value, void>::type* = 0)\r
27                 : impl_(std::make_shared<Y>(impl)) {}\r
28         \r
29         template<typename Y>    \r
30         safe_ptr(Y&& impl, typename std::enable_if<std::is_convertible<typename std::add_pointer<Y>::type, typename std::add_pointer<T>::type>::value, void>::type* = 0)\r
31                 : impl_(std::make_shared<Y>(std::forward<Y>(impl))) {}\r
32 \r
33         template<typename Y>\r
34         typename std::enable_if<std::is_convertible<Y*, T*>::value, safe_ptr<T>&>::type\r
35         operator=(const safe_ptr<Y>& other)\r
36         {\r
37                 safe_ptr<T> temp(other);\r
38                 temp.swap(*this);\r
39                 return *this;\r
40         }\r
41 \r
42         template <typename Y>\r
43         typename std::enable_if<std::is_convertible<typename std::add_pointer<Y>::type, typename std::add_pointer<T>::type>::value, safe_ptr<T>&>::type\r
44         operator=(Y&& impl)\r
45         {\r
46                 safe_ptr<T> temp(std::forward<T>(impl));\r
47                 temp.swap(*this);\r
48                 return *this;\r
49         }\r
50 \r
51         T& operator*() const { return *impl_.get();}\r
52 \r
53         T* operator->() const { return impl_.get();}\r
54 \r
55         T* get() const { return impl_.get();}\r
56 \r
57         bool unique() const { return impl_.unique();}\r
58 \r
59         long use_count() const { return impl_.use_count();}\r
60                                 \r
61         void swap(safe_ptr& other) { impl_.swap(other.impl_); } \r
62         \r
63         std::shared_ptr<T> get_shared() const   { return impl_; }\r
64 \r
65         static safe_ptr<T> from_shared(const std::shared_ptr<T>& impl) { return safe_ptr<T>(impl); }\r
66 \r
67 private:                \r
68         \r
69         template<typename Y>    \r
70         safe_ptr(const std::shared_ptr<Y>& impl, typename std::enable_if<std::is_convertible<Y*, T*>::value, void*>::type = 0) : impl_(impl)\r
71         {\r
72                 if(!impl)\r
73                         BOOST_THROW_EXCEPTION(null_argument() << msg_info("impl"));\r
74         }\r
75 \r
76         std::shared_ptr<T> impl_;\r
77 };\r
78 \r
79 template<class T, class U>\r
80 bool operator==(safe_ptr<T> const & a, safe_ptr<U> const & b)\r
81 {\r
82         return a.get() == b.get();\r
83 }\r
84 \r
85 template<class T, class U>\r
86 bool operator!=(safe_ptr<T> const & a, safe_ptr<U> const & b)\r
87 {\r
88         return a.get() != b.get();\r
89 }\r
90 \r
91 template<class T, class U>\r
92 bool operator<(safe_ptr<T> const & a, safe_ptr<U> const & b)\r
93 {\r
94         return a.get() < b.get();\r
95 }\r
96 \r
97 template<class T> void swap(safe_ptr<T> & a, safe_ptr<T> & b)\r
98 {\r
99         a.swap(b);\r
100 }\r
101 \r
102 template<class T> T* get_pointer(safe_ptr<T> const & p)\r
103 {\r
104         return p.get();\r
105 }\r
106 \r
107 template<typename T>\r
108 safe_ptr<T> make_safe()\r
109 {\r
110         static_assert(!std::is_abstract<T>::value, "Cannot construct abstract class.");\r
111         return safe_ptr<T>();\r
112 }\r
113 \r
114 template<typename T, typename P0>\r
115 safe_ptr<T> make_safe(P0&& p0)\r
116 {\r
117         static_assert(!std::is_abstract<T>::value, "Cannot construct abstract class.");\r
118         return safe_ptr<T>(T(std::forward<P0>(p0)));\r
119 }\r
120 \r
121 template<typename T, typename P0, typename P1>\r
122 safe_ptr<T> make_safe(P0&& p0, P1&& p1)\r
123 {\r
124         static_assert(!std::is_abstract<T>::value, "Cannot construct abstract class.");\r
125         return safe_ptr<T>(T(std::forward<P0>(p0), std::forward<P1>(p1)));\r
126 }\r
127 \r
128 template<typename T, typename P0, typename P1, typename P2>\r
129 safe_ptr<T> make_safe(P0&& p0, P1&& p1, P2&& p2)\r
130 {\r
131         static_assert(!std::is_abstract<T>::value, "Cannot construct abstract class.");\r
132         return safe_ptr<T>(T(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2)));\r
133 }\r
134 \r
135 }