소스 검색

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.
thislooksfun 4 년 전
부모
커밋
e55b8712d4
1개의 변경된 파일14개의 추가작업 그리고 18개의 파일을 삭제
  1. 14 18
      AK/HashTable.h

+ 14 - 18
AK/HashTable.h

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