OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2015 Google Inc. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license that can be | |
5 * found in the LICENSE file. | |
6 */ | |
7 | |
8 #ifndef SkUniquePtr_DEFINED | |
9 #define SkUniquePtr_DEFINED | |
10 | |
11 #include "SkTLogic.h" | |
12 #include <cstddef> | |
13 #include <utility> | |
14 | |
15 namespace skstd { | |
16 | |
17 template <typename T> struct default_delete { | |
18 /*constexpr*/ default_delete() /*noexcept*/ = default; | |
19 | |
20 template <typename U, typename = enable_if_t<is_convertible<U*, T*>::value>> | |
21 default_delete(const default_delete<U>&) /*noexcept*/ {} | |
22 | |
23 void operator()(T* obj) const { | |
24 static_assert(sizeof(T) > 0, "Deleting pointer to incomplete type!"); | |
25 delete obj; | |
26 } | |
27 }; | |
28 template <typename T> struct default_delete<T[]> { | |
29 /*constexpr*/ default_delete() /*noexcept*/ = default; | |
30 | |
31 void operator()(T* obj) const { | |
32 static_assert(sizeof(T) > 0, "Deleting pointer to incomplete type!"); | |
33 delete [] obj; | |
34 } | |
35 }; | |
36 | |
37 template <typename T, typename D = default_delete<T>> class unique_ptr { | |
38 // remove_reference_t<D>::pointer if that type exists, otherwise T*. | |
39 struct pointer_type_detector { | |
40 template <typename U> static typename U::pointer detector(typename U::po
inter*); | |
41 template <typename U> static T* detector(...); | |
42 using type = decltype(detector<remove_reference_t<D>>(0)); | |
43 }; | |
44 | |
45 public: | |
46 using pointer = typename pointer_type_detector::type; | |
47 using element_type = T; | |
48 using deleter_type = D; | |
49 | |
50 private: | |
51 template <typename B, bool> | |
52 struct compressed_base : private B { | |
53 /*constexpr*/ compressed_base() : B() {} | |
54 /*constexpr*/ compressed_base(const B& b) : B(b) {} | |
55 /*constexpr*/ compressed_base(B&& b) : B(std::move(b)) {} | |
56 /*constexpr*/ B& get() /*noexcept*/ { return *this; } | |
57 /*constexpr*/ B const& get() const /*noexcept*/ { return *this; } | |
58 void swap(compressed_base&) /*noexcept*/ { } | |
59 }; | |
60 | |
61 template <typename B> struct compressed_base<B, false> { | |
62 B fb; | |
63 /*constexpr*/ compressed_base() : B() {} | |
64 /*constexpr*/ compressed_base(const B& b) : fb(b) {} | |
65 /*constexpr*/ compressed_base(B&& b) : fb(std::move(b)) {} | |
66 /*constexpr*/ B& get() /*noexcept*/ { return fb; } | |
67 /*constexpr*/ B const& get() const /*noexcept*/ { return fb; } | |
68 void swap(compressed_base& that) /*noexcept*/ { SkTSwap(fb, that.fB); } | |
69 }; | |
70 | |
71 // C++14 adds '&& !std::is_final<deleter_type>::value' to the bool condition
. | |
72 // compressed_base_t exists and has this form to work around a bug in vs2013
sp2-3 | |
73 using compressed_base_t = compressed_base<deleter_type, std::is_empty<delete
r_type>::value>; | |
74 | |
75 struct compressed_data : private compressed_base_t { | |
76 pointer fPtr; | |
77 /*constexpr*/ compressed_data() : compressed_base_t(), fPtr() {} | |
78 /*constexpr*/ compressed_data(const pointer& ptr, const deleter_type& d) | |
79 : compressed_base_t(d), fPtr(ptr) {} | |
80 template <typename U1, typename U2, typename = enable_if_t< | |
81 is_convertible<U1, pointer>::value && is_convertible<U2, deleter_typ
e>::value | |
82 >> /*constexpr*/ compressed_data(U1&& ptr, U2&& d) | |
83 : compressed_base_t(std::forward<U2>(d)), fPtr(std::forward<U1>(ptr)
) {} | |
84 /*constexpr*/ pointer& getPointer() /*noexcept*/ { return fPtr; } | |
85 /*constexpr*/ pointer const& getPointer() const /*noexcept*/ { return fP
tr; } | |
86 /*constexpr*/ deleter_type& getDeleter() /*noexcept*/ { | |
87 return compressed_base_t::get(); | |
88 } | |
89 /*constexpr*/ deleter_type const& getDeleter() const /*noexcept*/ { | |
90 return compressed_base_t::get(); | |
91 } | |
92 void swap(compressed_data& that) /*noexcept*/ { | |
93 compressed_base_t::swap(static_cast<compressed_base_t>(that)); | |
94 SkTSwap(fPtr, that.fPtr); | |
95 } | |
96 }; | |
97 compressed_data data; | |
98 | |
99 public: | |
100 /*constexpr*/ unique_ptr() /*noexcept*/ : data() { | |
101 static_assert(!std::is_pointer<deleter_type>::value, "Deleter nullptr fu
nction pointer!"); | |
102 } | |
103 | |
104 /*constexpr*/ unique_ptr(std::nullptr_t) /*noexcept*/ : unique_ptr() { } | |
105 | |
106 explicit unique_ptr(pointer ptr) /*noexcept*/ : data(ptr, deleter_type()) { | |
107 static_assert(!std::is_pointer<deleter_type>::value, "Deleter nullptr fu
nction pointer!"); | |
108 } | |
109 | |
110 unique_ptr(pointer ptr, | |
111 conditional_t<std::is_reference<deleter_type>::value, | |
112 deleter_type, const deleter_type&> d) | |
113 /*noexcept*/ : data(ptr, d) | |
114 {} | |
115 | |
116 unique_ptr(pointer ptr, remove_reference_t<deleter_type>&& d) /*noexcept*/ | |
117 : data(std::move(ptr), std::move(d)) | |
118 { | |
119 static_assert(!std::is_reference<deleter_type>::value, | |
120 "Binding an rvalue reference deleter as an lvalue reference deleter
is not allowed."); | |
121 } | |
122 | |
123 | |
124 unique_ptr(unique_ptr&& that) /*noexcept*/ | |
125 : data(that.release(), std::forward<deleter_type>(that.get_deleter())) | |
126 {} | |
127 | |
128 template <typename U, typename ThatD, typename = enable_if_t< | |
129 is_convertible<typename unique_ptr<U, ThatD>::pointer, pointer>::value &
& | |
130 !std::is_array<U>::value && | |
131 conditional_t<std::is_reference<D>::value, | |
132 std::is_same<ThatD, D>, | |
133 is_convertible<ThatD, D>>::value>> | |
134 unique_ptr(unique_ptr<U, ThatD>&& that) /*noexcept*/ | |
135 : data(that.release(), std::forward<ThatD>(that.get_deleter())) | |
136 {} | |
137 | |
138 ~unique_ptr() /*noexcept*/ { | |
139 pointer& ptr = data.getPointer(); | |
140 if (ptr != nullptr) { | |
141 get_deleter()(ptr); | |
142 } | |
143 ptr = pointer(); | |
144 } | |
145 | |
146 unique_ptr& operator=(unique_ptr&& that) /*noexcept*/ { | |
147 reset(that.release()); | |
148 get_deleter() = std::forward<deleter_type>(that.get_deleter()); | |
149 return *this; | |
150 } | |
151 | |
152 template <typename U, typename ThatD> enable_if_t< | |
153 is_convertible<typename unique_ptr<U, ThatD>::pointer, pointer>::value &
& | |
154 !std::is_array<U>::value, | |
155 unique_ptr&> operator=(unique_ptr<U, ThatD>&& that) /*noexcept*/ { | |
156 reset(that.release()); | |
157 get_deleter() = std::forward<ThatD>(that.get_deleter()); | |
158 return *this; | |
159 } | |
160 | |
161 unique_ptr& operator=(std::nullptr_t) /*noexcept*/ { | |
162 reset(); | |
163 return *this; | |
164 } | |
165 | |
166 add_lvalue_reference_t<element_type> operator*() const { | |
167 SkASSERT(get() != pointer()); | |
168 return *get(); | |
169 } | |
170 | |
171 pointer operator->() const /*noexcept*/ { | |
172 SkASSERT(get() != pointer()); | |
173 return get(); | |
174 } | |
175 | |
176 pointer get() const /*noexcept*/ { | |
177 return data.getPointer(); | |
178 } | |
179 | |
180 deleter_type& get_deleter() /*noexcept*/ { | |
181 return data.getDeleter(); | |
182 } | |
183 | |
184 const deleter_type& get_deleter() const /*noexcept*/ { | |
185 return data.getDeleter(); | |
186 } | |
187 | |
188 //explicit operator bool() const noexcept { | |
189 bool is_attached() const /*noexcept*/ { | |
190 return get() == pointer() ? false : true; | |
191 } | |
192 | |
193 pointer release() /*noexcept*/ { | |
194 pointer ptr = get(); | |
195 data.getPointer() = pointer(); | |
196 return ptr; | |
197 } | |
198 | |
199 void reset(pointer ptr = pointer()) /*noexcept*/ { | |
200 SkTSwap(data.getPointer(), ptr); | |
201 if (ptr != pointer()) { | |
202 get_deleter()(ptr); | |
203 } | |
204 } | |
205 | |
206 void swap(unique_ptr& that) /*noexcept*/ { | |
207 SkTSwap(data, that.data); | |
208 } | |
209 | |
210 unique_ptr(const unique_ptr&) = delete; | |
211 unique_ptr& operator=(const unique_ptr&) = delete; | |
212 }; | |
213 | |
214 template <typename T, typename D> class unique_ptr<T[], D> { | |
215 // remove_reference_t<D>::pointer if that type exists, otherwise T*. | |
216 struct pointer_type_detector { | |
217 template <typename U> static typename U::pointer detector(typename U::po
inter*); | |
218 template <typename U> static T* detector(...); | |
219 using type = decltype(detector<remove_reference_t<D>>(0)); | |
220 }; | |
221 | |
222 public: | |
223 using pointer = typename pointer_type_detector::type; | |
224 using element_type = T; | |
225 using deleter_type = D; | |
226 | |
227 private: | |
228 template <typename B, bool> struct compressed_base : private B { | |
229 /*constexpr*/ compressed_base() : B() {} | |
230 /*constexpr*/ compressed_base(const B& b) : B(b) {} | |
231 /*constexpr*/ compressed_base(B&& b) : B(std::move(b)) {} | |
232 /*constexpr*/ B& get() /*noexcept*/ { return *this; } | |
233 /*constexpr*/ B const& get() const /*noexcept*/ { return *this; } | |
234 void swap(compressed_base&) /*noexcept*/ { } | |
235 }; | |
236 | |
237 template <typename B> struct compressed_base<B, false> { | |
238 B fb; | |
239 /*constexpr*/ compressed_base() : B() {} | |
240 /*constexpr*/ compressed_base(const B& b) : fb(b) {} | |
241 /*constexpr*/ compressed_base(B&& b) : fb(std::move(b)) {} | |
242 /*constexpr*/ B& get() /*noexcept*/ { return fb; } | |
243 /*constexpr*/ B const& get() const /*noexcept*/ { return fb; } | |
244 void swap(compressed_base& that) /*noexcept*/ { SkTSwap(fb, that.fB); } | |
245 }; | |
246 | |
247 // C++14 adds '&& !std::is_final<deleter_type>::value' to the bool condition
. | |
248 // compressed_base_t exists and has this form to work around a bug in vs2013
sp2-3 | |
249 using compressed_base_t = compressed_base<deleter_type, std::is_empty<delete
r_type>::value>; | |
250 | |
251 struct compressed_data : private compressed_base_t { | |
252 pointer fPtr; | |
253 /*constexpr*/ compressed_data() : compressed_base_t(), fPtr() {} | |
254 /*constexpr*/ compressed_data(const pointer& ptr, const deleter_type& d) | |
255 : compressed_base_t(d), fPtr(ptr) {} | |
256 template <typename U1, typename U2, typename = enable_if_t< | |
257 is_convertible<U1, pointer>::value && is_convertible<U2, deleter_typ
e>::value | |
258 >> /*constexpr*/ compressed_data(U1&& ptr, U2&& d) | |
259 : compressed_base_t(std::forward<U2>(d)), fPtr(std::forward<U1>(ptr)
) {} | |
260 /*constexpr*/ pointer& getPointer() /*noexcept*/ { return fPtr; } | |
261 /*constexpr*/ pointer const& getPointer() const /*noexcept*/ { return fP
tr; } | |
262 /*constexpr*/ deleter_type& getDeleter() /*noexcept*/ { | |
263 return compressed_base_t::get(); | |
264 } | |
265 /*constexpr*/ deleter_type const& getDeleter() const /*noexcept*/ { | |
266 return compressed_base_t::get(); | |
267 } | |
268 void swap(compressed_data& that) /*noexcept*/ { | |
269 compressed_base_t::swap(static_cast<compressed_base_t>(that)); | |
270 SkTSwap(fPtr, that.fPtr); | |
271 } | |
272 }; | |
273 compressed_data data; | |
274 | |
275 public: | |
276 /*constexpr*/ unique_ptr() /*noexcept*/ : data() { | |
277 static_assert(!std::is_pointer<deleter_type>::value, "Deleter nullptr fu
nction pointer!"); | |
278 } | |
279 | |
280 /*constexpr*/ unique_ptr(std::nullptr_t) /*noexcept*/ : unique_ptr() { } | |
281 | |
282 explicit unique_ptr(pointer ptr) /*noexcept*/ : data(ptr, deleter_type()) { | |
283 static_assert(!std::is_pointer<deleter_type>::value, "Deleter nullptr fu
nction pointer!"); | |
284 } | |
285 | |
286 unique_ptr(pointer ptr, | |
287 conditional_t<std::is_reference<deleter_type>::value, | |
288 deleter_type, const deleter_type&> d) | |
289 /*noexcept*/ : data(ptr, d) | |
290 {} | |
291 | |
292 unique_ptr(pointer ptr, remove_reference_t<deleter_type>&& d) /*noexcept*/ | |
293 : data(std::move(ptr), std::move(d)) | |
294 { | |
295 static_assert(!std::is_reference<deleter_type>::value, | |
296 "Binding an rvalue reference deleter as an lvalue reference deleter
is not allowed."); | |
297 } | |
298 | |
299 unique_ptr(unique_ptr&& that) /*noexcept*/ | |
300 : data(that.release(), std::forward<deleter_type>(that.get_deleter())) | |
301 {} | |
302 | |
303 ~unique_ptr() { | |
304 pointer& ptr = data.getPointer(); | |
305 if (ptr != nullptr) { | |
306 get_deleter()(ptr); | |
307 } | |
308 ptr = pointer(); | |
309 } | |
310 | |
311 unique_ptr& operator=(unique_ptr&& that) /*noexcept*/ { | |
312 reset(that.release()); | |
313 get_deleter() = std::forward<deleter_type>(that.get_deleter()); | |
314 return *this; | |
315 } | |
316 | |
317 unique_ptr& operator=(std::nullptr_t) /*noexcept*/ { | |
318 reset(); | |
319 return *this; | |
320 } | |
321 | |
322 add_lvalue_reference_t<element_type> operator[](size_t i) const { | |
323 SkASSERT(get() != pointer()); | |
324 return get()[i]; | |
325 } | |
326 | |
327 pointer get() const /*noexcept*/ { | |
328 return data.getPointer(); | |
329 } | |
330 | |
331 deleter_type& get_deleter() /*noexcept*/ { | |
332 return data.getDeleter(); | |
333 } | |
334 | |
335 const deleter_type& get_deleter() const /*noexcept*/ { | |
336 return data.getDeleter(); | |
337 } | |
338 | |
339 //explicit operator bool() const noexcept { | |
340 bool is_attached() const /*noexcept*/ { | |
341 return get() == pointer() ? false : true; | |
342 } | |
343 | |
344 pointer release() /*noexcept*/ { | |
345 pointer ptr = get(); | |
346 data.getPointer() = pointer(); | |
347 return ptr; | |
348 } | |
349 | |
350 void reset(pointer ptr = pointer()) /*noexcept*/ { | |
351 SkTSwap(data.getPointer(), ptr); | |
352 if (ptr != pointer()) { | |
353 get_deleter()(ptr); | |
354 } | |
355 } | |
356 | |
357 template <typename U> void reset(U*) = delete; | |
358 | |
359 void swap(unique_ptr& that) /*noexcept*/ { | |
360 data.swap(that.data); | |
361 } | |
362 | |
363 unique_ptr(const unique_ptr&) = delete; | |
364 unique_ptr& operator=(const unique_ptr&) = delete; | |
365 }; | |
366 | |
367 template <typename T, typename D> | |
368 inline void swap(unique_ptr<T, D>& a, unique_ptr<T, D>& b) /*noexcept*/ { | |
369 a.swap(b); | |
370 } | |
371 | |
372 template <typename T, typename D, typename U, typename ThatD> | |
373 inline bool operator==(const unique_ptr<T, D>& a, const unique_ptr<U, ThatD>& b)
{ | |
374 return a.get() == b.get(); | |
375 } | |
376 | |
377 template <typename T, typename D> | |
378 inline bool operator==(const unique_ptr<T, D>& a, std::nullptr_t) /*noexcept*/ { | |
379 //return !a; | |
380 return !a.is_attached(); | |
381 } | |
382 | |
383 template <typename T, typename D> | |
384 inline bool operator==(std::nullptr_t, const unique_ptr<T, D>& b) /*noexcept*/ { | |
385 //return !b; | |
386 return !b.is_attached(); | |
387 } | |
388 | |
389 template <typename T, typename D, typename U, typename ThatD> | |
390 inline bool operator!=(const unique_ptr<T, D>& a, const unique_ptr<U, ThatD>& b)
{ | |
391 return a.get() != b.get(); | |
392 } | |
393 | |
394 template <typename T, typename D> | |
395 inline bool operator!=(const unique_ptr<T, D>& a, std::nullptr_t) /*noexcept*/ { | |
396 //return (bool)a; | |
397 return a.is_attached(); | |
398 } | |
399 | |
400 template <typename T, typename D> | |
401 inline bool operator!=(std::nullptr_t, const unique_ptr<T, D>& b) /*noexcept*/ { | |
402 //return (bool)b; | |
403 return b.is_attached(); | |
404 } | |
405 | |
406 } // namespace skstd | |
407 | |
408 #endif | |
OLD | NEW |