aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/yt/memory/ref_counted.h
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/yt/memory/ref_counted.h
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/yt/memory/ref_counted.h')
-rw-r--r--library/cpp/yt/memory/ref_counted.h190
1 files changed, 190 insertions, 0 deletions
diff --git a/library/cpp/yt/memory/ref_counted.h b/library/cpp/yt/memory/ref_counted.h
new file mode 100644
index 0000000000..b683615b83
--- /dev/null
+++ b/library/cpp/yt/memory/ref_counted.h
@@ -0,0 +1,190 @@
+#pragma once
+
+#include <library/cpp/yt/misc/port.h>
+
+#include <library/cpp/yt/assert/assert.h>
+
+#include <library/cpp/ytalloc/api/ytalloc.h>
+
+#include <atomic>
+
+namespace NYT {
+
+////////////////////////////////////////////////////////////////////////////////
+
+//! A technical base class for ref-counted objects and promise states.
+class TRefCountedBase
+{
+public:
+ TRefCountedBase() = default;
+
+ // Make destructor protected
+ virtual ~TRefCountedBase() noexcept = default;
+
+ virtual void DestroyRefCounted() = 0;
+
+private:
+ TRefCountedBase(const TRefCountedBase&) = delete;
+ TRefCountedBase(TRefCountedBase&&) = delete;
+
+ TRefCountedBase& operator=(const TRefCountedBase&) = delete;
+ TRefCountedBase& operator=(TRefCountedBase&&) = delete;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T, class = void>
+struct TFreeMemory
+{
+ static void Do(void* ptr)
+ {
+ NYTAlloc::FreeNonNull(ptr);
+ }
+};
+
+template <class T>
+struct TFreeMemory<T, std::void_t<typename T::TAllocator>>
+{
+ static void Do(void* ptr)
+ {
+ using TAllocator = typename T::TAllocator;
+ TAllocator::Free(ptr);
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+class TRefCounter
+{
+public:
+ //! Returns current number of strong references to the object.
+ /*!
+ * Note that you should never ever use this method in production code.
+ * This method is mainly for debugging purposes.
+ */
+ int GetRefCount() const noexcept;
+
+ //! Increments the strong reference counter.
+ void Ref() const noexcept;
+
+ //! Increments the strong reference counter if it is not null.
+ bool TryRef() const noexcept;
+
+ //! Decrements the strong reference counter.
+ bool Unref() const;
+
+ //! Returns current number of weak references to the object.
+ int GetWeakRefCount() const noexcept;
+
+ //! Increments the weak reference counter.
+ void WeakRef() const noexcept;
+
+ //! Decrements the weak reference counter.
+ bool WeakUnref() const;
+
+private:
+ mutable std::atomic<int> StrongCount_ = 1;
+ mutable std::atomic<int> WeakCount_ = 1;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+const TRefCounter* GetRefCounter(const T* obj);
+
+template <class T>
+void DestroyRefCounted(const T* obj);
+
+template <class T>
+void DeallocateRefCounted(const T* obj);
+
+////////////////////////////////////////////////////////////////////////////////
+
+// API
+
+template <class T>
+void Ref(T* obj);
+
+template <class T>
+void Unref(T* obj);
+
+////////////////////////////////////////////////////////////////////////////////
+
+struct TRefCounted
+ : public TRefCountedBase
+ , public TRefCounter
+{
+ void Unref() const;
+
+ void WeakUnref() const;
+
+ template <class T>
+ static void DestroyRefCountedImpl(T* ptr);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Forward declaration.
+template <class T>
+class TIntrusivePtr;
+
+using TRefCountedPtr = TIntrusivePtr<TRefCounted>;
+
+// A bunch of helpful macros that enable working with intrusive pointers to incomplete types.
+/*
+ * Typically when you have a forward-declared type |T| and an instance
+ * of |TIntrusivePtr<T>| you need the complete definition of |T| to work with
+ * the pointer even if you're not actually using the members of |T|.
+ * E.g. the dtor of |TIntrusivePtr<T>|, should you ever need it, must be able
+ * to unref an instance of |T| and eventually destroy it.
+ * This may force #inclusion of way more headers than really seems necessary.
+ *
+ * |DECLARE_REFCOUNTED_STRUCT|, |DECLARE_REFCOUNTED_CLASS|, and |DEFINE_REFCOUNTED_TYPE|
+ * alleviate this issue by forcing TIntrusivePtr to work with the free-standing overloads
+ * of |Ref| and |Unref| instead of their template version.
+ * These overloads are declared together with the forward declaration of |T| and
+ * are subsequently defined afterwards.
+ */
+
+#define DECLARE_REFCOUNTED_TYPE(type) \
+ using type ## Ptr = ::NYT::TIntrusivePtr<type>; \
+ \
+ [[maybe_unused]] ATTRIBUTE_USED const ::NYT::TRefCounter* GetRefCounter(const type* obj); \
+ [[maybe_unused]] ATTRIBUTE_USED void DestroyRefCounted(const type* obj); \
+ [[maybe_unused]] ATTRIBUTE_USED void DeallocateRefCounted(const type* obj);
+
+//! Forward-declares a class type, defines an intrusive pointer for it, and finally
+//! declares Ref/Unref overloads. Use this macro in |public.h|-like files.
+#define DECLARE_REFCOUNTED_CLASS(type) \
+ class type; \
+ DECLARE_REFCOUNTED_TYPE(type)
+
+//! Forward-declares a struct type, defines an intrusive pointer for it, and finally
+//! declares Ref/Unref overloads. Use this macro in |public.h|-like files.
+#define DECLARE_REFCOUNTED_STRUCT(type) \
+ struct type; \
+ DECLARE_REFCOUNTED_TYPE(type)
+
+//! Provides implementations for Ref/Unref overloads. Use this macro right
+//! after the type's full definition.
+#define DEFINE_REFCOUNTED_TYPE(type) \
+ [[maybe_unused]] ATTRIBUTE_USED Y_FORCE_INLINE const ::NYT::TRefCounter* GetRefCounter(const type* obj) \
+ { \
+ return ::NYT::TRefCountedHelper<type>::GetRefCounter(obj); \
+ } \
+ [[maybe_unused]] ATTRIBUTE_USED Y_FORCE_INLINE void DestroyRefCounted(const type* obj) \
+ { \
+ ::NYT::TRefCountedHelper<type>::Destroy(obj); \
+ } \
+ [[maybe_unused]] ATTRIBUTE_USED Y_FORCE_INLINE void DeallocateRefCounted(const type* obj) \
+ { \
+ ::NYT::TRefCountedHelper<type>::Deallocate(obj); \
+ }
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace NYT
+
+#define REF_COUNTED_INL_H_
+#include "ref_counted-inl.h"
+#undef REF_COUNTED_INL_H_