#pragma once #include #include #include #include #include #include namespace __detail { struct RefCount { void ref() { m_ref_count++; } bool unref() { m_ref_count--; return m_ref_count == 0; } private: Atomic m_ref_count { 1 }; }; } template class SharedPtr { using RefCount = __detail::RefCount; public: SharedPtr() { m_ptr = nullptr; m_ref_count = nullptr; } SharedPtr(T* ptr, RefCount* ref_count) : m_ptr(ptr), m_ref_count(ref_count) { } SharedPtr(const SharedPtr& other) : m_ptr(other.m_ptr), m_ref_count(other.m_ref_count) { if (m_ref_count) m_ref_count->ref(); } SharedPtr(SharedPtr&& other) : m_ptr(other.m_ptr), m_ref_count(other.m_ref_count) { other.m_ptr = nullptr; other.m_ref_count = nullptr; } template operator SharedPtr() { if (m_ref_count) m_ref_count->ref(); return { (Tp*)m_ptr, m_ref_count }; } ~SharedPtr() { if (m_ref_count && m_ref_count->unref()) { delete m_ref_count; delete m_ptr; } } SharedPtr& operator=(const SharedPtr& other) { if (&other == this) return *this; if (m_ref_count && m_ref_count->unref()) { delete m_ref_count; delete m_ptr; } m_ptr = other.m_ptr; m_ref_count = other.m_ref_count; if (m_ref_count) m_ref_count->ref(); return *this; } bool operator==(const SharedPtr& other) { return m_ptr == other.m_ptr && m_ref_count == other.m_ref_count; } T* ptr() const { return m_ptr; } T* operator->() const { return m_ptr; } T& operator*() const { return *m_ptr; } operator bool() const { return m_ptr != nullptr; } private: T* m_ptr; RefCount* m_ref_count; }; // NOTE: ptr is deleted if any of the adopt_shared* functions fail to construct a SharedPtr. template Result> adopt_shared(T* ptr) { using RefCount = __detail::RefCount; auto guard = make_scope_guard([ptr] { delete ptr; }); RefCount* const ref_count = TRY(make()); guard.deactivate(); return SharedPtr { ptr, ref_count }; } template Result> make_shared(Args... args) { T* raw_ptr = TRY(make(args...)); return adopt_shared(raw_ptr); } template Result> adopt_shared_if_nonnull(T* ptr) { if (ptr) return adopt_shared(ptr); else return err(ENOMEM); } template Result> adopt_shared_from_owned(OwnedPtr&& other) { T* ptr = other.m_ptr; other.m_ptr = nullptr; const SharedPtr shared_ptr = TRY(adopt_shared(ptr)); return shared_ptr; }