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

This commit is contained in:
Andreas Kling 2018-10-14 22:08:36 +02:00
parent c94044a04a
commit 39444c5916
Notes: sideshowbarker 2024-07-19 18:48:15 +09:00
2 changed files with 31 additions and 15 deletions

View file

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

View file

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