Home | History | Annotate | Download | only in private
      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::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