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