#pragma once #include <luna/Alloc.h> #include <luna/Atomic.h> #include <luna/Hash.h> #include <luna/OwnedPtr.h> #include <luna/Result.h> #include <luna/ScopeGuard.h> #include <luna/TypeTraits.h> template <typename T> class SharedPtr; template <typename T> SharedPtr<T> adopt_shared(T*); struct Shareable { void ref() { m_ref_count++; } bool unref() { m_ref_count--; return m_ref_count == 0; } Atomic<int> m_ref_count { 0 }; }; template <typename T> class SharedPtr { public: SharedPtr() { m_ptr = nullptr; } SharedPtr(T* ptr) : m_ptr(ptr) { if (m_ptr) shareable()->ref(); } SharedPtr(const SharedPtr<T>& other) : m_ptr(other.m_ptr) { if (m_ptr) shareable()->ref(); } SharedPtr(SharedPtr<T>&& other) : m_ptr(other.m_ptr) { other.m_ptr = nullptr; } template <typename Tp> operator SharedPtr<Tp>() { return { (Tp*)m_ptr }; } ~SharedPtr() { if (m_ptr && shareable()->unref()) { delete m_ptr; } } SharedPtr<T>& operator=(const SharedPtr<T>& other) { if (&other == this) return *this; if (m_ptr && shareable()->unref()) { delete m_ptr; } m_ptr = other.m_ptr; if (m_ptr) shareable()->ref(); return *this; } bool operator==(const SharedPtr<T>& other) { return m_ptr == other.m_ptr; } 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; Shareable* shareable() { static_assert(IsBaseOf<Shareable, T>); return (Shareable*)m_ptr; } }; template <typename T> SharedPtr<T> adopt_shared(T* ptr) { return SharedPtr<T> { ptr }; } template <typename T, class... Args> Result<SharedPtr<T>> make_shared(Args... args) { T* raw_ptr = TRY(make<T>(args...)); return adopt_shared(raw_ptr); } template <typename T> Result<SharedPtr<T>> adopt_shared_if_nonnull(T* ptr) { if (ptr) return adopt_shared(ptr); else return err(ENOMEM); } template <typename T> SharedPtr<T> adopt_shared_from_owned(OwnedPtr<T>&& other) { T* ptr = other.m_ptr; other.m_ptr = nullptr; return SharedPtr<T> { ptr }; }