#include #include template class CSharedPtr; template class CWeakPtr; class CRefCounter { public: bool AddRef() { for(;;) { auto cnt = m_cnt.load(); if (!cnt) return false; if (m_cnt.compare_exchange_weak(cnt, cnt + 1)) break; } return true; } bool Release() noexcept { return --m_cnt == 0; } explicit operator bool() const noexcept { return m_cnt != 0; } protected: std::atomic m_cnt{1}; }; struct CSharedCounter { CRefCounter m_refs; CRefCounter m_weaks; }; struct CSharedRef { CSharedCounter *m_cnt; void *m_p; }; class CSharedPtrLock { public: void lock() noexcept { ++m_cnt; } void unlock() noexcept { --m_cnt; } void Wait() const noexcept { while (m_cnt != 0) std::this_thread::yield(); } protected: std::atomic m_cnt{0}; }; template CSharedPtrLock &GetSharedPtrLock() { static CSharedPtrLock _lock; return _lock; } class CSharedPtrBase { public: CSharedPtrBase() noexcept { } protected: CSharedPtrBase(CSharedRef ref) noexcept : m_ref(ref) { } CSharedPtrBase(CSharedPtrBase &&sp) noexcept : m_ref(sp.Detach()) { } void _swap(CSharedPtrBase &sp) noexcept { m_ref = sp.m_ref.exchange(m_ref); } CSharedRef Detach() noexcept { return m_ref.exchange({nullptr, nullptr}); } template CSharedRef GetSharedRef() const noexcept { std::unique_lock lock(GetSharedPtrLock()); auto ref = m_ref.load(); return ref.m_cnt && ref.m_cnt->m_weaks.AddRef()? ref: CSharedRef{nullptr, nullptr}; } std::atomic m_ref{{nullptr, nullptr}}; }; template class CSharedPtr : public CSharedPtrBase { template friend class CWeakPtr; public: template static CSharedPtr Make(TT&&... args) { return CSharedPtr(std::make_unique(std::forward(args)...)); }; CSharedPtr() noexcept { } explicit CSharedPtr(std::unique_ptr &&sp) : CSharedPtrBase({sp? new CSharedCounter(): nullptr, sp.get()}) { sp.release(); } explicit CSharedPtr(T *p) : CSharedPtr(std::unique_ptr(p)) { } CSharedPtr(const CSharedPtr &sp) noexcept : CSharedPtr(sp.GetSharedRef()) { } CSharedPtr(CSharedPtr &&sp) : CSharedPtrBase(sp.Detach()) { } ~CSharedPtr() { auto ref = Detach(); if (!ref.m_cnt) return; if (ref.m_p && ref.m_cnt->m_refs.Release()) delete reinterpret_cast(ref.m_p); if (ref.m_cnt->m_weaks.Release()) { GetSharedPtrLock().Wait(); delete ref.m_cnt; } } T *get() noexcept { return reinterpret_cast(m_ref.load().m_p); } void reset() noexcept { CSharedPtr()._swap(*this); } template void reset(T_&& p) { CSharedPtr(std::forward(p))._swap(*this); } explicit operator bool() const noexcept { return this->m_ref.load().m_p != nullptr; } T *operator->() noexcept { return get(); } T &operator *() noexcept { return *get(); } CSharedPtr &operator =(const CSharedPtr &sp) { if (&sp != this) CSharedPtr(sp)._swap(*this); return *this; } CSharedPtr &operator =(CSharedPtr &&sp) { _swap(sp); return *this; } protected: CSharedPtr(CSharedRef ref) noexcept : CSharedPtrBase({ref.m_cnt, ref.m_cnt && ref.m_p && ref.m_cnt->m_refs.AddRef()? ref.m_p: nullptr}) { } }; template class CWeakPtr : public CSharedPtrBase { public: CWeakPtr() noexcept { } CWeakPtr(CSharedPtr sp) noexcept : CSharedPtrBase(sp.GetSharedRef()) { } CWeakPtr(const CWeakPtr &sp) noexcept : CSharedPtrBase(sp.GetSharedRef()) { } CWeakPtr(CWeakPtr &&sp) noexcept : CSharedPtrBase(sp.Detach()) { } ~CWeakPtr() { auto ref = Detach(); if (ref.m_cnt && ref.m_cnt->m_weaks.Release()) { GetSharedPtrLock().Wait(); delete ref.m_cnt; } } CSharedPtr lock() const noexcept { return CSharedPtr(GetSharedRef()); } void reset() noexcept { CWeakPtr()._swap(*this); } template CWeakPtr &operator =(CSharedPtr sp) { CWeakPtr(std::move(sp))._swap(*this); return *this; } CWeakPtr &operator =(const CWeakPtr &sp) { if (&sp != this) CWeakPtr(sp)._swap(*this); return *this; } };