diff --git a/libs/util/include/psemek/util/hash_table.hpp b/libs/util/include/psemek/util/hash_table.hpp index b947a866..b42de66e 100644 --- a/libs/util/include/psemek/util/hash_table.hpp +++ b/libs/util/include/psemek/util/hash_table.hpp @@ -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 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(hash) + (i * (i + 1)) / 2) % storage_.capacity; - } - template std::pair, 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(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 hash_table_iterator 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(); } } };