#pragma once #include #if __is_kernel #include #endif namespace BAN { template class Weakable; template class WeakPtr; // FIXME: Write this without using locks... template class WeakLink : public RefCounted> { public: RefPtr try_lock() const { #if __is_kernel Kernel::SpinLockGuard _(m_weak_lock); #endif if (m_ptr && m_ptr->try_ref()) return RefPtr::adopt(m_ptr); return nullptr; } bool valid() const { return m_ptr; } void invalidate() { #if __is_kernel Kernel::SpinLockGuard _(m_weak_lock); #endif m_ptr = nullptr; } private: WeakLink(T* ptr) : m_ptr(ptr) {} private: T* m_ptr; #if __is_kernel mutable Kernel::SpinLock m_weak_lock; #endif friend class RefPtr>; }; template class Weakable { public: virtual ~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() const { if (m_link) return m_link->try_lock(); return nullptr; } void clear() { m_link.clear(); } bool valid() const { return m_link && m_link->valid(); } explicit operator bool() const { return valid(); } private: WeakPtr(const RefPtr>& link) : m_link(link) { } RefPtr>&& move_link() { return move(m_link); } private: RefPtr> m_link; friend class Weakable; }; }