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>>
default_deletedefault_delete21     default_delete(const default_delete<U>&) /*noexcept*/ {}
22 
operatordefault_delete23     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::pointer*);
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 vs2013sp2-3
73     using compressed_base_t = compressed_base<deleter_type, std::is_empty<deleter_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_type>::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 fPtr; }
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 function 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 function 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::pointer*);
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 vs2013sp2-3
249     using compressed_base_t = compressed_base<deleter_type, std::is_empty<deleter_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_type>::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 fPtr; }
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 function 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 function 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
409