100 using value_type = T;
102 using difference_type = ptrdiff_t;
103 using allocator_type = Allocator;
105 using const_reference = value_type
const &;
107 using const_pointer = value_type
const *;
113 constexpr iterator(
node_type *node,
bool used) noexcept : node(node), used(used) {}
115 [[nodiscard]]
constexpr node_type &operator*()
const noexcept
120 [[nodiscard]]
constexpr node_type *operator->()
const noexcept
125 [[nodiscard]]
constexpr friend bool operator==(
iterator const &lhs, std::default_sentinel_t)
noexcept
139 [[nodiscard]]
constexpr node_type const &operator*()
const noexcept
144 [[nodiscard]]
constexpr node_type const *operator->()
const noexcept
149 [[nodiscard]]
constexpr friend bool operator==(
iterator const &lhs, std::default_sentinel_t)
noexcept
163 constexpr hash_map() noexcept requires(allocator_always_equal) : _nodes(
nullptr), _capacity(0), _size(0), allocator()
165 reserve(initial_capacity);
173 std::destroy_n(_nodes, _capacity);
177 [[nodiscard]]
constexpr allocator_type get_allocator() const noexcept
182 hi_no_inline
constexpr void reserve(
std::size_t new_capacity)
noexcept
184 if (new_capacity > _capacity) {
187 move_nodes(_nodes, _capacity, new_nodes, new_capacity);
189 if (_nodes !=
nullptr) {
193 _capacity = new_capacity;
197 [[nodiscard]]
constexpr const_iterator
find(key_type
const &key)
const noexcept
203 hash = hash == 0 ? 1 : hash;
205 auto hash_plus_count = hash;
208 auto node = _nodes + hash_plus_count % _capacity;
209 if (node->hash() == 0 or (node->hash() == hash and node->key() == key)) {
210 return const_iterator{node};
218 [[nodiscard]]
constexpr iterator find_or_create(K &&key)
noexcept
224 hash = hash == 0 ? 1 : hash;
226 auto hash_plus_count = hash;
229 auto node = _nodes + hash_plus_count % _capacity;
231 if (node->hash() == hash and node->key() == key) {
232 return iterator{node,
true};
234 }
else if (node->hash() == 0) {
235 return or_create(*node, hash, std::forward<K>(key));
243 [[nodiscard]]
constexpr value_type &operator[](K &&key)
noexcept
245 return find_or_create(std::forward<K>(key))->value();
248 [[nodiscard]]
constexpr std::default_sentinel_t
end() const noexcept
253 [[nodiscard]]
constexpr std::default_sentinel_t cend() const noexcept
259 static constexpr std::size_t initial_capacity = 307;
261 node_type *_nodes =
nullptr;
264 [[no_unique_address]] allocator_type allocator;
267 hi_no_inline
constexpr iterator or_create(node_type &node,
std::size_t hash, K &&key)
noexcept
270 node.set(hash, std::forward<K>(key));
271 return iterator{&node,
false};
279 hi_no_inline
constexpr void move_nodes(node_type *src,
std::size_t src_size, node_type *dst,
std::size_t dst_size)
noexcept
282 hilet dst_ = std::uninitialized_value_construct_n(dst, dst_size);
285 auto const *
const src_last = src + src_size;
286 for (
auto src_it = src; src_it != src_last; ++src_it) {
288 hilet hash = src_it->hash();
291 auto hash_plus_count = hash;
293 hilet dst_it = dst_ + hash_plus_count % dst_size;
296 if (dst_it->hash() == 0) {
306 std::destroy_n(src, src_size);
317 hilet max_size = _capacity - (_capacity >> 2);
318 if (_size > max_size) {
321 auto new_capacity = (_capacity + (_capacity >> 1) + nr_entries) | 1;
322 reserve(new_capacity);
330using hash_map = hi::hash_map<Key, T, std::pmr::polymorphic_allocator<hi::hash_map_entry<Key, T>>>;
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:238
#define hi_assert_not_null(x,...)
Assert if an expression is not nullptr.
Definition assert.hpp:223
#define hi_axiom_not_null(expression,...)
Assert if an expression is not nullptr.
Definition assert.hpp:257