102 using key_type = Key;
103 using value_type = T;
105 using difference_type = ptrdiff_t;
106 using allocator_type = Allocator;
107 using reference = value_type &;
108 using const_reference = value_type
const &;
109 using pointer = value_type *;
110 using const_pointer = value_type
const *;
116 constexpr iterator(
node_type *node,
bool used) noexcept : node(node), used(used) {}
118 [[nodiscard]]
constexpr node_type &operator*()
const noexcept
123 [[nodiscard]]
constexpr node_type *operator->()
const noexcept
128 [[nodiscard]]
constexpr friend bool operator==(
iterator const &lhs, std::default_sentinel_t)
noexcept
142 [[nodiscard]]
constexpr node_type const &operator*()
const noexcept
147 [[nodiscard]]
constexpr node_type const *operator->()
const noexcept
152 [[nodiscard]]
constexpr friend bool operator==(
iterator const &lhs, std::default_sentinel_t)
noexcept
166 constexpr hash_map() noexcept requires(allocator_always_equal) : _nodes(
nullptr), _capacity(0), _size(0), allocator()
168 reserve(initial_capacity);
173 hi_assert_not_null(_nodes);
174 hi_axiom(_capacity != 0);
176 std::destroy_n(_nodes, _capacity);
180 [[nodiscard]]
constexpr allocator_type get_allocator() const noexcept
185 hi_no_inline
constexpr void reserve(
std::size_t new_capacity)
noexcept
187 if (new_capacity > _capacity) {
190 move_nodes(_nodes, _capacity, new_nodes, new_capacity);
192 if (_nodes !=
nullptr) {
196 _capacity = new_capacity;
200 [[nodiscard]]
constexpr const_iterator
find(key_type
const &key)
const noexcept
202 hi_assert_not_null(_nodes);
203 hi_axiom(_capacity != 0);
206 hash = hash == 0 ? 1 : hash;
208 auto hash_plus_count = hash;
211 auto node = _nodes + hash_plus_count % _capacity;
212 if (node->hash() == 0 or (node->hash() == hash and node->key() == key)) {
213 return const_iterator{node};
221 [[nodiscard]]
constexpr iterator find_or_create(K &&key)
noexcept
223 hi_assert_not_null(_nodes);
224 hi_axiom(_capacity != 0);
227 hash = hash == 0 ? 1 : hash;
229 auto hash_plus_count = hash;
232 auto node = _nodes + hash_plus_count % _capacity;
233 hi_axiom_not_null(node);
234 if (node->hash() == hash and node->key() == key) {
235 return iterator{node,
true};
237 }
else if (node->hash() == 0) {
238 return or_create(*node, hash, std::forward<K>(key));
246 [[nodiscard]]
constexpr value_type &operator[](K &&key)
noexcept
248 return find_or_create(std::forward<K>(key))->value();
251 [[nodiscard]]
constexpr std::default_sentinel_t
end() const noexcept
256 [[nodiscard]]
constexpr std::default_sentinel_t cend() const noexcept
262 constexpr static std::size_t initial_capacity = 307;
264 node_type *_nodes =
nullptr;
267 [[no_unique_address]] allocator_type allocator;
270 hi_no_inline
constexpr iterator or_create(node_type &node,
std::size_t hash, K &&key)
noexcept
273 node.set(hash, std::forward<K>(key));
274 return iterator{&node,
false};
282 hi_no_inline
constexpr void move_nodes(node_type *src,
std::size_t src_size, node_type *dst,
std::size_t dst_size)
noexcept
284 hi_axiom_not_null(dst);
285 hilet dst_ = std::uninitialized_value_construct_n(dst, dst_size);
286 hi_axiom_not_null(dst_);
288 auto const *
const src_last = src + src_size;
289 for (
auto src_it = src; src_it != src_last; ++src_it) {
290 hi_axiom_not_null(src_it);
291 hilet hash = src_it->hash();
294 auto hash_plus_count = hash;
296 hilet dst_it = dst_ + hash_plus_count % dst_size;
297 hi_axiom_not_null(dst_it);
299 if (dst_it->hash() == 0) {
309 std::destroy_n(src, src_size);
314 hi_assert_not_null(_nodes);
315 hi_axiom(_capacity != 0);
320 hilet max_size = _capacity - (_capacity >> 2);
321 if (_size > max_size) {
324 auto new_capacity = (_capacity + (_capacity >> 1) + nr_entries) | 1;
325 reserve(new_capacity);