2 * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 David Levin <levin@chromium.org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
22 #ifndef WTF_HashTable_h
23 #define WTF_HashTable_h
25 #include "FastMalloc.h"
26 #include "HashTraits.h"
27 #include "ValueCheck.h"
28 #include <wtf/Assertions.h>
29 #include <wtf/Threading.h>
33 #define DUMP_HASHTABLE_STATS 0
34 // Enables internal WTF consistency checks that are invoked automatically. Non-WTF callers can call checkTableConsistency() even if internal checks are disabled.
35 #define CHECK_HASHTABLE_CONSISTENCY 0
38 #define CHECK_HASHTABLE_ITERATORS 0
39 #define CHECK_HASHTABLE_USE_AFTER_DESTRUCTION 0
41 #define CHECK_HASHTABLE_ITERATORS 1
42 #define CHECK_HASHTABLE_USE_AFTER_DESTRUCTION 1
45 #if DUMP_HASHTABLE_STATS
47 struct HashTableStats {
49 // All of the variables are accessed in ~HashTableStats when the static struct is destroyed.
51 // The following variables are all atomically incremented when modified.
52 static int numAccesses;
53 static int numRehashes;
54 static int numRemoves;
55 static int numReinserts;
57 // The following variables are only modified in the recordCollisionAtCount method within a mutex.
58 static int maxCollisions;
59 static int numCollisions;
60 static int collisionGraph[4096];
62 static void recordCollisionAtCount(int count);
67 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
69 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
70 class HashTableIterator;
71 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
72 class HashTableConstIterator;
74 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
75 void addIterator(const HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>*,
76 HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>*);
78 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
79 void removeIterator(HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>*);
81 #if !CHECK_HASHTABLE_ITERATORS
83 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
84 inline void addIterator(const HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>*,
85 HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>*) { }
87 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
88 inline void removeIterator(HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>*) { }
92 typedef enum { HashItemKnownGood } HashItemKnownGoodTag;
94 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
95 class HashTableConstIterator {
97 typedef HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> HashTableType;
98 typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> iterator;
99 typedef HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> const_iterator;
100 typedef Value ValueType;
101 typedef const ValueType& ReferenceType;
102 typedef const ValueType* PointerType;
104 friend class HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>;
105 friend class HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>;
107 void skipEmptyBuckets()
109 while (m_position != m_endPosition && HashTableType::isEmptyOrDeletedBucket(*m_position))
113 HashTableConstIterator(const HashTableType* table, PointerType position, PointerType endPosition)
114 : m_position(position), m_endPosition(endPosition)
116 addIterator(table, this);
120 HashTableConstIterator(const HashTableType* table, PointerType position, PointerType endPosition, HashItemKnownGoodTag)
121 : m_position(position), m_endPosition(endPosition)
123 addIterator(table, this);
127 HashTableConstIterator()
129 addIterator(static_cast<const HashTableType*>(0), this);
132 // default copy, assignment and destructor are OK if CHECK_HASHTABLE_ITERATORS is 0
134 #if CHECK_HASHTABLE_ITERATORS
135 ~HashTableConstIterator()
137 removeIterator(this);
140 HashTableConstIterator(const const_iterator& other)
141 : m_position(other.m_position), m_endPosition(other.m_endPosition)
143 addIterator(other.m_table, this);
146 const_iterator& operator=(const const_iterator& other)
148 m_position = other.m_position;
149 m_endPosition = other.m_endPosition;
151 removeIterator(this);
152 addIterator(other.m_table, this);
158 PointerType get() const
163 ReferenceType operator*() const { return *get(); }
164 PointerType operator->() const { return get(); }
166 const_iterator& operator++()
169 ASSERT(m_position != m_endPosition);
175 // postfix ++ intentionally omitted
178 bool operator==(const const_iterator& other) const
180 checkValidity(other);
181 return m_position == other.m_position;
183 bool operator!=(const const_iterator& other) const
185 checkValidity(other);
186 return m_position != other.m_position;
190 void checkValidity() const
192 #if CHECK_HASHTABLE_ITERATORS
198 #if CHECK_HASHTABLE_ITERATORS
199 void checkValidity(const const_iterator& other) const
202 ASSERT_UNUSED(other, other.m_table);
203 ASSERT(m_table == other.m_table);
206 void checkValidity(const const_iterator&) const { }
209 PointerType m_position;
210 PointerType m_endPosition;
212 #if CHECK_HASHTABLE_ITERATORS
214 // Any modifications of the m_next or m_previous of an iterator that is in a linked list of a HashTable::m_iterator,
215 // should be guarded with m_table->m_mutex.
216 mutable const HashTableType* m_table;
217 mutable const_iterator* m_next;
218 mutable const_iterator* m_previous;
222 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
223 class HashTableIterator {
225 typedef HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> HashTableType;
226 typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> iterator;
227 typedef HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> const_iterator;
228 typedef Value ValueType;
229 typedef ValueType& ReferenceType;
230 typedef ValueType* PointerType;
232 friend class HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>;
234 HashTableIterator(HashTableType* table, PointerType pos, PointerType end) : m_iterator(table, pos, end) { }
235 HashTableIterator(HashTableType* table, PointerType pos, PointerType end, HashItemKnownGoodTag tag) : m_iterator(table, pos, end, tag) { }
238 HashTableIterator() { }
240 // default copy, assignment and destructor are OK
242 PointerType get() const { return const_cast<PointerType>(m_iterator.get()); }
243 ReferenceType operator*() const { return *get(); }
244 PointerType operator->() const { return get(); }
246 iterator& operator++() { ++m_iterator; return *this; }
248 // postfix ++ intentionally omitted
251 bool operator==(const iterator& other) const { return m_iterator == other.m_iterator; }
252 bool operator!=(const iterator& other) const { return m_iterator != other.m_iterator; }
254 operator const_iterator() const { return m_iterator; }
257 const_iterator m_iterator;
262 // Work around MSVC's standard library, whose swap for pairs does not swap by component.
263 template<typename T> inline void hashTableSwap(T& a, T& b)
268 // Swap pairs by component, in case of pair members that specialize swap.
269 template<typename T, typename U> inline void hashTableSwap(pair<T, U>& a, pair<T, U>& b)
271 swap(a.first, b.first);
272 swap(a.second, b.second);
275 template<typename T, bool useSwap> struct Mover;
276 template<typename T> struct Mover<T, true> { static void move(T& from, T& to) { hashTableSwap(from, to); } };
277 template<typename T> struct Mover<T, false> { static void move(T& from, T& to) { to = from; } };
279 template<typename Key, typename Value, typename HashFunctions> class IdentityHashTranslator {
281 static unsigned hash(const Key& key) { return HashFunctions::hash(key); }
282 static bool equal(const Key& a, const Key& b) { return HashFunctions::equal(a, b); }
283 static void translate(Value& location, const Key&, const Value& value) { location = value; }
286 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
289 typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> iterator;
290 typedef HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> const_iterator;
291 typedef Traits ValueTraits;
293 typedef Value ValueType;
294 typedef IdentityHashTranslator<Key, Value, HashFunctions> IdentityTranslatorType;
299 invalidateIterators();
300 deallocateTable(m_table, m_tableSize);
301 #if CHECK_HASHTABLE_USE_AFTER_DESTRUCTION
302 m_table = (ValueType*)(uintptr_t)0xbbadbeef;
306 HashTable(const HashTable&);
307 void swap(HashTable&);
308 HashTable& operator=(const HashTable&);
310 iterator begin() { return makeIterator(m_table); }
311 iterator end() { return makeKnownGoodIterator(m_table + m_tableSize); }
312 const_iterator begin() const { return makeConstIterator(m_table); }
313 const_iterator end() const { return makeKnownGoodConstIterator(m_table + m_tableSize); }
315 int size() const { return m_keyCount; }
316 int capacity() const { return m_tableSize; }
317 bool isEmpty() const { return !m_keyCount; }
319 pair<iterator, bool> add(const ValueType& value) { return add<KeyType, ValueType, IdentityTranslatorType>(Extractor::extract(value), value); }
321 // A special version of add() that finds the object by hashing and comparing
322 // with some other type, to avoid the cost of type conversion if the object is already
324 template<typename T, typename Extra, typename HashTranslator> pair<iterator, bool> add(const T& key, const Extra&);
325 template<typename T, typename Extra, typename HashTranslator> pair<iterator, bool> addPassingHashCode(const T& key, const Extra&);
327 iterator find(const KeyType& key) { return find<KeyType, IdentityTranslatorType>(key); }
328 const_iterator find(const KeyType& key) const { return find<KeyType, IdentityTranslatorType>(key); }
329 bool contains(const KeyType& key) const { return contains<KeyType, IdentityTranslatorType>(key); }
331 template <typename T, typename HashTranslator> iterator find(const T&);
332 template <typename T, typename HashTranslator> const_iterator find(const T&) const;
333 template <typename T, typename HashTranslator> bool contains(const T&) const;
335 void remove(const KeyType&);
336 void remove(iterator);
337 void removeWithoutEntryConsistencyCheck(iterator);
338 void removeWithoutEntryConsistencyCheck(const_iterator);
341 static bool isEmptyBucket(const ValueType& value) { return Extractor::extract(value) == KeyTraits::emptyValue(); }
342 static bool isDeletedBucket(const ValueType& value) { return KeyTraits::isDeletedValue(Extractor::extract(value)); }
343 static bool isEmptyOrDeletedBucket(const ValueType& value) { return isEmptyBucket(value) || isDeletedBucket(value); }
345 ValueType* lookup(const Key& key) { return lookup<Key, IdentityTranslatorType>(key); }
346 template<typename T, typename HashTranslator> ValueType* lookup(const T&);
349 void checkTableConsistency() const;
351 static void checkTableConsistency() { }
353 #if CHECK_HASHTABLE_CONSISTENCY
354 void internalCheckTableConsistency() const { checkTableConsistency(); }
355 void internalCheckTableConsistencyExceptSize() const { checkTableConsistencyExceptSize(); }
357 static void internalCheckTableConsistencyExceptSize() { }
358 static void internalCheckTableConsistency() { }
362 static ValueType* allocateTable(int size);
363 static void deallocateTable(ValueType* table, int size);
365 typedef pair<ValueType*, bool> LookupType;
366 typedef pair<LookupType, unsigned> FullLookupType;
368 LookupType lookupForWriting(const Key& key) { return lookupForWriting<Key, IdentityTranslatorType>(key); };
369 template<typename T, typename HashTranslator> FullLookupType fullLookupForWriting(const T&);
370 template<typename T, typename HashTranslator> LookupType lookupForWriting(const T&);
372 template<typename T, typename HashTranslator> void checkKey(const T&);
374 void removeAndInvalidateWithoutEntryConsistencyCheck(ValueType*);
375 void removeAndInvalidate(ValueType*);
376 void remove(ValueType*);
378 bool shouldExpand() const { return (m_keyCount + m_deletedCount) * m_maxLoad >= m_tableSize; }
379 bool mustRehashInPlace() const { return m_keyCount * m_minLoad < m_tableSize * 2; }
380 bool shouldShrink() const { return m_keyCount * m_minLoad < m_tableSize && m_tableSize > KeyTraits::minimumTableSize; }
382 void shrink() { rehash(m_tableSize / 2); }
384 void rehash(int newTableSize);
385 void reinsert(ValueType&);
387 static void initializeBucket(ValueType& bucket) { new (&bucket) ValueType(Traits::emptyValue()); }
388 static void deleteBucket(ValueType& bucket) { bucket.~ValueType(); Traits::constructDeletedValue(bucket); }
390 FullLookupType makeLookupResult(ValueType* position, bool found, unsigned hash)
391 { return FullLookupType(LookupType(position, found), hash); }
393 iterator makeIterator(ValueType* pos) { return iterator(this, pos, m_table + m_tableSize); }
394 const_iterator makeConstIterator(ValueType* pos) const { return const_iterator(this, pos, m_table + m_tableSize); }
395 iterator makeKnownGoodIterator(ValueType* pos) { return iterator(this, pos, m_table + m_tableSize, HashItemKnownGood); }
396 const_iterator makeKnownGoodConstIterator(ValueType* pos) const { return const_iterator(this, pos, m_table + m_tableSize, HashItemKnownGood); }
399 void checkTableConsistencyExceptSize() const;
401 static void checkTableConsistencyExceptSize() { }
404 #if CHECK_HASHTABLE_ITERATORS
405 void invalidateIterators();
407 static void invalidateIterators() { }
410 static const int m_maxLoad = 2;
411 static const int m_minLoad = 6;
419 #if CHECK_HASHTABLE_ITERATORS
421 // All access to m_iterators should be guarded with m_mutex.
422 mutable const_iterator* m_iterators;
423 mutable Mutex m_mutex;
427 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
428 inline HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::HashTable()
434 #if CHECK_HASHTABLE_ITERATORS
440 static inline unsigned doubleHash(unsigned key)
442 key = ~key + (key >> 23);
452 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
453 template<typename T, typename HashTranslator>
454 inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::checkKey(const T&)
460 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
461 template<typename T, typename HashTranslator>
462 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::checkKey(const T& key)
464 if (!HashFunctions::safeToCompareToEmptyOrDeleted)
466 ASSERT(!HashTranslator::equal(KeyTraits::emptyValue(), key));
467 ValueType deletedValue = Traits::emptyValue();
468 deletedValue.~ValueType();
469 Traits::constructDeletedValue(deletedValue);
470 ASSERT(!HashTranslator::equal(Extractor::extract(deletedValue), key));
471 new (&deletedValue) ValueType(Traits::emptyValue());
476 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
477 template<typename T, typename HashTranslator>
478 inline Value* HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::lookup(const T& key)
480 checkKey<T, HashTranslator>(key);
483 int sizeMask = m_tableSizeMask;
484 ValueType* table = m_table;
485 unsigned h = HashTranslator::hash(key);
486 int i = h & sizeMask;
491 #if DUMP_HASHTABLE_STATS
492 atomicIncrement(&HashTableStats::numAccesses);
497 ValueType* entry = table + i;
499 // we count on the compiler to optimize out this branch
500 if (HashFunctions::safeToCompareToEmptyOrDeleted) {
501 if (HashTranslator::equal(Extractor::extract(*entry), key))
504 if (isEmptyBucket(*entry))
507 if (isEmptyBucket(*entry))
510 if (!isDeletedBucket(*entry) && HashTranslator::equal(Extractor::extract(*entry), key))
513 #if DUMP_HASHTABLE_STATS
515 HashTableStats::recordCollisionAtCount(probeCount);
518 k = 1 | doubleHash(h);
519 i = (i + k) & sizeMask;
523 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
524 template<typename T, typename HashTranslator>
525 inline typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::LookupType HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::lookupForWriting(const T& key)
528 checkKey<T, HashTranslator>(key);
531 ValueType* table = m_table;
532 int sizeMask = m_tableSizeMask;
533 unsigned h = HashTranslator::hash(key);
534 int i = h & sizeMask;
536 #if DUMP_HASHTABLE_STATS
537 atomicIncrement(&HashTableStats::numAccesses);
541 ValueType* deletedEntry = 0;
544 ValueType* entry = table + i;
546 // we count on the compiler to optimize out this branch
547 if (HashFunctions::safeToCompareToEmptyOrDeleted) {
548 if (isEmptyBucket(*entry))
549 return LookupType(deletedEntry ? deletedEntry : entry, false);
551 if (HashTranslator::equal(Extractor::extract(*entry), key))
552 return LookupType(entry, true);
554 if (isDeletedBucket(*entry))
555 deletedEntry = entry;
557 if (isEmptyBucket(*entry))
558 return LookupType(deletedEntry ? deletedEntry : entry, false);
560 if (isDeletedBucket(*entry))
561 deletedEntry = entry;
562 else if (HashTranslator::equal(Extractor::extract(*entry), key))
563 return LookupType(entry, true);
565 #if DUMP_HASHTABLE_STATS
567 HashTableStats::recordCollisionAtCount(probeCount);
570 k = 1 | doubleHash(h);
571 i = (i + k) & sizeMask;
575 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
576 template<typename T, typename HashTranslator>
577 inline typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::FullLookupType HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::fullLookupForWriting(const T& key)
580 checkKey<T, HashTranslator>(key);
583 ValueType* table = m_table;
584 int sizeMask = m_tableSizeMask;
585 unsigned h = HashTranslator::hash(key);
586 int i = h & sizeMask;
588 #if DUMP_HASHTABLE_STATS
589 atomicIncrement(&HashTableStats::numAccesses);
593 ValueType* deletedEntry = 0;
596 ValueType* entry = table + i;
598 // we count on the compiler to optimize out this branch
599 if (HashFunctions::safeToCompareToEmptyOrDeleted) {
600 if (isEmptyBucket(*entry))
601 return makeLookupResult(deletedEntry ? deletedEntry : entry, false, h);
603 if (HashTranslator::equal(Extractor::extract(*entry), key))
604 return makeLookupResult(entry, true, h);
606 if (isDeletedBucket(*entry))
607 deletedEntry = entry;
609 if (isEmptyBucket(*entry))
610 return makeLookupResult(deletedEntry ? deletedEntry : entry, false, h);
612 if (isDeletedBucket(*entry))
613 deletedEntry = entry;
614 else if (HashTranslator::equal(Extractor::extract(*entry), key))
615 return makeLookupResult(entry, true, h);
617 #if DUMP_HASHTABLE_STATS
619 HashTableStats::recordCollisionAtCount(probeCount);
622 k = 1 | doubleHash(h);
623 i = (i + k) & sizeMask;
627 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
628 template<typename T, typename Extra, typename HashTranslator>
629 inline pair<typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::iterator, bool> HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::add(const T& key, const Extra& extra)
631 checkKey<T, HashTranslator>(key);
633 invalidateIterators();
638 internalCheckTableConsistency();
643 ValueType* table = m_table;
644 int sizeMask = m_tableSizeMask;
645 unsigned h = HashTranslator::hash(key);
646 int i = h & sizeMask;
648 #if DUMP_HASHTABLE_STATS
649 atomicIncrement(&HashTableStats::numAccesses);
653 ValueType* deletedEntry = 0;
658 // we count on the compiler to optimize out this branch
659 if (HashFunctions::safeToCompareToEmptyOrDeleted) {
660 if (isEmptyBucket(*entry))
663 if (HashTranslator::equal(Extractor::extract(*entry), key))
664 return std::make_pair(makeKnownGoodIterator(entry), false);
666 if (isDeletedBucket(*entry))
667 deletedEntry = entry;
669 if (isEmptyBucket(*entry))
672 if (isDeletedBucket(*entry))
673 deletedEntry = entry;
674 else if (HashTranslator::equal(Extractor::extract(*entry), key))
675 return std::make_pair(makeKnownGoodIterator(entry), false);
677 #if DUMP_HASHTABLE_STATS
679 HashTableStats::recordCollisionAtCount(probeCount);
682 k = 1 | doubleHash(h);
683 i = (i + k) & sizeMask;
687 initializeBucket(*deletedEntry);
688 entry = deletedEntry;
692 HashTranslator::translate(*entry, key, extra);
696 if (shouldExpand()) {
697 // FIXME: This makes an extra copy on expand. Probably not that bad since
698 // expand is rare, but would be better to have a version of expand that can
699 // follow a pivot entry and return the new position.
700 KeyType enteredKey = Extractor::extract(*entry);
702 pair<iterator, bool> p = std::make_pair(find(enteredKey), true);
703 ASSERT(p.first != end());
707 internalCheckTableConsistency();
709 return std::make_pair(makeKnownGoodIterator(entry), true);
712 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
713 template<typename T, typename Extra, typename HashTranslator>
714 inline pair<typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::iterator, bool> HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::addPassingHashCode(const T& key, const Extra& extra)
716 checkKey<T, HashTranslator>(key);
718 invalidateIterators();
723 internalCheckTableConsistency();
725 FullLookupType lookupResult = fullLookupForWriting<T, HashTranslator>(key);
727 ValueType* entry = lookupResult.first.first;
728 bool found = lookupResult.first.second;
729 unsigned h = lookupResult.second;
732 return std::make_pair(makeKnownGoodIterator(entry), false);
734 if (isDeletedBucket(*entry)) {
735 initializeBucket(*entry);
739 HashTranslator::translate(*entry, key, extra, h);
741 if (shouldExpand()) {
742 // FIXME: This makes an extra copy on expand. Probably not that bad since
743 // expand is rare, but would be better to have a version of expand that can
744 // follow a pivot entry and return the new position.
745 KeyType enteredKey = Extractor::extract(*entry);
747 pair<iterator, bool> p = std::make_pair(find(enteredKey), true);
748 ASSERT(p.first != end());
752 internalCheckTableConsistency();
754 return std::make_pair(makeKnownGoodIterator(entry), true);
757 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
758 inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::reinsert(ValueType& entry)
761 ASSERT(!lookupForWriting(Extractor::extract(entry)).second);
762 ASSERT(!isDeletedBucket(*(lookupForWriting(Extractor::extract(entry)).first)));
763 #if DUMP_HASHTABLE_STATS
764 atomicIncrement(&HashTableStats::numReinserts);
767 Mover<ValueType, Traits::needsDestruction>::move(entry, *lookupForWriting(Extractor::extract(entry)).first);
770 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
771 template <typename T, typename HashTranslator>
772 typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::iterator HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::find(const T& key)
777 ValueType* entry = lookup<T, HashTranslator>(key);
781 return makeKnownGoodIterator(entry);
784 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
785 template <typename T, typename HashTranslator>
786 typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::const_iterator HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::find(const T& key) const
791 ValueType* entry = const_cast<HashTable*>(this)->lookup<T, HashTranslator>(key);
795 return makeKnownGoodConstIterator(entry);
798 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
799 template <typename T, typename HashTranslator>
800 bool HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::contains(const T& key) const
805 return const_cast<HashTable*>(this)->lookup<T, HashTranslator>(key);
808 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
809 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::removeAndInvalidateWithoutEntryConsistencyCheck(ValueType* pos)
811 invalidateIterators();
815 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
816 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::removeAndInvalidate(ValueType* pos)
818 invalidateIterators();
819 internalCheckTableConsistency();
823 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
824 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::remove(ValueType* pos)
826 #if DUMP_HASHTABLE_STATS
827 atomicIncrement(&HashTableStats::numRemoves);
837 internalCheckTableConsistency();
840 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
841 inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::remove(iterator it)
846 removeAndInvalidate(const_cast<ValueType*>(it.m_iterator.m_position));
849 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
850 inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::removeWithoutEntryConsistencyCheck(iterator it)
855 removeAndInvalidateWithoutEntryConsistencyCheck(const_cast<ValueType*>(it.m_iterator.m_position));
858 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
859 inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::removeWithoutEntryConsistencyCheck(const_iterator it)
864 removeAndInvalidateWithoutEntryConsistencyCheck(const_cast<ValueType*>(it.m_position));
867 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
868 inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::remove(const KeyType& key)
873 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
874 Value* HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::allocateTable(int size)
876 // would use a template member function with explicit specializations here, but
877 // gcc doesn't appear to support that
878 if (Traits::emptyValueIsZero)
879 return static_cast<ValueType*>(fastZeroedMalloc(size * sizeof(ValueType)));
880 ValueType* result = static_cast<ValueType*>(fastMalloc(size * sizeof(ValueType)));
881 for (int i = 0; i < size; i++)
882 initializeBucket(result[i]);
886 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
887 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::deallocateTable(ValueType* table, int size)
889 if (Traits::needsDestruction) {
890 for (int i = 0; i < size; ++i) {
891 if (!isDeletedBucket(table[i]))
892 table[i].~ValueType();
898 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
899 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::expand()
902 if (m_tableSize == 0)
903 newSize = KeyTraits::minimumTableSize;
904 else if (mustRehashInPlace())
905 newSize = m_tableSize;
907 newSize = m_tableSize * 2;
912 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
913 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::rehash(int newTableSize)
915 internalCheckTableConsistencyExceptSize();
917 int oldTableSize = m_tableSize;
918 ValueType* oldTable = m_table;
920 #if DUMP_HASHTABLE_STATS
921 if (oldTableSize != 0)
922 atomicIncrement(&HashTableStats::numRehashes);
925 m_tableSize = newTableSize;
926 m_tableSizeMask = newTableSize - 1;
927 m_table = allocateTable(newTableSize);
929 for (int i = 0; i != oldTableSize; ++i)
930 if (!isEmptyOrDeletedBucket(oldTable[i]))
931 reinsert(oldTable[i]);
935 deallocateTable(oldTable, oldTableSize);
937 internalCheckTableConsistency();
940 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
941 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::clear()
943 invalidateIterators();
944 deallocateTable(m_table, m_tableSize);
951 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
952 HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::HashTable(const HashTable& other)
958 #if CHECK_HASHTABLE_ITERATORS
962 // Copy the hash table the dumb way, by adding each element to the new table.
963 // It might be more efficient to copy the table slots, but it's not clear that efficiency is needed.
964 const_iterator end = other.end();
965 for (const_iterator it = other.begin(); it != end; ++it)
969 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
970 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::swap(HashTable& other)
972 invalidateIterators();
973 other.invalidateIterators();
975 ValueType* tmp_table = m_table;
976 m_table = other.m_table;
977 other.m_table = tmp_table;
979 int tmp_tableSize = m_tableSize;
980 m_tableSize = other.m_tableSize;
981 other.m_tableSize = tmp_tableSize;
983 int tmp_tableSizeMask = m_tableSizeMask;
984 m_tableSizeMask = other.m_tableSizeMask;
985 other.m_tableSizeMask = tmp_tableSizeMask;
987 int tmp_keyCount = m_keyCount;
988 m_keyCount = other.m_keyCount;
989 other.m_keyCount = tmp_keyCount;
991 int tmp_deletedCount = m_deletedCount;
992 m_deletedCount = other.m_deletedCount;
993 other.m_deletedCount = tmp_deletedCount;
996 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
997 HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>& HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::operator=(const HashTable& other)
999 HashTable tmp(other);
1004 #if !ASSERT_DISABLED
1006 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
1007 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::checkTableConsistency() const
1009 checkTableConsistencyExceptSize();
1010 ASSERT(!m_table || !shouldExpand());
1011 ASSERT(!shouldShrink());
1014 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
1015 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::checkTableConsistencyExceptSize() const
1021 int deletedCount = 0;
1022 for (int j = 0; j < m_tableSize; ++j) {
1023 ValueType* entry = m_table + j;
1024 if (isEmptyBucket(*entry))
1027 if (isDeletedBucket(*entry)) {
1032 const_iterator it = find(Extractor::extract(*entry));
1033 ASSERT(entry == it.m_position);
1036 ValueCheck<Key>::checkConsistency(it->first);
1039 ASSERT(count == m_keyCount);
1040 ASSERT(deletedCount == m_deletedCount);
1041 ASSERT(m_tableSize >= KeyTraits::minimumTableSize);
1042 ASSERT(m_tableSizeMask);
1043 ASSERT(m_tableSize == m_tableSizeMask + 1);
1046 #endif // ASSERT_DISABLED
1048 #if CHECK_HASHTABLE_ITERATORS
1050 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
1051 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::invalidateIterators()
1053 MutexLocker lock(m_mutex);
1054 const_iterator* next;
1055 for (const_iterator* p = m_iterators; p; p = next) {
1064 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
1065 void addIterator(const HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>* table,
1066 HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>* it)
1068 it->m_table = table;
1071 // Insert iterator at head of doubly-linked list of iterators.
1075 MutexLocker lock(table->m_mutex);
1076 ASSERT(table->m_iterators != it);
1077 it->m_next = table->m_iterators;
1078 table->m_iterators = it;
1080 ASSERT(!it->m_next->m_previous);
1081 it->m_next->m_previous = it;
1086 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
1087 void removeIterator(HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>* it)
1089 typedef HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> HashTableType;
1090 typedef HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> const_iterator;
1092 // Delete iterator from doubly-linked list of iterators.
1094 ASSERT(!it->m_next);
1095 ASSERT(!it->m_previous);
1097 MutexLocker lock(it->m_table->m_mutex);
1099 ASSERT(it->m_next->m_previous == it);
1100 it->m_next->m_previous = it->m_previous;
1102 if (it->m_previous) {
1103 ASSERT(it->m_table->m_iterators != it);
1104 ASSERT(it->m_previous->m_next == it);
1105 it->m_previous->m_next = it->m_next;
1107 ASSERT(it->m_table->m_iterators == it);
1108 it->m_table->m_iterators = it->m_next;
1117 #endif // CHECK_HASHTABLE_ITERATORS
1119 // iterator adapters
1121 template<typename HashTableType, typename ValueType> struct HashTableConstIteratorAdapter {
1122 HashTableConstIteratorAdapter() {}
1123 HashTableConstIteratorAdapter(const typename HashTableType::const_iterator& impl) : m_impl(impl) {}
1125 const ValueType* get() const { return (const ValueType*)m_impl.get(); }
1126 const ValueType& operator*() const { return *get(); }
1127 const ValueType* operator->() const { return get(); }
1129 HashTableConstIteratorAdapter& operator++() { ++m_impl; return *this; }
1130 // postfix ++ intentionally omitted
1132 typename HashTableType::const_iterator m_impl;
1135 template<typename HashTableType, typename ValueType> struct HashTableIteratorAdapter {
1136 HashTableIteratorAdapter() {}
1137 HashTableIteratorAdapter(const typename HashTableType::iterator& impl) : m_impl(impl) {}
1139 ValueType* get() const { return (ValueType*)m_impl.get(); }
1140 ValueType& operator*() const { return *get(); }
1141 ValueType* operator->() const { return get(); }
1143 HashTableIteratorAdapter& operator++() { ++m_impl; return *this; }
1144 // postfix ++ intentionally omitted
1146 operator HashTableConstIteratorAdapter<HashTableType, ValueType>() {
1147 typename HashTableType::const_iterator i = m_impl;
1151 typename HashTableType::iterator m_impl;
1154 template<typename T, typename U>
1155 inline bool operator==(const HashTableConstIteratorAdapter<T, U>& a, const HashTableConstIteratorAdapter<T, U>& b)
1157 return a.m_impl == b.m_impl;
1160 template<typename T, typename U>
1161 inline bool operator!=(const HashTableConstIteratorAdapter<T, U>& a, const HashTableConstIteratorAdapter<T, U>& b)
1163 return a.m_impl != b.m_impl;
1166 template<typename T, typename U>
1167 inline bool operator==(const HashTableIteratorAdapter<T, U>& a, const HashTableIteratorAdapter<T, U>& b)
1169 return a.m_impl == b.m_impl;
1172 template<typename T, typename U>
1173 inline bool operator!=(const HashTableIteratorAdapter<T, U>& a, const HashTableIteratorAdapter<T, U>& b)
1175 return a.m_impl != b.m_impl;
1180 #include "HashIterators.h"
1182 #endif // WTF_HashTable_h