#pragma once #include #include #include #include namespace orbis { inline namespace utils { struct RcBase { std::atomic references{0}; virtual ~RcBase() = default; void incRef() { if (references.fetch_add(1, std::memory_order::relaxed) > 512) { assert(!"too many references"); } } // returns true if object was destroyed bool decRef() { if (references.fetch_sub(1, std::memory_order::relaxed) == 1) { delete this; return true; } return false; } }; template concept WithRc = requires(T t) { t.incRef(); t.decRef(); }; template class Ref { T *m_ref = nullptr; public: Ref() = default; template requires(std::is_base_of_v) Ref(OT *ref) : m_ref(ref) { ref->incRef(); } template requires(std::is_base_of_v) Ref(const Ref &other) : m_ref(other.get()) { if (m_ref != nullptr) { m_ref->incRef(); } } template requires(std::is_base_of_v) Ref(Ref &&other) : m_ref(other.release()) {} Ref(const Ref &other) : m_ref(other.get()) { if (m_ref != nullptr) { m_ref->incRef(); } } Ref(Ref &&other) : m_ref(other.release()) {} template requires(std::is_base_of_v) Ref &operator=(Ref &&other) { other.swap(*this); return *this; } template requires(std::is_base_of_v) Ref &operator=(OT *other) { *this = Ref(other); return *this; } template requires(std::is_base_of_v) Ref &operator=(const Ref &other) { *this = Ref(other); return *this; } Ref &operator=(const Ref &other) { *this = Ref(other); return *this; } Ref &operator=(Ref &&other) { other.swap(*this); return *this; } ~Ref() { if (m_ref != nullptr) { m_ref->decRef(); } } void swap(Ref &other) { std::swap(m_ref, other.m_ref); } T *get() const { return m_ref; } T *release() { return std::exchange(m_ref, nullptr); } T *operator->() const { return m_ref; } explicit operator bool() const { return m_ref != nullptr; } bool operator==(std::nullptr_t) const { return m_ref == nullptr; } bool operator!=(std::nullptr_t) const { return m_ref != nullptr; } auto operator<=>(const T *other) const { return m_ref <=> other; } auto operator<=>(const Ref &other) const = default; }; template requires(std::is_constructible_v) Ref create(ArgsT &&...args) { auto result = new T(std::forward(args)...); return Ref(result); } } // namespace utils } // namespace orbis