1#ifndef BUTIL_INTRUSIVE_PTR_HPP
2#define BUTIL_INTRUSIVE_PTR_HPP
3
4// Copyright (c) 2001, 2002 Peter Dimov
5//
6// Distributed under the Boost Software License, Version 1.0. (See
7// accompanying file LICENSE_1_0.txt or copy at
8// http://www.boost.org/LICENSE_1_0.txt)
9//
10// See http://www.boost.org/libs/smart_ptr/intrusive_ptr.html for documentation.
11//
12// intrusive_ptr
13//
14// A smart pointer that uses intrusive reference counting.
15//
16// Relies on unqualified calls to
17//
18// void intrusive_ptr_add_ref(T * p);
19// void intrusive_ptr_release(T * p);
20//
21// (p != 0)
22//
23// The object is responsible for destroying itself.
24
25#include <functional>
26#include <cstddef>
27#include <ostream>
28#include "butil/build_config.h"
29#include "butil/containers/hash_tables.h"
30
31namespace butil {
32
33namespace detail {
34
35// NOTE: sp_convertible is different from butil::is_convertible
36// (in butil/type_traits.h) that it converts pointers only. Using
37// butil::is_convertible results in ctor/dtor issues.
38template< class Y, class T > struct sp_convertible {
39 typedef char (&yes) [1];
40 typedef char (&no) [2];
41
42 static yes f( T* );
43 static no f( ... );
44
45 enum _vt { value = sizeof((f)(static_cast<Y*>(0))) == sizeof(yes) };
46};
47template< class Y, class T > struct sp_convertible<Y, T[]> {
48 enum _vt { value = false };
49};
50template< class Y, class T > struct sp_convertible<Y[], T[]> {
51 enum _vt { value = sp_convertible<Y[1], T[1]>::value };
52};
53template<class Y, std::size_t N, class T> struct sp_convertible<Y[N], T[]> {
54 enum _vt { value = sp_convertible<Y[1], T[1]>::value };
55};
56
57struct sp_empty {};
58template< bool > struct sp_enable_if_convertible_impl;
59template<> struct sp_enable_if_convertible_impl<true> { typedef sp_empty type; };
60template<> struct sp_enable_if_convertible_impl<false> {};
61template< class Y, class T > struct sp_enable_if_convertible
62 : public sp_enable_if_convertible_impl<sp_convertible<Y, T>::value> {};
63
64} // namespace detail
65
66template<class T> class intrusive_ptr {
67private:
68 typedef intrusive_ptr this_type;
69public:
70 typedef T element_type;
71 intrusive_ptr() BAIDU_NOEXCEPT : px(0) {}
72
73 intrusive_ptr(T * p, bool add_ref = true): px(p) {
74 if(px != 0 && add_ref) intrusive_ptr_add_ref(px);
75 }
76
77 template<class U>
78 intrusive_ptr(const intrusive_ptr<U>& rhs,
79 typename detail::sp_enable_if_convertible<U,T>::type = detail::sp_empty())
80 : px(rhs.get()) {
81 if(px != 0) intrusive_ptr_add_ref(px);
82 }
83
84 intrusive_ptr(const intrusive_ptr& rhs): px(rhs.px) {
85 if(px != 0) intrusive_ptr_add_ref(px);
86 }
87
88 ~intrusive_ptr() {
89 if(px != 0) intrusive_ptr_release(px);
90 }
91
92 template<class U> intrusive_ptr & operator=(const intrusive_ptr<U>& rhs) {
93 this_type(rhs).swap(*this);
94 return *this;
95 }
96
97// Move support
98#if defined(BUTIL_CXX11_ENABLED)
99 intrusive_ptr(intrusive_ptr && rhs) BAIDU_NOEXCEPT : px(rhs.px) {
100 rhs.px = 0;
101 }
102
103 intrusive_ptr & operator=(intrusive_ptr && rhs) BAIDU_NOEXCEPT {
104 this_type(static_cast< intrusive_ptr && >(rhs)).swap(*this);
105 return *this;
106 }
107#endif
108
109 intrusive_ptr & operator=(const intrusive_ptr& rhs) {
110 this_type(rhs).swap(*this);
111 return *this;
112 }
113
114 intrusive_ptr & operator=(T * rhs) {
115 this_type(rhs).swap(*this);
116 return *this;
117 }
118
119 void reset() BAIDU_NOEXCEPT {
120 this_type().swap(*this);
121 }
122
123 void reset(T * rhs) {
124 this_type(rhs).swap(*this);
125 }
126
127 void reset(T * rhs, bool add_ref) {
128 this_type(rhs, add_ref).swap(*this);
129 }
130
131 T * get() const BAIDU_NOEXCEPT {
132 return px;
133 }
134
135 T * detach() BAIDU_NOEXCEPT {
136 T * ret = px;
137 px = 0;
138 return ret;
139 }
140
141 T & operator*() const {
142 return *px;
143 }
144
145 T * operator->() const {
146 return px;
147 }
148
149 // implicit conversion to "bool"
150#if defined(BUTIL_CXX11_ENABLED)
151 explicit operator bool () const BAIDU_NOEXCEPT {
152 return px != 0;
153 }
154#elif defined(__CINT__)
155 operator bool () const BAIDU_NOEXCEPT {
156 return px != 0;
157 }
158#elif (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ < 304))
159 typedef element_type * (this_type::*unspecified_bool_type)() const;
160 operator unspecified_bool_type() const BAIDU_NOEXCEPT {
161 return px == 0? 0: &this_type::get;
162 }
163#else
164 typedef element_type * this_type::*unspecified_bool_type;
165 operator unspecified_bool_type() const BAIDU_NOEXCEPT {
166 return px == 0? 0: &this_type::px;
167 }
168#endif
169
170 // operator! is redundant, but some compilers need it
171 bool operator! () const BAIDU_NOEXCEPT {
172 return px == 0;
173 }
174
175 void swap(intrusive_ptr & rhs) BAIDU_NOEXCEPT {
176 T * tmp = px;
177 px = rhs.px;
178 rhs.px = tmp;
179 }
180
181private:
182 T * px;
183};
184
185template<class T, class U>
186inline bool operator==(const intrusive_ptr<T>& a, const intrusive_ptr<U>& b) {
187 return a.get() == b.get();
188}
189
190template<class T, class U>
191inline bool operator!=(const intrusive_ptr<T>& a, const intrusive_ptr<U>& b) {
192 return a.get() != b.get();
193}
194
195template<class T, class U>
196inline bool operator==(const intrusive_ptr<T>& a, U * b) {
197 return a.get() == b;
198}
199
200template<class T, class U>
201inline bool operator!=(const intrusive_ptr<T>& a, U * b) {
202 return a.get() != b;
203}
204
205template<class T, class U>
206inline bool operator==(T * a, const intrusive_ptr<U>& b) {
207 return a == b.get();
208}
209
210template<class T, class U>
211inline bool operator!=(T * a, const intrusive_ptr<U>& b) {
212 return a != b.get();
213}
214
215#if __GNUC__ == 2 && __GNUC_MINOR__ <= 96
216// Resolve the ambiguity between our op!= and the one in rel_ops
217template<class T>
218inline bool operator!=(const intrusive_ptr<T>& a, const intrusive_ptr<T>& b) {
219 return a.get() != b.get();
220}
221#endif
222
223#if defined(BUTIL_CXX11_ENABLED)
224template<class T>
225inline bool operator==(const intrusive_ptr<T>& p, std::nullptr_t) BAIDU_NOEXCEPT {
226 return p.get() == 0;
227}
228template<class T>
229inline bool operator==(std::nullptr_t, const intrusive_ptr<T>& p) BAIDU_NOEXCEPT {
230 return p.get() == 0;
231}
232
233template<class T>
234inline bool operator!=(const intrusive_ptr<T>& p, std::nullptr_t) BAIDU_NOEXCEPT {
235 return p.get() != 0;
236}
237template<class T>
238inline bool operator!=(std::nullptr_t, const intrusive_ptr<T>& p) BAIDU_NOEXCEPT {
239 return p.get() != 0;
240}
241#endif // BUTIL_CXX11_ENABLED
242
243template<class T>
244inline bool operator<(const intrusive_ptr<T>& a, const intrusive_ptr<T>& b) {
245 return std::less<T *>()(a.get(), b.get());
246}
247
248template<class T> void swap(intrusive_ptr<T> & lhs, intrusive_ptr<T> & rhs) {
249 lhs.swap(rhs);
250}
251
252// mem_fn support
253
254template<class T> T * get_pointer(const intrusive_ptr<T>& p) {
255 return p.get();
256}
257
258template<class T, class U> intrusive_ptr<T> static_pointer_cast(const intrusive_ptr<U>& p) {
259 return static_cast<T *>(p.get());
260}
261
262template<class T, class U> intrusive_ptr<T> const_pointer_cast(const intrusive_ptr<U>& p) {
263 return const_cast<T *>(p.get());
264}
265
266template<class T, class U> intrusive_ptr<T> dynamic_pointer_cast(const intrusive_ptr<U>& p) {
267 return dynamic_cast<T *>(p.get());
268}
269
270template<class Y> std::ostream & operator<< (std::ostream & os, const intrusive_ptr<Y>& p) {
271 os << p.get();
272 return os;
273}
274
275} // namespace butil
276
277// hash_value
278namespace BUTIL_HASH_NAMESPACE {
279
280#if defined(COMPILER_GCC)
281template<typename T>
282struct hash<butil::intrusive_ptr<T> > {
283 std::size_t operator()(const butil::intrusive_ptr<T>& p) const {
284 return hash<T*>()(p.get());
285 }
286};
287#elif defined(COMPILER_MSVC)
288template<typename T>
289inline size_t hash_value(const butil::intrusive_ptr<T>& sp) {
290 return hash_value(p.get());
291}
292#endif // COMPILER
293
294} // namespace BUTIL_HASH_NAMESPACE
295
296#endif // BUTIL_INTRUSIVE_PTR_HPP
297