libcopp  1.1.0
intrusive_ptr.h
Go to the documentation of this file.
1 
15 #ifndef STD_INTRUSIVE_PTR_H
16 #define STD_INTRUSIVE_PTR_H
17 
18 #pragma once
19 
20 #include <assert.h>
21 #include <cstddef>
22 #include <ostream>
23 
26 
27 namespace std {
28  //
29  // intrusive_ptr
30  //
31  // A smart pointer that uses intrusive reference counting.
32  //
33  // Relies on unqualified calls to
34  //
35  // void intrusive_ptr_add_ref(T * p);
36  // void intrusive_ptr_release(T * p);
37  //
38  // (p != NULL)
39  //
40  // The object is responsible for destroying itself.
41  //
42 
43  template <typename T>
44  class intrusive_ptr {
45  public:
47  typedef T element_type;
48 
49  UTIL_CONFIG_CONSTEXPR intrusive_ptr() UTIL_CONFIG_NOEXCEPT : px(NULL) {}
50 
51  intrusive_ptr(T *p, bool add_ref = true) : px(p) {
52  if (px != NULL && add_ref) {
53  intrusive_ptr_add_ref(px);
54  }
55  }
56 
57  template <typename U>
58  intrusive_ptr(intrusive_ptr<U> const &rhs) : px(rhs.get()) {
59  if (px != NULL) {
60  intrusive_ptr_add_ref(px);
61  }
62  }
63 
64  intrusive_ptr(self_type const &rhs) : px(rhs.px) {
65  if (px != NULL) {
66  intrusive_ptr_add_ref(px);
67  }
68  }
69 
71  if (px != NULL) {
72  intrusive_ptr_release(px);
73  }
74  }
75 
76  template <typename U>
77  friend class intrusive_ptr;
78 
79  template <typename U>
81  self_type(rhs).swap(*this);
82  return *this;
83  }
84 
85  // Move support
86 
87 #if defined(UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES) && UTIL_CONFIG_COMPILER_CXX_RVALUE_REFERENCES
88 
89  intrusive_ptr(self_type &&rhs) UTIL_CONFIG_NOEXCEPT : px(rhs.px) { rhs.px = NULL; }
90 
91  self_type &operator=(self_type &&rhs) UTIL_CONFIG_NOEXCEPT {
92  self_type(static_cast<self_type &&>(rhs)).swap(*this);
93  return *this;
94  }
95 
96  template <typename U>
97  intrusive_ptr(intrusive_ptr<U> &&rhs) UTIL_CONFIG_NOEXCEPT : px(rhs.px) {
98  rhs.px = NULL;
99  }
100 
101  template <typename U, typename Deleter>
102  self_type &operator=(std::unique_ptr<U, Deleter> &&rhs) {
103  self_type(rhs.release()).swap(*this);
104  return *this;
105  }
106 #endif
107 
108  self_type &operator=(self_type const &rhs) {
109  self_type(rhs).swap(*this);
110  return *this;
111  }
112 
113  inline void reset() UTIL_CONFIG_NOEXCEPT { self_type().swap(*this); }
114 
115  inline void reset(element_type *rhs) { self_type(rhs).swap(*this); }
116 
117  inline void reset(element_type *rhs, bool add_ref) { self_type(rhs, add_ref).swap(*this); }
118 
119  inline element_type *get() const UTIL_CONFIG_NOEXCEPT { return px; }
120 
121  inline element_type *detach() UTIL_CONFIG_NOEXCEPT {
122  element_type *ret = px;
123  px = NULL;
124  return ret;
125  }
126 
127  inline element_type &operator*() const {
128  assert(px != 0);
129  return *px;
130  }
131 
132  inline element_type *operator->() const {
133  assert(px != 0);
134  return px;
135  }
136 
137  // implicit conversion to "bool"
138  inline operator bool() const UTIL_CONFIG_NOEXCEPT { return px != NULL; }
139  // operator! is redundant, but some compilers need it
140  inline bool operator!() const UTIL_CONFIG_NOEXCEPT { return px == NULL; }
141 
142  inline void swap(intrusive_ptr &rhs) UTIL_CONFIG_NOEXCEPT {
143  element_type *tmp = px;
144  px = rhs.px;
145  rhs.px = tmp;
146  }
147 
148  private:
149  element_type *px;
150  };
151 
152  template <typename T, typename U>
153  inline bool operator==(intrusive_ptr<T> const &a, intrusive_ptr<U> const &b) {
154  return a.get() == b.get();
155  }
156 
157  template <typename T, typename U>
158  inline bool operator!=(intrusive_ptr<T> const &a, intrusive_ptr<U> const &b) {
159  return a.get() != b.get();
160  }
161 
162  template <typename T, typename U>
163  inline bool operator==(intrusive_ptr<T> const &a, U *b) {
164  return a.get() == b;
165  }
166 
167  template <typename T, typename U>
168  inline bool operator!=(intrusive_ptr<T> const &a, U *b) {
169  return a.get() != b;
170  }
171 
172  template <typename T, typename U>
173  inline bool operator==(T *a, intrusive_ptr<U> const &b) {
174  return a == b.get();
175  }
176 
177  template <typename T, typename U>
178  inline bool operator!=(T *a, intrusive_ptr<U> const &b) {
179  return a != b.get();
180  }
181 
182 #if defined(UTIL_CONFIG_COMPILER_CXX_NULLPTR) && UTIL_CONFIG_COMPILER_CXX_NULLPTR
183 
184  template <typename T>
185  inline bool operator==(intrusive_ptr<T> const &p, std::nullptr_t) UTIL_CONFIG_NOEXCEPT {
186  return p.get() == nullptr;
187  }
188 
189  template <typename T>
190  inline bool operator==(std::nullptr_t, intrusive_ptr<T> const &p) UTIL_CONFIG_NOEXCEPT {
191  return p.get() == nullptr;
192  }
193 
194  template <typename T>
195  inline bool operator!=(intrusive_ptr<T> const &p, std::nullptr_t) UTIL_CONFIG_NOEXCEPT {
196  return p.get() != nullptr;
197  }
198 
199  template <typename T>
200  inline bool operator!=(std::nullptr_t, intrusive_ptr<T> const &p) UTIL_CONFIG_NOEXCEPT {
201  return p.get() != nullptr;
202  }
203 
204 #endif
205 
206  template <typename T>
207  inline bool operator<(intrusive_ptr<T> const &a, intrusive_ptr<T> const &b) {
208  return std::less<T *>()(a.get(), b.get());
209  }
210 
211  template <typename T>
213  lhs.swap(rhs);
214  }
215 
216  // mem_fn support
217 
218  template <typename T>
220  return p.get();
221  }
222 
223  template <typename T, typename U>
225  return static_cast<T *>(p.get());
226  }
227 
228  template <typename T, typename U>
230  return const_cast<T *>(p.get());
231  }
232 
233  template <typename T, typename U>
235  return dynamic_cast<T *>(p.get());
236  }
237 
238  // operator<<
239  template <typename E, typename T, typename Y>
240  std::basic_ostream<E, T> &operator<<(std::basic_ostream<E, T> &os, intrusive_ptr<Y> const &p) {
241  os << p.get();
242  return os;
243  }
244 } // namespace std
245 
246 
247 #if defined(LOCK_DISABLE_MT) && LOCK_DISABLE_MT
248 #define UTIL_INTRUSIVE_PTR_ATOMIC_TYPE ::util::lock::atomic_int_type<util::lock::unsafe_int_type<size_t> >
249 #else
250 #define UTIL_INTRUSIVE_PTR_ATOMIC_TYPE ::util::lock::atomic_int_type<size_t>
251 #endif
252 
253 #define UTIL_INTRUSIVE_PTR_REF_MEMBER_DECL(T) \
254  \
255 private: \
256  UTIL_INTRUSIVE_PTR_ATOMIC_TYPE intrusive_ref_counter_; \
257  friend void intrusive_ptr_add_ref(T *p); \
258  friend void intrusive_ptr_release(T *p); \
259  \
260 public: \
261  const size_t use_count() const { return intrusive_ref_counter_.load(); }
262 
263 #define UTIL_INTRUSIVE_PTR_REF_FN_DECL(T) \
264  void intrusive_ptr_add_ref(T *p); \
265  void intrusive_ptr_release(T *p);
266 
267 #define UTIL_INTRUSIVE_PTR_REF_MEMBER_INIT() this->intrusive_ref_counter_.store(0)
268 
269 #define UTIL_INTRUSIVE_PTR_REF_FN_DEFI(T) \
270  void intrusive_ptr_add_ref(T *p) { \
271  if (nullptr != p) { \
272  ++p->intrusive_ref_counter_; \
273  } \
274  } \
275  void intrusive_ptr_release(T *p) { \
276  if (nullptr == p) { \
277  return; \
278  } \
279  assert(p->intrusive_ref_counter_.load() > 0); \
280  size_t ref = --p->intrusive_ref_counter_; \
281  if (0 == ref) { \
282  delete p; \
283  } \
284  }
285 
286 
287 #endif
T * get_pointer(intrusive_ptr< T > const &p)
self_type & operator=(self_type const &rhs)
element_type * operator->() const
intrusive_ptr(T *p, bool add_ref=true)
Definition: intrusive_ptr.h:51
intrusive_ptr< T > self_type
Definition: intrusive_ptr.h:46
intrusive_ptr & operator=(intrusive_ptr< U > const &rhs)
Definition: intrusive_ptr.h:80
STL namespace.
void reset(element_type *rhs)
element_type * detach() UTIL_CONFIG_NOEXCEPT
element_type & operator*() const
intrusive_ptr(intrusive_ptr< U > const &rhs)
Definition: intrusive_ptr.h:58
bool operator==(intrusive_ptr< T > const &a, intrusive_ptr< U > const &b)
intrusive_ptr(self_type const &rhs)
Definition: intrusive_ptr.h:64
bool operator!=(intrusive_ptr< T > const &a, intrusive_ptr< U > const &b)
element_type * px
void reset(element_type *rhs, bool add_ref)
UTIL_CONFIG_CONSTEXPR intrusive_ptr() UTIL_CONFIG_NOEXCEPT
Definition: intrusive_ptr.h:49
intrusive_ptr< T > dynamic_pointer_cast(intrusive_ptr< U > const &p)
element_type * get() const UTIL_CONFIG_NOEXCEPT
intrusive_ptr< T > const_pointer_cast(intrusive_ptr< U > const &p)
void swap(intrusive_ptr &rhs) UTIL_CONFIG_NOEXCEPT
void reset() UTIL_CONFIG_NOEXCEPT
intrusive_ptr< T > static_pointer_cast(intrusive_ptr< U > const &p)
bool operator!() const UTIL_CONFIG_NOEXCEPT