| // Copyright 2009 Howard Hinnant, Ion Gaztañaga. |
| // Distributed under the Boost Software License, Version 1.0. (See |
| // accompanying file LICENSE_1_0.txt or copy at |
| // http://www.boost.org/LICENSE_1_0.txt) |
| // See http://www.boost.org/libs/foreach for documentation |
| |
| // This is a C++03 emulation of std::unique_ptr placed in namespace boost. |
| // Reference http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2800.pdf |
| // for the latest unique_ptr specification, and |
| // reference http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html |
| // for any pending issues against this specification. |
| |
| #ifndef BUTIL_UNIQUE_PTR_H |
| #define BUTIL_UNIQUE_PTR_H |
| |
| #include "butil/build_config.h" |
| |
| #if defined(BUTIL_CXX11_ENABLED) |
| |
| #include <memory> // std::unique_ptr |
| |
| #elif !defined(BAIDU_NO_EMULATED_UNIQUE_PTR) |
| |
| #include <algorithm> // std::swap until C++11 |
| #include "butil/type_traits.h" |
| #include "butil/macros.h" // BAIDU_CASSERT |
| |
| namespace std { |
| |
| namespace up_detail { |
| |
| typedef char one; |
| struct two {one _[2];}; |
| |
| // An is_convertible<From, To> that considers From an rvalue (consistent with C++0X). |
| // This is a simplified version neglecting the types function, array, void and abstract types |
| // I had to make a special case out of is_convertible<T,T> to make move-only |
| // types happy. |
| |
| namespace is_conv_imp { |
| template <class T> one test1(const T&); |
| template <class T> two test1(...); |
| template <class T> one test2(T); |
| template <class T> two test2(...); |
| template <class T> T source(); |
| } |
| |
| template <class T1, class T2> |
| struct is_convertible { |
| static const bool value = sizeof(is_conv_imp::test1<T2>(is_conv_imp::source<T1>())) == 1; |
| }; |
| |
| template <class T> |
| struct is_convertible<T, T> { |
| static const bool value = sizeof(is_conv_imp::test2<T>(is_conv_imp::source<T>())) == 1; |
| }; |
| |
| template <class T> |
| class rv { |
| T& r_; |
| |
| public: |
| explicit rv(T& r) : r_(r) {} |
| T* operator->() {return &r_;} |
| T& operator*() {return r_;} |
| }; |
| |
| template <class T> |
| struct identity { |
| typedef T type; |
| }; |
| |
| } // up_detail |
| |
| template <class T> |
| inline |
| typename butil::enable_if< |
| !up_detail::is_convertible<T, up_detail::rv<T> >::value, |
| T& |
| >::type |
| move(T& t) { |
| return t; |
| } |
| |
| template <class T> |
| inline |
| typename butil::enable_if < |
| !up_detail::is_convertible<T, up_detail::rv<T> >::value, |
| const T& |
| >::type |
| move(const T& t) { |
| return t; |
| } |
| |
| template <class T> |
| inline |
| typename butil::enable_if < |
| up_detail::is_convertible<T, up_detail::rv<T> >::value, |
| T |
| >::type |
| move(T& t) { |
| return T(up_detail::rv<T>(t)); |
| } |
| |
| template <class T> |
| inline |
| typename butil::enable_if < |
| butil::is_reference<T>::value, |
| T |
| >::type |
| forward(typename up_detail::identity<T>::type t) { |
| return t; |
| } |
| |
| template <class T> |
| inline |
| typename butil::enable_if < |
| !butil::is_reference<T>::value, |
| T |
| >::type |
| forward(typename up_detail::identity<T>::type& t) { |
| return move(t); |
| } |
| |
| template <class T> |
| inline |
| typename butil::enable_if < |
| !butil::is_reference<T>::value, |
| T |
| >::type |
| forward(const typename up_detail::identity<T>::type& t) { |
| return move(const_cast<T&>(t)); |
| } |
| |
| namespace up_detail { |
| |
| // A move-aware but stripped-down compressed_pair which only optimizes storage for T2 |
| template <class T1, class T2, bool = butil::is_empty<T2>::value> |
| class UniquePtrStorage { |
| T1 t1_; |
| T2 t2_; |
| |
| typedef typename butil::add_reference<T2>::type T2_reference; |
| typedef typename butil::add_reference<const T2>::type T2_const_reference; |
| |
| UniquePtrStorage(const UniquePtrStorage&); |
| UniquePtrStorage& operator=(const UniquePtrStorage&); |
| public: |
| operator rv<UniquePtrStorage>() {return rv<UniquePtrStorage>(*this);} |
| |
| UniquePtrStorage() : t1_(), t2_() {} |
| explicit UniquePtrStorage(T1 t1) : t1_(move(t1)), t2_() {} |
| UniquePtrStorage(T1 t1, T2 t2) : t1_(move(t1)), t2_(forward<T2>(t2)) {} |
| |
| T1& first() {return t1_;} |
| const T1& first() const {return t1_;} |
| |
| T2_reference second() {return t2_;} |
| T2_const_reference second() const {return t2_;} |
| }; |
| |
| template <class T1, class T2> |
| class UniquePtrStorage<T1, T2, true> : private T2 { |
| T1 t1_; |
| typedef T2 t2_; |
| |
| UniquePtrStorage(const UniquePtrStorage&); |
| UniquePtrStorage& operator=(const UniquePtrStorage&); |
| public: |
| operator rv<UniquePtrStorage>() {return rv<UniquePtrStorage>(*this);} |
| |
| UniquePtrStorage() : t1_() {} |
| explicit UniquePtrStorage(T1 t1) : t1_(move(t1)) {} |
| UniquePtrStorage(T1 t1, T2 t2) : t2_(move(t2)), t1_(move(t1)) {} |
| |
| T1& first() {return t1_;} |
| const T1& first() const {return t1_;} |
| |
| T2& second() {return *this;} |
| const T2& second() const {return *this;} |
| }; |
| |
| template <class T1, class T2, bool b> |
| inline |
| void |
| swap(UniquePtrStorage<T1, T2, b>& x, UniquePtrStorage<T1, T2, b>& y) { |
| using std::swap; |
| swap(x.first(), y.first()); |
| swap(x.second(), y.second()); |
| } |
| |
| } // up_detail |
| |
| template <class T> |
| struct default_delete { |
| default_delete() {} |
| template <class U> |
| default_delete(const default_delete<U>&, |
| typename butil::enable_if<up_detail::is_convertible<U*, T*>::value>::type* = 0) {} |
| |
| void operator()(T* ptr) const { |
| BAIDU_CASSERT(sizeof(T) > 0, T_is_empty); |
| delete ptr; |
| } |
| }; |
| |
| template <class T> |
| struct default_delete<T[]> { |
| void operator()(T* ptr) const { |
| BAIDU_CASSERT(sizeof(T) > 0, T_is_empty); |
| delete [] ptr; |
| } |
| |
| private: |
| |
| template <class U> void operator()(U*) const; |
| }; |
| |
| namespace up_detail { |
| |
| namespace pointer_type_imp { |
| |
| template <class U> static two test(...); |
| template <class U> static one test(typename U::pointer* = 0); |
| |
| } // pointer_type_imp |
| |
| template <class T> |
| struct has_pointer_type { |
| static const bool value = sizeof(pointer_type_imp::test<T>(0)) == 1; |
| }; |
| |
| namespace pointer_type_imp { |
| |
| template <class T, class D, bool = has_pointer_type<D>::value> |
| struct pointer_type { |
| typedef typename D::pointer type; |
| }; |
| |
| template <class T, class D> |
| struct pointer_type<T, D, false> { |
| typedef T* type; |
| }; |
| |
| } // pointer_type_imp |
| |
| template <class T, class D> |
| struct pointer_type { |
| typedef typename pointer_type_imp::pointer_type<T, |
| typename butil::remove_reference<D>::type>::type type; |
| }; |
| |
| } // up_detail |
| |
| template <class T, class D = default_delete<T> > |
| class unique_ptr { |
| public: |
| typedef T element_type; |
| typedef D deleter_type; |
| typedef typename up_detail::pointer_type<element_type, deleter_type>::type pointer; |
| |
| private: |
| up_detail::UniquePtrStorage<pointer, deleter_type> ptr_; |
| |
| typedef typename butil::add_reference<deleter_type>::type deleter_reference; |
| typedef typename butil::add_reference<const deleter_type>::type deleter_const_reference; |
| |
| struct nat {int for_bool_;}; |
| |
| unique_ptr(unique_ptr&); |
| unique_ptr& operator=(unique_ptr&); |
| |
| public: |
| operator up_detail::rv<unique_ptr>() { |
| return up_detail::rv<unique_ptr>(*this); |
| } |
| unique_ptr(up_detail::rv<unique_ptr> r) |
| : ptr_(r->release(), forward<deleter_type>(r->get_deleter())) {} |
| unique_ptr& operator=(up_detail::rv<unique_ptr> r) { |
| reset(r->release()); |
| ptr_.second() = move(r->get_deleter()); |
| return *this; |
| } |
| |
| unique_ptr() {} |
| |
| explicit unique_ptr(pointer p) : ptr_(p) {} |
| |
| unique_ptr(pointer p, typename butil::conditional<butil::is_reference<D>::value, |
| volatile typename butil::remove_reference<D>::type&, D>::type d) |
| : ptr_(move(p), forward<D>(const_cast<typename butil::add_reference<D>::type>(d))) {} |
| |
| template <class U, class E> |
| unique_ptr(unique_ptr<U, E> u, |
| typename butil::enable_if < |
| !butil::is_array<U>::value && |
| up_detail::is_convertible<typename unique_ptr<U>::pointer, pointer>::value |
| && |
| up_detail::is_convertible<E, deleter_type>::value && |
| ( |
| !butil::is_reference<deleter_type>::value || |
| butil::is_same<deleter_type, E>::value) |
| >::type* = 0) |
| : ptr_(u.release(), forward<D>(forward<E>(u.get_deleter()))) {} |
| |
| ~unique_ptr() { |
| BAIDU_CASSERT(!butil::is_reference<deleter_type>::value, deleter_is_ref); |
| BAIDU_CASSERT(!butil::is_pointer<deleter_type>::value, deleter_is_pointer); |
| reset(); |
| } |
| |
| unique_ptr& operator=(int nat::*) { |
| reset(); |
| return *this; |
| } |
| |
| template <class U, class E> |
| unique_ptr& operator=(unique_ptr<U, E> u) { |
| reset(u.release()); |
| ptr_.second() = move(u.get_deleter()); |
| return *this; |
| } |
| |
| typename butil::add_reference<T>::type operator*() const {return *get();} |
| pointer operator->() const {return get();} |
| pointer get() const {return ptr_.first();} |
| deleter_reference get_deleter() {return ptr_.second();} |
| deleter_const_reference get_deleter() const {return ptr_.second();} |
| operator int nat::*() const {return get() ? &nat::for_bool_ : 0;} |
| |
| void reset(pointer p = pointer()) { |
| pointer t = get(); |
| if (t != pointer()) |
| get_deleter()(t); |
| ptr_.first() = p; |
| } |
| |
| pointer release() { |
| pointer tmp = get(); |
| ptr_.first() = pointer(); |
| return tmp; |
| } |
| |
| void swap(unique_ptr& u) {up_detail::swap(ptr_, u.ptr_);} |
| }; |
| |
| template <class T, class D> |
| class unique_ptr<T[], D> { |
| public: |
| typedef T element_type; |
| typedef D deleter_type; |
| typedef typename up_detail::pointer_type<element_type, deleter_type>::type pointer; |
| |
| private: |
| up_detail::UniquePtrStorage<pointer, deleter_type> ptr_; |
| |
| typedef typename butil::add_reference<deleter_type>::type deleter_reference; |
| typedef typename butil::add_reference<const deleter_type>::type deleter_const_reference; |
| |
| struct nat {int for_bool_;}; |
| |
| unique_ptr(unique_ptr&); |
| unique_ptr& operator=(unique_ptr&); |
| |
| public: |
| operator up_detail::rv<unique_ptr>() {return up_detail::rv<unique_ptr>(*this);} |
| unique_ptr(up_detail::rv<unique_ptr> r) |
| : ptr_(r->release(), forward<deleter_type>(r->get_deleter())) {} |
| unique_ptr& operator=(up_detail::rv<unique_ptr> r) { |
| reset(r->release()); |
| ptr_.second() = move(r->get_deleter()); |
| return *this; |
| } |
| |
| unique_ptr() {} |
| |
| explicit unique_ptr(pointer p) : ptr_(p) {} |
| |
| unique_ptr(pointer p, typename butil::conditional<butil::is_reference<D>::value, |
| volatile typename butil::remove_reference<D>::type&, D>::type d) |
| : ptr_(move(p), forward<D>(const_cast<typename butil::add_reference<D>::type>(d))) {} |
| |
| ~unique_ptr() { |
| BAIDU_CASSERT(!butil::is_reference<deleter_type>::value, deleter_is_ref); |
| BAIDU_CASSERT(!butil::is_pointer<deleter_type>::value, deleter_is_pointer); |
| reset(); |
| } |
| |
| T& operator[](size_t i) const {return get()[i];} |
| pointer get() const {return ptr_.first();} |
| deleter_reference get_deleter() {return ptr_.second();} |
| deleter_const_reference get_deleter() const {return ptr_.second();} |
| operator int nat::*() const {return get() ? &nat::for_bool_ : 0;} |
| |
| void reset(pointer p = pointer()) { |
| pointer t = get(); |
| if (t != pointer()) |
| get_deleter()(t); |
| ptr_.first() = p; |
| } |
| |
| pointer release() { |
| pointer tmp = get(); |
| ptr_.first() = pointer(); |
| return tmp; |
| } |
| |
| void swap(unique_ptr& u) {up_detail::swap(ptr_, u.ptr_);} |
| private: |
| template <class U> |
| explicit unique_ptr( |
| U, typename butil::enable_if<up_detail::is_convertible<U, pointer>::value>::type* = 0); |
| |
| template <class U> |
| unique_ptr(U, typename butil::conditional<butil::is_reference<D>::value, |
| volatile typename butil::remove_reference<D>::type&, D>::type, |
| typename butil::enable_if<up_detail::is_convertible<U, pointer>::value>::type* = 0); |
| }; |
| |
| template<class T, class D> |
| inline |
| void |
| swap(unique_ptr<T, D>& x, unique_ptr<T, D>& y) { |
| x.swap(y); |
| } |
| |
| template<class T1, class D1, class T2, class D2> |
| inline |
| bool |
| operator==(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y) { |
| return x.get() == y.get(); |
| } |
| |
| template<class T1, class D1, class T2, class D2> |
| inline |
| bool |
| operator!=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y) { |
| return !(x == y); |
| } |
| |
| template<class T1, class D1, class T2, class D2> |
| inline |
| bool |
| operator<(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y) { |
| return x.get() < y.get(); |
| } |
| |
| template<class T1, class D1, class T2, class D2> |
| inline |
| bool |
| operator<=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y) { |
| return !(y < x); |
| } |
| |
| template<class T1, class D1, class T2, class D2> |
| inline |
| bool |
| operator>(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y) { |
| return y < x; |
| } |
| |
| template<class T1, class D1, class T2, class D2> |
| inline |
| bool |
| operator>=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y) { |
| return !(x < y); |
| } |
| |
| } // namespace std |
| |
| #endif // BUTIL_CXX11_ENABLED |
| #endif // BUTIL_UNIQUE_PTR_H |