SharedPtr.hpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /*
  2. * Copyright (c)2013-2020 ZeroTier, Inc.
  3. *
  4. * Use of this software is governed by the Business Source License included
  5. * in the LICENSE.TXT file in the project's root directory.
  6. *
  7. * Change Date: 2024-01-01
  8. *
  9. * On the date above, in accordance with the Business Source License, use
  10. * of this software will be governed by version 2.0 of the Apache License.
  11. */
  12. /****/
  13. #ifndef ZT_SHAREDPTR_HPP
  14. #define ZT_SHAREDPTR_HPP
  15. #include "AtomicCounter.hpp"
  16. namespace ZeroTier {
  17. /**
  18. * Simple zero-overhead introspective reference counted pointer
  19. *
  20. * This is an introspective shared pointer. Classes that need to be reference
  21. * counted must list this as a 'friend' and must have a private instance of
  22. * AtomicCounter called __refCount.
  23. */
  24. template<typename T>
  25. class SharedPtr
  26. {
  27. public:
  28. ZT_ALWAYS_INLINE SharedPtr() : _ptr((T *)0) {}
  29. explicit ZT_ALWAYS_INLINE SharedPtr(T *obj) : _ptr(obj) { ++obj->__refCount; }
  30. ZT_ALWAYS_INLINE SharedPtr(const SharedPtr &sp) : _ptr(sp._getAndInc()) {}
  31. ZT_ALWAYS_INLINE ~SharedPtr()
  32. {
  33. if (_ptr) {
  34. if (--_ptr->__refCount <= 0)
  35. delete _ptr;
  36. }
  37. }
  38. ZT_ALWAYS_INLINE SharedPtr &operator=(const SharedPtr &sp)
  39. {
  40. if (_ptr != sp._ptr) {
  41. T *p = sp._getAndInc();
  42. if (_ptr) {
  43. if (--_ptr->__refCount <= 0)
  44. delete _ptr;
  45. }
  46. _ptr = p;
  47. }
  48. return *this;
  49. }
  50. /**
  51. * Set to a naked pointer and increment its reference count
  52. *
  53. * This assumes this SharedPtr is NULL and that ptr is not a 'zombie.' No
  54. * checks are performed.
  55. *
  56. * @param ptr Naked pointer to assign
  57. */
  58. ZT_ALWAYS_INLINE void set(T *ptr)
  59. {
  60. zero();
  61. ++ptr->__refCount;
  62. _ptr = ptr;
  63. }
  64. /**
  65. * Swap with another pointer 'for free' without ref count overhead
  66. *
  67. * @param with Pointer to swap with
  68. */
  69. ZT_ALWAYS_INLINE void swap(SharedPtr &with)
  70. {
  71. T *tmp = _ptr;
  72. _ptr = with._ptr;
  73. with._ptr = tmp;
  74. }
  75. /**
  76. * Set this value to one from another pointer and set that pointer to zero (avoids ref count changes)
  77. *
  78. * @param from Origin pointer; will be zeroed
  79. */
  80. ZT_ALWAYS_INLINE void move(SharedPtr &from)
  81. {
  82. if (_ptr) {
  83. if (--_ptr->__refCount <= 0)
  84. delete _ptr;
  85. }
  86. _ptr = from._ptr;
  87. from._ptr = nullptr;
  88. }
  89. ZT_ALWAYS_INLINE operator bool() const { return (_ptr != nullptr); }
  90. ZT_ALWAYS_INLINE T &operator*() const { return *_ptr; }
  91. ZT_ALWAYS_INLINE T *operator->() const { return _ptr; }
  92. /**
  93. * @return Raw pointer to held object
  94. */
  95. ZT_ALWAYS_INLINE T *ptr() const { return _ptr; }
  96. /**
  97. * Set this pointer to NULL
  98. */
  99. ZT_ALWAYS_INLINE void zero()
  100. {
  101. if (_ptr) {
  102. if (--_ptr->__refCount <= 0)
  103. delete _ptr;
  104. _ptr = (T *)0;
  105. }
  106. }
  107. /**
  108. * @return Number of references according to this object's ref count or 0 if NULL
  109. */
  110. ZT_ALWAYS_INLINE int references()
  111. {
  112. if (_ptr)
  113. return _ptr->__refCount.load();
  114. return 0;
  115. }
  116. ZT_ALWAYS_INLINE bool operator==(const SharedPtr &sp) const { return (_ptr == sp._ptr); }
  117. ZT_ALWAYS_INLINE bool operator!=(const SharedPtr &sp) const { return (_ptr != sp._ptr); }
  118. ZT_ALWAYS_INLINE bool operator>(const SharedPtr &sp) const { return (_ptr > sp._ptr); }
  119. ZT_ALWAYS_INLINE bool operator<(const SharedPtr &sp) const { return (_ptr < sp._ptr); }
  120. ZT_ALWAYS_INLINE bool operator>=(const SharedPtr &sp) const { return (_ptr >= sp._ptr); }
  121. ZT_ALWAYS_INLINE bool operator<=(const SharedPtr &sp) const { return (_ptr <= sp._ptr); }
  122. private:
  123. ZT_ALWAYS_INLINE T *_getAndInc() const
  124. {
  125. if (_ptr)
  126. ++_ptr->__refCount;
  127. return _ptr;
  128. }
  129. T *_ptr;
  130. };
  131. } // namespace ZeroTier
  132. namespace std {
  133. template<typename T>
  134. ZT_ALWAYS_INLINE void swap(ZeroTier::SharedPtr<T> &a,ZeroTier::SharedPtr<T> &b) { a.swap(b); }
  135. }
  136. #endif