/* * Copyright (c) 2025, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include namespace GC { class GC_API RootHashMapBase { public: virtual void gather_roots(HashMap&) const = 0; protected: explicit RootHashMapBase(Heap&); ~RootHashMapBase(); void assign_heap(Heap*); Heap* m_heap { nullptr }; IntrusiveListNode m_list_node; public: using List = IntrusiveList<&RootHashMapBase::m_list_node>; }; template, typename ValueTraits = Traits, bool IsOrdered = false> class RootHashMap final : public RootHashMapBase , public HashMap { using HashMapBase = HashMap; public: explicit RootHashMap(Heap& heap) : RootHashMapBase(heap) { } ~RootHashMap() = default; virtual void gather_roots(HashMap& roots) const override { static constexpr bool KeyIsGCType = IsBaseOf || IsConvertible; static constexpr bool ValueIsGCType = IsBaseOf || IsConvertible; static_assert(KeyIsGCType || ValueIsGCType, "RootHashMap requires at least one of key or value types to be convertible to Cell const* or derive from NanBoxedValue"); for (auto& [key, value] : *this) { if constexpr (IsBaseOf) { if (key.is_cell()) roots.set(&const_cast(key).as_cell(), HeapRoot { .type = HeapRoot::Type::RootHashMap }); } else if constexpr (IsConvertible) { roots.set(const_cast(static_cast(key)), HeapRoot { .type = HeapRoot::Type::RootHashMap }); } if constexpr (IsBaseOf) { if (value.is_cell()) roots.set(&const_cast(value).as_cell(), HeapRoot { .type = HeapRoot::Type::RootHashMap }); } else if constexpr (IsConvertible) { roots.set(const_cast(static_cast(value)), HeapRoot { .type = HeapRoot::Type::RootHashMap }); } } } }; template, typename ValueTraits = Traits> using OrderedRootHashMap = RootHashMap; }