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 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>
struct hash_table_entry
{
@ -331,42 +350,34 @@ namespace psemek::util
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>
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)
{
std::size_t index = probe_index(hash, i);
auto & entry = storage_.table[index];
auto & entry = storage_.table[indexer.index];
if (!entry.has_value() || entry.is_tombstone())
{
entry.set_value(std::forward<H>(value), hash);
++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())))
{
return {storage_.iterator(index), false};
return {storage_.iterator(indexer.index), false};
}
else
++i;
indexer.next();
}
}
template <typename Key>
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)
{
std::size_t index = probe_index(hash, i);
auto & entry = storage_.table[index];
auto & entry = storage_.table[indexer.index];
if (!entry.is_tombstone())
{
if (!entry.has_value())
@ -375,10 +386,10 @@ namespace psemek::util
}
else if (entry.hash_equal(hash) && equal()(key, key_projector()(entry.value())))
{
return storage_.iterator(index);
return storage_.iterator(indexer.index);
}
}
++i;
indexer.next();
}
}
};