diff --git a/BAN/include/BAN/WeakPtr.h b/BAN/include/BAN/WeakPtr.h new file mode 100644 index 00000000..687f4204 --- /dev/null +++ b/BAN/include/BAN/WeakPtr.h @@ -0,0 +1,107 @@ +#pragma once + +#include + +namespace BAN +{ + + template + class Weakable; + + template + class WeakPtr; + + template + class WeakLink : public RefCounted> + { + public: + RefPtr lock() { ASSERT(m_ptr); return raw_ptr(); } + T* raw_ptr() { return m_ptr; } + + bool valid() const { return m_ptr; } + void invalidate() { m_ptr = nullptr; } + + private: + WeakLink(T* ptr) : m_ptr(ptr) {} + + private: + T* m_ptr; + + friend class RefPtr>; + }; + + template + class Weakable + { + public: + ~Weakable() + { + if (m_link) + m_link->invalidate(); + } + + ErrorOr> get_weak_ptr() const + { + if (!m_link) + m_link = TRY(RefPtr>::create((T*)this)); + return WeakPtr(m_link); + } + + private: + mutable RefPtr> m_link; + }; + + template + class WeakPtr + { + public: + WeakPtr() = default; + WeakPtr(WeakPtr&& other) { *this = move(other); } + WeakPtr(const WeakPtr& other) { *this = other; } + WeakPtr(const RefPtr& other) { *this = other; } + + WeakPtr& operator=(WeakPtr&& other) + { + clear(); + m_link = move(other.m_link); + return *this; + } + WeakPtr& operator=(const WeakPtr& other) + { + clear(); + m_link = other.m_link; + return *this; + } + WeakPtr& operator=(const RefPtr& other) + { + clear(); + if (other) + m_link = MUST(other->get_weak_ptr()).move_link(); + return *this; + } + + RefPtr lock() + { + if (m_link->valid()) + return m_link->lock(); + return nullptr; + } + + void clear() { m_link.clear(); } + + bool valid() const { return m_link && m_link->valid(); } + + private: + WeakPtr(const RefPtr>& link) + : m_link(link) + { } + + RefPtr>&& move_link() { return move(m_link); } + + private: + RefPtr> m_link; + + friend class Weakable; + }; + +} \ No newline at end of file