#pragma once #include "Atomic.h" #include #include // Unfinished. Only std::default_delete will work as expected. template class atomic_ptr_base : D { protected: atomic_t m_ptr; constexpr atomic_ptr_base(T* ptr) : m_ptr(ptr) { } public: ~atomic_ptr_base() { if (m_ptr) { (*this)(m_ptr.load()); } } D& get_deleter() { return *this; } const D& get_deleter() const { return *this; } }; // Simple atomic pointer with unique ownership. Draft, unfinished. template> class atomic_ptr final : atomic_ptr_base { using base = atomic_ptr_base; static_assert(sizeof(T*) == sizeof(base), "atomic_ptr<> error: invalid deleter (empty class expected)"); public: constexpr atomic_ptr() : base(nullptr) { } constexpr atomic_ptr(std::nullptr_t) : base(nullptr) { } explicit atomic_ptr(T* ptr) : base(ptr) { } template::value>> atomic_ptr(std::unique_ptr&& ptr) : base(ptr.release()) { } atomic_ptr& operator =(std::nullptr_t) { if (T* old = base::m_ptr.exchange(nullptr)) { this->get_deleter()(old); } return *this; } template::value>> atomic_ptr& operator =(std::unique_ptr&& ptr) { if (T* old = base::m_ptr.exchange(ptr.release())) { this->get_deleter()(old); } return *this; } void swap(std::unique_ptr& ptr) { ptr.reset(base::m_ptr.exchange(ptr.release())); } std::add_lvalue_reference_t operator *() const { return *base::m_ptr; } T* operator ->() const { return base::m_ptr; } T* get() const { return base::m_ptr; } explicit operator bool() const { return base::m_ptr != nullptr; } T* release() const { return base::m_ptr.exchange(0); } void reset(T* ptr = nullptr) { if (T* old = base::m_ptr.exchange(ptr)) { this->get_deleter()(old); } } // Steal the pointer from `ptr`, convert old value to unique_ptr std::unique_ptr exchange(std::unique_ptr&& ptr) { return std::unique_ptr(base::m_ptr.exchange(ptr.release())); } // If pointer is null, steal it from `ptr` bool test_and_swap(std::unique_ptr&& ptr) { if (base::m_ptr.compare_and_swap_test(nullptr, ptr.get())) { ptr.release(); return true; } return false; } }; template class atomic_ptr final : atomic_ptr_base { // TODO };