OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012 Apple Inc. All rights reserv
ed. | 2 * Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012 Apple Inc. All rights reserv
ed. |
3 * Copyright (C) 2008 David Levin <levin@chromium.org> | 3 * Copyright (C) 2008 David Levin <levin@chromium.org> |
4 * | 4 * |
5 * This library is free software; you can redistribute it and/or | 5 * This library is free software; you can redistribute it and/or |
6 * modify it under the terms of the GNU Library General Public | 6 * modify it under the terms of the GNU Library General Public |
7 * License as published by the Free Software Foundation; either | 7 * License as published by the Free Software Foundation; either |
8 * version 2 of the License, or (at your option) any later version. | 8 * version 2 of the License, or (at your option) any later version. |
9 * | 9 * |
10 * This library is distributed in the hope that it will be useful, | 10 * This library is distributed in the hope that it will be useful, |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
234 template<typename Key, typename Value, typename Extractor, typename HashFunc
tions, typename Traits, typename KeyTraits, typename Allocator> | 234 template<typename Key, typename Value, typename Extractor, typename HashFunc
tions, typename Traits, typename KeyTraits, typename Allocator> |
235 class HashTable : public HashTableDestructorBase<HashTable<Key, Value, Extra
ctor, HashFunctions, Traits, KeyTraits, Allocator>, Allocator::isGarbageCollecte
d> { | 235 class HashTable : public HashTableDestructorBase<HashTable<Key, Value, Extra
ctor, HashFunctions, Traits, KeyTraits, Allocator>, Allocator::isGarbageCollecte
d> { |
236 public: | 236 public: |
237 typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits,
KeyTraits, Allocator> iterator; | 237 typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits,
KeyTraits, Allocator> iterator; |
238 typedef HashTableConstIterator<Key, Value, Extractor, HashFunctions, Tra
its, KeyTraits, Allocator> const_iterator; | 238 typedef HashTableConstIterator<Key, Value, Extractor, HashFunctions, Tra
its, KeyTraits, Allocator> const_iterator; |
239 typedef Traits ValueTraits; | 239 typedef Traits ValueTraits; |
240 typedef Key KeyType; | 240 typedef Key KeyType; |
241 typedef typename KeyTraits::PeekInType KeyPeekInType; | 241 typedef typename KeyTraits::PeekInType KeyPeekInType; |
242 typedef typename KeyTraits::PassInType KeyPassInType; | 242 typedef typename KeyTraits::PassInType KeyPassInType; |
243 typedef Value ValueType; | 243 typedef Value ValueType; |
| 244 typedef Extractor ExtractorType; |
| 245 typedef KeyTraits KeyTraitsType; |
244 typedef typename Traits::PeekInType ValuePeekInType; | 246 typedef typename Traits::PeekInType ValuePeekInType; |
245 typedef IdentityHashTranslator<HashFunctions> IdentityTranslatorType; | 247 typedef IdentityHashTranslator<HashFunctions> IdentityTranslatorType; |
246 typedef HashTableAddResult<ValueType> AddResult; | 248 typedef HashTableAddResult<ValueType> AddResult; |
247 | 249 |
248 #if DUMP_HASHTABLE_STATS_PER_TABLE | 250 #if DUMP_HASHTABLE_STATS_PER_TABLE |
249 struct Stats { | 251 struct Stats { |
250 Stats() | 252 Stats() |
251 : numAccesses(0) | 253 : numAccesses(0) |
252 , numRehashes(0) | 254 , numRehashes(0) |
253 , numRemoves(0) | 255 , numRemoves(0) |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
289 } | 291 } |
290 }; | 292 }; |
291 #endif | 293 #endif |
292 | 294 |
293 HashTable(); | 295 HashTable(); |
294 void finalize() | 296 void finalize() |
295 { | 297 { |
296 ASSERT(!Allocator::isGarbageCollected); | 298 ASSERT(!Allocator::isGarbageCollected); |
297 if (LIKELY(!m_table)) | 299 if (LIKELY(!m_table)) |
298 return; | 300 return; |
299 deallocateTable(m_table, m_tableSize); | 301 deleteAllBucketsAndDeallocate(m_table, m_tableSize); |
300 m_table = 0; | 302 m_table = 0; |
301 } | 303 } |
302 | 304 |
303 HashTable(const HashTable&); | 305 HashTable(const HashTable&); |
304 void swap(HashTable&); | 306 void swap(HashTable&); |
305 HashTable& operator=(const HashTable&); | 307 HashTable& operator=(const HashTable&); |
306 | 308 |
307 // When the hash table is empty, just return the same iterator for end a
s for begin. | 309 // When the hash table is empty, just return the same iterator for end a
s for begin. |
308 // This is more efficient because we don't have to skip all the empty an
d deleted | 310 // This is more efficient because we don't have to skip all the empty an
d deleted |
309 // buckets, and iterating an empty table is a common case that's worth o
ptimizing. | 311 // buckets, and iterating an empty table is a common case that's worth o
ptimizing. |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
344 static bool isDeletedBucket(const ValueType& value) { return KeyTraits::
isDeletedValue(Extractor::extract(value)); } | 346 static bool isDeletedBucket(const ValueType& value) { return KeyTraits::
isDeletedValue(Extractor::extract(value)); } |
345 static bool isEmptyOrDeletedBucket(const ValueType& value) { return Hash
TableHelper<ValueType, Extractor, KeyTraits>:: isEmptyOrDeletedBucket(value); } | 347 static bool isEmptyOrDeletedBucket(const ValueType& value) { return Hash
TableHelper<ValueType, Extractor, KeyTraits>:: isEmptyOrDeletedBucket(value); } |
346 | 348 |
347 ValueType* lookup(KeyPeekInType key) { return lookup<IdentityTranslatorT
ype>(key); } | 349 ValueType* lookup(KeyPeekInType key) { return lookup<IdentityTranslatorT
ype>(key); } |
348 template<typename HashTranslator, typename T> ValueType* lookup(const T&
); | 350 template<typename HashTranslator, typename T> ValueType* lookup(const T&
); |
349 | 351 |
350 void trace(typename Allocator::Visitor*); | 352 void trace(typename Allocator::Visitor*); |
351 | 353 |
352 private: | 354 private: |
353 static ValueType* allocateTable(unsigned size); | 355 static ValueType* allocateTable(unsigned size); |
354 static void deallocateTable(ValueType* table, unsigned size); | 356 static void deleteAllBucketsAndDeallocate(ValueType* table, unsigned siz
e); |
355 | 357 |
356 typedef std::pair<ValueType*, bool> LookupType; | 358 typedef std::pair<ValueType*, bool> LookupType; |
357 typedef std::pair<LookupType, unsigned> FullLookupType; | 359 typedef std::pair<LookupType, unsigned> FullLookupType; |
358 | 360 |
359 LookupType lookupForWriting(const Key& key) { return lookupForWriting<Id
entityTranslatorType>(key); }; | 361 LookupType lookupForWriting(const Key& key) { return lookupForWriting<Id
entityTranslatorType>(key); }; |
360 template<typename HashTranslator, typename T> FullLookupType fullLookupF
orWriting(const T&); | 362 template<typename HashTranslator, typename T> FullLookupType fullLookupF
orWriting(const T&); |
361 template<typename HashTranslator, typename T> LookupType lookupForWritin
g(const T&); | 363 template<typename HashTranslator, typename T> LookupType lookupForWritin
g(const T&); |
362 | 364 |
363 void remove(ValueType*); | 365 void remove(ValueType*); |
364 | 366 |
(...skipping 512 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
877 | 879 |
878 template<typename Key, typename Value, typename Extractor, typename HashFunc
tions, typename Traits, typename KeyTraits, typename Allocator> | 880 template<typename Key, typename Value, typename Extractor, typename HashFunc
tions, typename Traits, typename KeyTraits, typename Allocator> |
879 inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTrait
s, Allocator>::remove(KeyPeekInType key) | 881 inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTrait
s, Allocator>::remove(KeyPeekInType key) |
880 { | 882 { |
881 remove(find(key)); | 883 remove(find(key)); |
882 } | 884 } |
883 | 885 |
884 template<typename Key, typename Value, typename Extractor, typename HashFunc
tions, typename Traits, typename KeyTraits, typename Allocator> | 886 template<typename Key, typename Value, typename Extractor, typename HashFunc
tions, typename Traits, typename KeyTraits, typename Allocator> |
885 Value* HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Al
locator>::allocateTable(unsigned size) | 887 Value* HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Al
locator>::allocateTable(unsigned size) |
886 { | 888 { |
887 typedef typename Allocator::template HashTableBackingHelper<Key, Value,
Extractor, Traits, KeyTraits>::Type HashTableBacking; | 889 typedef typename Allocator::template HashTableBackingHelper<HashTable>::
Type HashTableBacking; |
888 | 890 |
889 size_t allocSize = size * sizeof(ValueType); | 891 size_t allocSize = size * sizeof(ValueType); |
890 ValueType* result; | 892 ValueType* result; |
891 if (Traits::emptyValueIsZero) { | 893 if (Traits::emptyValueIsZero) { |
892 result = Allocator::template zeroedBackingMalloc<ValueType*, HashTab
leBacking>(allocSize); | 894 result = Allocator::template zeroedBackingMalloc<ValueType*, HashTab
leBacking>(allocSize); |
893 } else { | 895 } else { |
894 result = Allocator::template backingMalloc<ValueType*, HashTableBack
ing>(allocSize); | 896 result = Allocator::template backingMalloc<ValueType*, HashTableBack
ing>(allocSize); |
895 for (unsigned i = 0; i < size; i++) | 897 for (unsigned i = 0; i < size; i++) |
896 initializeBucket(result[i]); | 898 initializeBucket(result[i]); |
897 } | 899 } |
898 return result; | 900 return result; |
899 } | 901 } |
900 | 902 |
901 template<typename Key, typename Value, typename Extractor, typename HashFunc
tions, typename Traits, typename KeyTraits, typename Allocator> | 903 template<typename Key, typename Value, typename Extractor, typename HashFunc
tions, typename Traits, typename KeyTraits, typename Allocator> |
902 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allo
cator>::deallocateTable(ValueType* table, unsigned size) | 904 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allo
cator>::deleteAllBucketsAndDeallocate(ValueType* table, unsigned size) |
903 { | 905 { |
904 if (Allocator::isGarbageCollected) | |
905 return; | |
906 if (Traits::needsDestruction) { | 906 if (Traits::needsDestruction) { |
907 for (unsigned i = 0; i < size; ++i) { | 907 for (unsigned i = 0; i < size; ++i) { |
908 if (!isDeletedBucket(table[i])) | 908 // This code is called when the hash table is cleared or |
909 table[i].~ValueType(); | 909 // resized. We have allocated a new backing store and we need |
| 910 // to run the destructors on the old backing store, as it is |
| 911 // being freed. If we are GCing we need to both call the |
| 912 // destructor and mark the bucket as deleted, otherwise the |
| 913 // destructor gets called again when the GC finds the backing |
| 914 // store. With the default allocator it's enough to call the |
| 915 // destructor, since we will free the memory explicitly and |
| 916 // we won't see the memory with the bucket again. |
| 917 if (!isEmptyOrDeletedBucket(table[i])) { |
| 918 if (Allocator::isGarbageCollected) |
| 919 deleteBucket(table[i]); |
| 920 else |
| 921 table[i].~ValueType(); |
| 922 } |
910 } | 923 } |
911 } | 924 } |
912 Allocator::backingFree(table); | 925 Allocator::backingFree(table); |
913 } | 926 } |
914 | 927 |
915 template<typename Key, typename Value, typename Extractor, typename HashFunc
tions, typename Traits, typename KeyTraits, typename Allocator> | 928 template<typename Key, typename Value, typename Extractor, typename HashFunc
tions, typename Traits, typename KeyTraits, typename Allocator> |
916 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allo
cator>::expand() | 929 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allo
cator>::expand() |
917 { | 930 { |
918 unsigned newSize; | 931 unsigned newSize; |
919 if (!m_tableSize) { | 932 if (!m_tableSize) { |
(...skipping 27 matching lines...) Expand all Loading... |
947 m_table = allocateTable(newTableSize); | 960 m_table = allocateTable(newTableSize); |
948 m_tableSize = newTableSize; | 961 m_tableSize = newTableSize; |
949 m_tableSizeMask = newTableSize - 1; | 962 m_tableSizeMask = newTableSize - 1; |
950 | 963 |
951 for (unsigned i = 0; i != oldTableSize; ++i) | 964 for (unsigned i = 0; i != oldTableSize; ++i) |
952 if (!isEmptyOrDeletedBucket(oldTable[i])) | 965 if (!isEmptyOrDeletedBucket(oldTable[i])) |
953 reinsert(oldTable[i]); | 966 reinsert(oldTable[i]); |
954 | 967 |
955 m_deletedCount = 0; | 968 m_deletedCount = 0; |
956 | 969 |
957 deallocateTable(oldTable, oldTableSize); | 970 deleteAllBucketsAndDeallocate(oldTable, oldTableSize); |
958 } | 971 } |
959 | 972 |
960 template<typename Key, typename Value, typename Extractor, typename HashFunc
tions, typename Traits, typename KeyTraits, typename Allocator> | 973 template<typename Key, typename Value, typename Extractor, typename HashFunc
tions, typename Traits, typename KeyTraits, typename Allocator> |
961 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allo
cator>::clear() | 974 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allo
cator>::clear() |
962 { | 975 { |
963 if (!m_table) | 976 if (!m_table) |
964 return; | 977 return; |
965 | 978 |
966 deallocateTable(m_table, m_tableSize); | 979 deleteAllBucketsAndDeallocate(m_table, m_tableSize); |
967 m_table = 0; | 980 m_table = 0; |
968 m_tableSize = 0; | 981 m_tableSize = 0; |
969 m_tableSizeMask = 0; | 982 m_tableSizeMask = 0; |
970 m_keyCount = 0; | 983 m_keyCount = 0; |
971 } | 984 } |
972 | 985 |
973 template<typename Key, typename Value, typename Extractor, typename HashFunc
tions, typename Traits, typename KeyTraits, typename Allocator> | 986 template<typename Key, typename Value, typename Extractor, typename HashFunc
tions, typename Traits, typename KeyTraits, typename Allocator> |
974 HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator
>::HashTable(const HashTable& other) | 987 HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator
>::HashTable(const HashTable& other) |
975 : m_table(0) | 988 : m_table(0) |
976 , m_tableSize(0) | 989 , m_tableSize(0) |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1166 inline bool operator!=(const HashTableIteratorAdapter<T, U>& a, const HashTa
bleConstIteratorAdapter<T, U>& b) | 1179 inline bool operator!=(const HashTableIteratorAdapter<T, U>& a, const HashTa
bleConstIteratorAdapter<T, U>& b) |
1167 { | 1180 { |
1168 return a.m_impl != b.m_impl; | 1181 return a.m_impl != b.m_impl; |
1169 } | 1182 } |
1170 | 1183 |
1171 } // namespace WTF | 1184 } // namespace WTF |
1172 | 1185 |
1173 #include "wtf/HashIterators.h" | 1186 #include "wtf/HashIterators.h" |
1174 | 1187 |
1175 #endif // WTF_HashTable_h | 1188 #endif // WTF_HashTable_h |
OLD | NEW |