AK: Inline HashTable writing bucket lookup

The old approach was more complex and also had a very bad edge case
with lots of collisions. This approach eliminates that possiblility.
It also makes both reading and writing lookups a little bit faster.
This commit is contained in:
thislooksfun 2021-04-01 21:02:33 -05:00 committed by Andreas Kling
parent 509eb10df4
commit e55b8712d4
Notes: sideshowbarker 2024-07-18 20:54:19 +09:00

View File

@ -304,7 +304,7 @@ private:
}
template<typename Finder>
Bucket* lookup_with_hash(unsigned hash, Finder finder, Bucket** usable_bucket_for_writing = nullptr) const
Bucket* lookup_with_hash(unsigned hash, Finder finder) const
{
if (is_empty())
return nullptr;
@ -312,10 +312,6 @@ private:
for (;;) {
auto& bucket = m_buckets[hash % m_capacity];
if (usable_bucket_for_writing && !*usable_bucket_for_writing && !bucket.used) {
*usable_bucket_for_writing = &bucket;
}
if (bucket.used && finder(*bucket.slot()))
return &bucket;
@ -333,25 +329,25 @@ private:
Bucket& lookup_for_writing(const T& value)
{
auto hash = TraitsForT::hash(value);
Bucket* usable_bucket_for_writing = nullptr;
if (auto* bucket_for_reading = lookup_with_hash(
hash,
[&value](auto& entry) { return TraitsForT::equals(entry, value); },
&usable_bucket_for_writing)) {
return *const_cast<Bucket*>(bucket_for_reading);
}
if (should_grow())
rehash(capacity() * 2);
else if (usable_bucket_for_writing)
return *usable_bucket_for_writing;
auto hash = TraitsForT::hash(value);
Bucket* first_empty_bucket = nullptr;
for (;;) {
auto& bucket = m_buckets[hash % m_capacity];
if (!bucket.used)
if (bucket.used && TraitsForT::equals(*bucket.slot(), value))
return bucket;
if (!bucket.used) {
if (!first_empty_bucket)
first_empty_bucket = &bucket;
if (!bucket.deleted)
return *const_cast<Bucket*>(first_empty_bucket);
}
hash = double_hash(hash);
}
}