Micro-optimize hash table probing
All checks were successful
Run tests / Run tests (push) Successful in 7m6s

This commit is contained in:
Nikita Lisitsa 2026-08-22 15:56:29 +03:00
parent 6601824986
commit aea5de0f6a

View file

@ -18,6 +18,25 @@ namespace psemek::util
constexpr std::uint64_t tombstone_mask = 1ull << 62; constexpr std::uint64_t tombstone_mask = 1ull << 62;
constexpr std::uint64_t hash_value_mask = ~(stored_value_mask | tombstone_mask); constexpr std::uint64_t hash_value_mask = ~(stored_value_mask | tombstone_mask);
struct indexer
{
std::size_t index;
std::size_t capacity;
std::size_t step = 0;
indexer(std::size_t index, std::size_t capacity)
: index{index & (capacity - 1)}
, capacity{capacity}
{}
void next()
{
step += 1;
index += step;
index &= (capacity - 1);
}
};
template <typename T> template <typename T>
struct hash_table_entry struct hash_table_entry
{ {
@ -331,42 +350,34 @@ namespace psemek::util
reallocate(capacity()); reallocate(capacity());
} }
std::size_t probe_index(std::uint64_t hash, std::size_t i) const
{
return (static_cast<std::size_t>(hash) + (i * (i + 1)) / 2) % storage_.capacity;
}
template <typename H> template <typename H>
std::pair<hash_table_iterator<T>, bool> insert_impl(H && value, std::uint64_t hash) std::pair<hash_table_iterator<T>, bool> insert_impl(H && value, std::uint64_t hash)
{ {
std::size_t i = 0; struct indexer indexer{hash, storage_.capacity};
while (true) while (true)
{ {
std::size_t index = probe_index(hash, i); auto & entry = storage_.table[indexer.index];
auto & entry = storage_.table[index];
if (!entry.has_value() || entry.is_tombstone()) if (!entry.has_value() || entry.is_tombstone())
{ {
entry.set_value(std::forward<H>(value), hash); entry.set_value(std::forward<H>(value), hash);
++size_; ++size_;
return {storage_.iterator(index), true}; return {storage_.iterator(indexer.index), true};
} }
else if (entry.hash_equal(hash) && equal()(key_projector()(value), key_projector()(entry.value()))) else if (entry.hash_equal(hash) && equal()(key_projector()(value), key_projector()(entry.value())))
{ {
return {storage_.iterator(index), false}; return {storage_.iterator(indexer.index), false};
} }
else indexer.next();
++i;
} }
} }
template <typename Key> template <typename Key>
hash_table_iterator<T> find_impl(Key const & key, std::uint64_t hash) const hash_table_iterator<T> find_impl(Key const & key, std::uint64_t hash) const
{ {
std::size_t i = 0; struct indexer indexer{hash, storage_.capacity};
while (true) while (true)
{ {
std::size_t index = probe_index(hash, i); auto & entry = storage_.table[indexer.index];
auto & entry = storage_.table[index];
if (!entry.is_tombstone()) if (!entry.is_tombstone())
{ {
if (!entry.has_value()) if (!entry.has_value())
@ -375,10 +386,10 @@ namespace psemek::util
} }
else if (entry.hash_equal(hash) && equal()(key, key_projector()(entry.value()))) else if (entry.hash_equal(hash) && equal()(key, key_projector()(entry.value())))
{ {
return storage_.iterator(index); return storage_.iterator(indexer.index);
} }
} }
++i; indexer.next();
} }
} }
}; };