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
> m_minTableSize
; }
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_minTableSize
= 64;
411 static const int m_maxLoad
= 2;
412 static const int m_minLoad
= 6;
420 #if CHECK_HASHTABLE_ITERATORS
422 // All access to m_iterators should be guarded with m_mutex.
423 mutable const_iterator
* m_iterators
;
424 mutable Mutex m_mutex
;
428 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
429 inline HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::HashTable()
435 #if CHECK_HASHTABLE_ITERATORS
441 static inline unsigned doubleHash(unsigned key
)
443 key
= ~key
+ (key
>> 23);
453 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
454 template<typename T
, typename HashTranslator
>
455 inline void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::checkKey(const T
&)
461 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
462 template<typename T
, typename HashTranslator
>
463 void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::checkKey(const T
& key
)
465 if (!HashFunctions::safeToCompareToEmptyOrDeleted
)
467 ASSERT(!HashTranslator::equal(KeyTraits::emptyValue(), key
));
468 ValueType deletedValue
= Traits::emptyValue();
469 deletedValue
.~ValueType();
470 Traits::constructDeletedValue(deletedValue
);
471 ASSERT(!HashTranslator::equal(Extractor::extract(deletedValue
), key
));
472 new (&deletedValue
) ValueType(Traits::emptyValue());
477 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
478 template<typename T
, typename HashTranslator
>
479 inline Value
* HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::lookup(const T
& key
)
481 checkKey
<T
, HashTranslator
>(key
);
484 int sizeMask
= m_tableSizeMask
;
485 ValueType
* table
= m_table
;
486 unsigned h
= HashTranslator::hash(key
);
487 int i
= h
& sizeMask
;
492 #if DUMP_HASHTABLE_STATS
493 atomicIncrement(&HashTableStats::numAccesses
);
498 ValueType
* entry
= table
+ i
;
500 // we count on the compiler to optimize out this branch
501 if (HashFunctions::safeToCompareToEmptyOrDeleted
) {
502 if (HashTranslator::equal(Extractor::extract(*entry
), key
))
505 if (isEmptyBucket(*entry
))
508 if (isEmptyBucket(*entry
))
511 if (!isDeletedBucket(*entry
) && HashTranslator::equal(Extractor::extract(*entry
), key
))
514 #if DUMP_HASHTABLE_STATS
516 HashTableStats::recordCollisionAtCount(probeCount
);
519 k
= 1 | doubleHash(h
);
520 i
= (i
+ k
) & sizeMask
;
524 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
525 template<typename T
, typename HashTranslator
>
526 inline typename HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::LookupType HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::lookupForWriting(const T
& key
)
529 checkKey
<T
, HashTranslator
>(key
);
532 ValueType
* table
= m_table
;
533 int sizeMask
= m_tableSizeMask
;
534 unsigned h
= HashTranslator::hash(key
);
535 int i
= h
& sizeMask
;
537 #if DUMP_HASHTABLE_STATS
538 atomicIncrement(&HashTableStats::numAccesses
);
542 ValueType
* deletedEntry
= 0;
545 ValueType
* entry
= table
+ i
;
547 // we count on the compiler to optimize out this branch
548 if (HashFunctions::safeToCompareToEmptyOrDeleted
) {
549 if (isEmptyBucket(*entry
))
550 return LookupType(deletedEntry
? deletedEntry
: entry
, false);
552 if (HashTranslator::equal(Extractor::extract(*entry
), key
))
553 return LookupType(entry
, true);
555 if (isDeletedBucket(*entry
))
556 deletedEntry
= entry
;
558 if (isEmptyBucket(*entry
))
559 return LookupType(deletedEntry
? deletedEntry
: entry
, false);
561 if (isDeletedBucket(*entry
))
562 deletedEntry
= entry
;
563 else if (HashTranslator::equal(Extractor::extract(*entry
), key
))
564 return LookupType(entry
, true);
566 #if DUMP_HASHTABLE_STATS
568 HashTableStats::recordCollisionAtCount(probeCount
);
571 k
= 1 | doubleHash(h
);
572 i
= (i
+ k
) & sizeMask
;
576 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
577 template<typename T
, typename HashTranslator
>
578 inline typename HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::FullLookupType HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::fullLookupForWriting(const T
& key
)
581 checkKey
<T
, HashTranslator
>(key
);
584 ValueType
* table
= m_table
;
585 int sizeMask
= m_tableSizeMask
;
586 unsigned h
= HashTranslator::hash(key
);
587 int i
= h
& sizeMask
;
589 #if DUMP_HASHTABLE_STATS
590 atomicIncrement(&HashTableStats::numAccesses
);
594 ValueType
* deletedEntry
= 0;
597 ValueType
* entry
= table
+ i
;
599 // we count on the compiler to optimize out this branch
600 if (HashFunctions::safeToCompareToEmptyOrDeleted
) {
601 if (isEmptyBucket(*entry
))
602 return makeLookupResult(deletedEntry
? deletedEntry
: entry
, false, h
);
604 if (HashTranslator::equal(Extractor::extract(*entry
), key
))
605 return makeLookupResult(entry
, true, h
);
607 if (isDeletedBucket(*entry
))
608 deletedEntry
= entry
;
610 if (isEmptyBucket(*entry
))
611 return makeLookupResult(deletedEntry
? deletedEntry
: entry
, false, h
);
613 if (isDeletedBucket(*entry
))
614 deletedEntry
= entry
;
615 else if (HashTranslator::equal(Extractor::extract(*entry
), key
))
616 return makeLookupResult(entry
, true, h
);
618 #if DUMP_HASHTABLE_STATS
620 HashTableStats::recordCollisionAtCount(probeCount
);
623 k
= 1 | doubleHash(h
);
624 i
= (i
+ k
) & sizeMask
;
628 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
629 template<typename T
, typename Extra
, typename HashTranslator
>
630 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
)
632 checkKey
<T
, HashTranslator
>(key
);
634 invalidateIterators();
639 internalCheckTableConsistency();
644 ValueType
* table
= m_table
;
645 int sizeMask
= m_tableSizeMask
;
646 unsigned h
= HashTranslator::hash(key
);
647 int i
= h
& sizeMask
;
649 #if DUMP_HASHTABLE_STATS
650 atomicIncrement(&HashTableStats::numAccesses
);
654 ValueType
* deletedEntry
= 0;
659 // we count on the compiler to optimize out this branch
660 if (HashFunctions::safeToCompareToEmptyOrDeleted
) {
661 if (isEmptyBucket(*entry
))
664 if (HashTranslator::equal(Extractor::extract(*entry
), key
))
665 return std::make_pair(makeKnownGoodIterator(entry
), false);
667 if (isDeletedBucket(*entry
))
668 deletedEntry
= entry
;
670 if (isEmptyBucket(*entry
))
673 if (isDeletedBucket(*entry
))
674 deletedEntry
= entry
;
675 else if (HashTranslator::equal(Extractor::extract(*entry
), key
))
676 return std::make_pair(makeKnownGoodIterator(entry
), false);
678 #if DUMP_HASHTABLE_STATS
680 HashTableStats::recordCollisionAtCount(probeCount
);
683 k
= 1 | doubleHash(h
);
684 i
= (i
+ k
) & sizeMask
;
688 initializeBucket(*deletedEntry
);
689 entry
= deletedEntry
;
693 HashTranslator::translate(*entry
, key
, extra
);
697 if (shouldExpand()) {
698 // FIXME: This makes an extra copy on expand. Probably not that bad since
699 // expand is rare, but would be better to have a version of expand that can
700 // follow a pivot entry and return the new position.
701 KeyType enteredKey
= Extractor::extract(*entry
);
703 pair
<iterator
, bool> p
= std::make_pair(find(enteredKey
), true);
704 ASSERT(p
.first
!= end());
708 internalCheckTableConsistency();
710 return std::make_pair(makeKnownGoodIterator(entry
), true);
713 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
714 template<typename T
, typename Extra
, typename HashTranslator
>
715 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
)
717 checkKey
<T
, HashTranslator
>(key
);
719 invalidateIterators();
724 internalCheckTableConsistency();
726 FullLookupType lookupResult
= fullLookupForWriting
<T
, HashTranslator
>(key
);
728 ValueType
* entry
= lookupResult
.first
.first
;
729 bool found
= lookupResult
.first
.second
;
730 unsigned h
= lookupResult
.second
;
733 return std::make_pair(makeKnownGoodIterator(entry
), false);
735 if (isDeletedBucket(*entry
)) {
736 initializeBucket(*entry
);
740 HashTranslator::translate(*entry
, key
, extra
, h
);
742 if (shouldExpand()) {
743 // FIXME: This makes an extra copy on expand. Probably not that bad since
744 // expand is rare, but would be better to have a version of expand that can
745 // follow a pivot entry and return the new position.
746 KeyType enteredKey
= Extractor::extract(*entry
);
748 pair
<iterator
, bool> p
= std::make_pair(find(enteredKey
), true);
749 ASSERT(p
.first
!= end());
753 internalCheckTableConsistency();
755 return std::make_pair(makeKnownGoodIterator(entry
), true);
758 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
759 inline void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::reinsert(ValueType
& entry
)
762 ASSERT(!lookupForWriting(Extractor::extract(entry
)).second
);
763 ASSERT(!isDeletedBucket(*(lookupForWriting(Extractor::extract(entry
)).first
)));
764 #if DUMP_HASHTABLE_STATS
765 atomicIncrement(&HashTableStats::numReinserts
);
768 Mover
<ValueType
, Traits::needsDestruction
>::move(entry
, *lookupForWriting(Extractor::extract(entry
)).first
);
771 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
772 template <typename T
, typename HashTranslator
>
773 typename HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::iterator HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::find(const T
& key
)
778 ValueType
* entry
= lookup
<T
, HashTranslator
>(key
);
782 return makeKnownGoodIterator(entry
);
785 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
786 template <typename T
, typename HashTranslator
>
787 typename HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::const_iterator HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::find(const T
& key
) const
792 ValueType
* entry
= const_cast<HashTable
*>(this)->lookup
<T
, HashTranslator
>(key
);
796 return makeKnownGoodConstIterator(entry
);
799 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
800 template <typename T
, typename HashTranslator
>
801 bool HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::contains(const T
& key
) const
806 return const_cast<HashTable
*>(this)->lookup
<T
, HashTranslator
>(key
);
809 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
810 void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::removeAndInvalidateWithoutEntryConsistencyCheck(ValueType
* pos
)
812 invalidateIterators();
816 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
817 void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::removeAndInvalidate(ValueType
* pos
)
819 invalidateIterators();
820 internalCheckTableConsistency();
824 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
825 void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::remove(ValueType
* pos
)
827 #if DUMP_HASHTABLE_STATS
828 atomicIncrement(&HashTableStats::numRemoves
);
838 internalCheckTableConsistency();
841 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
842 inline void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::remove(iterator it
)
847 removeAndInvalidate(const_cast<ValueType
*>(it
.m_iterator
.m_position
));
850 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
851 inline void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::removeWithoutEntryConsistencyCheck(iterator it
)
856 removeAndInvalidateWithoutEntryConsistencyCheck(const_cast<ValueType
*>(it
.m_iterator
.m_position
));
859 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
860 inline void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::removeWithoutEntryConsistencyCheck(const_iterator it
)
865 removeAndInvalidateWithoutEntryConsistencyCheck(const_cast<ValueType
*>(it
.m_position
));
868 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
869 inline void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::remove(const KeyType
& key
)
874 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
875 Value
* HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::allocateTable(int size
)
877 // would use a template member function with explicit specializations here, but
878 // gcc doesn't appear to support that
879 if (Traits::emptyValueIsZero
)
880 return static_cast<ValueType
*>(fastZeroedMalloc(size
* sizeof(ValueType
)));
881 ValueType
* result
= static_cast<ValueType
*>(fastMalloc(size
* sizeof(ValueType
)));
882 for (int i
= 0; i
< size
; i
++)
883 initializeBucket(result
[i
]);
887 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
888 void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::deallocateTable(ValueType
* table
, int size
)
890 if (Traits::needsDestruction
) {
891 for (int i
= 0; i
< size
; ++i
) {
892 if (!isDeletedBucket(table
[i
]))
893 table
[i
].~ValueType();
899 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
900 void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::expand()
903 if (m_tableSize
== 0)
904 newSize
= m_minTableSize
;
905 else if (mustRehashInPlace())
906 newSize
= m_tableSize
;
908 newSize
= m_tableSize
* 2;
913 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
914 void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::rehash(int newTableSize
)
916 internalCheckTableConsistencyExceptSize();
918 int oldTableSize
= m_tableSize
;
919 ValueType
* oldTable
= m_table
;
921 #if DUMP_HASHTABLE_STATS
922 if (oldTableSize
!= 0)
923 atomicIncrement(&HashTableStats::numRehashes
);
926 m_tableSize
= newTableSize
;
927 m_tableSizeMask
= newTableSize
- 1;
928 m_table
= allocateTable(newTableSize
);
930 for (int i
= 0; i
!= oldTableSize
; ++i
)
931 if (!isEmptyOrDeletedBucket(oldTable
[i
]))
932 reinsert(oldTable
[i
]);
936 deallocateTable(oldTable
, oldTableSize
);
938 internalCheckTableConsistency();
941 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
942 void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::clear()
944 invalidateIterators();
945 deallocateTable(m_table
, m_tableSize
);
952 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
953 HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::HashTable(const HashTable
& other
)
959 #if CHECK_HASHTABLE_ITERATORS
963 // Copy the hash table the dumb way, by adding each element to the new table.
964 // It might be more efficient to copy the table slots, but it's not clear that efficiency is needed.
965 const_iterator end
= other
.end();
966 for (const_iterator it
= other
.begin(); it
!= end
; ++it
)
970 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
971 void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::swap(HashTable
& other
)
973 invalidateIterators();
974 other
.invalidateIterators();
976 ValueType
* tmp_table
= m_table
;
977 m_table
= other
.m_table
;
978 other
.m_table
= tmp_table
;
980 int tmp_tableSize
= m_tableSize
;
981 m_tableSize
= other
.m_tableSize
;
982 other
.m_tableSize
= tmp_tableSize
;
984 int tmp_tableSizeMask
= m_tableSizeMask
;
985 m_tableSizeMask
= other
.m_tableSizeMask
;
986 other
.m_tableSizeMask
= tmp_tableSizeMask
;
988 int tmp_keyCount
= m_keyCount
;
989 m_keyCount
= other
.m_keyCount
;
990 other
.m_keyCount
= tmp_keyCount
;
992 int tmp_deletedCount
= m_deletedCount
;
993 m_deletedCount
= other
.m_deletedCount
;
994 other
.m_deletedCount
= tmp_deletedCount
;
997 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
998 HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>& HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::operator=(const HashTable
& other
)
1000 HashTable
tmp(other
);
1005 #if !ASSERT_DISABLED
1007 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
1008 void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::checkTableConsistency() const
1010 checkTableConsistencyExceptSize();
1011 ASSERT(!m_table
|| !shouldExpand());
1012 ASSERT(!shouldShrink());
1015 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
1016 void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::checkTableConsistencyExceptSize() const
1022 int deletedCount
= 0;
1023 for (int j
= 0; j
< m_tableSize
; ++j
) {
1024 ValueType
* entry
= m_table
+ j
;
1025 if (isEmptyBucket(*entry
))
1028 if (isDeletedBucket(*entry
)) {
1033 const_iterator it
= find(Extractor::extract(*entry
));
1034 ASSERT(entry
== it
.m_position
);
1037 ValueCheck
<Key
>::checkConsistency(it
->first
);
1040 ASSERT(count
== m_keyCount
);
1041 ASSERT(deletedCount
== m_deletedCount
);
1042 ASSERT(m_tableSize
>= m_minTableSize
);
1043 ASSERT(m_tableSizeMask
);
1044 ASSERT(m_tableSize
== m_tableSizeMask
+ 1);
1047 #endif // ASSERT_DISABLED
1049 #if CHECK_HASHTABLE_ITERATORS
1051 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
1052 void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::invalidateIterators()
1054 MutexLocker
lock(m_mutex
);
1055 const_iterator
* next
;
1056 for (const_iterator
* p
= m_iterators
; p
; p
= next
) {
1065 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
1066 void addIterator(const HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>* table
,
1067 HashTableConstIterator
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>* it
)
1069 it
->m_table
= table
;
1072 // Insert iterator at head of doubly-linked list of iterators.
1076 MutexLocker
lock(table
->m_mutex
);
1077 ASSERT(table
->m_iterators
!= it
);
1078 it
->m_next
= table
->m_iterators
;
1079 table
->m_iterators
= it
;
1081 ASSERT(!it
->m_next
->m_previous
);
1082 it
->m_next
->m_previous
= it
;
1087 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
1088 void removeIterator(HashTableConstIterator
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>* it
)
1090 typedef HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
> HashTableType
;
1091 typedef HashTableConstIterator
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
> const_iterator
;
1093 // Delete iterator from doubly-linked list of iterators.
1095 ASSERT(!it
->m_next
);
1096 ASSERT(!it
->m_previous
);
1098 MutexLocker
lock(it
->m_table
->m_mutex
);
1100 ASSERT(it
->m_next
->m_previous
== it
);
1101 it
->m_next
->m_previous
= it
->m_previous
;
1103 if (it
->m_previous
) {
1104 ASSERT(it
->m_table
->m_iterators
!= it
);
1105 ASSERT(it
->m_previous
->m_next
== it
);
1106 it
->m_previous
->m_next
= it
->m_next
;
1108 ASSERT(it
->m_table
->m_iterators
== it
);
1109 it
->m_table
->m_iterators
= it
->m_next
;
1118 #endif // CHECK_HASHTABLE_ITERATORS
1120 // iterator adapters
1122 template<typename HashTableType
, typename ValueType
> struct HashTableConstIteratorAdapter
{
1123 HashTableConstIteratorAdapter() {}
1124 HashTableConstIteratorAdapter(const typename
HashTableType::const_iterator
& impl
) : m_impl(impl
) {}
1126 const ValueType
* get() const { return (const ValueType
*)m_impl
.get(); }
1127 const ValueType
& operator*() const { return *get(); }
1128 const ValueType
* operator->() const { return get(); }
1130 HashTableConstIteratorAdapter
& operator++() { ++m_impl
; return *this; }
1131 // postfix ++ intentionally omitted
1133 typename
HashTableType::const_iterator m_impl
;
1136 template<typename HashTableType
, typename ValueType
> struct HashTableIteratorAdapter
{
1137 HashTableIteratorAdapter() {}
1138 HashTableIteratorAdapter(const typename
HashTableType::iterator
& impl
) : m_impl(impl
) {}
1140 ValueType
* get() const { return (ValueType
*)m_impl
.get(); }
1141 ValueType
& operator*() const { return *get(); }
1142 ValueType
* operator->() const { return get(); }
1144 HashTableIteratorAdapter
& operator++() { ++m_impl
; return *this; }
1145 // postfix ++ intentionally omitted
1147 operator HashTableConstIteratorAdapter
<HashTableType
, ValueType
>() {
1148 typename
HashTableType::const_iterator i
= m_impl
;
1152 typename
HashTableType::iterator m_impl
;
1155 template<typename T
, typename U
>
1156 inline bool operator==(const HashTableConstIteratorAdapter
<T
, U
>& a
, const HashTableConstIteratorAdapter
<T
, U
>& b
)
1158 return a
.m_impl
== b
.m_impl
;
1161 template<typename T
, typename U
>
1162 inline bool operator!=(const HashTableConstIteratorAdapter
<T
, U
>& a
, const HashTableConstIteratorAdapter
<T
, U
>& b
)
1164 return a
.m_impl
!= b
.m_impl
;
1167 template<typename T
, typename U
>
1168 inline bool operator==(const HashTableIteratorAdapter
<T
, U
>& a
, const HashTableIteratorAdapter
<T
, U
>& b
)
1170 return a
.m_impl
== b
.m_impl
;
1173 template<typename T
, typename U
>
1174 inline bool operator!=(const HashTableIteratorAdapter
<T
, U
>& a
, const HashTableIteratorAdapter
<T
, U
>& b
)
1176 return a
.m_impl
!= b
.m_impl
;
1181 #include "HashIterators.h"
1183 #endif // WTF_HashTable_h