Micro-optimize hash table probing
All checks were successful
Run tests / Run tests (push) Successful in 7m6s
All checks were successful
Run tests / Run tests (push) Successful in 7m6s
This commit is contained in:
parent
6601824986
commit
aea5de0f6a
1 changed files with 28 additions and 17 deletions
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue