SharedPtr.hpp 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
  4. *
  5. * (c) ZeroTier, Inc.
  6. * https://www.zerotier.com/
  7. */
  8. #ifndef ZT_SHAREDPTR_HPP
  9. #define ZT_SHAREDPTR_HPP
  10. #include "AtomicCounter.hpp"
  11. #include "Mutex.hpp"
  12. namespace ZeroTier {
  13. /**
  14. * Simple zero-overhead introspective reference counted pointer
  15. *
  16. * This is an introspective shared pointer. Classes that need to be reference
  17. * counted must list this as a 'friend' and must have a private instance of
  18. * AtomicCounter called __refCount.
  19. */
  20. template <typename T> class SharedPtr {
  21. public:
  22. SharedPtr() : _ptr((T*)0)
  23. {
  24. }
  25. SharedPtr(T* obj) : _ptr(obj)
  26. {
  27. ++obj->__refCount;
  28. }
  29. SharedPtr(const SharedPtr& sp) : _ptr(sp._getAndInc())
  30. {
  31. }
  32. ~SharedPtr()
  33. {
  34. if (_ptr) {
  35. if (--_ptr->__refCount <= 0) {
  36. delete _ptr;
  37. }
  38. }
  39. }
  40. inline SharedPtr& operator=(const SharedPtr& sp)
  41. {
  42. if (_ptr != sp._ptr) {
  43. T* p = sp._getAndInc();
  44. if (_ptr) {
  45. if (--_ptr->__refCount <= 0) {
  46. delete _ptr;
  47. }
  48. }
  49. _ptr = p;
  50. }
  51. return *this;
  52. }
  53. /**
  54. * Set to a naked pointer and increment its reference count
  55. *
  56. * This assumes this SharedPtr is NULL and that ptr is not a 'zombie.' No
  57. * checks are performed.
  58. *
  59. * @param ptr Naked pointer to assign
  60. */
  61. inline void set(T* ptr)
  62. {
  63. zero();
  64. ++ptr->__refCount;
  65. _ptr = ptr;
  66. }
  67. /**
  68. * Swap with another pointer 'for free' without ref count overhead
  69. *
  70. * @param with Pointer to swap with
  71. */
  72. inline void swap(SharedPtr& with)
  73. {
  74. T* tmp = _ptr;
  75. _ptr = with._ptr;
  76. with._ptr = tmp;
  77. }
  78. inline operator bool() const
  79. {
  80. return (_ptr != (T*)0);
  81. }
  82. inline T& operator*() const
  83. {
  84. return *_ptr;
  85. }
  86. inline T* operator->() const
  87. {
  88. return _ptr;
  89. }
  90. /**
  91. * @return Raw pointer to held object
  92. */
  93. inline T* ptr() const
  94. {
  95. return _ptr;
  96. }
  97. /**
  98. * Set this pointer to NULL
  99. */
  100. inline void zero()
  101. {
  102. if (_ptr) {
  103. if (--_ptr->__refCount <= 0) {
  104. delete _ptr;
  105. }
  106. _ptr = (T*)0;
  107. }
  108. }
  109. /**
  110. * @return Number of references according to this object's ref count or 0 if NULL
  111. */
  112. inline int references()
  113. {
  114. if (_ptr) {
  115. return _ptr->__refCount.load();
  116. }
  117. return 0;
  118. }
  119. inline bool operator==(const SharedPtr& sp) const
  120. {
  121. return (_ptr == sp._ptr);
  122. }
  123. inline bool operator!=(const SharedPtr& sp) const
  124. {
  125. return (_ptr != sp._ptr);
  126. }
  127. inline bool operator>(const SharedPtr& sp) const
  128. {
  129. return (_ptr > sp._ptr);
  130. }
  131. inline bool operator<(const SharedPtr& sp) const
  132. {
  133. return (_ptr < sp._ptr);
  134. }
  135. inline bool operator>=(const SharedPtr& sp) const
  136. {
  137. return (_ptr >= sp._ptr);
  138. }
  139. inline bool operator<=(const SharedPtr& sp) const
  140. {
  141. return (_ptr <= sp._ptr);
  142. }
  143. private:
  144. inline T* _getAndInc() const
  145. {
  146. if (_ptr) {
  147. ++_ptr->__refCount;
  148. }
  149. return _ptr;
  150. }
  151. T* _ptr;
  152. };
  153. } // namespace ZeroTier
  154. #endif