ref_counted.h 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. #pragma once
  2. #include <library/cpp/yt/misc/port.h>
  3. #include <library/cpp/yt/assert/assert.h>
  4. #include <atomic>
  5. namespace NYT {
  6. ////////////////////////////////////////////////////////////////////////////////
  7. //! A technical base class for ref-counted objects and promise states.
  8. class TRefCountedBase
  9. {
  10. public:
  11. TRefCountedBase() = default;
  12. TRefCountedBase(const TRefCountedBase&) = delete;
  13. TRefCountedBase(TRefCountedBase&&) = delete;
  14. TRefCountedBase& operator=(const TRefCountedBase&) = delete;
  15. TRefCountedBase& operator=(TRefCountedBase&&) = delete;
  16. virtual ~TRefCountedBase() noexcept = default;
  17. virtual void DestroyRefCounted() = 0;
  18. };
  19. ////////////////////////////////////////////////////////////////////////////////
  20. class TRefCounter
  21. {
  22. public:
  23. //! Returns current number of strong references to the object.
  24. /*!
  25. * Note that you should never ever use this method in production code.
  26. * This method is mainly for debugging purposes.
  27. */
  28. int GetRefCount() const noexcept;
  29. //! Increments the strong reference counter.
  30. //! The current strong RC must be positive.
  31. void Ref(int n = 1) const noexcept;
  32. //! Increments the strong reference counter.
  33. //! The current strong RC may be zero.
  34. void DangerousRef(int n = 1) const noexcept;
  35. //! Increments the strong reference counter if it is not null.
  36. bool TryRef() const noexcept;
  37. //! Decrements the strong reference counter.
  38. bool Unref(int n = 1) const;
  39. //! Returns current number of weak references to the object.
  40. int GetWeakRefCount() const noexcept;
  41. //! Increments the weak reference counter.
  42. void WeakRef() const noexcept;
  43. //! Decrements the weak reference counter.
  44. bool WeakUnref() const;
  45. private:
  46. // NB: Must we 64 bit as TAtomicIntrusivePtr grabs refs in 64K batches.
  47. using TRefCount = i64;
  48. mutable std::atomic<TRefCount> StrongCount_ = 1;
  49. mutable std::atomic<TRefCount> WeakCount_ = 1;
  50. };
  51. ////////////////////////////////////////////////////////////////////////////////
  52. template <class T>
  53. const TRefCounter* GetRefCounter(const T* obj);
  54. template <class T>
  55. void DestroyRefCounted(const T* obj);
  56. template <class T>
  57. void DeallocateRefCounted(const T* obj);
  58. ////////////////////////////////////////////////////////////////////////////////
  59. template <class T>
  60. void Ref(T* obj, int n = 1);
  61. template <class T>
  62. void Unref(T* obj, int n = 1);
  63. ////////////////////////////////////////////////////////////////////////////////
  64. class TRefCounted
  65. : public TRefCountedBase
  66. , public TRefCounter
  67. {
  68. public:
  69. void Unref() const;
  70. void WeakUnref() const;
  71. protected:
  72. template <class T>
  73. static void DestroyRefCountedImpl(T* obj);
  74. };
  75. ////////////////////////////////////////////////////////////////////////////////
  76. // Forward declaration.
  77. template <class T>
  78. class TIntrusivePtr;
  79. using TRefCountedPtr = TIntrusivePtr<TRefCounted>;
  80. // A bunch of helpful macros that enable working with intrusive pointers to incomplete types.
  81. /*
  82. * Typically when you have a forward-declared type |T| and an instance
  83. * of |TIntrusivePtr<T>| you need the complete definition of |T| to work with
  84. * the pointer even if you're not actually using the members of |T|.
  85. * E.g. the dtor of |TIntrusivePtr<T>|, should you ever need it, must be able
  86. * to unref an instance of |T| and eventually destroy it.
  87. * This may force #inclusion of way more headers than really seems necessary.
  88. *
  89. * |DECLARE_REFCOUNTED_STRUCT|, |DECLARE_REFCOUNTED_CLASS|, and |DEFINE_REFCOUNTED_TYPE|
  90. * alleviate this issue by forcing TIntrusivePtr to work with the free-standing overloads
  91. * of |Ref| and |Unref| instead of their template version.
  92. * These overloads are declared together with the forward declaration of |T| and
  93. * are subsequently defined afterwards.
  94. */
  95. #define DECLARE_REFCOUNTED_TYPE(type) \
  96. using type ## Ptr = ::NYT::TIntrusivePtr<type>; \
  97. \
  98. [[maybe_unused]] YT_ATTRIBUTE_USED const ::NYT::TRefCounter* GetRefCounter(const type* obj); \
  99. [[maybe_unused]] YT_ATTRIBUTE_USED void DestroyRefCounted(const type* obj); \
  100. [[maybe_unused]] YT_ATTRIBUTE_USED void DeallocateRefCounted(const type* obj);
  101. //! Forward-declares a class type, defines an intrusive pointer for it, and finally
  102. //! declares Ref/Unref overloads. Use this macro in |public.h|-like files.
  103. #define DECLARE_REFCOUNTED_CLASS(type) \
  104. class type; \
  105. DECLARE_REFCOUNTED_TYPE(type)
  106. //! Forward-declares a struct type, defines an intrusive pointer for it, and finally
  107. //! declares Ref/Unref overloads. Use this macro in |public.h|-like files.
  108. #define DECLARE_REFCOUNTED_STRUCT(type) \
  109. struct type; \
  110. DECLARE_REFCOUNTED_TYPE(type)
  111. //! Provides implementations for Ref/Unref overloads. Use this macro right
  112. //! after the type's full definition.
  113. #define DEFINE_REFCOUNTED_TYPE(type) \
  114. [[maybe_unused]] YT_ATTRIBUTE_USED Y_FORCE_INLINE const ::NYT::TRefCounter* GetRefCounter(const type* obj) \
  115. { \
  116. return ::NYT::NDetail::TRefCountedTraits<type>::GetRefCounter(obj); \
  117. } \
  118. [[maybe_unused]] YT_ATTRIBUTE_USED Y_FORCE_INLINE void DestroyRefCounted(const type* obj) \
  119. { \
  120. ::NYT::NDetail::TRefCountedTraits<type>::Destroy(obj); \
  121. } \
  122. [[maybe_unused]] YT_ATTRIBUTE_USED Y_FORCE_INLINE void DeallocateRefCounted(const type* obj) \
  123. { \
  124. ::NYT::NDetail::TRefCountedTraits<type>::Deallocate(obj); \
  125. }
  126. //! Provides weak implementations for Ref/Unref overloads.
  127. //! Do not use if unsure.
  128. #define DEFINE_WEAK_REFCOUNTED_TYPE(type) \
  129. [[maybe_unused]] Y_WEAK YT_ATTRIBUTE_USED const ::NYT::TRefCounter* GetRefCounter(const type*) \
  130. { \
  131. YT_ABORT(); \
  132. } \
  133. [[maybe_unused]] Y_WEAK YT_ATTRIBUTE_USED void DestroyRefCounted(const type*) \
  134. { \
  135. YT_ABORT(); \
  136. } \
  137. [[maybe_unused]] Y_WEAK YT_ATTRIBUTE_USED void DeallocateRefCounted(const type*) \
  138. { \
  139. YT_ABORT(); \
  140. }
  141. ////////////////////////////////////////////////////////////////////////////////
  142. } // namespace NYT
  143. #define REF_COUNTED_INL_H_
  144. #include "ref_counted-inl.h"
  145. #undef REF_COUNTED_INL_H_