98 using difference_type = ptrdiff_t;
99 using allocator_type = Allocator;
101 using const_reference = value_type
const &;
103 using const_pointer = value_type
const *;
109 constexpr iterator(
node_type *node,
bool used) noexcept : node(node), used(used) {}
111 [[nodiscard]]
constexpr node_type &operator*()
const noexcept
116 [[nodiscard]]
constexpr node_type *operator->()
const noexcept
121 [[nodiscard]]
constexpr friend bool operator==(
iterator const &lhs, std::default_sentinel_t)
noexcept
135 [[nodiscard]]
constexpr node_type const &operator*()
const noexcept
140 [[nodiscard]]
constexpr node_type const *operator->()
const noexcept
145 [[nodiscard]]
constexpr friend bool operator==(
iterator const &lhs, std::default_sentinel_t)
noexcept
159 constexpr hash_map() noexcept requires(allocator_always_equal) : _nodes(
nullptr), _capacity(0), _size(0), allocator()
161 reserve(initial_capacity);
166 hi_axiom(_nodes !=
nullptr);
167 hi_axiom(_capacity != 0);
169 std::destroy_n(_nodes, _capacity);
173 [[nodiscard]]
constexpr allocator_type get_allocator() const noexcept
178 hi_no_inline
constexpr void reserve(
std::size_t new_capacity)
noexcept
180 if (new_capacity > _capacity) {
183 move_nodes(_nodes, _capacity, new_nodes, new_capacity);
185 if (_nodes !=
nullptr) {
189 _capacity = new_capacity;
193 [[nodiscard]]
constexpr const_iterator
find(key_type
const &key)
const noexcept
195 hi_axiom(_nodes !=
nullptr);
196 hi_axiom(_capacity != 0);
199 hash = hash == 0 ? 1 : hash;
201 auto hash_plus_count = hash;
204 auto node = _nodes + hash_plus_count % _capacity;
205 if (node->hash() == 0 or (node->hash() == hash and node->key() == key)) {
206 return const_iterator{node};
214 [[nodiscard]]
constexpr iterator find_or_create(K &&key)
noexcept
216 hi_axiom(_nodes !=
nullptr);
217 hi_axiom(_capacity != 0);
220 hash = hash == 0 ? 1 : hash;
222 auto hash_plus_count = hash;
225 auto node = _nodes + hash_plus_count % _capacity;
226 if (node->hash() == hash and node->key() == key) {
227 return iterator{node,
true};
229 }
else if (node->hash() == 0) {
230 return or_create(*node, hash, std::forward<K>(key));
238 [[nodiscard]]
constexpr value_type &operator[](K &&key)
noexcept
240 return find_or_create(std::forward<K>(key))->value();
243 [[nodiscard]]
constexpr std::default_sentinel_t
end() const noexcept
248 [[nodiscard]]
constexpr std::default_sentinel_t cend() const noexcept
254 static constexpr std::size_t initial_capacity = 307;
256 node_type *_nodes =
nullptr;
259 [[no_unique_address]] allocator_type allocator;
262 hi_no_inline
constexpr iterator or_create(node_type &node,
std::size_t hash, K &&key)
noexcept
265 node.set(hash, std::forward<K>(key));
266 return iterator{&node,
false};
274 hi_no_inline
constexpr void move_nodes(node_type *src,
std::size_t src_size, node_type *dst,
std::size_t dst_size)
noexcept
276 auto *dst_ = std::uninitialized_value_construct_n(dst, dst_size);
278 hilet src_last = src + src_size;
279 for (
auto src_it = src; src_it != src_last; ++src_it) {
280 hilet hash = src_it->hash();
283 auto hash_plus_count = hash;
285 auto dst_it = dst_ + hash_plus_count % dst_size;
286 if (dst_it->hash() == 0) {
296 std::destroy_n(src, src_size);
301 hi_axiom(_nodes !=
nullptr);
302 hi_axiom(_capacity != 0);
307 hilet max_size = _capacity - (_capacity >> 2);
308 if (_size > max_size) {
311 auto new_capacity = (_capacity + (_capacity >> 1) + nr_entries) | 1;
312 reserve(new_capacity);