]> git.sesse.net Git - casparcg/blob - common/memory/safe_ptr.h
2.0.0.2
[casparcg] / common / memory / safe_ptr.h
1 /*\r
2 * copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
3 *\r
4 *  This file is part of CasparCG.\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 */\r
20 #pragma once\r
21 \r
22 #include <memory>\r
23 #include <type_traits>\r
24 #include <exception>\r
25 \r
26 #include "../utility/assert.h"\r
27 \r
28 namespace caspar {\r
29         \r
30 template<typename T>\r
31 class safe_ptr\r
32 {       \r
33         std::shared_ptr<T> impl_;\r
34         template <typename> friend class safe_ptr;\r
35 public:\r
36         typedef T element_type;\r
37         \r
38         safe_ptr() : impl_(std::make_shared<T>()){}     \r
39         \r
40         safe_ptr(const safe_ptr<T>& other) : impl_(other.impl_){}  // noexcept\r
41         safe_ptr(safe_ptr<T>&& other) : impl_(std::move(other.impl_)){}\r
42 \r
43         template<typename U>\r
44         safe_ptr(const safe_ptr<U>& other, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) : impl_(other.impl_){}  // noexcept\r
45                 \r
46         template<typename U>    \r
47         safe_ptr(const U& impl, typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type, T*>::value, void>::type* = 0)\r
48                 : impl_(std::make_shared<U>(impl)) {}\r
49         \r
50         template<typename U, typename D>                \r
51         safe_ptr(const U& impl, D dtor, typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type, T*>::value, void>::type* = 0)\r
52                 : impl_(new U(impl), dtor) {}\r
53 \r
54         template<typename U>    \r
55         safe_ptr(U&& impl, typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type, T*>::value, void>::type* = 0)\r
56                 : impl_(std::make_shared<U>(std::forward<U>(impl))) {}\r
57 \r
58         template<typename U, typename D>        \r
59         safe_ptr(U&& impl, D dtor, typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type, T*>::value, void>::type* = 0)\r
60                 : impl_(new U(std::forward<U>(impl)), dtor) {}\r
61                         \r
62         template<typename U>    \r
63         explicit safe_ptr(const std::shared_ptr<U>& impl, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) : impl_(impl)\r
64         {\r
65                 if(!impl_)\r
66                         throw std::invalid_argument("impl");\r
67         }\r
68         \r
69         template<typename U>    \r
70         explicit safe_ptr(std::shared_ptr<U>&& impl, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) : impl_(std::move(impl))\r
71         {\r
72                 if(!impl_)\r
73                         throw std::invalid_argument("impl");\r
74         }\r
75 \r
76         template<typename U>    \r
77         explicit safe_ptr(U* impl, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) : impl_(impl)\r
78         {\r
79                 if(!impl_)\r
80                         throw std::invalid_argument("impl");\r
81         }\r
82 \r
83         template<typename U, typename D>        \r
84         explicit safe_ptr(U* impl, D dtor, typename std::enable_if<std::is_convertible<U*, T*>::value, void*>::type = 0) : impl_(impl, dtor)\r
85         {\r
86                 if(!impl_)\r
87                         throw std::invalid_argument("impl");\r
88         }\r
89 \r
90         template<typename U>\r
91         typename std::enable_if<std::is_convertible<U*, T*>::value, safe_ptr<T>&>::type\r
92         operator=(const safe_ptr<U>& other)\r
93         {\r
94                 safe_ptr<T> temp(other);\r
95                 temp.swap(*this);\r
96                 return *this;\r
97         }\r
98 \r
99         template <typename U>\r
100         typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type, T*>::value, safe_ptr<T>&>::type\r
101         operator=(U&& impl)\r
102         {\r
103                 safe_ptr<T> temp(std::forward<T>(impl));\r
104                 temp.swap(*this);\r
105                 return *this;\r
106         }\r
107 \r
108         T& operator*() const // noexcept\r
109         {\r
110                 CASPAR_ASSERT(impl_);\r
111                 return *impl_.get();\r
112         } \r
113 \r
114         T* operator->() const // noexcept\r
115         {\r
116                 CASPAR_ASSERT(impl_);\r
117                 return impl_.get();\r
118         } \r
119 \r
120         T* get() const // noexcept\r
121         {\r
122                 CASPAR_ASSERT(impl_);\r
123                 return impl_.get();\r
124         }  \r
125 \r
126         bool unique() const { return impl_.unique();}  // noexcept\r
127 \r
128         long use_count() const { return impl_.use_count();}  // noexcept\r
129                                 \r
130         void swap(safe_ptr& other) { impl_.swap(other.impl_); }  // noexcept\r
131         \r
132         operator const std::shared_ptr<T>&() const { return impl_;}  // noexcept\r
133 \r
134         template<class U>\r
135         bool owner_before(const safe_ptr<T>& ptr){ return impl_.owner_before(ptr.impl_); }  // noexcept\r
136 \r
137         template<class U>\r
138         bool owner_before(const std::shared_ptr<U>& ptr){ return impl_.owner_before(ptr); }  // noexcept\r
139         \r
140         template<class D, class U> \r
141         D* get_deleter(safe_ptr<U> const& ptr) { return impl_.get_deleter(); }  // noexcept\r
142 };\r
143 \r
144 template<class T, class U>\r
145 bool operator==(const safe_ptr<T>& a, const safe_ptr<U>& b)  // noexcept\r
146 {\r
147         return a.get() == b.get();\r
148 }\r
149 \r
150 template<class T, class U>\r
151 bool operator!=(const safe_ptr<T>& a, const safe_ptr<U>& b) // noexcept\r
152 {\r
153         return a.get() != b.get();\r
154 }\r
155 \r
156 template<class T, class U>\r
157 bool operator<(const safe_ptr<T>& a, const safe_ptr<U>& b)  // noexcept\r
158 {\r
159         return a.get() < b.get();\r
160 }\r
161 \r
162 template<class T, class U>\r
163 bool operator>(const safe_ptr<T>& a, const safe_ptr<U>& b)  // noexcept\r
164 {\r
165         return a.get() > b.get();\r
166 }\r
167 \r
168 template<class T, class U>\r
169 bool operator>=(const safe_ptr<T>& a, const safe_ptr<U>& b)  // noexcept\r
170 {\r
171         return a.get() >= b.get();\r
172 }\r
173 \r
174 template<class T, class U>\r
175 bool operator<=(const safe_ptr<T>& a, const safe_ptr<U>& b)  // noexcept\r
176 {\r
177         return a.get() <= b.get();\r
178 }\r
179 \r
180 template<class E, class T, class U>\r
181 std::basic_ostream<E, T>& operator<<(std::basic_ostream<E, T>& out,     const safe_ptr<U>& p)\r
182 {\r
183         return out << p.get();\r
184 }\r
185 \r
186 template<class T> \r
187 void swap(safe_ptr<T>& a, safe_ptr<T>& b)  // noexcept\r
188 {\r
189         a.swap(b);\r
190 }\r
191 \r
192 template<class T> \r
193 T* get_pointer(safe_ptr<T> const& p)  // noexcept\r
194 {\r
195         return p.get();\r
196 }\r
197 \r
198 template <class T, class U>\r
199 safe_ptr<T> static_pointer_cast(const safe_ptr<U>& p)  // noexcept\r
200 {\r
201         return safe_ptr<T>(std::static_pointer_cast<T>(std::shared_ptr<U>(p)));\r
202 }\r
203 \r
204 template <class T, class U>\r
205 safe_ptr<T> const_pointer_cast(const safe_ptr<U>& p)  // noexcept\r
206 {\r
207         return safe_ptr<T>(std::const_pointer_cast<T>(std::shared_ptr<U>(p)));\r
208 }\r
209 \r
210 template <class T, class U>\r
211 safe_ptr<T> dynamic_pointer_cast(const safe_ptr<U>& p)\r
212 {\r
213         auto temp = std::dynamic_pointer_cast<T>(std::shared_ptr<U>(p));\r
214         if(!temp)\r
215                 throw std::bad_cast();\r
216         return safe_ptr<T>(temp);\r
217 }\r
218 \r
219 template<typename T>\r
220 safe_ptr<T> make_safe(const std::shared_ptr<T>& ptr)\r
221 {\r
222         return safe_ptr<T>(ptr);\r
223 }\r
224 \r
225 template<typename T>\r
226 safe_ptr<T> make_safe(std::shared_ptr<T>&& ptr)\r
227 {\r
228         return safe_ptr<T>(std::move(ptr));\r
229 }\r
230 \r
231 template<typename T>\r
232 safe_ptr<T> make_safe()\r
233 {\r
234         return safe_ptr<T>();\r
235 }\r
236 \r
237 template<typename T, typename P0>\r
238 safe_ptr<T> make_safe(P0&& p0)\r
239 {\r
240         return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0)));\r
241 }\r
242 \r
243 template<typename T, typename P0, typename P1>\r
244 safe_ptr<T> make_safe(P0&& p0, P1&& p1)\r
245 {\r
246         return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1)));\r
247 }\r
248 \r
249 template<typename T, typename P0, typename P1, typename P2>\r
250 safe_ptr<T> make_safe(P0&& p0, P1&& p1, P2&& p2)\r
251 {\r
252         return safe_ptr<T>(std::make_shared<T>(std::forward<P0>(p0), std::forward<P1>(p1), std::forward<P2>(p2)));\r
253 }\r
254 \r
255 template<typename T, typename P0, typename P1, typename P2, typename P3>\r
256 safe_ptr<T> make_safe(P0&& p0, P1&& p1, P2&& p2, P3&& p3)\r
257 {\r
258         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
259 }\r
260 \r
261 template<typename T, typename P0, typename P1, typename P2, typename P3, typename P4>\r
262 safe_ptr<T> make_safe(P0&& p0, P1&& p1, P2&& p2, P3&& p3, P4&& p4)\r
263 {\r
264         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
265 }\r
266 \r
267 }