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 <wtf/Assertions.h>
28 #include <wtf/Threading.h>
32 #define DUMP_HASHTABLE_STATS 0
33 #define CHECK_HASHTABLE_CONSISTENCY 0
36 #define CHECK_HASHTABLE_ITERATORS 0
37 #define CHECK_HASHTABLE_USE_AFTER_DESTRUCTION 0
39 #define CHECK_HASHTABLE_ITERATORS 1
40 #define CHECK_HASHTABLE_USE_AFTER_DESTRUCTION 1
43 #if DUMP_HASHTABLE_STATS
45 struct HashTableStats
{
47 // All of the variables are accessed in ~HashTableStats when the static struct is destroyed.
49 // The following variables are all atomically incremented when modified.
50 static int numAccesses
;
51 static int numRehashes
;
52 static int numRemoves
;
53 static int numReinserts
;
55 // The following variables are only modified in the recordCollisionAtCount method within a mutex.
56 static int maxCollisions
;
57 static int numCollisions
;
58 static int collisionGraph
[4096];
60 static void recordCollisionAtCount(int count
);
65 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
67 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
68 class HashTableIterator
;
69 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
70 class HashTableConstIterator
;
72 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
73 void addIterator(const HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>*,
74 HashTableConstIterator
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>*);
76 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
77 void removeIterator(HashTableConstIterator
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>*);
79 #if !CHECK_HASHTABLE_ITERATORS
81 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
82 inline void addIterator(const HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>*,
83 HashTableConstIterator
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>*) { }
85 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
86 inline void removeIterator(HashTableConstIterator
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>*) { }
90 typedef enum { HashItemKnownGood
} HashItemKnownGoodTag
;
92 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
93 class HashTableConstIterator
{
95 typedef HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
> HashTableType
;
96 typedef HashTableIterator
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
> iterator
;
97 typedef HashTableConstIterator
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
> const_iterator
;
98 typedef Value ValueType
;
99 typedef const ValueType
& ReferenceType
;
100 typedef const ValueType
* PointerType
;
102 friend class HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>;
103 friend class HashTableIterator
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>;
105 void skipEmptyBuckets()
107 while (m_position
!= m_endPosition
&& HashTableType::isEmptyOrDeletedBucket(*m_position
))
111 HashTableConstIterator(const HashTableType
* table
, PointerType position
, PointerType endPosition
)
112 : m_position(position
), m_endPosition(endPosition
)
114 addIterator(table
, this);
118 HashTableConstIterator(const HashTableType
* table
, PointerType position
, PointerType endPosition
, HashItemKnownGoodTag
)
119 : m_position(position
), m_endPosition(endPosition
)
121 addIterator(table
, this);
125 HashTableConstIterator()
127 addIterator(0, this);
130 // default copy, assignment and destructor are OK if CHECK_HASHTABLE_ITERATORS is 0
132 #if CHECK_HASHTABLE_ITERATORS
133 ~HashTableConstIterator()
135 removeIterator(this);
138 HashTableConstIterator(const const_iterator
& other
)
139 : m_position(other
.m_position
), m_endPosition(other
.m_endPosition
)
141 addIterator(other
.m_table
, this);
144 const_iterator
& operator=(const const_iterator
& other
)
146 m_position
= other
.m_position
;
147 m_endPosition
= other
.m_endPosition
;
149 removeIterator(this);
150 addIterator(other
.m_table
, this);
156 PointerType
get() const
161 ReferenceType
operator*() const { return *get(); }
162 PointerType
operator->() const { return get(); }
164 const_iterator
& operator++()
167 ASSERT(m_position
!= m_endPosition
);
173 // postfix ++ intentionally omitted
176 bool operator==(const const_iterator
& other
) const
178 checkValidity(other
);
179 return m_position
== other
.m_position
;
181 bool operator!=(const const_iterator
& other
) const
183 checkValidity(other
);
184 return m_position
!= other
.m_position
;
188 void checkValidity() const
190 #if CHECK_HASHTABLE_ITERATORS
196 #if CHECK_HASHTABLE_ITERATORS
197 void checkValidity(const const_iterator
& other
) const
200 ASSERT(other
.m_table
);
201 ASSERT(m_table
== other
.m_table
);
204 void checkValidity(const const_iterator
&) const { }
207 PointerType m_position
;
208 PointerType m_endPosition
;
210 #if CHECK_HASHTABLE_ITERATORS
212 // Any modifications of the m_next or m_previous of an iterator that is in a linked list of a HashTable::m_iterator,
213 // should be guarded with m_table->m_mutex.
214 mutable const HashTableType
* m_table
;
215 mutable const_iterator
* m_next
;
216 mutable const_iterator
* m_previous
;
220 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
221 class HashTableIterator
{
223 typedef HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
> HashTableType
;
224 typedef HashTableIterator
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
> iterator
;
225 typedef HashTableConstIterator
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
> const_iterator
;
226 typedef Value ValueType
;
227 typedef ValueType
& ReferenceType
;
228 typedef ValueType
* PointerType
;
230 friend class HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>;
232 HashTableIterator(HashTableType
* table
, PointerType pos
, PointerType end
) : m_iterator(table
, pos
, end
) { }
233 HashTableIterator(HashTableType
* table
, PointerType pos
, PointerType end
, HashItemKnownGoodTag tag
) : m_iterator(table
, pos
, end
, tag
) { }
236 HashTableIterator() { }
238 // default copy, assignment and destructor are OK
240 PointerType
get() const { return const_cast<PointerType
>(m_iterator
.get()); }
241 ReferenceType
operator*() const { return *get(); }
242 PointerType
operator->() const { return get(); }
244 iterator
& operator++() { ++m_iterator
; return *this; }
246 // postfix ++ intentionally omitted
249 bool operator==(const iterator
& other
) const { return m_iterator
== other
.m_iterator
; }
250 bool operator!=(const iterator
& other
) const { return m_iterator
!= other
.m_iterator
; }
252 operator const_iterator() const { return m_iterator
; }
255 const_iterator m_iterator
;
261 // Visual C++ has a swap for pairs defined.
263 // swap pairs by component, in case of pair members that specialize swap
264 template<typename T
, typename U
> inline void swap(pair
<T
, U
>& a
, pair
<T
, U
>& b
)
266 swap(a
.first
, b
.first
);
267 swap(a
.second
, b
.second
);
271 template<typename T
, bool useSwap
> struct Mover
;
272 template<typename T
> struct Mover
<T
, true> { static void move(T
& from
, T
& to
) { swap(from
, to
); } };
273 template<typename T
> struct Mover
<T
, false> { static void move(T
& from
, T
& to
) { to
= from
; } };
275 template<typename Key
, typename Value
, typename HashFunctions
> class IdentityHashTranslator
{
277 static unsigned hash(const Key
& key
) { return HashFunctions::hash(key
); }
278 static bool equal(const Key
& a
, const Key
& b
) { return HashFunctions::equal(a
, b
); }
279 static void translate(Value
& location
, const Key
&, const Value
& value
) { location
= value
; }
282 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
285 typedef HashTableIterator
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
> iterator
;
286 typedef HashTableConstIterator
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
> const_iterator
;
287 typedef Traits ValueTraits
;
289 typedef Value ValueType
;
290 typedef IdentityHashTranslator
<Key
, Value
, HashFunctions
> IdentityTranslatorType
;
295 invalidateIterators();
296 deallocateTable(m_table
, m_tableSize
);
297 #if CHECK_HASHTABLE_USE_AFTER_DESTRUCTION
298 m_table
= (ValueType
*)(uintptr_t)0xbbadbeef;
302 HashTable(const HashTable
&);
303 void swap(HashTable
&);
304 HashTable
& operator=(const HashTable
&);
306 iterator
begin() { return makeIterator(m_table
); }
307 iterator
end() { return makeKnownGoodIterator(m_table
+ m_tableSize
); }
308 const_iterator
begin() const { return makeConstIterator(m_table
); }
309 const_iterator
end() const { return makeKnownGoodConstIterator(m_table
+ m_tableSize
); }
311 int size() const { return m_keyCount
; }
312 int capacity() const { return m_tableSize
; }
313 bool isEmpty() const { return !m_keyCount
; }
315 pair
<iterator
, bool> add(const ValueType
& value
) { return add
<KeyType
, ValueType
, IdentityTranslatorType
>(Extractor::extract(value
), value
); }
317 // A special version of add() that finds the object by hashing and comparing
318 // with some other type, to avoid the cost of type conversion if the object is already
320 template<typename T
, typename Extra
, typename HashTranslator
> pair
<iterator
, bool> add(const T
& key
, const Extra
&);
321 template<typename T
, typename Extra
, typename HashTranslator
> pair
<iterator
, bool> addPassingHashCode(const T
& key
, const Extra
&);
323 iterator
find(const KeyType
& key
) { return find
<KeyType
, IdentityTranslatorType
>(key
); }
324 const_iterator
find(const KeyType
& key
) const { return find
<KeyType
, IdentityTranslatorType
>(key
); }
325 bool contains(const KeyType
& key
) const { return contains
<KeyType
, IdentityTranslatorType
>(key
); }
327 template <typename T
, typename HashTranslator
> iterator
find(const T
&);
328 template <typename T
, typename HashTranslator
> const_iterator
find(const T
&) const;
329 template <typename T
, typename HashTranslator
> bool contains(const T
&) const;
331 void remove(const KeyType
&);
332 void remove(iterator
);
333 void removeWithoutEntryConsistencyCheck(iterator
);
336 static bool isEmptyBucket(const ValueType
& value
) { return Extractor::extract(value
) == KeyTraits::emptyValue(); }
337 static bool isDeletedBucket(const ValueType
& value
) { return KeyTraits::isDeletedValue(Extractor::extract(value
)); }
338 static bool isEmptyOrDeletedBucket(const ValueType
& value
) { return isEmptyBucket(value
) || isDeletedBucket(value
); }
340 ValueType
* lookup(const Key
& key
) { return lookup
<Key
, IdentityTranslatorType
>(key
); }
341 template<typename T
, typename HashTranslator
> ValueType
* lookup(const T
&);
343 #if CHECK_HASHTABLE_CONSISTENCY
344 void checkTableConsistency() const;
346 static void checkTableConsistency() { }
350 static ValueType
* allocateTable(int size
);
351 static void deallocateTable(ValueType
* table
, int size
);
353 typedef pair
<ValueType
*, bool> LookupType
;
354 typedef pair
<LookupType
, unsigned> FullLookupType
;
356 LookupType
lookupForWriting(const Key
& key
) { return lookupForWriting
<Key
, IdentityTranslatorType
>(key
); };
357 template<typename T
, typename HashTranslator
> FullLookupType
fullLookupForWriting(const T
&);
358 template<typename T
, typename HashTranslator
> LookupType
lookupForWriting(const T
&);
360 template<typename T
, typename HashTranslator
> void checkKey(const T
&);
362 void removeAndInvalidateWithoutEntryConsistencyCheck(ValueType
*);
363 void removeAndInvalidate(ValueType
*);
364 void remove(ValueType
*);
366 bool shouldExpand() const { return (m_keyCount
+ m_deletedCount
) * m_maxLoad
>= m_tableSize
; }
367 bool mustRehashInPlace() const { return m_keyCount
* m_minLoad
< m_tableSize
* 2; }
368 bool shouldShrink() const { return m_keyCount
* m_minLoad
< m_tableSize
&& m_tableSize
> m_minTableSize
; }
370 void shrink() { rehash(m_tableSize
/ 2); }
372 void rehash(int newTableSize
);
373 void reinsert(ValueType
&);
375 static void initializeBucket(ValueType
& bucket
) { new (&bucket
) ValueType(Traits::emptyValue()); }
376 static void deleteBucket(ValueType
& bucket
) { bucket
.~ValueType(); Traits::constructDeletedValue(bucket
); }
378 FullLookupType
makeLookupResult(ValueType
* position
, bool found
, unsigned hash
)
379 { return FullLookupType(LookupType(position
, found
), hash
); }
381 iterator
makeIterator(ValueType
* pos
) { return iterator(this, pos
, m_table
+ m_tableSize
); }
382 const_iterator
makeConstIterator(ValueType
* pos
) const { return const_iterator(this, pos
, m_table
+ m_tableSize
); }
383 iterator
makeKnownGoodIterator(ValueType
* pos
) { return iterator(this, pos
, m_table
+ m_tableSize
, HashItemKnownGood
); }
384 const_iterator
makeKnownGoodConstIterator(ValueType
* pos
) const { return const_iterator(this, pos
, m_table
+ m_tableSize
, HashItemKnownGood
); }
386 #if CHECK_HASHTABLE_CONSISTENCY
387 void checkTableConsistencyExceptSize() const;
389 static void checkTableConsistencyExceptSize() { }
392 #if CHECK_HASHTABLE_ITERATORS
393 void invalidateIterators();
395 static void invalidateIterators() { }
398 static const int m_minTableSize
= 64;
399 static const int m_maxLoad
= 2;
400 static const int m_minLoad
= 6;
408 #if CHECK_HASHTABLE_ITERATORS
410 // All access to m_iterators should be guarded with m_mutex.
411 mutable const_iterator
* m_iterators
;
412 mutable Mutex m_mutex
;
416 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
417 inline HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::HashTable()
423 #if CHECK_HASHTABLE_ITERATORS
429 static inline unsigned doubleHash(unsigned key
)
431 key
= ~key
+ (key
>> 23);
441 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
442 template<typename T
, typename HashTranslator
>
443 inline void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::checkKey(const T
&)
449 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
450 template<typename T
, typename HashTranslator
>
451 void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::checkKey(const T
& key
)
453 if (!HashFunctions::safeToCompareToEmptyOrDeleted
)
455 ASSERT(!HashTranslator::equal(KeyTraits::emptyValue(), key
));
456 ValueType deletedValue
= Traits::emptyValue();
457 deletedValue
.~ValueType();
458 Traits::constructDeletedValue(deletedValue
);
459 ASSERT(!HashTranslator::equal(Extractor::extract(deletedValue
), key
));
460 new (&deletedValue
) ValueType(Traits::emptyValue());
465 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
466 template<typename T
, typename HashTranslator
>
467 inline Value
* HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::lookup(const T
& key
)
469 checkKey
<T
, HashTranslator
>(key
);
472 int sizeMask
= m_tableSizeMask
;
473 ValueType
* table
= m_table
;
474 unsigned h
= HashTranslator::hash(key
);
475 int i
= h
& sizeMask
;
480 #if DUMP_HASHTABLE_STATS
481 atomicIncrement(&HashTableStats::numAccesses
);
486 ValueType
* entry
= table
+ i
;
488 // we count on the compiler to optimize out this branch
489 if (HashFunctions::safeToCompareToEmptyOrDeleted
) {
490 if (HashTranslator::equal(Extractor::extract(*entry
), key
))
493 if (isEmptyBucket(*entry
))
496 if (isEmptyBucket(*entry
))
499 if (!isDeletedBucket(*entry
) && HashTranslator::equal(Extractor::extract(*entry
), key
))
502 #if DUMP_HASHTABLE_STATS
504 HashTableStats::recordCollisionAtCount(probeCount
);
507 k
= 1 | doubleHash(h
);
508 i
= (i
+ k
) & sizeMask
;
512 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
513 template<typename T
, typename HashTranslator
>
514 inline typename HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::LookupType HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::lookupForWriting(const T
& key
)
517 checkKey
<T
, HashTranslator
>(key
);
520 ValueType
* table
= m_table
;
521 int sizeMask
= m_tableSizeMask
;
522 unsigned h
= HashTranslator::hash(key
);
523 int i
= h
& sizeMask
;
525 #if DUMP_HASHTABLE_STATS
526 atomicIncrement(&HashTableStats::numAccesses
);
530 ValueType
* deletedEntry
= 0;
533 ValueType
* entry
= table
+ i
;
535 // we count on the compiler to optimize out this branch
536 if (HashFunctions::safeToCompareToEmptyOrDeleted
) {
537 if (isEmptyBucket(*entry
))
538 return LookupType(deletedEntry
? deletedEntry
: entry
, false);
540 if (HashTranslator::equal(Extractor::extract(*entry
), key
))
541 return LookupType(entry
, true);
543 if (isDeletedBucket(*entry
))
544 deletedEntry
= entry
;
546 if (isEmptyBucket(*entry
))
547 return LookupType(deletedEntry
? deletedEntry
: entry
, false);
549 if (isDeletedBucket(*entry
))
550 deletedEntry
= entry
;
551 else if (HashTranslator::equal(Extractor::extract(*entry
), key
))
552 return LookupType(entry
, true);
554 #if DUMP_HASHTABLE_STATS
556 HashTableStats::recordCollisionAtCount(probeCount
);
559 k
= 1 | doubleHash(h
);
560 i
= (i
+ k
) & sizeMask
;
564 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
565 template<typename T
, typename HashTranslator
>
566 inline typename HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::FullLookupType HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::fullLookupForWriting(const T
& key
)
569 checkKey
<T
, HashTranslator
>(key
);
572 ValueType
* table
= m_table
;
573 int sizeMask
= m_tableSizeMask
;
574 unsigned h
= HashTranslator::hash(key
);
575 int i
= h
& sizeMask
;
577 #if DUMP_HASHTABLE_STATS
578 atomicIncrement(&HashTableStats::numAccesses
);
582 ValueType
* deletedEntry
= 0;
585 ValueType
* entry
= table
+ i
;
587 // we count on the compiler to optimize out this branch
588 if (HashFunctions::safeToCompareToEmptyOrDeleted
) {
589 if (isEmptyBucket(*entry
))
590 return makeLookupResult(deletedEntry
? deletedEntry
: entry
, false, h
);
592 if (HashTranslator::equal(Extractor::extract(*entry
), key
))
593 return makeLookupResult(entry
, true, h
);
595 if (isDeletedBucket(*entry
))
596 deletedEntry
= entry
;
598 if (isEmptyBucket(*entry
))
599 return makeLookupResult(deletedEntry
? deletedEntry
: entry
, false, h
);
601 if (isDeletedBucket(*entry
))
602 deletedEntry
= entry
;
603 else if (HashTranslator::equal(Extractor::extract(*entry
), key
))
604 return makeLookupResult(entry
, true, h
);
606 #if DUMP_HASHTABLE_STATS
608 HashTableStats::recordCollisionAtCount(probeCount
);
611 k
= 1 | doubleHash(h
);
612 i
= (i
+ k
) & sizeMask
;
616 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
617 template<typename T
, typename Extra
, typename HashTranslator
>
618 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
)
620 checkKey
<T
, HashTranslator
>(key
);
622 invalidateIterators();
627 checkTableConsistency();
632 ValueType
* table
= m_table
;
633 int sizeMask
= m_tableSizeMask
;
634 unsigned h
= HashTranslator::hash(key
);
635 int i
= h
& sizeMask
;
637 #if DUMP_HASHTABLE_STATS
638 atomicIncrement(&HashTableStats::numAccesses
);
642 ValueType
* deletedEntry
= 0;
647 // we count on the compiler to optimize out this branch
648 if (HashFunctions::safeToCompareToEmptyOrDeleted
) {
649 if (isEmptyBucket(*entry
))
652 if (HashTranslator::equal(Extractor::extract(*entry
), key
))
653 return std::make_pair(makeKnownGoodIterator(entry
), false);
655 if (isDeletedBucket(*entry
))
656 deletedEntry
= entry
;
658 if (isEmptyBucket(*entry
))
661 if (isDeletedBucket(*entry
))
662 deletedEntry
= entry
;
663 else if (HashTranslator::equal(Extractor::extract(*entry
), key
))
664 return std::make_pair(makeKnownGoodIterator(entry
), false);
666 #if DUMP_HASHTABLE_STATS
668 HashTableStats::recordCollisionAtCount(probeCount
);
671 k
= 1 | doubleHash(h
);
672 i
= (i
+ k
) & sizeMask
;
676 initializeBucket(*deletedEntry
);
677 entry
= deletedEntry
;
681 HashTranslator::translate(*entry
, key
, extra
);
685 if (shouldExpand()) {
686 // FIXME: This makes an extra copy on expand. Probably not that bad since
687 // expand is rare, but would be better to have a version of expand that can
688 // follow a pivot entry and return the new position.
689 KeyType enteredKey
= Extractor::extract(*entry
);
691 pair
<iterator
, bool> p
= std::make_pair(find(enteredKey
), true);
692 ASSERT(p
.first
!= end());
696 checkTableConsistency();
698 return std::make_pair(makeKnownGoodIterator(entry
), true);
701 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
702 template<typename T
, typename Extra
, typename HashTranslator
>
703 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
)
705 checkKey
<T
, HashTranslator
>(key
);
707 invalidateIterators();
712 checkTableConsistency();
714 FullLookupType lookupResult
= fullLookupForWriting
<T
, HashTranslator
>(key
);
716 ValueType
* entry
= lookupResult
.first
.first
;
717 bool found
= lookupResult
.first
.second
;
718 unsigned h
= lookupResult
.second
;
721 return std::make_pair(makeKnownGoodIterator(entry
), false);
723 if (isDeletedBucket(*entry
)) {
724 initializeBucket(*entry
);
728 HashTranslator::translate(*entry
, key
, extra
, h
);
730 if (shouldExpand()) {
731 // FIXME: This makes an extra copy on expand. Probably not that bad since
732 // expand is rare, but would be better to have a version of expand that can
733 // follow a pivot entry and return the new position.
734 KeyType enteredKey
= Extractor::extract(*entry
);
736 pair
<iterator
, bool> p
= std::make_pair(find(enteredKey
), true);
737 ASSERT(p
.first
!= end());
741 checkTableConsistency();
743 return std::make_pair(makeKnownGoodIterator(entry
), true);
746 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
747 inline void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::reinsert(ValueType
& entry
)
750 ASSERT(!lookupForWriting(Extractor::extract(entry
)).second
);
751 ASSERT(!isDeletedBucket(*(lookupForWriting(Extractor::extract(entry
)).first
)));
752 #if DUMP_HASHTABLE_STATS
753 atomicIncrement(&HashTableStats::numReinserts
);
756 Mover
<ValueType
, Traits::needsDestruction
>::move(entry
, *lookupForWriting(Extractor::extract(entry
)).first
);
759 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
760 template <typename T
, typename HashTranslator
>
761 typename HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::iterator HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::find(const T
& key
)
766 ValueType
* entry
= lookup
<T
, HashTranslator
>(key
);
770 return makeKnownGoodIterator(entry
);
773 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
774 template <typename T
, typename HashTranslator
>
775 typename HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::const_iterator HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::find(const T
& key
) const
780 ValueType
* entry
= const_cast<HashTable
*>(this)->lookup
<T
, HashTranslator
>(key
);
784 return makeKnownGoodConstIterator(entry
);
787 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
788 template <typename T
, typename HashTranslator
>
789 bool HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::contains(const T
& key
) const
794 return const_cast<HashTable
*>(this)->lookup
<T
, HashTranslator
>(key
);
797 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
798 void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::removeAndInvalidateWithoutEntryConsistencyCheck(ValueType
* pos
)
800 invalidateIterators();
804 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
805 void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::removeAndInvalidate(ValueType
* pos
)
807 invalidateIterators();
808 checkTableConsistency();
812 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
813 void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::remove(ValueType
* pos
)
815 #if DUMP_HASHTABLE_STATS
816 atomicIncrement(&HashTableStats::numRemoves
);
826 checkTableConsistency();
829 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
830 inline void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::remove(iterator it
)
835 removeAndInvalidate(const_cast<ValueType
*>(it
.m_iterator
.m_position
));
838 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
839 inline void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::removeWithoutEntryConsistencyCheck(iterator it
)
844 removeAndInvalidateWithoutEntryConsistencyCheck(const_cast<ValueType
*>(it
.m_iterator
.m_position
));
847 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
848 inline void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::remove(const KeyType
& key
)
853 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
854 Value
* HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::allocateTable(int size
)
856 // would use a template member function with explicit specializations here, but
857 // gcc doesn't appear to support that
858 if (Traits::emptyValueIsZero
)
859 return static_cast<ValueType
*>(fastZeroedMalloc(size
* sizeof(ValueType
)));
860 ValueType
* result
= static_cast<ValueType
*>(fastMalloc(size
* sizeof(ValueType
)));
861 for (int i
= 0; i
< size
; i
++)
862 initializeBucket(result
[i
]);
866 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
867 void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::deallocateTable(ValueType
* table
, int size
)
869 if (Traits::needsDestruction
) {
870 for (int i
= 0; i
< size
; ++i
) {
871 if (!isDeletedBucket(table
[i
]))
872 table
[i
].~ValueType();
878 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
879 void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::expand()
882 if (m_tableSize
== 0)
883 newSize
= m_minTableSize
;
884 else if (mustRehashInPlace())
885 newSize
= m_tableSize
;
887 newSize
= m_tableSize
* 2;
892 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
893 void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::rehash(int newTableSize
)
895 checkTableConsistencyExceptSize();
897 int oldTableSize
= m_tableSize
;
898 ValueType
* oldTable
= m_table
;
900 #if DUMP_HASHTABLE_STATS
901 if (oldTableSize
!= 0)
902 atomicIncrement(&HashTableStats::numRehashes
);
905 m_tableSize
= newTableSize
;
906 m_tableSizeMask
= newTableSize
- 1;
907 m_table
= allocateTable(newTableSize
);
909 for (int i
= 0; i
!= oldTableSize
; ++i
)
910 if (!isEmptyOrDeletedBucket(oldTable
[i
]))
911 reinsert(oldTable
[i
]);
915 deallocateTable(oldTable
, oldTableSize
);
917 checkTableConsistency();
920 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
921 void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::clear()
923 invalidateIterators();
924 deallocateTable(m_table
, m_tableSize
);
931 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
932 HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::HashTable(const HashTable
& other
)
938 #if CHECK_HASHTABLE_ITERATORS
942 // Copy the hash table the dumb way, by adding each element to the new table.
943 // It might be more efficient to copy the table slots, but it's not clear that efficiency is needed.
944 const_iterator end
= other
.end();
945 for (const_iterator it
= other
.begin(); it
!= end
; ++it
)
949 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
950 void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::swap(HashTable
& other
)
952 invalidateIterators();
953 other
.invalidateIterators();
955 ValueType
* tmp_table
= m_table
;
956 m_table
= other
.m_table
;
957 other
.m_table
= tmp_table
;
959 int tmp_tableSize
= m_tableSize
;
960 m_tableSize
= other
.m_tableSize
;
961 other
.m_tableSize
= tmp_tableSize
;
963 int tmp_tableSizeMask
= m_tableSizeMask
;
964 m_tableSizeMask
= other
.m_tableSizeMask
;
965 other
.m_tableSizeMask
= tmp_tableSizeMask
;
967 int tmp_keyCount
= m_keyCount
;
968 m_keyCount
= other
.m_keyCount
;
969 other
.m_keyCount
= tmp_keyCount
;
971 int tmp_deletedCount
= m_deletedCount
;
972 m_deletedCount
= other
.m_deletedCount
;
973 other
.m_deletedCount
= tmp_deletedCount
;
976 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
977 HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>& HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::operator=(const HashTable
& other
)
979 HashTable
tmp(other
);
984 #if CHECK_HASHTABLE_CONSISTENCY
986 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
987 void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::checkTableConsistency() const
989 checkTableConsistencyExceptSize();
990 ASSERT(!shouldExpand());
991 ASSERT(!shouldShrink());
994 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
995 void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::checkTableConsistencyExceptSize() const
1001 int deletedCount
= 0;
1002 for (int j
= 0; j
< m_tableSize
; ++j
) {
1003 ValueType
* entry
= m_table
+ j
;
1004 if (isEmptyBucket(*entry
))
1007 if (isDeletedBucket(*entry
)) {
1012 const_iterator it
= find(Extractor::extract(*entry
));
1013 ASSERT(entry
== it
.m_position
);
1017 ASSERT(count
== m_keyCount
);
1018 ASSERT(deletedCount
== m_deletedCount
);
1019 ASSERT(m_tableSize
>= m_minTableSize
);
1020 ASSERT(m_tableSizeMask
);
1021 ASSERT(m_tableSize
== m_tableSizeMask
+ 1);
1024 #endif // CHECK_HASHTABLE_CONSISTENCY
1026 #if CHECK_HASHTABLE_ITERATORS
1028 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
1029 void HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>::invalidateIterators()
1031 MutexLocker
lock(m_mutex
);
1032 const_iterator
* next
;
1033 for (const_iterator
* p
= m_iterators
; p
; p
= next
) {
1042 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
1043 void addIterator(const HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>* table
,
1044 HashTableConstIterator
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>* it
)
1046 it
->m_table
= table
;
1049 // Insert iterator at head of doubly-linked list of iterators.
1053 MutexLocker
lock(table
->m_mutex
);
1054 ASSERT(table
->m_iterators
!= it
);
1055 it
->m_next
= table
->m_iterators
;
1056 table
->m_iterators
= it
;
1058 ASSERT(!it
->m_next
->m_previous
);
1059 it
->m_next
->m_previous
= it
;
1064 template<typename Key
, typename Value
, typename Extractor
, typename HashFunctions
, typename Traits
, typename KeyTraits
>
1065 void removeIterator(HashTableConstIterator
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
>* it
)
1067 typedef HashTable
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
> HashTableType
;
1068 typedef HashTableConstIterator
<Key
, Value
, Extractor
, HashFunctions
, Traits
, KeyTraits
> const_iterator
;
1070 // Delete iterator from doubly-linked list of iterators.
1072 ASSERT(!it
->m_next
);
1073 ASSERT(!it
->m_previous
);
1075 MutexLocker
lock(it
->m_table
->m_mutex
);
1077 ASSERT(it
->m_next
->m_previous
== it
);
1078 it
->m_next
->m_previous
= it
->m_previous
;
1080 if (it
->m_previous
) {
1081 ASSERT(it
->m_table
->m_iterators
!= it
);
1082 ASSERT(it
->m_previous
->m_next
== it
);
1083 it
->m_previous
->m_next
= it
->m_next
;
1085 ASSERT(it
->m_table
->m_iterators
== it
);
1086 it
->m_table
->m_iterators
= it
->m_next
;
1095 #endif // CHECK_HASHTABLE_ITERATORS
1097 // iterator adapters
1099 template<typename HashTableType
, typename ValueType
> struct HashTableConstIteratorAdapter
{
1100 HashTableConstIteratorAdapter(const typename
HashTableType::const_iterator
& impl
) : m_impl(impl
) {}
1102 const ValueType
* get() const { return (const ValueType
*)m_impl
.get(); }
1103 const ValueType
& operator*() const { return *get(); }
1104 const ValueType
* operator->() const { return get(); }
1106 HashTableConstIteratorAdapter
& operator++() { ++m_impl
; return *this; }
1107 // postfix ++ intentionally omitted
1109 typename
HashTableType::const_iterator m_impl
;
1112 template<typename HashTableType
, typename ValueType
> struct HashTableIteratorAdapter
{
1113 HashTableIteratorAdapter(const typename
HashTableType::iterator
& impl
) : m_impl(impl
) {}
1115 ValueType
* get() const { return (ValueType
*)m_impl
.get(); }
1116 ValueType
& operator*() const { return *get(); }
1117 ValueType
* operator->() const { return get(); }
1119 HashTableIteratorAdapter
& operator++() { ++m_impl
; return *this; }
1120 // postfix ++ intentionally omitted
1122 operator HashTableConstIteratorAdapter
<HashTableType
, ValueType
>() {
1123 typename
HashTableType::const_iterator i
= m_impl
;
1127 typename
HashTableType::iterator m_impl
;
1130 template<typename T
, typename U
>
1131 inline bool operator==(const HashTableConstIteratorAdapter
<T
, U
>& a
, const HashTableConstIteratorAdapter
<T
, U
>& b
)
1133 return a
.m_impl
== b
.m_impl
;
1136 template<typename T
, typename U
>
1137 inline bool operator!=(const HashTableConstIteratorAdapter
<T
, U
>& a
, const HashTableConstIteratorAdapter
<T
, U
>& b
)
1139 return a
.m_impl
!= b
.m_impl
;
1142 template<typename T
, typename U
>
1143 inline bool operator==(const HashTableIteratorAdapter
<T
, U
>& a
, const HashTableIteratorAdapter
<T
, U
>& b
)
1145 return a
.m_impl
== b
.m_impl
;
1148 template<typename T
, typename U
>
1149 inline bool operator!=(const HashTableIteratorAdapter
<T
, U
>& a
, const HashTableIteratorAdapter
<T
, U
>& b
)
1151 return a
.m_impl
!= b
.m_impl
;
1156 #include "HashIterators.h"
1158 #endif // WTF_HashTable_h