CsPointer  2.0.0
cs_intrusive_pointer.h
1 
19 #ifndef LIB_CS_INTRUSIVE_POINTER_H
20 #define LIB_CS_INTRUSIVE_POINTER_H
21 
22 #include <atomic>
23 #include <memory>
24 
25 namespace CsPointer {
26 
27 enum class CsIntrusiveAction {
28  Normal,
29  NoDelete,
30 };
31 
33 {
34  public:
35  virtual ~CsIntrusiveBase() = default;
36 
37  private:
38  mutable std::atomic<std::size_t> m_count = 0;
39 
40  void cs_inc_ref_count() const noexcept {
41  m_count.fetch_add(1);
42  }
43 
44  void cs_dec_ref_count(CsIntrusiveAction action) const {
45  std::size_t old_count = m_count.fetch_sub(1);
46 
47  if (action != CsIntrusiveAction::NoDelete) {
48  if (old_count == 1) {
49  delete this;
50  }
51  }
52  }
53 
54  std::size_t cs_get_ref_count() const {
55  return m_count.load();
56  }
57 
58  friend class CsIntrusiveDefaultPolicy;
59 };
60 
61 class CsIntrusiveBase_CM
62 {
63  public:
64  CsIntrusiveBase_CM() = default;
65 
66  CsIntrusiveBase_CM(const CsIntrusiveBase_CM &other) noexcept {
67  m_count = 0;
68  }
69 
70  CsIntrusiveBase_CM &operator=(const CsIntrusiveBase_CM &other) noexcept {
71  // copy assignment does not alter the reference count
72  return *this;
73  }
74 
75  CsIntrusiveBase_CM(CsIntrusiveBase_CM &&other) noexcept {
76  m_count = 0;
77  }
78 
79  CsIntrusiveBase_CM &operator=(CsIntrusiveBase_CM &&other) noexcept {
80  // move assignment does not alter the reference count
81  return *this;
82  }
83 
84  virtual ~CsIntrusiveBase_CM() = default;
85 
86  private:
87  mutable std::atomic<std::size_t> m_count = 0;
88 
89  void cs_inc_ref_count() const noexcept {
90  m_count.fetch_add(1);
91  }
92 
93  void cs_dec_ref_count(CsIntrusiveAction action) const {
94  std::size_t old_count = m_count.fetch_sub(1);
95 
96  if (action != CsIntrusiveAction::NoDelete) {
97  if (old_count == 1) {
98  delete this;
99  }
100  }
101  }
102 
103  std::size_t cs_get_ref_count() const {
104  return m_count.load();
105  }
106 
107  friend class CsIntrusiveDefaultPolicy;
108 };
109 
111 {
112  public:
113  template <typename T>
114  static void inc_ref_count(const T *ptr) noexcept {
115  ptr->cs_inc_ref_count();
116  }
117 
118  template <typename T>
119  static void dec_ref_count(const T *ptr, CsIntrusiveAction action = CsIntrusiveAction::Normal) {
120  ptr->cs_dec_ref_count(action);
121  }
122 
123  template <typename T>
124  static std::size_t get_ref_count(const T *ptr) noexcept {
125  return ptr->cs_get_ref_count();
126  }
127 };
128 
129 template <typename T, typename Policy = CsIntrusiveDefaultPolicy>
131 {
132  public:
133  using pointer = T *;
134  using element_type = T;
135 
136  using Pointer = pointer;
138 
139  constexpr CsIntrusivePointer() noexcept
140  : m_ptr(nullptr)
141  {
142  }
143 
144  constexpr CsIntrusivePointer(std::nullptr_t) noexcept
145  : m_ptr(nullptr)
146  {
147  }
148 
149  template <typename U>
150  explicit CsIntrusivePointer(U *p)
151  : m_ptr(p)
152  {
153  // static_assert(std::is_base_of_v<CsIntrusiveBase, T>, "Class T must inherit from CsIntrusiveBase");
154 
155  if (m_ptr != nullptr) {
156  Policy::inc_ref_count(m_ptr);
157  }
158  }
159 
161  {
162  if (m_ptr != nullptr) {
163  Policy::dec_ref_count(m_ptr);
164  }
165  }
166 
167  // copy constructor
169  : m_ptr(other.m_ptr)
170  {
171  if (m_ptr != nullptr) {
172  Policy::inc_ref_count(m_ptr);
173  }
174  }
175 
177  return *this = other.m_ptr;
178  }
179 
180  // move constructor
182  : m_ptr(other.m_ptr)
183  {
184  other.m_ptr = nullptr;
185  }
186 
188  if (m_ptr == other.m_ptr) {
189  return *this;
190  }
191 
192  if (m_ptr != nullptr) {
193  Policy::dec_ref_count(m_ptr);
194  m_ptr = nullptr;
195  }
196 
197  std::swap(m_ptr, other.m_ptr);
198  return *this;
199  }
200 
202  if (m_ptr != p) {
203  if (p != nullptr) {
204  Policy::inc_ref_count(p);
205  }
206 
207  if (m_ptr != nullptr) {
208  Policy::dec_ref_count(m_ptr);
209  }
210 
211  m_ptr = p;
212  }
213 
214  return *this;
215  }
216 
217  template <typename U>
219  : m_ptr(p.m_ptr)
220  {
221  if (m_ptr != nullptr) {
222  Policy::inc_ref_count(m_ptr);
223  }
224  }
225 
226  template <typename U>
228  CsIntrusivePointer<T>(p).swap(*this);
229  return *this;
230  }
231 
232  template <typename U>
234  : m_ptr(p.m_ptr)
235  {
236  p.m_ptr = nullptr;
237  }
238 
239  template <typename U>
241  if (m_ptr == p.m_ptr) {
242  return *this;
243  }
244 
245  if (m_ptr != nullptr) {
246  Policy::dec_ref_count(m_ptr);
247  }
248 
249  m_ptr = p.m_ptr;
250  p.m_ptr = nullptr;
251 
252  return *this;
253  }
254 
255  T &operator*() const noexcept {
256  return *m_ptr;
257  }
258 
259  T *operator->() const noexcept {
260  return m_ptr;
261  }
262 
263  bool operator !() const noexcept {
264  return m_ptr == nullptr;
265  }
266 
267  operator bool() const {
268  return m_ptr != nullptr;
269  }
270 
271  //
272  void clear() noexcept {
273  reset();
274  }
275 
276  Pointer data() const noexcept {
277  return m_ptr;
278  }
279 
280  Pointer get() const noexcept
281  {
282  return m_ptr;
283  }
284 
285  bool is_null() const noexcept {
286  return m_ptr == nullptr;
287  }
288 
289  Pointer release_if() noexcept {
290  if (use_count() == 1) {
291  Pointer tmpPtr = m_ptr;
292  Policy::dec_ref_count(m_ptr, CsIntrusiveAction::NoDelete);
293 
294  m_ptr = nullptr;
295 
296  return tmpPtr;
297 
298  } else {
299  return nullptr;
300 
301  }
302  }
303 
304  void reset() {
305  if (m_ptr != nullptr) {
306  Policy::dec_ref_count(m_ptr);
307  }
308 
309  m_ptr = nullptr;
310  }
311 
312  template <typename U>
313  void reset(U *p) {
314  CsIntrusivePointer<T>(p).swap(*this);
315  }
316 
317  void swap(CsIntrusivePointer &other) noexcept {
318  std::swap(m_ptr, other.m_ptr);
319  }
320 
321  std::size_t use_count() const noexcept {
322  if (m_ptr == nullptr) {
323  return 0;
324 
325  } else {
326  return Policy::get_ref_count(m_ptr);
327  }
328  }
329 
330  private:
331  T *m_ptr;
332 
333  template <typename U, typename OtherPolicy>
334  friend class CsIntrusivePointer;
335 };
336 
337 template <typename T, typename... Args>
339 {
340  return CsIntrusivePointer<T>(new T(std::forward<Args>(args)...));
341 }
342 
343 // equal
344 template <typename T1, typename T2>
345 bool operator==(const CsIntrusivePointer<T1> &ptr1, const CsIntrusivePointer<T2> &ptr2) noexcept
346 {
347  return ptr1.get() == ptr2.get();
348 }
349 
350 template <typename T1, typename T2>
351 bool operator==(const CsIntrusivePointer<T1> &ptr1, const T2 *ptr2) noexcept
352 {
353  return ptr1.get() == ptr2;
354 }
355 
356 template <typename T1, typename T2>
357 bool operator==(const T1 *ptr1, const CsIntrusivePointer<T2> &ptr2) noexcept
358 {
359  return ptr1 == ptr2.get();
360 }
361 
362 template <typename T>
363 bool operator==(const CsIntrusivePointer<T> &ptr1, std::nullptr_t) noexcept
364 {
365  return ptr1.get() == nullptr;
366 }
367 
368 template <typename T>
369 bool operator==(std::nullptr_t, const CsIntrusivePointer<T> &ptr2) noexcept
370 {
371  return nullptr == ptr2.get();
372 }
373 
374 // not equal
375 template <typename T1, typename T2>
376 bool operator!=(const CsIntrusivePointer<T1> &ptr1, const CsIntrusivePointer<T2> &ptr2) noexcept
377 {
378  return ptr1.get() != ptr2.get();
379 }
380 
381 template <typename T1, typename T2>
382 bool operator!=(const CsIntrusivePointer<T1> &ptr1, const T2 *ptr2) noexcept
383 {
384  return ptr1.get() != ptr2;
385 }
386 
387 template <typename T1, typename T2>
388 bool operator!=(const T1 *ptr1, const CsIntrusivePointer<T2> &ptr2) noexcept
389 {
390  return ptr1 != ptr2.get();
391 }
392 
393 template <typename T>
394 bool operator!=(const CsIntrusivePointer<T> &ptr1, std::nullptr_t) noexcept
395 {
396  return ptr1.get() != nullptr;
397 }
398 
399 template <typename T>
400 bool operator!=(std::nullptr_t, const CsIntrusivePointer<T> &ptr2) noexcept
401 {
402  return nullptr != ptr2.get();
403 }
404 
405 // compare
406 template <typename T1, typename T2>
407 bool operator<(const CsIntrusivePointer<T1> &ptr1, const CsIntrusivePointer<T2> &ptr2) noexcept
408 {
409  return ptr1.get() < ptr2.get();
410 }
411 
412 template <typename T1, typename T2>
413 bool operator<=(const CsIntrusivePointer<T1> &ptr1, const CsIntrusivePointer<T2> &ptr2) noexcept
414 {
415  return ptr1.get() <= ptr2.get();
416 }
417 
418 template <typename T1, typename T2>
419 bool operator>(const CsIntrusivePointer<T1> &ptr1, const CsIntrusivePointer<T2> &ptr2) noexcept
420 {
421  return ptr1.get() > ptr2.get();
422 }
423 
424 template <typename T1, typename T2>
425 bool operator>=(const CsIntrusivePointer<T1> &ptr1, const CsIntrusivePointer<T2> &ptr2) noexcept
426 {
427  return ptr1.get() >= ptr2.get();
428 }
429 
430 template <typename T>
432 {
433  ptr1.swap(ptr2);
434 }
435 
436 // cast functions
437 template <typename T, typename U>
439 {
440  return CsIntrusivePointer<T>(const_cast<T *> (ptr.get()));
441 }
442 
443 template <typename T, typename U>
445 {
446  return CsIntrusivePointer<T>(dynamic_cast<T *> (ptr.get()));
447 }
448 
449 template <typename T, typename U>
451 {
452  return CsIntrusivePointer<T>(static_cast<T *> (ptr.get()));
453 }
454 
455 } // end namespace
456 
457 #endif
CsIntrusivePointer< T > static_pointer_cast(const CsIntrusivePointer< U > &ptr)
Definition: cs_intrusive_pointer.h:450
bool operator>=(const CsIntrusivePointer< T1 > &ptr1, const CsIntrusivePointer< T2 > ptr2)
bool operator>(const CsIntrusivePointer< T1 > &ptr1, const CsIntrusivePointer< T2 > ptr2)
bool operator<=(const CsIntrusivePointer< T1 > &ptr1, const CsIntrusivePointer< T2 > ptr2)
bool operator<(const CsIntrusivePointer< T1 > &ptr1, const CsIntrusivePointer< T2 > ptr2)
void reset(U *p)
Definition: cs_intrusive_pointer.h:313
bool is_null() const noexcept
Definition: cs_intrusive_pointer.h:285
bool operator==(const CsIntrusivePointer< T1 > &ptr1, const CsIntrusivePointer< T2 > &ptr2) noexcept
Definition: cs_intrusive_pointer.h:345
Pointer get() const noexcept
Definition: cs_intrusive_pointer.h:280
void reset()
Definition: cs_intrusive_pointer.h:304
CsIntrusivePointer< T > const_pointer_cast(const CsIntrusivePointer< U > &ptr)
Definition: cs_intrusive_pointer.h:438
void clear() noexcept
Definition: cs_intrusive_pointer.h:272
constexpr CsIntrusivePointer() noexcept
Definition: cs_intrusive_pointer.h:139
std::size_t use_count() const noexcept
Definition: cs_intrusive_pointer.h:321
element_type ElementType
Definition: cs_intrusive_pointer.h:137
CsIntrusivePointer & operator=(const CsIntrusivePointer< U > &p)
Definition: cs_intrusive_pointer.h:227
pointer Pointer
Definition: cs_intrusive_pointer.h:136
CsIntrusivePointer(const CsIntrusivePointer &other)
Definition: cs_intrusive_pointer.h:168
Pointer data() const noexcept
Definition: cs_intrusive_pointer.h:276
T * pointer
Definition: cs_intrusive_pointer.h:133
Namespace for the CsPointer library.
T * operator->() const noexcept
Definition: cs_intrusive_pointer.h:259
static void dec_ref_count(const T *ptr, CsIntrusiveAction action=CsIntrusiveAction::Normal)
Definition: cs_intrusive_pointer.h:119
CsIntrusivePointer< T > dynamic_pointer_cast(const CsIntrusivePointer< U > &ptr)
Definition: cs_intrusive_pointer.h:444
static void inc_ref_count(const T *ptr) noexcept
Definition: cs_intrusive_pointer.h:114
CsIntrusivePointer & operator=(T *p)
Definition: cs_intrusive_pointer.h:201
T element_type
Definition: cs_intrusive_pointer.h:134
CsIntrusivePointer(CsIntrusivePointer &&other) noexcept
Definition: cs_intrusive_pointer.h:181
virtual ~CsIntrusiveBase() = default
constexpr CsIntrusivePointer(std::nullptr_t) noexcept
Definition: cs_intrusive_pointer.h:144
bool operator!=(const CsIntrusivePointer< T1 > &ptr1, const CsIntrusivePointer< T2 > &ptr2) noexcept
Definition: cs_intrusive_pointer.h:376
Default implementation for incrementing or decrementing the reference count for CsIntrusivePointer...
Definition: cs_intrusive_pointer.h:110
Implements reference count functions for CsIntrusivePointer.
Definition: cs_intrusive_pointer.h:32
Pointer release_if() noexcept
Definition: cs_intrusive_pointer.h:289
CsIntrusivePointer(U *p)
Definition: cs_intrusive_pointer.h:150
T & operator*() const noexcept
Definition: cs_intrusive_pointer.h:255
~CsIntrusivePointer()
Definition: cs_intrusive_pointer.h:160
static std::size_t get_ref_count(const T *ptr) noexcept
Definition: cs_intrusive_pointer.h:124
CsIntrusivePointer & operator=(const CsIntrusivePointer &other)
Definition: cs_intrusive_pointer.h:176
CsIntrusivePointer & operator=(CsIntrusivePointer &&other) noexcept
Definition: cs_intrusive_pointer.h:187
CsIntrusivePointer(const CsIntrusivePointer< U > &p) noexcept
Definition: cs_intrusive_pointer.h:218
CsIntrusivePointer(CsIntrusivePointer< U > &&p) noexcept
Definition: cs_intrusive_pointer.h:233
CsIntrusivePointer< T > make_intrusive(Args &&...args)
Definition: cs_intrusive_pointer.h:338
Manages a pointer to an object, the reference count is stored in the object.
Definition: cs_intrusive_pointer.h:130
bool operator!() const noexcept
Definition: cs_intrusive_pointer.h:263
void swap(CsIntrusivePointer &other) noexcept
Definition: cs_intrusive_pointer.h:317
CsIntrusivePointer & operator=(CsIntrusivePointer< U > &&p)
Definition: cs_intrusive_pointer.h:240