/* * Copyright (c) 2024, Andreas Kling * Copyright (c) 2026, Luke Wilde * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include namespace GC { class GC_API ConservativeHashTableBase { AK_MAKE_NONCOPYABLE(ConservativeHashTableBase); public: virtual void for_each_possible_value(AK::Function callback) const = 0; protected: ConservativeHashTableBase(); explicit ConservativeHashTableBase(Heap&); ~ConservativeHashTableBase(); Heap* m_heap { nullptr }; IntrusiveListNode m_list_node; public: using List = IntrusiveList<&ConservativeHashTableBase::m_list_node>; }; template, bool IsOrdered = false> class GC_API ConservativeHashTable final : public ConservativeHashTableBase , public HashTable { using HashTableBase = HashTable; public: ConservativeHashTable() : ConservativeHashTableBase() { } ConservativeHashTable(ConservativeHashTable const& other) : ConservativeHashTableBase(*other.m_heap) , HashTableBase(static_cast(other)) { } ConservativeHashTable(ConservativeHashTable&& other) : ConservativeHashTableBase(*other.m_heap) , HashTableBase(move(static_cast(other))) { } ConservativeHashTable& operator=(ConservativeHashTable const& other) { if (&other == this) return *this; HashTableBase::operator=(static_cast(other)); return *this; } ~ConservativeHashTable() = default; virtual void for_each_possible_value(AK::Function callback) const override { for (auto& entry : *this) { auto entry_bytes = ReadonlyBytes { &entry, sizeof(T) }; for (size_t i = 0; i + sizeof(FlatPtr) <= entry_bytes.size(); i += sizeof(FlatPtr)) { FlatPtr value; memcpy(&value, entry_bytes.offset(i), sizeof(FlatPtr)); callback(value); } } } }; template> using OrderedConservativeHashTable = ConservativeHashTable; }