/* * Copyright (c) 2025, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include namespace GC { class WeakBlock; class WeakImpl { public: // NOTE: Null GC::Weaks point at this WeakImpl. This allows Weak to always chase the impl pointer without null-checking it. static GC_API WeakImpl the_null_weak_impl; WeakImpl() = default; WeakImpl(void* ptr) : m_ptr(ptr) { } void* ptr() const { return m_ptr; } void set_ptr(Badge, void* ptr) { m_ptr = ptr; } bool operator==(WeakImpl const& other) const { return m_ptr == other.m_ptr; } bool operator!=(WeakImpl const& other) const { return m_ptr != other.m_ptr; } void ref() const { ++m_ref_count; } void unref() const { VERIFY(m_ref_count); --m_ref_count; } size_t ref_count() const { return m_ref_count; } enum class State { Allocated, Freelist, }; void set_state(State state) { m_state = state; } State state() const { return m_state; } private: mutable size_t m_ref_count { 0 }; State m_state { State::Allocated }; void* m_ptr { nullptr }; }; template class Weak { public: constexpr Weak() = default; Weak(nullptr_t) { } Weak(T const* ptr); Weak(T const& ptr); template Weak(Weak const& other) requires(IsConvertible); Weak(Ref const& other); template Weak(Ref const& other) requires(IsConvertible); template Weak& operator=(Weak const& other) requires(IsConvertible) { m_impl = other.impl(); return *this; } Weak& operator=(Ref const& other); template Weak& operator=(Ref const& other) requires(IsConvertible); Weak& operator=(T const& other); template Weak& operator=(U const& other) requires(IsConvertible); Weak& operator=(T const* other); template Weak& operator=(U const* other) requires(IsConvertible); T* operator->() const { ASSERT(ptr()); return ptr(); } [[nodiscard]] T& operator*() const { ASSERT(ptr()); return *ptr(); } Ptr ptr() const { return static_cast(impl().ptr()); } explicit operator bool() const { return !!ptr(); } bool operator!() const { return !ptr(); } operator T*() const { return ptr(); } Ref as_nonnull() const { ASSERT(ptr()); return *ptr(); } WeakImpl& impl() const { return *m_impl; } private: NonnullRefPtr m_impl { WeakImpl::the_null_weak_impl }; }; template inline bool operator==(Weak const& a, Ptr const& b) { return a.ptr() == b.ptr(); } template inline bool operator==(Weak const& a, Ref const& b) { return a.ptr() == b.ptr(); } } namespace AK { template struct Traits> : public DefaultTraits> { static unsigned hash(GC::Weak const& value) { return Traits::hash(value.ptr()); } }; template struct Formatter> : Formatter { ErrorOr format(FormatBuilder& builder, GC::Weak const& value) { return Formatter::format(builder, value.ptr()); } }; }