#ifndef BUTIL_INTRUSIVE_PTR_HPP #define BUTIL_INTRUSIVE_PTR_HPP // Copyright (c) 2001, 2002 Peter Dimov // // 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/smart_ptr/intrusive_ptr.html for documentation. // // intrusive_ptr // // A smart pointer that uses intrusive reference counting. // // Relies on unqualified calls to // // void intrusive_ptr_add_ref(T * p); // void intrusive_ptr_release(T * p); // // (p != 0) // // The object is responsible for destroying itself. #include #include #include #include "butil/build_config.h" #include "butil/containers/hash_tables.h" namespace butil { namespace detail { // NOTE: sp_convertible is different from butil::is_convertible // (in butil/type_traits.h) that it converts pointers only. Using // butil::is_convertible results in ctor/dtor issues. template< class Y, class T > struct sp_convertible { typedef char (&yes) [1]; typedef char (&no) [2]; static yes f( T* ); static no f( ... ); enum _vt { value = sizeof((f)(static_cast(0))) == sizeof(yes) }; }; template< class Y, class T > struct sp_convertible { enum _vt { value = false }; }; template< class Y, class T > struct sp_convertible { enum _vt { value = sp_convertible::value }; }; template struct sp_convertible { enum _vt { value = sp_convertible::value }; }; struct sp_empty {}; template< bool > struct sp_enable_if_convertible_impl; template<> struct sp_enable_if_convertible_impl { typedef sp_empty type; }; template<> struct sp_enable_if_convertible_impl {}; template< class Y, class T > struct sp_enable_if_convertible : public sp_enable_if_convertible_impl::value> {}; } // namespace detail template class intrusive_ptr { private: typedef intrusive_ptr this_type; public: typedef T element_type; intrusive_ptr() BAIDU_NOEXCEPT : px(0) {} intrusive_ptr(T * p, bool add_ref = true): px(p) { if(px != 0 && add_ref) intrusive_ptr_add_ref(px); } template intrusive_ptr(const intrusive_ptr& rhs, typename detail::sp_enable_if_convertible::type = detail::sp_empty()) : px(rhs.get()) { if(px != 0) intrusive_ptr_add_ref(px); } intrusive_ptr(const intrusive_ptr& rhs): px(rhs.px) { if(px != 0) intrusive_ptr_add_ref(px); } ~intrusive_ptr() { if(px != 0) intrusive_ptr_release(px); } template intrusive_ptr & operator=(const intrusive_ptr& rhs) { this_type(rhs).swap(*this); return *this; } // Move support #if defined(BUTIL_CXX11_ENABLED) intrusive_ptr(intrusive_ptr && rhs) BAIDU_NOEXCEPT : px(rhs.px) { rhs.px = 0; } intrusive_ptr & operator=(intrusive_ptr && rhs) BAIDU_NOEXCEPT { this_type(static_cast< intrusive_ptr && >(rhs)).swap(*this); return *this; } #endif intrusive_ptr & operator=(const intrusive_ptr& rhs) { this_type(rhs).swap(*this); return *this; } intrusive_ptr & operator=(T * rhs) { this_type(rhs).swap(*this); return *this; } void reset() BAIDU_NOEXCEPT { this_type().swap(*this); } void reset(T * rhs) { this_type(rhs).swap(*this); } void reset(T * rhs, bool add_ref) { this_type(rhs, add_ref).swap(*this); } T * get() const BAIDU_NOEXCEPT { return px; } T * detach() BAIDU_NOEXCEPT { T * ret = px; px = 0; return ret; } T & operator*() const { return *px; } T * operator->() const { return px; } // implicit conversion to "bool" #if defined(BUTIL_CXX11_ENABLED) explicit operator bool () const BAIDU_NOEXCEPT { return px != 0; } #elif defined(__CINT__) operator bool () const BAIDU_NOEXCEPT { return px != 0; } #elif (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ < 304)) typedef element_type * (this_type::*unspecified_bool_type)() const; operator unspecified_bool_type() const BAIDU_NOEXCEPT { return px == 0? 0: &this_type::get; } #else typedef element_type * this_type::*unspecified_bool_type; operator unspecified_bool_type() const BAIDU_NOEXCEPT { return px == 0? 0: &this_type::px; } #endif // operator! is redundant, but some compilers need it bool operator! () const BAIDU_NOEXCEPT { return px == 0; } void swap(intrusive_ptr & rhs) BAIDU_NOEXCEPT { T * tmp = px; px = rhs.px; rhs.px = tmp; } private: T * px; }; template inline bool operator==(const intrusive_ptr& a, const intrusive_ptr& b) { return a.get() == b.get(); } template inline bool operator!=(const intrusive_ptr& a, const intrusive_ptr& b) { return a.get() != b.get(); } template inline bool operator==(const intrusive_ptr& a, U * b) { return a.get() == b; } template inline bool operator!=(const intrusive_ptr& a, U * b) { return a.get() != b; } template inline bool operator==(T * a, const intrusive_ptr& b) { return a == b.get(); } template inline bool operator!=(T * a, const intrusive_ptr& b) { return a != b.get(); } #if __GNUC__ == 2 && __GNUC_MINOR__ <= 96 // Resolve the ambiguity between our op!= and the one in rel_ops template inline bool operator!=(const intrusive_ptr& a, const intrusive_ptr& b) { return a.get() != b.get(); } #endif #if defined(BUTIL_CXX11_ENABLED) template inline bool operator==(const intrusive_ptr& p, std::nullptr_t) BAIDU_NOEXCEPT { return p.get() == 0; } template inline bool operator==(std::nullptr_t, const intrusive_ptr& p) BAIDU_NOEXCEPT { return p.get() == 0; } template inline bool operator!=(const intrusive_ptr& p, std::nullptr_t) BAIDU_NOEXCEPT { return p.get() != 0; } template inline bool operator!=(std::nullptr_t, const intrusive_ptr& p) BAIDU_NOEXCEPT { return p.get() != 0; } #endif // BUTIL_CXX11_ENABLED template inline bool operator<(const intrusive_ptr& a, const intrusive_ptr& b) { return std::less()(a.get(), b.get()); } template void swap(intrusive_ptr & lhs, intrusive_ptr & rhs) { lhs.swap(rhs); } // mem_fn support template T * get_pointer(const intrusive_ptr& p) { return p.get(); } template intrusive_ptr static_pointer_cast(const intrusive_ptr& p) { return static_cast(p.get()); } template intrusive_ptr const_pointer_cast(const intrusive_ptr& p) { return const_cast(p.get()); } template intrusive_ptr dynamic_pointer_cast(const intrusive_ptr& p) { return dynamic_cast(p.get()); } template std::ostream & operator<< (std::ostream & os, const intrusive_ptr& p) { os << p.get(); return os; } } // namespace butil // hash_value namespace BUTIL_HASH_NAMESPACE { #if defined(COMPILER_GCC) template struct hash > { std::size_t operator()(const butil::intrusive_ptr& p) const { return hash()(p.get()); } }; #elif defined(COMPILER_MSVC) template inline size_t hash_value(const butil::intrusive_ptr& sp) { return hash_value(p.get()); } #endif // COMPILER } // namespace BUTIL_HASH_NAMESPACE #endif // BUTIL_INTRUSIVE_PTR_HPP