297 lines
7.6 KiB
C++
297 lines
7.6 KiB
C++
#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 <functional>
|
|
#include <cstddef>
|
|
#include <ostream>
|
|
#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<Y*>(0))) == sizeof(yes) };
|
|
};
|
|
template< class Y, class T > struct sp_convertible<Y, T[]> {
|
|
enum _vt { value = false };
|
|
};
|
|
template< class Y, class T > struct sp_convertible<Y[], T[]> {
|
|
enum _vt { value = sp_convertible<Y[1], T[1]>::value };
|
|
};
|
|
template<class Y, std::size_t N, class T> struct sp_convertible<Y[N], T[]> {
|
|
enum _vt { value = sp_convertible<Y[1], T[1]>::value };
|
|
};
|
|
|
|
struct sp_empty {};
|
|
template< bool > struct sp_enable_if_convertible_impl;
|
|
template<> struct sp_enable_if_convertible_impl<true> { typedef sp_empty type; };
|
|
template<> struct sp_enable_if_convertible_impl<false> {};
|
|
template< class Y, class T > struct sp_enable_if_convertible
|
|
: public sp_enable_if_convertible_impl<sp_convertible<Y, T>::value> {};
|
|
|
|
} // namespace detail
|
|
|
|
template<class T> 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<class U>
|
|
intrusive_ptr(const intrusive_ptr<U>& rhs,
|
|
typename detail::sp_enable_if_convertible<U,T>::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<class U> intrusive_ptr & operator=(const intrusive_ptr<U>& 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<class T, class U>
|
|
inline bool operator==(const intrusive_ptr<T>& a, const intrusive_ptr<U>& b) {
|
|
return a.get() == b.get();
|
|
}
|
|
|
|
template<class T, class U>
|
|
inline bool operator!=(const intrusive_ptr<T>& a, const intrusive_ptr<U>& b) {
|
|
return a.get() != b.get();
|
|
}
|
|
|
|
template<class T, class U>
|
|
inline bool operator==(const intrusive_ptr<T>& a, U * b) {
|
|
return a.get() == b;
|
|
}
|
|
|
|
template<class T, class U>
|
|
inline bool operator!=(const intrusive_ptr<T>& a, U * b) {
|
|
return a.get() != b;
|
|
}
|
|
|
|
template<class T, class U>
|
|
inline bool operator==(T * a, const intrusive_ptr<U>& b) {
|
|
return a == b.get();
|
|
}
|
|
|
|
template<class T, class U>
|
|
inline bool operator!=(T * a, const intrusive_ptr<U>& b) {
|
|
return a != b.get();
|
|
}
|
|
|
|
#if __GNUC__ == 2 && __GNUC_MINOR__ <= 96
|
|
// Resolve the ambiguity between our op!= and the one in rel_ops
|
|
template<class T>
|
|
inline bool operator!=(const intrusive_ptr<T>& a, const intrusive_ptr<T>& b) {
|
|
return a.get() != b.get();
|
|
}
|
|
#endif
|
|
|
|
#if defined(BUTIL_CXX11_ENABLED)
|
|
template<class T>
|
|
inline bool operator==(const intrusive_ptr<T>& p, std::nullptr_t) BAIDU_NOEXCEPT {
|
|
return p.get() == 0;
|
|
}
|
|
template<class T>
|
|
inline bool operator==(std::nullptr_t, const intrusive_ptr<T>& p) BAIDU_NOEXCEPT {
|
|
return p.get() == 0;
|
|
}
|
|
|
|
template<class T>
|
|
inline bool operator!=(const intrusive_ptr<T>& p, std::nullptr_t) BAIDU_NOEXCEPT {
|
|
return p.get() != 0;
|
|
}
|
|
template<class T>
|
|
inline bool operator!=(std::nullptr_t, const intrusive_ptr<T>& p) BAIDU_NOEXCEPT {
|
|
return p.get() != 0;
|
|
}
|
|
#endif // BUTIL_CXX11_ENABLED
|
|
|
|
template<class T>
|
|
inline bool operator<(const intrusive_ptr<T>& a, const intrusive_ptr<T>& b) {
|
|
return std::less<T *>()(a.get(), b.get());
|
|
}
|
|
|
|
template<class T> void swap(intrusive_ptr<T> & lhs, intrusive_ptr<T> & rhs) {
|
|
lhs.swap(rhs);
|
|
}
|
|
|
|
// mem_fn support
|
|
|
|
template<class T> T * get_pointer(const intrusive_ptr<T>& p) {
|
|
return p.get();
|
|
}
|
|
|
|
template<class T, class U> intrusive_ptr<T> static_pointer_cast(const intrusive_ptr<U>& p) {
|
|
return static_cast<T *>(p.get());
|
|
}
|
|
|
|
template<class T, class U> intrusive_ptr<T> const_pointer_cast(const intrusive_ptr<U>& p) {
|
|
return const_cast<T *>(p.get());
|
|
}
|
|
|
|
template<class T, class U> intrusive_ptr<T> dynamic_pointer_cast(const intrusive_ptr<U>& p) {
|
|
return dynamic_cast<T *>(p.get());
|
|
}
|
|
|
|
template<class Y> std::ostream & operator<< (std::ostream & os, const intrusive_ptr<Y>& p) {
|
|
os << p.get();
|
|
return os;
|
|
}
|
|
|
|
} // namespace butil
|
|
|
|
// hash_value
|
|
namespace BUTIL_HASH_NAMESPACE {
|
|
|
|
#if defined(COMPILER_GCC)
|
|
template<typename T>
|
|
struct hash<butil::intrusive_ptr<T> > {
|
|
std::size_t operator()(const butil::intrusive_ptr<T>& p) const {
|
|
return hash<T*>()(p.get());
|
|
}
|
|
};
|
|
#elif defined(COMPILER_MSVC)
|
|
template<typename T>
|
|
inline size_t hash_value(const butil::intrusive_ptr<T>& sp) {
|
|
return hash_value(p.get());
|
|
}
|
|
#endif // COMPILER
|
|
|
|
} // namespace BUTIL_HASH_NAMESPACE
|
|
|
|
#endif // BUTIL_INTRUSIVE_PTR_HPP
|