1 /* 2 * Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012 Apple Inc. All rights reserved. 3 * Copyright (C) 2008 David Levin <levin (at) chromium.org> 4 * 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. 9 * 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. 14 * 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. 19 * 20 */ 21 22 #ifndef WTF_HashTable_h 23 #define WTF_HashTable_h 24 25 #include "wtf/Alignment.h" 26 #include "wtf/Assertions.h" 27 #include "wtf/HashTraits.h" 28 #include "wtf/PartitionAlloc.h" 29 #include "wtf/WTF.h" 30 #include <string.h> 31 32 #define DUMP_HASHTABLE_STATS 0 33 #define DUMP_HASHTABLE_STATS_PER_TABLE 0 34 35 #if DUMP_HASHTABLE_STATS_PER_TABLE 36 #include "wtf/DataLog.h" 37 #endif 38 39 namespace WTF { 40 41 #if DUMP_HASHTABLE_STATS 42 43 struct HashTableStats { 44 // The following variables are all atomically incremented when modified. 45 static int numAccesses; 46 static int numRehashes; 47 static int numRemoves; 48 static int numReinserts; 49 50 // The following variables are only modified in the recordCollisionAtCount method within a mutex. 51 static int maxCollisions; 52 static int numCollisions; 53 static int collisionGraph[4096]; 54 55 static void recordCollisionAtCount(int count); 56 static void dumpStats(); 57 }; 58 59 #endif 60 61 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 62 class HashTable; 63 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 64 class HashTableIterator; 65 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 66 class HashTableConstIterator; 67 68 typedef enum { HashItemKnownGood } HashItemKnownGoodTag; 69 70 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 71 class HashTableConstIterator { 72 private: 73 typedef HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> HashTableType; 74 typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> iterator; 75 typedef HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> const_iterator; 76 typedef Value ValueType; 77 typedef const ValueType& ReferenceType; 78 typedef const ValueType* PointerType; 79 80 friend class HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>; 81 friend class HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>; 82 83 void skipEmptyBuckets() 84 { 85 while (m_position != m_endPosition && HashTableType::isEmptyOrDeletedBucket(*m_position)) 86 ++m_position; 87 } 88 89 HashTableConstIterator(const HashTableType* table, PointerType position, PointerType endPosition) 90 : m_position(position), m_endPosition(endPosition) 91 { 92 skipEmptyBuckets(); 93 } 94 95 HashTableConstIterator(const HashTableType* table, PointerType position, PointerType endPosition, HashItemKnownGoodTag) 96 : m_position(position), m_endPosition(endPosition) 97 { 98 } 99 100 public: 101 HashTableConstIterator() 102 { 103 } 104 105 PointerType get() const 106 { 107 return m_position; 108 } 109 ReferenceType operator*() const { return *get(); } 110 PointerType operator->() const { return get(); } 111 112 const_iterator& operator++() 113 { 114 ASSERT(m_position != m_endPosition); 115 ++m_position; 116 skipEmptyBuckets(); 117 return *this; 118 } 119 120 // postfix ++ intentionally omitted 121 122 // Comparison. 123 bool operator==(const const_iterator& other) const 124 { 125 return m_position == other.m_position; 126 } 127 bool operator!=(const const_iterator& other) const 128 { 129 return m_position != other.m_position; 130 } 131 bool operator==(const iterator& other) const 132 { 133 return *this == static_cast<const_iterator>(other); 134 } 135 bool operator!=(const iterator& other) const 136 { 137 return *this != static_cast<const_iterator>(other); 138 } 139 140 private: 141 PointerType m_position; 142 PointerType m_endPosition; 143 }; 144 145 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 146 class HashTableIterator { 147 private: 148 typedef HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> HashTableType; 149 typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> iterator; 150 typedef HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> const_iterator; 151 typedef Value ValueType; 152 typedef ValueType& ReferenceType; 153 typedef ValueType* PointerType; 154 155 friend class HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>; 156 157 HashTableIterator(HashTableType* table, PointerType pos, PointerType end) : m_iterator(table, pos, end) { } 158 HashTableIterator(HashTableType* table, PointerType pos, PointerType end, HashItemKnownGoodTag tag) : m_iterator(table, pos, end, tag) { } 159 160 public: 161 HashTableIterator() { } 162 163 // default copy, assignment and destructor are OK 164 165 PointerType get() const { return const_cast<PointerType>(m_iterator.get()); } 166 ReferenceType operator*() const { return *get(); } 167 PointerType operator->() const { return get(); } 168 169 iterator& operator++() { ++m_iterator; return *this; } 170 171 // postfix ++ intentionally omitted 172 173 // Comparison. 174 bool operator==(const iterator& other) const { return m_iterator == other.m_iterator; } 175 bool operator!=(const iterator& other) const { return m_iterator != other.m_iterator; } 176 bool operator==(const const_iterator& other) const { return m_iterator == other; } 177 bool operator!=(const const_iterator& other) const { return m_iterator != other; } 178 179 operator const_iterator() const { return m_iterator; } 180 181 private: 182 const_iterator m_iterator; 183 }; 184 185 using std::swap; 186 187 // Work around MSVC's standard library, whose swap for pairs does not swap by component. 188 template<typename T> inline void hashTableSwap(T& a, T& b) 189 { 190 swap(a, b); 191 } 192 193 template<typename T, typename U> inline void hashTableSwap(KeyValuePair<T, U>& a, KeyValuePair<T, U>& b) 194 { 195 swap(a.key, b.key); 196 swap(a.value, b.value); 197 } 198 199 template<typename T, bool useSwap> struct Mover; 200 template<typename T> struct Mover<T, true> { static void move(T& from, T& to) { hashTableSwap(from, to); } }; 201 template<typename T> struct Mover<T, false> { static void move(T& from, T& to) { to = from; } }; 202 203 template<typename HashFunctions> class IdentityHashTranslator { 204 public: 205 template<typename T> static unsigned hash(const T& key) { return HashFunctions::hash(key); } 206 template<typename T, typename U> static bool equal(const T& a, const U& b) { return HashFunctions::equal(a, b); } 207 template<typename T, typename U> static void translate(T& location, const U&, const T& value) { location = value; } 208 }; 209 210 template<typename IteratorType> struct HashTableAddResult { 211 HashTableAddResult(IteratorType iter, bool isNewEntry) : iterator(iter), isNewEntry(isNewEntry) { } 212 IteratorType iterator; 213 bool isNewEntry; 214 }; 215 216 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 217 class HashTable { 218 public: 219 typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> iterator; 220 typedef HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits> const_iterator; 221 typedef Traits ValueTraits; 222 typedef Key KeyType; 223 typedef Value ValueType; 224 typedef IdentityHashTranslator<HashFunctions> IdentityTranslatorType; 225 typedef HashTableAddResult<iterator> AddResult; 226 227 #if DUMP_HASHTABLE_STATS_PER_TABLE 228 struct Stats { 229 Stats() 230 : numAccesses(0) 231 , numRehashes(0) 232 , numRemoves(0) 233 , numReinserts(0) 234 , maxCollisions(0) 235 , numCollisions(0) 236 , collisionGraph() 237 { 238 } 239 240 int numAccesses; 241 int numRehashes; 242 int numRemoves; 243 int numReinserts; 244 245 int maxCollisions; 246 int numCollisions; 247 int collisionGraph[4096]; 248 249 void recordCollisionAtCount(int count) 250 { 251 if (count > maxCollisions) 252 maxCollisions = count; 253 numCollisions++; 254 collisionGraph[count]++; 255 } 256 257 void dumpStats() 258 { 259 dataLogF("\nWTF::HashTable::Stats dump\n\n"); 260 dataLogF("%d accesses\n", numAccesses); 261 dataLogF("%d total collisions, average %.2f probes per access\n", numCollisions, 1.0 * (numAccesses + numCollisions) / numAccesses); 262 dataLogF("longest collision chain: %d\n", maxCollisions); 263 for (int i = 1; i <= maxCollisions; i++) { 264 dataLogF(" %d lookups with exactly %d collisions (%.2f%% , %.2f%% with this many or more)\n", collisionGraph[i], i, 100.0 * (collisionGraph[i] - collisionGraph[i+1]) / numAccesses, 100.0 * collisionGraph[i] / numAccesses); 265 } 266 dataLogF("%d rehashes\n", numRehashes); 267 dataLogF("%d reinserts\n", numReinserts); 268 } 269 }; 270 #endif 271 272 HashTable(); 273 ~HashTable() 274 { 275 if (LIKELY(!m_table)) 276 return; 277 deallocateTable(m_table, m_tableSize); 278 m_table = 0; 279 } 280 281 HashTable(const HashTable&); 282 void swap(HashTable&); 283 HashTable& operator=(const HashTable&); 284 285 // When the hash table is empty, just return the same iterator for end as for begin. 286 // This is more efficient because we don't have to skip all the empty and deleted 287 // buckets, and iterating an empty table is a common case that's worth optimizing. 288 iterator begin() { return isEmpty() ? end() : makeIterator(m_table); } 289 iterator end() { return makeKnownGoodIterator(m_table + m_tableSize); } 290 const_iterator begin() const { return isEmpty() ? end() : makeConstIterator(m_table); } 291 const_iterator end() const { return makeKnownGoodConstIterator(m_table + m_tableSize); } 292 293 unsigned size() const { return m_keyCount; } 294 unsigned capacity() const { return m_tableSize; } 295 bool isEmpty() const { return !m_keyCount; } 296 297 AddResult add(const ValueType& value) { return add<IdentityTranslatorType>(Extractor::extract(value), value); } 298 299 // A special version of add() that finds the object by hashing and comparing 300 // with some other type, to avoid the cost of type conversion if the object is already 301 // in the table. 302 template<typename HashTranslator, typename T, typename Extra> AddResult add(const T& key, const Extra&); 303 template<typename HashTranslator, typename T, typename Extra> AddResult addPassingHashCode(const T& key, const Extra&); 304 305 iterator find(const KeyType& key) { return find<IdentityTranslatorType>(key); } 306 const_iterator find(const KeyType& key) const { return find<IdentityTranslatorType>(key); } 307 bool contains(const KeyType& key) const { return contains<IdentityTranslatorType>(key); } 308 309 template<typename HashTranslator, typename T> iterator find(const T&); 310 template<typename HashTranslator, typename T> const_iterator find(const T&) const; 311 template<typename HashTranslator, typename T> bool contains(const T&) const; 312 313 void remove(const KeyType&); 314 void remove(iterator); 315 void remove(const_iterator); 316 void clear(); 317 318 static bool isEmptyBucket(const ValueType& value) { return isHashTraitsEmptyValue<KeyTraits>(Extractor::extract(value)); } 319 static bool isDeletedBucket(const ValueType& value) { return KeyTraits::isDeletedValue(Extractor::extract(value)); } 320 static bool isEmptyOrDeletedBucket(const ValueType& value) { return isEmptyBucket(value) || isDeletedBucket(value); } 321 322 ValueType* lookup(const Key& key) { return lookup<IdentityTranslatorType>(key); } 323 template<typename HashTranslator, typename T> ValueType* lookup(const T&); 324 325 private: 326 static ValueType* allocateTable(unsigned size); 327 static void deallocateTable(ValueType* table, unsigned size); 328 329 typedef std::pair<ValueType*, bool> LookupType; 330 typedef std::pair<LookupType, unsigned> FullLookupType; 331 332 LookupType lookupForWriting(const Key& key) { return lookupForWriting<IdentityTranslatorType>(key); }; 333 template<typename HashTranslator, typename T> FullLookupType fullLookupForWriting(const T&); 334 template<typename HashTranslator, typename T> LookupType lookupForWriting(const T&); 335 336 void remove(ValueType*); 337 338 bool shouldExpand() const { return (m_keyCount + m_deletedCount) * m_maxLoad >= m_tableSize; } 339 bool mustRehashInPlace() const { return m_keyCount * m_minLoad < m_tableSize * 2; } 340 bool shouldShrink() const { return m_keyCount * m_minLoad < m_tableSize && m_tableSize > KeyTraits::minimumTableSize; } 341 void expand(); 342 void shrink() { rehash(m_tableSize / 2); } 343 344 void rehash(unsigned newTableSize); 345 void reinsert(ValueType&); 346 347 static void initializeBucket(ValueType& bucket); 348 static void deleteBucket(ValueType& bucket) { bucket.~ValueType(); Traits::constructDeletedValue(bucket); } 349 350 FullLookupType makeLookupResult(ValueType* position, bool found, unsigned hash) 351 { return FullLookupType(LookupType(position, found), hash); } 352 353 iterator makeIterator(ValueType* pos) { return iterator(this, pos, m_table + m_tableSize); } 354 const_iterator makeConstIterator(ValueType* pos) const { return const_iterator(this, pos, m_table + m_tableSize); } 355 iterator makeKnownGoodIterator(ValueType* pos) { return iterator(this, pos, m_table + m_tableSize, HashItemKnownGood); } 356 const_iterator makeKnownGoodConstIterator(ValueType* pos) const { return const_iterator(this, pos, m_table + m_tableSize, HashItemKnownGood); } 357 358 static const unsigned m_maxLoad = 2; 359 static const unsigned m_minLoad = 6; 360 361 ValueType* m_table; 362 unsigned m_tableSize; 363 unsigned m_tableSizeMask; 364 unsigned m_keyCount; 365 unsigned m_deletedCount; 366 367 #if DUMP_HASHTABLE_STATS_PER_TABLE 368 public: 369 mutable OwnPtr<Stats> m_stats; 370 #endif 371 }; 372 373 // Set all the bits to one after the most significant bit: 00110101010 -> 00111111111. 374 template<unsigned size> struct OneifyLowBits; 375 template<> 376 struct OneifyLowBits<0> { 377 static const unsigned value = 0; 378 }; 379 template<unsigned number> 380 struct OneifyLowBits { 381 static const unsigned value = number | OneifyLowBits<(number >> 1)>::value; 382 }; 383 // Compute the first power of two integer that is an upper bound of the parameter 'number'. 384 template<unsigned number> 385 struct UpperPowerOfTwoBound { 386 static const unsigned value = (OneifyLowBits<number - 1>::value + 1) * 2; 387 }; 388 389 // Because power of two numbers are the limit of maxLoad, their capacity is twice the 390 // UpperPowerOfTwoBound, or 4 times their values. 391 template<unsigned size, bool isPowerOfTwo> struct HashTableCapacityForSizeSplitter; 392 template<unsigned size> 393 struct HashTableCapacityForSizeSplitter<size, true> { 394 static const unsigned value = size * 4; 395 }; 396 template<unsigned size> 397 struct HashTableCapacityForSizeSplitter<size, false> { 398 static const unsigned value = UpperPowerOfTwoBound<size>::value; 399 }; 400 401 // HashTableCapacityForSize computes the upper power of two capacity to hold the size parameter. 402 // This is done at compile time to initialize the HashTraits. 403 template<unsigned size> 404 struct HashTableCapacityForSize { 405 static const unsigned value = HashTableCapacityForSizeSplitter<size, !(size & (size - 1))>::value; 406 COMPILE_ASSERT(size > 0, HashTableNonZeroMinimumCapacity); 407 COMPILE_ASSERT(!static_cast<int>(value >> 31), HashTableNoCapacityOverflow); 408 COMPILE_ASSERT(value > (2 * size), HashTableCapacityHoldsContentSize); 409 }; 410 411 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 412 inline HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::HashTable() 413 : m_table(0) 414 , m_tableSize(0) 415 , m_tableSizeMask(0) 416 , m_keyCount(0) 417 , m_deletedCount(0) 418 #if DUMP_HASHTABLE_STATS_PER_TABLE 419 , m_stats(adoptPtr(new Stats)) 420 #endif 421 { 422 } 423 424 inline unsigned doubleHash(unsigned key) 425 { 426 key = ~key + (key >> 23); 427 key ^= (key << 12); 428 key ^= (key >> 7); 429 key ^= (key << 2); 430 key ^= (key >> 20); 431 return key; 432 } 433 434 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 435 template<typename HashTranslator, typename T> 436 inline Value* HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::lookup(const T& key) 437 { 438 int k = 0; 439 int sizeMask = m_tableSizeMask; 440 ValueType* table = m_table; 441 unsigned h = HashTranslator::hash(key); 442 int i = h & sizeMask; 443 444 if (!table) 445 return 0; 446 447 #if DUMP_HASHTABLE_STATS 448 atomicIncrement(&HashTableStats::numAccesses); 449 int probeCount = 0; 450 #endif 451 452 #if DUMP_HASHTABLE_STATS_PER_TABLE 453 ++m_stats->numAccesses; 454 int perTableProbeCount = 0; 455 #endif 456 457 while (1) { 458 ValueType* entry = table + i; 459 460 // we count on the compiler to optimize out this branch 461 if (HashFunctions::safeToCompareToEmptyOrDeleted) { 462 if (HashTranslator::equal(Extractor::extract(*entry), key)) 463 return entry; 464 465 if (isEmptyBucket(*entry)) 466 return 0; 467 } else { 468 if (isEmptyBucket(*entry)) 469 return 0; 470 471 if (!isDeletedBucket(*entry) && HashTranslator::equal(Extractor::extract(*entry), key)) 472 return entry; 473 } 474 #if DUMP_HASHTABLE_STATS 475 ++probeCount; 476 HashTableStats::recordCollisionAtCount(probeCount); 477 #endif 478 479 #if DUMP_HASHTABLE_STATS_PER_TABLE 480 ++perTableProbeCount; 481 m_stats->recordCollisionAtCount(perTableProbeCount); 482 #endif 483 484 if (!k) 485 k = 1 | doubleHash(h); 486 i = (i + k) & sizeMask; 487 } 488 } 489 490 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 491 template<typename HashTranslator, typename T> 492 inline typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::LookupType HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::lookupForWriting(const T& key) 493 { 494 ASSERT(m_table); 495 496 int k = 0; 497 ValueType* table = m_table; 498 int sizeMask = m_tableSizeMask; 499 unsigned h = HashTranslator::hash(key); 500 int i = h & sizeMask; 501 502 #if DUMP_HASHTABLE_STATS 503 atomicIncrement(&HashTableStats::numAccesses); 504 int probeCount = 0; 505 #endif 506 507 #if DUMP_HASHTABLE_STATS_PER_TABLE 508 ++m_stats->numAccesses; 509 int perTableProbeCount = 0; 510 #endif 511 512 ValueType* deletedEntry = 0; 513 514 while (1) { 515 ValueType* entry = table + i; 516 517 // we count on the compiler to optimize out this branch 518 if (HashFunctions::safeToCompareToEmptyOrDeleted) { 519 if (isEmptyBucket(*entry)) 520 return LookupType(deletedEntry ? deletedEntry : entry, false); 521 522 if (HashTranslator::equal(Extractor::extract(*entry), key)) 523 return LookupType(entry, true); 524 525 if (isDeletedBucket(*entry)) 526 deletedEntry = entry; 527 } else { 528 if (isEmptyBucket(*entry)) 529 return LookupType(deletedEntry ? deletedEntry : entry, false); 530 531 if (isDeletedBucket(*entry)) 532 deletedEntry = entry; 533 else if (HashTranslator::equal(Extractor::extract(*entry), key)) 534 return LookupType(entry, true); 535 } 536 #if DUMP_HASHTABLE_STATS 537 ++probeCount; 538 HashTableStats::recordCollisionAtCount(probeCount); 539 #endif 540 541 #if DUMP_HASHTABLE_STATS_PER_TABLE 542 ++perTableProbeCount; 543 m_stats->recordCollisionAtCount(perTableProbeCount); 544 #endif 545 546 if (!k) 547 k = 1 | doubleHash(h); 548 i = (i + k) & sizeMask; 549 } 550 } 551 552 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 553 template<typename HashTranslator, typename T> 554 inline typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::FullLookupType HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::fullLookupForWriting(const T& key) 555 { 556 ASSERT(m_table); 557 558 int k = 0; 559 ValueType* table = m_table; 560 int sizeMask = m_tableSizeMask; 561 unsigned h = HashTranslator::hash(key); 562 int i = h & sizeMask; 563 564 #if DUMP_HASHTABLE_STATS 565 atomicIncrement(&HashTableStats::numAccesses); 566 int probeCount = 0; 567 #endif 568 569 #if DUMP_HASHTABLE_STATS_PER_TABLE 570 ++m_stats->numAccesses; 571 int perTableProbeCount = 0; 572 #endif 573 574 ValueType* deletedEntry = 0; 575 576 while (1) { 577 ValueType* entry = table + i; 578 579 // we count on the compiler to optimize out this branch 580 if (HashFunctions::safeToCompareToEmptyOrDeleted) { 581 if (isEmptyBucket(*entry)) 582 return makeLookupResult(deletedEntry ? deletedEntry : entry, false, h); 583 584 if (HashTranslator::equal(Extractor::extract(*entry), key)) 585 return makeLookupResult(entry, true, h); 586 587 if (isDeletedBucket(*entry)) 588 deletedEntry = entry; 589 } else { 590 if (isEmptyBucket(*entry)) 591 return makeLookupResult(deletedEntry ? deletedEntry : entry, false, h); 592 593 if (isDeletedBucket(*entry)) 594 deletedEntry = entry; 595 else if (HashTranslator::equal(Extractor::extract(*entry), key)) 596 return makeLookupResult(entry, true, h); 597 } 598 #if DUMP_HASHTABLE_STATS 599 ++probeCount; 600 HashTableStats::recordCollisionAtCount(probeCount); 601 #endif 602 603 #if DUMP_HASHTABLE_STATS_PER_TABLE 604 ++perTableProbeCount; 605 m_stats->recordCollisionAtCount(perTableProbeCount); 606 #endif 607 608 if (!k) 609 k = 1 | doubleHash(h); 610 i = (i + k) & sizeMask; 611 } 612 } 613 614 template<bool emptyValueIsZero> struct HashTableBucketInitializer; 615 616 template<> struct HashTableBucketInitializer<false> { 617 template<typename Traits, typename Value> static void initialize(Value& bucket) 618 { 619 new (NotNull, &bucket) Value(Traits::emptyValue()); 620 } 621 }; 622 623 template<> struct HashTableBucketInitializer<true> { 624 template<typename Traits, typename Value> static void initialize(Value& bucket) 625 { 626 // This initializes the bucket without copying the empty value. 627 // That makes it possible to use this with types that don't support copying. 628 // The memset to 0 looks like a slow operation but is optimized by the compilers. 629 memset(&bucket, 0, sizeof(bucket)); 630 } 631 }; 632 633 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 634 inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::initializeBucket(ValueType& bucket) 635 { 636 HashTableBucketInitializer<Traits::emptyValueIsZero>::template initialize<Traits>(bucket); 637 } 638 639 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 640 template<typename HashTranslator, typename T, typename Extra> 641 typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::AddResult HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::add(const T& key, const Extra& extra) 642 { 643 if (!m_table) 644 expand(); 645 646 ASSERT(m_table); 647 648 int k = 0; 649 ValueType* table = m_table; 650 int sizeMask = m_tableSizeMask; 651 unsigned h = HashTranslator::hash(key); 652 int i = h & sizeMask; 653 654 #if DUMP_HASHTABLE_STATS 655 atomicIncrement(&HashTableStats::numAccesses); 656 int probeCount = 0; 657 #endif 658 659 #if DUMP_HASHTABLE_STATS_PER_TABLE 660 ++m_stats->numAccesses; 661 int perTableProbeCount = 0; 662 #endif 663 664 ValueType* deletedEntry = 0; 665 ValueType* entry; 666 while (1) { 667 entry = table + i; 668 669 // we count on the compiler to optimize out this branch 670 if (HashFunctions::safeToCompareToEmptyOrDeleted) { 671 if (isEmptyBucket(*entry)) 672 break; 673 674 if (HashTranslator::equal(Extractor::extract(*entry), key)) 675 return AddResult(makeKnownGoodIterator(entry), false); 676 677 if (isDeletedBucket(*entry)) 678 deletedEntry = entry; 679 } else { 680 if (isEmptyBucket(*entry)) 681 break; 682 683 if (isDeletedBucket(*entry)) 684 deletedEntry = entry; 685 else if (HashTranslator::equal(Extractor::extract(*entry), key)) 686 return AddResult(makeKnownGoodIterator(entry), false); 687 } 688 #if DUMP_HASHTABLE_STATS 689 ++probeCount; 690 HashTableStats::recordCollisionAtCount(probeCount); 691 #endif 692 693 #if DUMP_HASHTABLE_STATS_PER_TABLE 694 ++perTableProbeCount; 695 m_stats->recordCollisionAtCount(perTableProbeCount); 696 #endif 697 698 if (!k) 699 k = 1 | doubleHash(h); 700 i = (i + k) & sizeMask; 701 } 702 703 if (deletedEntry) { 704 initializeBucket(*deletedEntry); 705 entry = deletedEntry; 706 --m_deletedCount; 707 } 708 709 HashTranslator::translate(*entry, key, extra); 710 711 ++m_keyCount; 712 713 if (shouldExpand()) { 714 // FIXME: This makes an extra copy on expand. Probably not that bad since 715 // expand is rare, but would be better to have a version of expand that can 716 // follow a pivot entry and return the new position. 717 KeyType enteredKey = Extractor::extract(*entry); 718 expand(); 719 AddResult result(find(enteredKey), true); 720 ASSERT(result.iterator != end()); 721 return result; 722 } 723 724 return AddResult(makeKnownGoodIterator(entry), true); 725 } 726 727 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 728 template<typename HashTranslator, typename T, typename Extra> 729 typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::AddResult HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::addPassingHashCode(const T& key, const Extra& extra) 730 { 731 if (!m_table) 732 expand(); 733 734 FullLookupType lookupResult = fullLookupForWriting<HashTranslator>(key); 735 736 ValueType* entry = lookupResult.first.first; 737 bool found = lookupResult.first.second; 738 unsigned h = lookupResult.second; 739 740 if (found) 741 return AddResult(makeKnownGoodIterator(entry), false); 742 743 if (isDeletedBucket(*entry)) { 744 initializeBucket(*entry); 745 --m_deletedCount; 746 } 747 748 HashTranslator::translate(*entry, key, extra, h); 749 ++m_keyCount; 750 if (shouldExpand()) { 751 // FIXME: This makes an extra copy on expand. Probably not that bad since 752 // expand is rare, but would be better to have a version of expand that can 753 // follow a pivot entry and return the new position. 754 KeyType enteredKey = Extractor::extract(*entry); 755 expand(); 756 AddResult result(find(enteredKey), true); 757 ASSERT(result.iterator != end()); 758 return result; 759 } 760 761 return AddResult(makeKnownGoodIterator(entry), true); 762 } 763 764 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 765 inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::reinsert(ValueType& entry) 766 { 767 ASSERT(m_table); 768 ASSERT(!lookupForWriting(Extractor::extract(entry)).second); 769 ASSERT(!isDeletedBucket(*(lookupForWriting(Extractor::extract(entry)).first))); 770 #if DUMP_HASHTABLE_STATS 771 atomicIncrement(&HashTableStats::numReinserts); 772 #endif 773 #if DUMP_HASHTABLE_STATS_PER_TABLE 774 ++m_stats->numReinserts; 775 #endif 776 777 Mover<ValueType, Traits::needsDestruction>::move(entry, *lookupForWriting(Extractor::extract(entry)).first); 778 } 779 780 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 781 template <typename HashTranslator, typename T> 782 typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::iterator HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::find(const T& key) 783 { 784 if (!m_table) 785 return end(); 786 787 ValueType* entry = lookup<HashTranslator>(key); 788 if (!entry) 789 return end(); 790 791 return makeKnownGoodIterator(entry); 792 } 793 794 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 795 template <typename HashTranslator, typename T> 796 typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::const_iterator HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::find(const T& key) const 797 { 798 if (!m_table) 799 return end(); 800 801 ValueType* entry = const_cast<HashTable*>(this)->lookup<HashTranslator>(key); 802 if (!entry) 803 return end(); 804 805 return makeKnownGoodConstIterator(entry); 806 } 807 808 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 809 template <typename HashTranslator, typename T> 810 bool HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::contains(const T& key) const 811 { 812 if (!m_table) 813 return false; 814 815 return const_cast<HashTable*>(this)->lookup<HashTranslator>(key); 816 } 817 818 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 819 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::remove(ValueType* pos) 820 { 821 #if DUMP_HASHTABLE_STATS 822 atomicIncrement(&HashTableStats::numRemoves); 823 #endif 824 #if DUMP_HASHTABLE_STATS_PER_TABLE 825 ++m_stats->numRemoves; 826 #endif 827 828 deleteBucket(*pos); 829 ++m_deletedCount; 830 --m_keyCount; 831 832 if (shouldShrink()) 833 shrink(); 834 } 835 836 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 837 inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::remove(iterator it) 838 { 839 if (it == end()) 840 return; 841 842 remove(const_cast<ValueType*>(it.m_iterator.m_position)); 843 } 844 845 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 846 inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::remove(const_iterator it) 847 { 848 if (it == end()) 849 return; 850 851 remove(const_cast<ValueType*>(it.m_position)); 852 } 853 854 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 855 inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::remove(const KeyType& key) 856 { 857 remove(find(key)); 858 } 859 860 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 861 Value* HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::allocateTable(unsigned size) 862 { 863 size_t allocSize = size * sizeof(ValueType); 864 ValueType* result = static_cast<ValueType*>(partitionAllocGeneric(WTF::Partitions::getBufferPartition(), allocSize)); 865 if (Traits::emptyValueIsZero) { 866 memset(result, '\0', allocSize); 867 } else { 868 for (unsigned i = 0; i < size; i++) 869 initializeBucket(result[i]); 870 } 871 return result; 872 } 873 874 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 875 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::deallocateTable(ValueType* table, unsigned size) 876 { 877 if (Traits::needsDestruction) { 878 for (unsigned i = 0; i < size; ++i) { 879 if (!isDeletedBucket(table[i])) 880 table[i].~ValueType(); 881 } 882 } 883 partitionFreeGeneric(WTF::Partitions::getBufferPartition(), table); 884 } 885 886 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 887 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::expand() 888 { 889 unsigned newSize; 890 if (!m_tableSize) { 891 newSize = KeyTraits::minimumTableSize; 892 } else if (mustRehashInPlace()) { 893 newSize = m_tableSize; 894 } else { 895 newSize = m_tableSize * 2; 896 RELEASE_ASSERT(newSize > m_tableSize); 897 } 898 899 rehash(newSize); 900 } 901 902 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 903 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::rehash(unsigned newTableSize) 904 { 905 unsigned oldTableSize = m_tableSize; 906 ValueType* oldTable = m_table; 907 908 #if DUMP_HASHTABLE_STATS 909 if (oldTableSize != 0) 910 atomicIncrement(&HashTableStats::numRehashes); 911 #endif 912 913 #if DUMP_HASHTABLE_STATS_PER_TABLE 914 if (oldTableSize != 0) 915 ++m_stats->numRehashes; 916 #endif 917 918 m_tableSize = newTableSize; 919 m_tableSizeMask = newTableSize - 1; 920 m_table = allocateTable(newTableSize); 921 922 for (unsigned i = 0; i != oldTableSize; ++i) 923 if (!isEmptyOrDeletedBucket(oldTable[i])) 924 reinsert(oldTable[i]); 925 926 m_deletedCount = 0; 927 928 deallocateTable(oldTable, oldTableSize); 929 } 930 931 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 932 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::clear() 933 { 934 if (!m_table) 935 return; 936 937 deallocateTable(m_table, m_tableSize); 938 m_table = 0; 939 m_tableSize = 0; 940 m_tableSizeMask = 0; 941 m_keyCount = 0; 942 } 943 944 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 945 HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::HashTable(const HashTable& other) 946 : m_table(0) 947 , m_tableSize(0) 948 , m_tableSizeMask(0) 949 , m_keyCount(0) 950 , m_deletedCount(0) 951 #if DUMP_HASHTABLE_STATS_PER_TABLE 952 , m_stats(adoptPtr(new Stats(*other.m_stats))) 953 #endif 954 { 955 // Copy the hash table the dumb way, by adding each element to the new table. 956 // It might be more efficient to copy the table slots, but it's not clear that efficiency is needed. 957 const_iterator end = other.end(); 958 for (const_iterator it = other.begin(); it != end; ++it) 959 add(*it); 960 } 961 962 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 963 void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::swap(HashTable& other) 964 { 965 ValueType* tmp_table = m_table; 966 m_table = other.m_table; 967 other.m_table = tmp_table; 968 969 int tmp_tableSize = m_tableSize; 970 m_tableSize = other.m_tableSize; 971 other.m_tableSize = tmp_tableSize; 972 973 int tmp_tableSizeMask = m_tableSizeMask; 974 m_tableSizeMask = other.m_tableSizeMask; 975 other.m_tableSizeMask = tmp_tableSizeMask; 976 977 int tmp_keyCount = m_keyCount; 978 m_keyCount = other.m_keyCount; 979 other.m_keyCount = tmp_keyCount; 980 981 int tmp_deletedCount = m_deletedCount; 982 m_deletedCount = other.m_deletedCount; 983 other.m_deletedCount = tmp_deletedCount; 984 985 #if DUMP_HASHTABLE_STATS_PER_TABLE 986 m_stats.swap(other.m_stats); 987 #endif 988 } 989 990 template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits> 991 HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>& HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::operator=(const HashTable& other) 992 { 993 HashTable tmp(other); 994 swap(tmp); 995 return *this; 996 } 997 998 // iterator adapters 999 1000 template<typename HashTableType, typename ValueType> struct HashTableConstIteratorAdapter { 1001 HashTableConstIteratorAdapter() {} 1002 HashTableConstIteratorAdapter(const typename HashTableType::const_iterator& impl) : m_impl(impl) {} 1003 1004 const ValueType* get() const { return (const ValueType*)m_impl.get(); } 1005 const ValueType& operator*() const { return *get(); } 1006 const ValueType* operator->() const { return get(); } 1007 1008 HashTableConstIteratorAdapter& operator++() { ++m_impl; return *this; } 1009 // postfix ++ intentionally omitted 1010 1011 typename HashTableType::const_iterator m_impl; 1012 }; 1013 1014 template<typename HashTableType, typename ValueType> struct HashTableIteratorAdapter { 1015 HashTableIteratorAdapter() {} 1016 HashTableIteratorAdapter(const typename HashTableType::iterator& impl) : m_impl(impl) {} 1017 1018 ValueType* get() const { return (ValueType*)m_impl.get(); } 1019 ValueType& operator*() const { return *get(); } 1020 ValueType* operator->() const { return get(); } 1021 1022 HashTableIteratorAdapter& operator++() { ++m_impl; return *this; } 1023 // postfix ++ intentionally omitted 1024 1025 operator HashTableConstIteratorAdapter<HashTableType, ValueType>() { 1026 typename HashTableType::const_iterator i = m_impl; 1027 return i; 1028 } 1029 1030 typename HashTableType::iterator m_impl; 1031 }; 1032 1033 template<typename T, typename U> 1034 inline bool operator==(const HashTableConstIteratorAdapter<T, U>& a, const HashTableConstIteratorAdapter<T, U>& b) 1035 { 1036 return a.m_impl == b.m_impl; 1037 } 1038 1039 template<typename T, typename U> 1040 inline bool operator!=(const HashTableConstIteratorAdapter<T, U>& a, const HashTableConstIteratorAdapter<T, U>& b) 1041 { 1042 return a.m_impl != b.m_impl; 1043 } 1044 1045 template<typename T, typename U> 1046 inline bool operator==(const HashTableIteratorAdapter<T, U>& a, const HashTableIteratorAdapter<T, U>& b) 1047 { 1048 return a.m_impl == b.m_impl; 1049 } 1050 1051 template<typename T, typename U> 1052 inline bool operator!=(const HashTableIteratorAdapter<T, U>& a, const HashTableIteratorAdapter<T, U>& b) 1053 { 1054 return a.m_impl != b.m_impl; 1055 } 1056 1057 // All 4 combinations of ==, != and Const,non const. 1058 template<typename T, typename U> 1059 inline bool operator==(const HashTableConstIteratorAdapter<T, U>& a, const HashTableIteratorAdapter<T, U>& b) 1060 { 1061 return a.m_impl == b.m_impl; 1062 } 1063 1064 template<typename T, typename U> 1065 inline bool operator!=(const HashTableConstIteratorAdapter<T, U>& a, const HashTableIteratorAdapter<T, U>& b) 1066 { 1067 return a.m_impl != b.m_impl; 1068 } 1069 1070 template<typename T, typename U> 1071 inline bool operator==(const HashTableIteratorAdapter<T, U>& a, const HashTableConstIteratorAdapter<T, U>& b) 1072 { 1073 return a.m_impl == b.m_impl; 1074 } 1075 1076 template<typename T, typename U> 1077 inline bool operator!=(const HashTableIteratorAdapter<T, U>& a, const HashTableConstIteratorAdapter<T, U>& b) 1078 { 1079 return a.m_impl != b.m_impl; 1080 } 1081 1082 } // namespace WTF 1083 1084 #include "wtf/HashIterators.h" 1085 1086 #endif // WTF_HashTable_h 1087