summaryrefslogtreecommitdiffstats
path: root/util/generic/ptr.h
diff options
context:
space:
mode:
authorDevtools Arcadia <[email protected]>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <[email protected]>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/generic/ptr.h
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/generic/ptr.h')
-rw-r--r--util/generic/ptr.h1145
1 files changed, 1145 insertions, 0 deletions
diff --git a/util/generic/ptr.h b/util/generic/ptr.h
new file mode 100644
index 00000000000..19db0e3ec55
--- /dev/null
+++ b/util/generic/ptr.h
@@ -0,0 +1,1145 @@
+#pragma once
+
+#include "fwd.h"
+#include "utility.h"
+#include "intrlist.h"
+#include "refcount.h"
+#include "typetraits.h"
+#include "singleton.h"
+
+#include <utility>
+
+#include <util/system/yassert.h>
+#include <util/system/defaults.h>
+
+template <class T, class U>
+using TGuardConversion = typename std::enable_if_t<std::is_convertible<U*, T*>::value>;
+
+template <class T>
+inline void AssertTypeComplete() {
+ // If compiler triggers this error from destructor of your class with
+ // smart pointer, then may be you should move the destructor definition
+ // to the .cpp file, where type T have full definition.
+ //
+ // 'delete' called on pointer to incomplete type is
+ // undefined behavior (missing destructor call/corrupted memory manager).
+ // 'sizeof' is used to trigger compile-time error.
+ static_assert(sizeof(T) != 0, "Type must be complete");
+}
+
+template <class T>
+inline void CheckedDelete(T* t) {
+ AssertTypeComplete<T>();
+
+ delete t;
+}
+
+template <class T>
+inline void CheckedArrayDelete(T* t) {
+ AssertTypeComplete<T>();
+
+ delete[] t;
+}
+
+class TNoAction {
+public:
+ template <class T>
+ static inline void Destroy(T*) noexcept {
+ }
+};
+
+class TDelete {
+public:
+ template <class T>
+ static inline void Destroy(T* t) noexcept {
+ CheckedDelete(t);
+ }
+
+ /*
+ * special handling for nullptr - call nothing
+ */
+ static inline void Destroy(std::nullptr_t) noexcept {
+ }
+
+ /*
+ * special handling for void* - call ::operator delete()
+ */
+ static void Destroy(void* t) noexcept;
+};
+
+class TDeleteArray {
+public:
+ template <class T>
+ static inline void Destroy(T* t) noexcept {
+ CheckedArrayDelete(t);
+ }
+};
+
+class TDestructor {
+public:
+ template <class T>
+ static inline void Destroy(T* t) noexcept {
+ (void)t;
+ t->~T();
+ }
+};
+
+class TFree {
+public:
+ template <class T>
+ static inline void Destroy(T* t) noexcept {
+ DoDestroy((void*)t);
+ }
+
+private:
+ /*
+ * we do not want dependancy on cstdlib here...
+ */
+ static void DoDestroy(void* t) noexcept;
+};
+
+template <class Base, class T>
+class TPointerCommon {
+public:
+ using TValueType = T;
+
+ inline T* operator->() const noexcept {
+ T* ptr = AsT();
+ Y_ASSERT(ptr);
+ return ptr;
+ }
+
+#ifndef __cpp_impl_three_way_comparison
+ template <class C>
+ inline bool operator==(const C& p) const noexcept {
+ return (p == AsT());
+ }
+
+ template <class C>
+ inline bool operator!=(const C& p) const noexcept {
+ return (p != AsT());
+ }
+#endif
+
+ inline explicit operator bool() const noexcept {
+ return nullptr != AsT();
+ }
+
+protected:
+ inline T* AsT() const noexcept {
+ return (static_cast<const Base*>(this))->Get();
+ }
+
+ static inline T* DoRelease(T*& t) noexcept {
+ T* ret = t;
+ t = nullptr;
+ return ret;
+ }
+};
+
+template <class Base, class T>
+class TPointerBase: public TPointerCommon<Base, T> {
+public:
+ inline T& operator*() const noexcept {
+ Y_ASSERT(this->AsT());
+
+ return *(this->AsT());
+ }
+
+ inline T& operator[](size_t n) const noexcept {
+ Y_ASSERT(this->AsT());
+
+ return (this->AsT())[n];
+ }
+};
+
+/*
+ * void*-like pointers does not have operator*
+ */
+template <class Base>
+class TPointerBase<Base, void>: public TPointerCommon<Base, void> {
+};
+
+template <class T, class D>
+class TAutoPtr: public TPointerBase<TAutoPtr<T, D>, T> {
+public:
+ inline TAutoPtr(T* t = nullptr) noexcept
+ : T_(t)
+ {
+ }
+
+ inline TAutoPtr(const TAutoPtr& t) noexcept
+ : T_(t.Release())
+ {
+ }
+
+ inline ~TAutoPtr() {
+ DoDestroy();
+ }
+
+ inline TAutoPtr& operator=(const TAutoPtr& t) noexcept {
+ if (this != &t) {
+ Reset(t.Release());
+ }
+
+ return *this;
+ }
+
+ inline T* Release() const noexcept Y_WARN_UNUSED_RESULT {
+ return this->DoRelease(T_);
+ }
+
+ inline void Reset(T* t) noexcept {
+ if (T_ != t) {
+ DoDestroy();
+ T_ = t;
+ }
+ }
+
+ inline void Reset() noexcept {
+ Destroy();
+ }
+
+ inline void Destroy() noexcept {
+ Reset(nullptr);
+ }
+
+ inline void Swap(TAutoPtr& r) noexcept {
+ DoSwap(T_, r.T_);
+ }
+
+ inline T* Get() const noexcept {
+ return T_;
+ }
+
+#ifdef __cpp_impl_three_way_comparison
+ template <class Other>
+ inline bool operator==(const Other& p) const noexcept {
+ return (p == Get());
+ }
+#endif
+private:
+ inline void DoDestroy() noexcept {
+ if (T_) {
+ D::Destroy(T_);
+ }
+ }
+
+private:
+ mutable T* T_;
+};
+
+template <class T, class D>
+class THolder: public TPointerBase<THolder<T, D>, T> {
+public:
+ constexpr THolder() noexcept
+ : T_(nullptr)
+ {
+ }
+
+ constexpr THolder(std::nullptr_t) noexcept
+ : T_(nullptr)
+ {
+ }
+
+ explicit THolder(T* t) noexcept
+ : T_(t)
+ {
+ }
+
+ inline THolder(TAutoPtr<T, D> t) noexcept
+ : T_(t.Release())
+ {
+ }
+
+ template <class U, class = TGuardConversion<T, U>>
+ inline THolder(TAutoPtr<U, D> t) noexcept
+ : T_(t.Release())
+ {
+ }
+
+ inline THolder(THolder&& that) noexcept
+ : T_(that.Release())
+ {
+ }
+
+ template <class U, class = TGuardConversion<T, U>>
+ inline THolder(THolder<U, D>&& that) noexcept
+ : T_(that.Release())
+ {
+ }
+
+ THolder(const THolder&) = delete;
+ THolder& operator=(const THolder&) = delete;
+
+ inline ~THolder() {
+ DoDestroy();
+ }
+
+ inline void Destroy() noexcept {
+ Reset(nullptr);
+ }
+
+ inline T* Release() noexcept Y_WARN_UNUSED_RESULT {
+ return this->DoRelease(T_);
+ }
+
+ inline void Reset(T* t) noexcept {
+ if (T_ != t) {
+ DoDestroy();
+ T_ = t;
+ }
+ }
+
+ inline void Reset(TAutoPtr<T, D> t) noexcept {
+ Reset(t.Release());
+ }
+
+ inline void Reset() noexcept {
+ Destroy();
+ }
+
+ inline void Swap(THolder& r) noexcept {
+ DoSwap(T_, r.T_);
+ }
+
+ inline T* Get() const noexcept {
+ return T_;
+ }
+
+ inline operator TAutoPtr<T, D>() noexcept {
+ return Release();
+ }
+
+ THolder& operator=(std::nullptr_t) noexcept {
+ this->Reset(nullptr);
+ return *this;
+ }
+
+ THolder& operator=(THolder&& that) noexcept {
+ this->Reset(that.Release());
+ return *this;
+ }
+
+ template <class U>
+ THolder& operator=(THolder<U, D>&& that) noexcept {
+ this->Reset(that.Release());
+ return *this;
+ }
+
+#ifdef __cpp_impl_three_way_comparison
+ template <class Other>
+ inline bool operator==(const Other& p) const noexcept {
+ return (p == Get());
+ }
+#endif
+private:
+ inline void DoDestroy() noexcept {
+ if (T_) {
+ D::Destroy(T_);
+ }
+ }
+
+private:
+ T* T_;
+};
+
+template <typename T, typename... Args>
+[[nodiscard]] THolder<T> MakeHolder(Args&&... args) {
+ return THolder<T>(new T(std::forward<Args>(args)...));
+}
+
+/*
+ * usage:
+ * class T: public TRefCounted<T>
+ * and we get methods Ref() && UnRef() with
+ * proper destruction of last UnRef()
+ */
+template <class T, class C, class D>
+class TRefCounted {
+public:
+ inline TRefCounted(long initval = 0) noexcept
+ : Counter_(initval)
+ {
+ }
+
+ inline ~TRefCounted() = default;
+
+ inline void Ref(TAtomicBase d) noexcept {
+ auto resultCount = Counter_.Add(d);
+ Y_ASSERT(resultCount >= d);
+ (void)resultCount;
+ }
+
+ inline void Ref() noexcept {
+ auto resultCount = Counter_.Inc();
+ Y_ASSERT(resultCount != 0);
+ (void)resultCount;
+ }
+
+ inline void UnRef(TAtomicBase d) noexcept {
+ auto resultCount = Counter_.Sub(d);
+ Y_ASSERT(resultCount >= 0);
+ if (resultCount == 0) {
+ D::Destroy(static_cast<T*>(this));
+ }
+ }
+
+ inline void UnRef() noexcept {
+ UnRef(1);
+ }
+
+ inline TAtomicBase RefCount() const noexcept {
+ return Counter_.Val();
+ }
+
+ inline void DecRef() noexcept {
+ auto resultCount = Counter_.Dec();
+ Y_ASSERT(resultCount >= 0);
+ (void)resultCount;
+ }
+
+ TRefCounted(const TRefCounted&)
+ : Counter_(0)
+ {
+ }
+
+ void operator=(const TRefCounted&) {
+ }
+
+private:
+ C Counter_;
+};
+
+/**
+ * Atomically reference-counted base with a virtual destructor.
+ *
+ * @note Plays well with inheritance, should be used for refcounted base classes.
+ */
+struct TThrRefBase: public TRefCounted<TThrRefBase, TAtomicCounter> {
+ virtual ~TThrRefBase();
+};
+
+/**
+ * Atomically reference-counted base.
+ *
+ * Deletes refcounted object as type T.
+ *
+ * @warning Additional care should be taken with regard to inheritance. If used
+ * as a base class, @p T should either declare a virtual destructor, or be
+ * derived from @p TThrRefBase instead. Otherwise, only destructor of class @p T
+ * would be called, potentially slicing the object and creating memory leaks.
+ *
+ * @note To avoid accidental inheritance when it is not originally intended,
+ * class @p T should be marked as final.
+ */
+template <class T, class D = TDelete>
+using TAtomicRefCount = TRefCounted<T, TAtomicCounter, D>;
+
+/**
+ * Non-atomically reference-counted base.
+ *
+ * @warning Not thread-safe. Use with great care. If in doubt, use @p ThrRefBase
+ * or @p TAtomicRefCount instead.
+ */
+template <class T, class D = TDelete>
+using TSimpleRefCount = TRefCounted<T, TSimpleCounter, D>;
+
+template <class T>
+class TDefaultIntrusivePtrOps {
+public:
+ static inline void Ref(T* t) noexcept {
+ Y_ASSERT(t);
+
+ t->Ref();
+ }
+
+ static inline void UnRef(T* t) noexcept {
+ Y_ASSERT(t);
+
+ t->UnRef();
+ }
+
+ static inline void DecRef(T* t) noexcept {
+ Y_ASSERT(t);
+
+ t->DecRef();
+ }
+
+ static inline long RefCount(const T* t) noexcept {
+ Y_ASSERT(t);
+
+ return t->RefCount();
+ }
+};
+
+template <class T, class Ops>
+class TIntrusivePtr: public TPointerBase<TIntrusivePtr<T, Ops>, T> {
+ template <class U, class O>
+ friend class TIntrusivePtr;
+
+ template <class U, class O>
+ friend class TIntrusiveConstPtr;
+
+public:
+ struct TNoIncrement {
+ };
+
+ inline TIntrusivePtr(T* t = nullptr) noexcept
+ : T_(t)
+ {
+ Ops();
+ Ref();
+ }
+
+ inline TIntrusivePtr(T* t, TNoIncrement) noexcept
+ : T_(t)
+ {
+ Ops();
+ }
+
+ inline ~TIntrusivePtr() {
+ UnRef();
+ }
+
+ inline TIntrusivePtr(const TIntrusivePtr& p) noexcept
+ : T_(p.T_)
+ {
+ Ref();
+ }
+
+ // NOTE:
+ // without std::enable_if_t compiler sometimes tries to use this constructor inappropriately
+ // e.g.
+ // struct A {};
+ // struct B {};
+ // void Func(TIntrusivePtr<A>);
+ // void Func(TIntrusivePtr<B>);
+ // ...
+ // Func(TIntrusivePtr<A>(new A)); // <--- compiler can't decide which version of Func to use
+ template <class U, class = TGuardConversion<T, U>>
+ inline TIntrusivePtr(const TIntrusivePtr<U>& p) noexcept
+ : T_(p.Get())
+ {
+ Ref();
+ }
+
+ template <class U, class = TGuardConversion<T, U>>
+ inline TIntrusivePtr(TIntrusivePtr<U>&& p) noexcept
+ : T_(p.T_)
+ {
+ p.T_ = nullptr;
+ }
+
+ inline TIntrusivePtr(TIntrusivePtr&& p) noexcept
+ : T_(nullptr)
+ {
+ Swap(p);
+ }
+
+ inline TIntrusivePtr& operator=(TIntrusivePtr p) noexcept {
+ p.Swap(*this);
+
+ return *this;
+ }
+
+ // Effectively replace both:
+ // Reset(const TIntrusivePtr&)
+ // Reset(TIntrusivePtr&&)
+ inline void Reset(TIntrusivePtr t) noexcept {
+ Swap(t);
+ }
+
+ inline void Reset() noexcept {
+ Drop();
+ }
+
+ inline T* Get() const noexcept {
+ return T_;
+ }
+
+ inline void Swap(TIntrusivePtr& r) noexcept {
+ DoSwap(T_, r.T_);
+ }
+
+ inline void Drop() noexcept {
+ TIntrusivePtr(nullptr).Swap(*this);
+ }
+
+ inline T* Release() const noexcept Y_WARN_UNUSED_RESULT {
+ T* res = T_;
+ if (T_) {
+ Ops::DecRef(T_);
+ T_ = nullptr;
+ }
+ return res;
+ }
+
+ inline long RefCount() const noexcept {
+ return T_ ? Ops::RefCount(T_) : 0;
+ }
+
+#ifdef __cpp_impl_three_way_comparison
+ template <class Other>
+ inline bool operator==(const Other& p) const noexcept {
+ return (p == Get());
+ }
+#endif
+private:
+ inline void Ref() noexcept {
+ if (T_) {
+ Ops::Ref(T_);
+ }
+ }
+
+ inline void UnRef() noexcept {
+ if (T_) {
+ Ops::UnRef(T_);
+ }
+ }
+
+private:
+ mutable T* T_;
+};
+
+template <class T, class Ops>
+struct THash<TIntrusivePtr<T, Ops>>: THash<const T*> {
+ using THash<const T*>::operator();
+ inline size_t operator()(const TIntrusivePtr<T, Ops>& ptr) const {
+ return THash<const T*>::operator()(ptr.Get());
+ }
+};
+
+// Behaves like TIntrusivePtr but returns const T* to prevent user from accidentally modifying the referenced object.
+template <class T, class Ops>
+class TIntrusiveConstPtr: public TPointerBase<TIntrusiveConstPtr<T, Ops>, const T> {
+public:
+ inline TIntrusiveConstPtr(T* t = nullptr) noexcept // we need a non-const pointer to Ref(), UnRef() and eventually delete it.
+ : T_(t)
+ {
+ Ops();
+ Ref();
+ }
+
+ inline ~TIntrusiveConstPtr() {
+ UnRef();
+ }
+
+ inline TIntrusiveConstPtr(const TIntrusiveConstPtr& p) noexcept
+ : T_(p.T_)
+ {
+ Ref();
+ }
+
+ inline TIntrusiveConstPtr(TIntrusiveConstPtr&& p) noexcept
+ : T_(nullptr)
+ {
+ Swap(p);
+ }
+
+ inline TIntrusiveConstPtr(TIntrusivePtr<T> p) noexcept
+ : T_(p.T_)
+ {
+ p.T_ = nullptr;
+ }
+
+ template <class U, class = TGuardConversion<T, U>>
+ inline TIntrusiveConstPtr(const TIntrusiveConstPtr<U>& p) noexcept
+ : T_(p.T_)
+ {
+ Ref();
+ }
+
+ template <class U, class = TGuardConversion<T, U>>
+ inline TIntrusiveConstPtr(TIntrusiveConstPtr<U>&& p) noexcept
+ : T_(p.T_)
+ {
+ p.T_ = nullptr;
+ }
+
+ inline TIntrusiveConstPtr& operator=(TIntrusiveConstPtr p) noexcept {
+ p.Swap(*this);
+
+ return *this;
+ }
+
+ // Effectively replace both:
+ // Reset(const TIntrusiveConstPtr&)
+ // Reset(TIntrusiveConstPtr&&)
+ inline void Reset(TIntrusiveConstPtr t) noexcept {
+ Swap(t);
+ }
+
+ inline void Reset() noexcept {
+ Drop();
+ }
+
+ inline const T* Get() const noexcept {
+ return T_;
+ }
+
+ inline void Swap(TIntrusiveConstPtr& r) noexcept {
+ DoSwap(T_, r.T_);
+ }
+
+ inline void Drop() noexcept {
+ TIntrusiveConstPtr(nullptr).Swap(*this);
+ }
+
+ inline long RefCount() const noexcept {
+ return T_ ? Ops::RefCount(T_) : 0;
+ }
+
+#ifdef __cpp_impl_three_way_comparison
+ template <class Other>
+ inline bool operator==(const Other& p) const noexcept {
+ return (p == Get());
+ }
+#endif
+private:
+ inline void Ref() noexcept {
+ if (T_ != nullptr) {
+ Ops::Ref(T_);
+ }
+ }
+
+ inline void UnRef() noexcept {
+ if (T_ != nullptr) {
+ Ops::UnRef(T_);
+ }
+ }
+
+private:
+ T* T_;
+
+ template <class U, class O>
+ friend class TIntrusiveConstPtr;
+};
+
+template <class T, class Ops>
+struct THash<TIntrusiveConstPtr<T, Ops>>: THash<const T*> {
+ using THash<const T*>::operator();
+ inline size_t operator()(const TIntrusiveConstPtr<T, Ops>& ptr) const {
+ return THash<const T*>::operator()(ptr.Get());
+ }
+};
+
+template <class T, class Ops>
+class TSimpleIntrusiveOps {
+ using TFunc = void (*)(T*)
+#if __cplusplus >= 201703
+ noexcept
+#endif
+ ;
+
+ static void DoRef(T* t) noexcept {
+ Ops::Ref(t);
+ }
+
+ static void DoUnRef(T* t) noexcept {
+ Ops::UnRef(t);
+ }
+
+public:
+ inline TSimpleIntrusiveOps() noexcept {
+ InitStaticOps();
+ }
+
+ inline ~TSimpleIntrusiveOps() = default;
+
+ static inline void Ref(T* t) noexcept {
+ Ref_(t);
+ }
+
+ static inline void UnRef(T* t) noexcept {
+ UnRef_(t);
+ }
+
+private:
+ static inline void InitStaticOps() noexcept {
+ struct TInit {
+ inline TInit() noexcept {
+ Ref_ = DoRef;
+ UnRef_ = DoUnRef;
+ }
+ };
+
+ Singleton<TInit>();
+ }
+
+private:
+ static TFunc Ref_;
+ static TFunc UnRef_;
+};
+
+template <class T, class Ops>
+typename TSimpleIntrusiveOps<T, Ops>::TFunc TSimpleIntrusiveOps<T, Ops>::Ref_ = nullptr;
+
+template <class T, class Ops>
+typename TSimpleIntrusiveOps<T, Ops>::TFunc TSimpleIntrusiveOps<T, Ops>::UnRef_ = nullptr;
+
+template <typename T, class Ops = TDefaultIntrusivePtrOps<T>, typename... Args>
+[[nodiscard]] TIntrusivePtr<T, Ops> MakeIntrusive(Args&&... args) {
+ return new T{std::forward<Args>(args)...};
+}
+
+template <typename T, class Ops = TDefaultIntrusivePtrOps<T>, typename... Args>
+[[nodiscard]] TIntrusiveConstPtr<T, Ops> MakeIntrusiveConst(Args&&... args) {
+ return new T{std::forward<Args>(args)...};
+}
+
+template <class T, class C, class D>
+class TSharedPtr: public TPointerBase<TSharedPtr<T, C, D>, T> {
+ template <class TT, class CC, class DD>
+ friend class TSharedPtr;
+
+public:
+ inline TSharedPtr() noexcept
+ : T_(nullptr)
+ , C_(nullptr)
+ {
+ }
+
+ inline TSharedPtr(T* t) {
+ THolder<T, D> h(t);
+
+ Init(h);
+ }
+
+ inline TSharedPtr(TAutoPtr<T, D> t) {
+ Init(t);
+ }
+
+ inline TSharedPtr(T* t, C* c) noexcept
+ : T_(t)
+ , C_(c)
+ {
+ }
+
+ template <class TT, class = TGuardConversion<T, TT>>
+ inline TSharedPtr(THolder<TT>&& t) {
+ Init(t);
+ }
+
+ inline ~TSharedPtr() {
+ UnRef();
+ }
+
+ inline TSharedPtr(const TSharedPtr& t) noexcept
+ : T_(t.T_)
+ , C_(t.C_)
+ {
+ Ref();
+ }
+
+ inline TSharedPtr(TSharedPtr&& t) noexcept
+ : T_(nullptr)
+ , C_(nullptr)
+ {
+ Swap(t);
+ }
+
+ template <class TT, class = TGuardConversion<T, TT>>
+ inline TSharedPtr(const TSharedPtr<TT, C, D>& t) noexcept
+ : T_(t.T_)
+ , C_(t.C_)
+ {
+ Ref();
+ }
+
+ template <class TT, class = TGuardConversion<T, TT>>
+ inline TSharedPtr(TSharedPtr<TT, C, D>&& t) noexcept
+ : T_(t.T_)
+ , C_(t.C_)
+ {
+ t.T_ = nullptr;
+ t.C_ = nullptr;
+ }
+
+ inline TSharedPtr& operator=(TSharedPtr t) noexcept {
+ t.Swap(*this);
+
+ return *this;
+ }
+
+ // Effectively replace both:
+ // Reset(const TSharedPtr& t)
+ // Reset(TSharedPtr&& t)
+ inline void Reset(TSharedPtr t) noexcept {
+ Swap(t);
+ }
+
+ inline void Reset() noexcept {
+ Drop();
+ }
+
+ inline void Drop() noexcept {
+ TSharedPtr().Swap(*this);
+ }
+
+ inline T* Get() const noexcept {
+ return T_;
+ }
+
+ inline C* ReferenceCounter() const noexcept {
+ return C_;
+ }
+
+ inline void Swap(TSharedPtr& r) noexcept {
+ DoSwap(T_, r.T_);
+ DoSwap(C_, r.C_);
+ }
+
+ inline long RefCount() const noexcept {
+ return C_ ? C_->Val() : 0;
+ }
+
+#ifdef __cpp_impl_three_way_comparison
+ template <class Other>
+ inline bool operator==(const Other& p) const noexcept {
+ return (p == Get());
+ }
+#endif
+private:
+ template <class X>
+ inline void Init(X& t) {
+ C_ = !!t ? new C(1) : nullptr;
+ T_ = t.Release();
+ }
+
+ inline void Ref() noexcept {
+ if (C_) {
+ C_->Inc();
+ }
+ }
+
+ inline void UnRef() noexcept {
+ if (C_ && !C_->Dec()) {
+ DoDestroy();
+ }
+ }
+
+ inline void DoDestroy() noexcept {
+ if (T_) {
+ D::Destroy(T_);
+ }
+
+ delete C_;
+ }
+
+private:
+ T* T_;
+ C* C_;
+};
+
+template <class T, class C, class D>
+struct THash<TSharedPtr<T, C, D>>: THash<const T*> {
+ using THash<const T*>::operator();
+ inline size_t operator()(const TSharedPtr<T, C, D>& ptr) const {
+ return THash<const T*>::operator()(ptr.Get());
+ }
+};
+
+template <class T, class D = TDelete>
+using TAtomicSharedPtr = TSharedPtr<T, TAtomicCounter, D>;
+
+// use with great care. if in doubt, use TAtomicSharedPtr instead
+template <class T, class D = TDelete>
+using TSimpleSharedPtr = TSharedPtr<T, TSimpleCounter, D>;
+
+template <typename T, typename C, typename... Args>
+[[nodiscard]] TSharedPtr<T, C> MakeShared(Args&&... args) {
+ return new T{std::forward<Args>(args)...};
+}
+
+template <typename T, typename... Args>
+[[nodiscard]] inline TAtomicSharedPtr<T> MakeAtomicShared(Args&&... args) {
+ return MakeShared<T, TAtomicCounter>(std::forward<Args>(args)...);
+}
+
+template <typename T, typename... Args>
+[[nodiscard]] inline TSimpleSharedPtr<T> MakeSimpleShared(Args&&... args) {
+ return MakeShared<T, TSimpleCounter>(std::forward<Args>(args)...);
+}
+
+class TCopyClone {
+public:
+ template <class T>
+ static inline T* Copy(T* t) {
+ if (t)
+ return t->Clone();
+ return nullptr;
+ }
+};
+
+class TCopyNew {
+public:
+ template <class T>
+ static inline T* Copy(T* t) {
+ if (t)
+ return new T(*t);
+ return nullptr;
+ }
+};
+
+template <class T, class C, class D>
+class TCopyPtr: public TPointerBase<TCopyPtr<T, C, D>, T> {
+public:
+ inline TCopyPtr(T* t = nullptr) noexcept
+ : T_(t)
+ {
+ }
+
+ inline TCopyPtr(const TCopyPtr& t)
+ : T_(C::Copy(t.Get()))
+ {
+ }
+
+ inline TCopyPtr(TCopyPtr&& t) noexcept
+ : T_(nullptr)
+ {
+ Swap(t);
+ }
+
+ inline ~TCopyPtr() {
+ DoDestroy();
+ }
+
+ inline TCopyPtr& operator=(TCopyPtr t) noexcept {
+ t.Swap(*this);
+
+ return *this;
+ }
+
+ inline T* Release() noexcept Y_WARN_UNUSED_RESULT {
+ return DoRelease(T_);
+ }
+
+ inline void Reset(T* t) noexcept {
+ if (T_ != t) {
+ DoDestroy();
+ T_ = t;
+ }
+ }
+
+ inline void Reset() noexcept {
+ Destroy();
+ }
+
+ inline void Destroy() noexcept {
+ Reset(nullptr);
+ }
+
+ inline void Swap(TCopyPtr& r) noexcept {
+ DoSwap(T_, r.T_);
+ }
+
+ inline T* Get() const noexcept {
+ return T_;
+ }
+
+#ifdef __cpp_impl_three_way_comparison
+ template <class Other>
+ inline bool operator==(const Other& p) const noexcept {
+ return (p == Get());
+ }
+#endif
+private:
+ inline void DoDestroy() noexcept {
+ if (T_)
+ D::Destroy(T_);
+ }
+
+private:
+ T* T_;
+};
+
+// Copy-on-write pointer
+template <class TPtr, class TCopy>
+class TCowPtr: public TPointerBase<TCowPtr<TPtr, TCopy>, const typename TPtr::TValueType> {
+ using T = typename TPtr::TValueType;
+
+public:
+ inline TCowPtr() = default;
+
+ inline TCowPtr(const TPtr& p)
+ : T_(p)
+ {
+ }
+
+ inline TCowPtr(T* p)
+ : T_(p)
+ {
+ }
+
+ inline const T* Get() const noexcept {
+ return Const();
+ }
+
+ inline const T* Const() const noexcept {
+ return T_.Get();
+ }
+
+ inline T* Mutable() {
+ Unshare();
+
+ return T_.Get();
+ }
+
+ inline bool Shared() const noexcept {
+ return T_.RefCount() > 1;
+ }
+
+ inline void Swap(TCowPtr& r) noexcept {
+ T_.Swap(r.T_);
+ }
+
+ inline void Reset(TCowPtr p) {
+ p.Swap(*this);
+ }
+
+ inline void Reset() {
+ T_.Reset();
+ }
+
+#ifdef __cpp_impl_three_way_comparison
+ template <class Other>
+ inline bool operator==(const Other& p) const noexcept {
+ return (p == Get());
+ }
+#endif
+private:
+ inline void Unshare() {
+ if (Shared()) {
+ Reset(TCopy::Copy(T_.Get()));
+ }
+ }
+
+private:
+ TPtr T_;
+};
+
+// saves .Get() on argument passing. Intended usage: Func(TPtrArg<X> p); ... TIntrusivePtr<X> p2; Func(p2);
+template <class T>
+class TPtrArg {
+ T* Ptr;
+
+public:
+ TPtrArg(T* p)
+ : Ptr(p)
+ {
+ }
+ TPtrArg(const TIntrusivePtr<T>& p)
+ : Ptr(p.Get())
+ {
+ }
+ operator T*() const {
+ return Ptr;
+ }
+ T* operator->() const {
+ return Ptr;
+ }
+ T* Get() const {
+ return Ptr;
+ }
+};