فهرست منبع

Fix HashTable::find() return iterator for items found in non-0 buckets.

Andreas Kling 6 سال پیش
والد
کامیت
39444c5916
2فایلهای تغییر یافته به همراه31 افزوده شده و 15 حذف شده
  1. 13 5
      AK/DoublyLinkedList.h
  2. 18 10
      AK/HashTable.h

+ 13 - 5
AK/DoublyLinkedList.h

@@ -40,10 +40,12 @@ public:
     {
         auto* node = new Node(std::move(value));
         if (!m_head) {
+            ASSERT(!m_tail);
             m_head = node;
             m_tail = node;
             return;
         }
+        ASSERT(m_tail);
         m_tail->next = node;
         node->prev = m_tail;
         m_tail = node;
@@ -112,14 +114,20 @@ public:
     {
         ASSERT(it.m_node);
         auto* node = it.m_node;
-        if (node->prev)
+        if (node->prev) {
+            ASSERT(node != m_head);
             node->prev->next = node->next;
-        if (node->next)
-            node->next->prev = node->prev;
-        if (m_head == node)
+        } else {
+            ASSERT(node == m_head);
             m_head = node->next;
-        if (m_tail == node)
+        }
+        if (node->next) {
+            ASSERT(node != m_tail);
+            node->next->prev = node->prev;
+        } else {
+            ASSERT(node == m_tail);
             m_tail = node->prev;
+        }
         delete node;
     }
 

+ 18 - 10
AK/HashTable.h

@@ -104,8 +104,9 @@ public:
         }
     private:
         friend class HashTable;
-        explicit Iterator(HashTable& table, bool isEnd, typename DoublyLinkedList<T>::Iterator bucketIterator = DoublyLinkedList<T>::Iterator::universalEnd())
+        explicit Iterator(HashTable& table, bool isEnd, typename DoublyLinkedList<T>::Iterator bucketIterator = DoublyLinkedList<T>::Iterator::universalEnd(), unsigned bucketIndex = 0)
             : m_table(table)
+            , m_bucketIndex(bucketIndex)
             , m_isEnd(isEnd)
             , m_bucketIterator(bucketIterator)
         {
@@ -179,8 +180,9 @@ public:
         }
     private:
         friend class HashTable;
-        ConstIterator(const HashTable& table, bool isEnd, typename DoublyLinkedList<T>::ConstIterator bucketIterator = DoublyLinkedList<T>::ConstIterator::universalEnd())
+        ConstIterator(const HashTable& table, bool isEnd, typename DoublyLinkedList<T>::ConstIterator bucketIterator = DoublyLinkedList<T>::ConstIterator::universalEnd(), unsigned bucketIndex = 0)
             : m_table(table)
+            , m_bucketIndex(bucketIndex)
             , m_isEnd(isEnd)
             , m_bucketIterator(bucketIterator)
         {
@@ -217,8 +219,8 @@ public:
     void remove(Iterator&);
 
 private:
-    Bucket& lookup(const T&);
-    const Bucket& lookup(const T&) const;
+    Bucket& lookup(const T&, unsigned* bucketIndex = nullptr);
+    const Bucket& lookup(const T&, unsigned* bucketIndex = nullptr) const;
     void rehash(unsigned capacity);
     void insert(T&&);
 
@@ -305,10 +307,11 @@ auto HashTable<T, TraitsForT>::find(const T& value) -> Iterator
 {
     if (isEmpty())
         return end();
-    auto& bucket = lookup(value);
+    unsigned bucketIndex;
+    auto& bucket = lookup(value, &bucketIndex);
     auto bucketIterator = bucket.chain.find(value);
     if (bucketIterator != bucket.chain.end())
-        return Iterator(*this, false, bucketIterator);
+        return Iterator(*this, false, bucketIterator, bucketIndex);
     return end();
 }
 
@@ -317,10 +320,11 @@ auto HashTable<T, TraitsForT>::find(const T& value) const -> ConstIterator
 {
     if (isEmpty())
         return end();
-    auto& bucket = lookup(value);
+    unsigned bucketIndex;
+    auto& bucket = lookup(value, &bucketIndex);
     auto bucketIterator = bucket.chain.find(value);
     if (bucketIterator != bucket.chain.end())
-        return ConstIterator(*this, false, bucketIterator);
+        return ConstIterator(*this, false, bucketIterator, bucketIndex);
     return end();
 }
 
@@ -333,7 +337,7 @@ void HashTable<T, TraitsForT>::remove(Iterator& it)
 }
 
 template<typename T, typename TraitsForT>
-typename HashTable<T, TraitsForT>::Bucket& HashTable<T, TraitsForT>::lookup(const T& value)
+typename HashTable<T, TraitsForT>::Bucket& HashTable<T, TraitsForT>::lookup(const T& value, unsigned* bucketIndex)
 {
     unsigned hash = TraitsForT::hash(value);
 #ifdef HASHTABLE_DEBUG
@@ -341,11 +345,13 @@ typename HashTable<T, TraitsForT>::Bucket& HashTable<T, TraitsForT>::lookup(cons
     TraitsForT::dump(value);
     printf(" is %u\n", hash);
 #endif
+    if (bucketIndex)
+        *bucketIndex = hash % m_capacity;
     return m_buckets[hash % m_capacity];
 }
 
 template<typename T, typename TraitsForT>
-const typename HashTable<T, TraitsForT>::Bucket& HashTable<T, TraitsForT>::lookup(const T& value) const
+const typename HashTable<T, TraitsForT>::Bucket& HashTable<T, TraitsForT>::lookup(const T& value, unsigned* bucketIndex) const
 {
     unsigned hash = TraitsForT::hash(value);
 #ifdef HASHTABLE_DEBUG
@@ -353,6 +359,8 @@ const typename HashTable<T, TraitsForT>::Bucket& HashTable<T, TraitsForT>::looku
     TraitsForT::dump(value);
     printf(" is %u\n", hash);
 #endif
+    if (bucketIndex)
+        *bucketIndex = hash % m_capacity;
     return m_buckets[hash % m_capacity];
 }