From a141c401f78467bc15f62882fca5d55a007cacbb Mon Sep 17 00:00:00 2001 From: Steven Le Rouzic Date: Mon, 17 Feb 2025 00:21:48 +0100 Subject: Reorganize everything --- asl/containers/hash_map.hpp | 178 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 asl/containers/hash_map.hpp (limited to 'asl/containers/hash_map.hpp') diff --git a/asl/containers/hash_map.hpp b/asl/containers/hash_map.hpp new file mode 100644 index 0000000..104bd6a --- /dev/null +++ b/asl/containers/hash_map.hpp @@ -0,0 +1,178 @@ +#pragma once + +#include "asl/base/utility.hpp" +#include "asl/base/meta.hpp" +#include "asl/hashing/hash.hpp" +#include "asl/memory/allocator.hpp" +#include "asl/containers/hash_set.hpp" + +namespace asl +{ + +namespace hash_map_internal +{ + +template +struct Slot +{ + K key; + V value; +}; + +template KeyHasher> +struct SlotHasher : public KeyHasher +{ + using KeyHasher::hash; + + constexpr static uint64_t hash(const Slot& slot) + { + return KeyHasher::hash(slot.key); + } +}; + +template KeyComparator> +struct SlotComparator : public KeyComparator +{ + using KeyComparator::eq; + + constexpr static bool eq(const Slot& a, const Slot& b) + { + return KeyComparator::eq(a.key, b.key); + } + + constexpr static bool eq(const Slot& a, const K& b) + { + return KeyComparator::eq(a.key, b); + } +}; + +} // namespace hash_map_internal + +template< + is_object K, + is_object V, + allocator Allocator = DefaultAllocator, + key_hasher KeyHasher = default_key_hasher, + key_comparator KeyComparator = default_key_comparator +> +requires moveable && moveable +class hash_map : protected hash_set< + hash_map_internal::Slot, + Allocator, + hash_map_internal::SlotHasher, + hash_map_internal::SlotComparator> +{ + using Base = + hash_set< + hash_map_internal::Slot, + Allocator, + hash_map_internal::SlotHasher, + hash_map_internal::SlotComparator>; + +public: + constexpr hash_map() requires default_constructible = default; + + explicit constexpr hash_map(Allocator allocator) + : Base{ASL_MOVE(allocator)} + {} + + hash_map(const hash_map&) requires copyable && copyable = default; + + hash_map& operator=(const hash_map&) requires copyable && copyable = default; + + hash_map(hash_map&&) = default; + + hash_map& operator=(hash_map&&) = default; + + ~hash_map() = default; + + using Base::destroy; + + using Base::clear; + + using Base::size; + + using Base::remove; + + using Base::contains; + + template + requires + key_hasher && + key_comparator && + constructible_from && + constructible_from + void insert(U&& key, Arg0&& arg0, Args1&&... args1) + { + Base::maybe_grow_to_fit_one_more(); + + auto result = Base::find_slot_insert(key); + + // NOLINTBEGIN(*-pointer-arithmetic) + + ASL_ASSERT(result.first_available_index >= 0); + + if (result.already_present_index >= 0) + { + if (result.already_present_index != result.first_available_index) + { + ASL_ASSERT((Base::m_tags[result.first_available_index] & Base::kHasValue) == 0); + + Base::m_values[result.first_available_index].construct_unsafe(ASL_MOVE(Base::m_values[result.already_present_index].as_init_unsafe())); + Base::m_values[result.already_present_index].destroy_unsafe(); + + Base::m_tags[result.first_available_index] = result.tag; + Base::m_tags[result.already_present_index] = Base::kTombstone; + } + + ASL_ASSERT(Base::m_tags[result.first_available_index] == result.tag); + + if constexpr (sizeof...(Args1) == 0 && assignable_from) + { + Base::m_values[result.first_available_index].as_init_unsafe().value = ASL_FWD(arg0); + } + else + { + Base::m_values[result.first_available_index].as_init_unsafe().value = ASL_MOVE(V{ASL_FWD(arg0), ASL_FWD(args1)...}); + } + } + else + { + ASL_ASSERT((Base::m_tags[result.first_available_index] & Base::kHasValue) == 0); + Base::m_values[result.first_available_index].construct_unsafe(ASL_FWD(key), V{ASL_FWD(arg0), ASL_FWD(args1)...}); + Base::m_tags[result.first_available_index] = result.tag; + Base::m_size += 1; + } + + // NOLINTEND(*-pointer-arithmetic) + } + + // @Todo(C++23) Deducing this + template + requires key_hasher && key_comparator + const V* get(const U& value) const + { + isize_t index = Base::find_slot_lookup(value); + if (index >= 0) + { + // NOLINTNEXTLINE(*-pointer-arithmetic) + return &Base::m_values[index].as_init_unsafe().value; + } + return nullptr; + } + + template + requires key_hasher && key_comparator + V* get(const U& value) + { + isize_t index = Base::find_slot_lookup(value); + if (index >= 0) + { + // NOLINTNEXTLINE(*-pointer-arithmetic) + return &Base::m_values[index].as_init_unsafe().value; + } + return nullptr; + } +}; + +} // namespace asl -- cgit