/* * Copyright (c) 2026, Luke Wilde * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include namespace GC { class GC_API ConservativeHashMapBase { AK_MAKE_NONCOPYABLE(ConservativeHashMapBase); public: virtual void for_each_possible_value(AK::Function callback) const = 0; protected: ConservativeHashMapBase(); explicit ConservativeHashMapBase(Heap&); ~ConservativeHashMapBase(); Heap* m_heap { nullptr }; IntrusiveListNode m_list_node; public: using List = IntrusiveList<&ConservativeHashMapBase::m_list_node>; }; template, typename ValueTraits = Traits, bool IsOrdered = false> class GC_API ConservativeHashMap final : public ConservativeHashMapBase , public HashMap { using HashMapBase = HashMap; public: ConservativeHashMap() : ConservativeHashMapBase() { } ConservativeHashMap(ConservativeHashMap const& other) : ConservativeHashMapBase(*other.m_heap) , HashMapBase(static_cast(other)) { } ConservativeHashMap(ConservativeHashMap&& other) : ConservativeHashMapBase(*other.m_heap) , HashMapBase(move(static_cast(other))) { } ConservativeHashMap& operator=(ConservativeHashMap const& other) { if (&other == this) return *this; HashMapBase::operator=(static_cast(other)); return *this; } ~ConservativeHashMap() = default; virtual void for_each_possible_value(AK::Function callback) const override { auto scan_bytes = [&](ReadonlyBytes bytes) { for (size_t i = 0; i + sizeof(FlatPtr) <= bytes.size(); i += sizeof(FlatPtr)) { FlatPtr value; memcpy(&value, bytes.offset(i), sizeof(FlatPtr)); callback(value); } }; for (auto& [key, value] : *this) { scan_bytes({ &key, sizeof(K) }); scan_bytes({ &value, sizeof(V) }); } } }; template, typename ValueTraits = Traits> using OrderedConservativeHashMap = ConservativeHashMap; }