/* * Copyright 2015 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SkUniquePtr_DEFINED #define SkUniquePtr_DEFINED #include "SkTLogic.h" #include "SkUtility.h" namespace skstd { template struct default_delete { /*constexpr*/ default_delete() /*noexcept*/ = default; template ::value>> default_delete(const default_delete&) /*noexcept*/ {} void operator()(T* obj) const { static_assert(sizeof(T) > 0, "Deleting pointer to incomplete type!"); delete obj; } }; template struct default_delete { /*constexpr*/ default_delete() /*noexcept*/ = default; void operator()(T* obj) const { static_assert(sizeof(T) > 0, "Deleting pointer to incomplete type!"); delete [] obj; } }; template > class unique_ptr { // remove_reference_t::pointer if that type exists, otherwise T*. struct pointer_type_detector { template static typename U::pointer detector(typename U::pointer*); template static T* detector(...); using type = decltype(detector>(0)); }; public: using pointer = typename pointer_type_detector::type; using element_type = T; using deleter_type = D; private: template ::value /*&& !is_final::value*/> struct compressed_base : private B { /*constexpr*/ compressed_base() : B() {} /*constexpr*/ compressed_base(const B& b) : B(b) {} /*constexpr*/ compressed_base(const B&& b) : B(move(b)) {} /*constexpr*/ B& get() /*noexcept*/ { return *this; } /*constexpr*/ B const& get() const /*noexcept*/ { return *this; } void swap(compressed_base&) /*noexcept*/ { } }; template struct compressed_base { B fb; /*constexpr*/ compressed_base() : B() {} /*constexpr*/ compressed_base(const B& b) : fb(b) {} /*constexpr*/ compressed_base(const B&& b) : fb(move(b)) {} /*constexpr*/ B& get() /*noexcept*/ { return fb; } /*constexpr*/ B const& get() const /*noexcept*/ { return fb; } void swap(compressed_base& that) /*noexcept*/ { SkTSwap(fb, that.fB); } }; struct compressed_data : private compressed_base { pointer fPtr; /*constexpr*/ compressed_data() : compressed_base(), fPtr() {} /*constexpr*/ compressed_data(const pointer& ptr, const deleter_type& d) : compressed_base(d), fPtr(ptr) {} template ::value && is_convertible::value >> /*constexpr*/ compressed_data(U1&& ptr, U2&& d) : compressed_base(skstd::forward(d)), fPtr(skstd::forward(ptr)) {} /*constexpr*/ pointer& getPointer() /*noexcept*/ { return fPtr; } /*constexpr*/ pointer const& getPointer() const /*noexcept*/ { return fPtr; } /*constexpr*/ deleter_type& getDeleter() /*noexcept*/ { return compressed_base::get(); } /*constexpr*/ deleter_type const& getDeleter() const /*noexcept*/ { return compressed_base::get(); } void swap(compressed_data& that) /*noexcept*/ { compressed_base::swap(static_cast>(that)); SkTSwap(fPtr, that.fPtr); } }; compressed_data data; public: /*constexpr*/ unique_ptr() /*noexcept*/ : data() { static_assert(!is_pointer::value, "Deleter is nullptr function pointer!"); } /*constexpr*/ unique_ptr(skstd::nullptr_t) /*noexcept*/ : unique_ptr() { } explicit unique_ptr(pointer ptr) /*noexcept*/ : data(ptr, deleter_type()) { static_assert(!is_pointer::value, "Deleter is nullptr function pointer!"); } unique_ptr(pointer ptr, conditional_t::value, deleter_type,const deleter_type&> d) /*noexcept*/ : data(ptr, d) {} unique_ptr(pointer ptr, remove_reference_t&& d) /*noexcept*/ : data(move(ptr), move(d)) { static_assert(!is_reference::value, "Binding an rvalue reference deleter as an lvalue reference deleter is not allowed."); } unique_ptr(unique_ptr&& that) /*noexcept*/ : data(that.release(), forward(that.get_deleter())) {} template ::pointer, pointer>::value && !is_array::value && conditional_t::value, is_same, is_convertible>::value>> unique_ptr(unique_ptr&& that) /*noexcept*/ : data(that.release(), forward(that.get_deleter())) {} ~unique_ptr() /*noexcept*/ { pointer& ptr = data.getPointer(); if (ptr != nullptr) { get_deleter()(ptr); } ptr = pointer(); } unique_ptr& operator=(unique_ptr&& that) /*noexcept*/ { reset(that.release()); get_deleter() = forward(that.get_deleter()); return *this; } template enable_if_t< is_convertible::pointer, pointer>::value && !is_array::value, unique_ptr&> operator=(unique_ptr&& that) /*noexcept*/ { reset(that.release()); get_deleter() = forward(that.get_deleter()); return *this; } unique_ptr& operator=(skstd::nullptr_t) /*noexcept*/ { reset(); return *this; } add_lvalue_reference_t operator*() const { SkASSERT(get() != pointer()); return *get(); } pointer operator->() const /*noexcept*/ { SkASSERT(get() != pointer()); return get(); } pointer get() const /*noexcept*/ { return data.getPointer(); } deleter_type& get_deleter() /*noexcept*/ { return data.getDeleter(); } const deleter_type& get_deleter() const /*noexcept*/ { return data.getDeleter(); } //explicit operator bool() const noexcept { bool is_attached() const /*noexcept*/ { return get() == pointer() ? false : true; } pointer release() /*noexcept*/ { pointer ptr = get(); data.getPointer() = pointer(); return ptr; } void reset(pointer ptr = pointer()) /*noexcept*/ { SkTSwap(data.getPointer(), ptr); if (ptr != pointer()) { get_deleter()(ptr); } } void swap(unique_ptr& that) /*noexcept*/ { SkTSwap(data, that.data); } unique_ptr(const unique_ptr&) = delete; unique_ptr& operator=(const unique_ptr&) = delete; }; template class unique_ptr { // remove_reference_t::pointer if that type exists, otherwise T*. struct pointer_type_detector { template static typename U::pointer detector(typename U::pointer*); template static T* detector(...); using type = decltype(detector>(0)); }; public: using pointer = typename pointer_type_detector::type; using element_type = T; using deleter_type = D; private: template ::value /*&& !is_final::value*/> struct compressed_base : private B { /*constexpr*/ compressed_base() : B() {} /*constexpr*/ compressed_base(const B& b) : B(b) {} /*constexpr*/ compressed_base(const B&& b) : B(move(b)) {} /*constexpr*/ B& get() /*noexcept*/ { return *this; } /*constexpr*/ B const& get() const /*noexcept*/ { return *this; } void swap(compressed_base&) /*noexcept*/ { } }; template struct compressed_base { B fb; /*constexpr*/ compressed_base() : B() {} /*constexpr*/ compressed_base(const B& b) : fb(b) {} /*constexpr*/ compressed_base(const B&& b) : fb(move(b)) {} /*constexpr*/ B& get() /*noexcept*/ { return fb; } /*constexpr*/ B const& get() const /*noexcept*/ { return fb; } void swap(compressed_base& that) /*noexcept*/ { SkTSwap(fb, that.fB); } }; struct compressed_data : private compressed_base { pointer fPtr; /*constexpr*/ compressed_data() : compressed_base(), fPtr() {} /*constexpr*/ compressed_data(const pointer& ptr, const deleter_type& d) : compressed_base(d), fPtr(ptr) {} template ::value && is_convertible::value >> /*constexpr*/ compressed_data(U1&& ptr, U2&& d) : compressed_base(skstd::forward(d)), fPtr(skstd::forward(ptr)) {} /*constexpr*/ pointer& getPointer() /*noexcept*/ { return fPtr; } /*constexpr*/ pointer const& getPointer() const /*noexcept*/ { return fPtr; } /*constexpr*/ deleter_type& getDeleter() /*noexcept*/ { return compressed_base::get(); } /*constexpr*/ deleter_type const& getDeleter() const /*noexcept*/ { return compressed_base::get(); } void swap(compressed_data& that) /*noexcept*/ { compressed_base::swap(static_cast>(that)); SkTSwap(fPtr, that.fPtr); } }; compressed_data data; public: /*constexpr*/ unique_ptr() /*noexcept*/ : data() { static_assert(!is_pointer::value, "Deleter is nullptr function pointer!"); } /*constexpr*/ unique_ptr(skstd::nullptr_t) /*noexcept*/ : unique_ptr() { } explicit unique_ptr(pointer ptr) /*noexcept*/ : data(ptr, deleter_type()) { static_assert(!is_pointer::value, "Deleter is nullptr function pointer!"); } unique_ptr(pointer ptr, conditional_t::value, deleter_type,const deleter_type&> d) /*noexcept*/ : data(ptr, d) {} unique_ptr(pointer ptr, remove_reference_t&& d) /*noexcept*/ : data(move(ptr), move(d)) { static_assert(!is_reference::value, "Binding an rvalue reference deleter as an lvalue reference deleter is not allowed."); } unique_ptr(unique_ptr&& that) /*noexcept*/ : data(that.release(), forward(that.get_deleter())) {} ~unique_ptr() { pointer& ptr = data.getPointer(); if (ptr != nullptr) { get_deleter()(ptr); } ptr = pointer(); } unique_ptr& operator=(unique_ptr&& that) /*noexcept*/ { reset(that.release()); get_deleter() = forward(that.get_deleter()); return *this; } unique_ptr& operator=(skstd::nullptr_t) /*noexcept*/ { reset(); return *this; } add_lvalue_reference_t operator[](size_t i) const { SkASSERT(get() != pointer()); return get()[i]; } pointer get() const /*noexcept*/ { return data.getPointer(); } deleter_type& get_deleter() /*noexcept*/ { return data.getDeleter(); } const deleter_type& get_deleter() const /*noexcept*/ { return data.getDeleter(); } //explicit operator bool() const noexcept { bool is_attached() const /*noexcept*/ { return get() == pointer() ? false : true; } pointer release() /*noexcept*/ { pointer ptr = get(); data.getPointer() = pointer(); return ptr; } void reset(pointer ptr = pointer()) /*noexcept*/ { SkTSwap(data.getPointer(), ptr); if (ptr != pointer()) { get_deleter()(ptr); } } template void reset(U*) = delete; void swap(unique_ptr& that) /*noexcept*/ { data.swap(that.data); } unique_ptr(const unique_ptr&) = delete; unique_ptr& operator=(const unique_ptr&) = delete; }; template inline void swap(unique_ptr& a, unique_ptr& b) /*noexcept*/ { a.swap(b); } template inline bool operator==(const unique_ptr& a, const unique_ptr& b) { return a.get() == b.get(); } template inline bool operator==(const unique_ptr& a, skstd::nullptr_t) /*noexcept*/ { //return !a; return !a.is_attached(); } template inline bool operator==(skstd::nullptr_t, const unique_ptr& b) /*noexcept*/ { //return !b; return !b.is_attached(); } template inline bool operator!=(const unique_ptr& a, const unique_ptr& b) { return a.get() != b.get(); } template inline bool operator!=(const unique_ptr& a, skstd::nullptr_t) /*noexcept*/ { //return (bool)a; return a.is_attached(); } template inline bool operator!=(skstd::nullptr_t, const unique_ptr& b) /*noexcept*/ { //return (bool)b; return b.is_attached(); } } // namespace skstd #endif