 Chromium Code Reviews
 Chromium Code Reviews Issue 152883002:
  (Concept patch) Simplify WTF::HashTable::add() return value for size and performance  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/blink.git@master
    
  
    Issue 152883002:
  (Concept patch) Simplify WTF::HashTable::add() return value for size and performance  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/blink.git@master| 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 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 199 template<typename T> struct Mover<T, true> { static void move(T& from, T& to ) { hashTableSwap(from, to); } }; | 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& t o) { to = from; } }; | 200 template<typename T> struct Mover<T, false> { static void move(T& from, T& t o) { to = from; } }; | 
| 201 | 201 | 
| 202 template<typename HashFunctions> class IdentityHashTranslator { | 202 template<typename HashFunctions> class IdentityHashTranslator { | 
| 203 public: | 203 public: | 
| 204 template<typename T> static unsigned hash(const T& key) { return HashFun ctions::hash(key); } | 204 template<typename T> static unsigned hash(const T& key) { return HashFun ctions::hash(key); } | 
| 205 template<typename T, typename U> static bool equal(const T& a, const U& b) { return HashFunctions::equal(a, b); } | 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, cons t U&, const T& value) { location = value; } | 206 template<typename T, typename U> static void translate(T& location, cons t U&, const T& value) { location = value; } | 
| 207 }; | 207 }; | 
| 208 | 208 | 
| 209 template<typename IteratorType> struct HashTableAddResult { | 209 template<typename ValueType> struct HashTableAddResult { | 
| 210 HashTableAddResult(IteratorType iter, bool isNewEntry) : iterator(iter), isNewEntry(isNewEntry) { } | 210 HashTableAddResult(ValueType* iterator, bool isNewEntry) : iterator(iter ator), isNewEntry(isNewEntry) { } | 
| 
Erik Corry
2014/02/04 14:27:15
If this is no longer an iterator, should it be cal
 
eseidel
2014/02/05 22:17:20
No. :)  But presumably Daniel did this to minimize
 | |
| 211 IteratorType iterator; | 211 ValueType* iterator; | 
| 212 bool isNewEntry; | 212 bool isNewEntry; | 
| 213 }; | 213 }; | 
| 214 | 214 | 
| 215 template<typename Value, typename Extractor, typename KeyTraits> | 215 template<typename Value, typename Extractor, typename KeyTraits> | 
| 216 struct HashTableHelper { | 216 struct HashTableHelper { | 
| 217 static bool isEmptyBucket(const Value& value) { return isHashTraitsEmpty Value<KeyTraits>(Extractor::extract(value)); } | 217 static bool isEmptyBucket(const Value& value) { return isHashTraitsEmpty Value<KeyTraits>(Extractor::extract(value)); } | 
| 218 static bool isDeletedBucket(const Value& value) { return KeyTraits::isDe letedValue(Extractor::extract(value)); } | 218 static bool isDeletedBucket(const Value& value) { return KeyTraits::isDe letedValue(Extractor::extract(value)); } | 
| 219 static bool isEmptyOrDeletedBucket(const Value& value) { return isEmptyB ucket(value) || isDeletedBucket(value); } | 219 static bool isEmptyOrDeletedBucket(const Value& value) { return isEmptyB ucket(value) || isDeletedBucket(value); } | 
| 220 }; | 220 }; | 
| 221 | 221 | 
| 222 template<typename Key, typename Value, typename Extractor, typename HashFunc tions, typename Traits, typename KeyTraits, typename Allocator> | 222 template<typename Key, typename Value, typename Extractor, typename HashFunc tions, typename Traits, typename KeyTraits, typename Allocator> | 
| 223 class HashTable { | 223 class HashTable { | 
| 224 public: | 224 public: | 
| 225 typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator> iterator; | 225 typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator> iterator; | 
| 226 typedef HashTableConstIterator<Key, Value, Extractor, HashFunctions, Tra its, KeyTraits, Allocator> const_iterator; | 226 typedef HashTableConstIterator<Key, Value, Extractor, HashFunctions, Tra its, KeyTraits, Allocator> const_iterator; | 
| 227 typedef Traits ValueTraits; | 227 typedef Traits ValueTraits; | 
| 228 typedef Key KeyType; | 228 typedef Key KeyType; | 
| 229 typedef typename KeyTraits::PeekInType KeyPeekInType; | 229 typedef typename KeyTraits::PeekInType KeyPeekInType; | 
| 230 typedef typename KeyTraits::PassInType KeyPassInType; | 230 typedef typename KeyTraits::PassInType KeyPassInType; | 
| 231 typedef Value ValueType; | 231 typedef Value ValueType; | 
| 232 typedef typename Traits::PeekInType ValuePeekInType; | 232 typedef typename Traits::PeekInType ValuePeekInType; | 
| 233 typedef IdentityHashTranslator<HashFunctions> IdentityTranslatorType; | 233 typedef IdentityHashTranslator<HashFunctions> IdentityTranslatorType; | 
| 234 typedef HashTableAddResult<iterator> AddResult; | 234 typedef HashTableAddResult<ValueType> AddResult; | 
| 235 | 235 | 
| 236 #if DUMP_HASHTABLE_STATS_PER_TABLE | 236 #if DUMP_HASHTABLE_STATS_PER_TABLE | 
| 237 struct Stats { | 237 struct Stats { | 
| 238 Stats() | 238 Stats() | 
| 239 : numAccesses(0) | 239 : numAccesses(0) | 
| 240 , numRehashes(0) | 240 , numRehashes(0) | 
| 241 , numRemoves(0) | 241 , numRemoves(0) | 
| 242 , numReinserts(0) | 242 , numReinserts(0) | 
| 243 , maxCollisions(0) | 243 , maxCollisions(0) | 
| 244 , numCollisions(0) | 244 , numCollisions(0) | 
| (...skipping 436 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 681 ValueType* entry; | 681 ValueType* entry; | 
| 682 while (1) { | 682 while (1) { | 
| 683 entry = table + i; | 683 entry = table + i; | 
| 684 | 684 | 
| 685 // we count on the compiler to optimize out this branch | 685 // we count on the compiler to optimize out this branch | 
| 686 if (HashFunctions::safeToCompareToEmptyOrDeleted) { | 686 if (HashFunctions::safeToCompareToEmptyOrDeleted) { | 
| 687 if (isEmptyBucket(*entry)) | 687 if (isEmptyBucket(*entry)) | 
| 688 break; | 688 break; | 
| 689 | 689 | 
| 690 if (HashTranslator::equal(Extractor::extract(*entry), key)) | 690 if (HashTranslator::equal(Extractor::extract(*entry), key)) | 
| 691 return AddResult(makeKnownGoodIterator(entry), false); | 691 return AddResult(entry, false); | 
| 692 | 692 | 
| 693 if (isDeletedBucket(*entry)) | 693 if (isDeletedBucket(*entry)) | 
| 694 deletedEntry = entry; | 694 deletedEntry = entry; | 
| 695 } else { | 695 } else { | 
| 696 if (isEmptyBucket(*entry)) | 696 if (isEmptyBucket(*entry)) | 
| 697 break; | 697 break; | 
| 698 | 698 | 
| 699 if (isDeletedBucket(*entry)) | 699 if (isDeletedBucket(*entry)) | 
| 700 deletedEntry = entry; | 700 deletedEntry = entry; | 
| 701 else if (HashTranslator::equal(Extractor::extract(*entry), key)) | 701 else if (HashTranslator::equal(Extractor::extract(*entry), key)) | 
| 702 return AddResult(makeKnownGoodIterator(entry), false); | 702 return AddResult(entry, false); | 
| 703 } | 703 } | 
| 704 #if DUMP_HASHTABLE_STATS | 704 #if DUMP_HASHTABLE_STATS | 
| 705 ++probeCount; | 705 ++probeCount; | 
| 706 HashTableStats::recordCollisionAtCount(probeCount); | 706 HashTableStats::recordCollisionAtCount(probeCount); | 
| 707 #endif | 707 #endif | 
| 708 | 708 | 
| 709 #if DUMP_HASHTABLE_STATS_PER_TABLE | 709 #if DUMP_HASHTABLE_STATS_PER_TABLE | 
| 710 ++perTableProbeCount; | 710 ++perTableProbeCount; | 
| 711 m_stats->recordCollisionAtCount(perTableProbeCount); | 711 m_stats->recordCollisionAtCount(perTableProbeCount); | 
| 712 #endif | 712 #endif | 
| (...skipping 12 matching lines...) Expand all Loading... | |
| 725 HashTranslator::translate(*entry, key, extra); | 725 HashTranslator::translate(*entry, key, extra); | 
| 726 | 726 | 
| 727 ++m_keyCount; | 727 ++m_keyCount; | 
| 728 | 728 | 
| 729 if (shouldExpand()) { | 729 if (shouldExpand()) { | 
| 730 // FIXME: This makes an extra copy on expand. Probably not that bad since | 730 // FIXME: This makes an extra copy on expand. Probably not that bad since | 
| 731 // expand is rare, but would be better to have a version of expand t hat can | 731 // expand is rare, but would be better to have a version of expand t hat can | 
| 732 // follow a pivot entry and return the new position. | 732 // follow a pivot entry and return the new position. | 
| 733 typename WTF::RemoveReference<KeyPassInType>::Type enteredKey = Extr actor::extract(*entry); | 733 typename WTF::RemoveReference<KeyPassInType>::Type enteredKey = Extr actor::extract(*entry); | 
| 734 expand(); | 734 expand(); | 
| 735 AddResult result(find(enteredKey), true); | 735 iterator findResult = find(enteredKey); | 
| 736 ASSERT(result.iterator != end()); | 736 ASSERT(findResult != end()); | 
| 737 ValueType* resultValue = findResult.get(); | |
| 738 AddResult result(resultValue, true); | |
| 737 return result; | 739 return result; | 
| 738 } | 740 } | 
| 739 | 741 | 
| 740 return AddResult(makeKnownGoodIterator(entry), true); | 742 return AddResult(entry, true); | 
| 741 } | 743 } | 
| 742 | 744 | 
| 743 template<typename Key, typename Value, typename Extractor, typename HashFunc tions, typename Traits, typename KeyTraits, typename Allocator> | 745 template<typename Key, typename Value, typename Extractor, typename HashFunc tions, typename Traits, typename KeyTraits, typename Allocator> | 
| 744 template<typename HashTranslator, typename T, typename Extra> | 746 template<typename HashTranslator, typename T, typename Extra> | 
| 745 typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::AddResult HashTable<Key, Value, Extractor, HashFunctions, Traits, Ke yTraits, Allocator>::addPassingHashCode(const T& key, const Extra& extra) | 747 typename HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::AddResult HashTable<Key, Value, Extractor, HashFunctions, Traits, Ke yTraits, Allocator>::addPassingHashCode(const T& key, const Extra& extra) | 
| 746 { | 748 { | 
| 747 if (!m_table) | 749 if (!m_table) | 
| 748 expand(); | 750 expand(); | 
| 749 | 751 | 
| 750 FullLookupType lookupResult = fullLookupForWriting<HashTranslator>(key); | 752 FullLookupType lookupResult = fullLookupForWriting<HashTranslator>(key); | 
| 751 | 753 | 
| 752 ValueType* entry = lookupResult.first.first; | 754 ValueType* entry = lookupResult.first.first; | 
| 753 bool found = lookupResult.first.second; | 755 bool found = lookupResult.first.second; | 
| 754 unsigned h = lookupResult.second; | 756 unsigned h = lookupResult.second; | 
| 755 | 757 | 
| 756 if (found) | 758 if (found) | 
| 757 return AddResult(makeKnownGoodIterator(entry), false); | 759 return AddResult(entry, false); | 
| 758 | 760 | 
| 759 if (isDeletedBucket(*entry)) { | 761 if (isDeletedBucket(*entry)) { | 
| 760 initializeBucket(*entry); | 762 initializeBucket(*entry); | 
| 761 --m_deletedCount; | 763 --m_deletedCount; | 
| 762 } | 764 } | 
| 763 | 765 | 
| 764 HashTranslator::translate(*entry, key, extra, h); | 766 HashTranslator::translate(*entry, key, extra, h); | 
| 765 ++m_keyCount; | 767 ++m_keyCount; | 
| 766 if (shouldExpand()) { | 768 if (shouldExpand()) { | 
| 767 // FIXME: This makes an extra copy on expand. Probably not that bad since | 769 // FIXME: This makes an extra copy on expand. Probably not that bad since | 
| 768 // expand is rare, but would be better to have a version of expand t hat can | 770 // expand is rare, but would be better to have a version of expand t hat can | 
| 769 // follow a pivot entry and return the new position. | 771 // follow a pivot entry and return the new position. | 
| 770 typename WTF::RemoveReference<KeyPassInType>::Type enteredKey = Extr actor::extract(*entry); | 772 typename WTF::RemoveReference<KeyPassInType>::Type enteredKey = Extr actor::extract(*entry); | 
| 771 expand(); | 773 expand(); | 
| 772 AddResult result(find(enteredKey), true); | 774 iterator findResult = find(enteredKey); | 
| 773 ASSERT(result.iterator != end()); | 775 ASSERT(findResult != end()); | 
| 776 ValueType* resultValue = findResult.get(); | |
| 777 AddResult result(resultValue, true); | |
| 774 return result; | 778 return result; | 
| 775 } | 779 } | 
| 776 | 780 | 
| 777 return AddResult(makeKnownGoodIterator(entry), true); | 781 return AddResult(entry, true); | 
| 778 } | 782 } | 
| 779 | 783 | 
| 780 template<typename Key, typename Value, typename Extractor, typename HashFunc tions, typename Traits, typename KeyTraits, typename Allocator> | 784 template<typename Key, typename Value, typename Extractor, typename HashFunc tions, typename Traits, typename KeyTraits, typename Allocator> | 
| 781 inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTrait s, Allocator>::reinsert(ValueType& entry) | 785 inline void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTrait s, Allocator>::reinsert(ValueType& entry) | 
| 782 { | 786 { | 
| 783 ASSERT(m_table); | 787 ASSERT(m_table); | 
| 784 ASSERT(!lookupForWriting(Extractor::extract(entry)).second); | 788 ASSERT(!lookupForWriting(Extractor::extract(entry)).second); | 
| 785 ASSERT(!isDeletedBucket(*(lookupForWriting(Extractor::extract(entry)).fi rst))); | 789 ASSERT(!isDeletedBucket(*(lookupForWriting(Extractor::extract(entry)).fi rst))); | 
| 786 #if DUMP_HASHTABLE_STATS | 790 #if DUMP_HASHTABLE_STATS | 
| 787 atomicIncrement(&HashTableStats::numReinserts); | 791 atomicIncrement(&HashTableStats::numReinserts); | 
| (...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1161 inline bool operator!=(const HashTableIteratorAdapter<T, U>& a, const HashTa bleConstIteratorAdapter<T, U>& b) | 1165 inline bool operator!=(const HashTableIteratorAdapter<T, U>& a, const HashTa bleConstIteratorAdapter<T, U>& b) | 
| 1162 { | 1166 { | 
| 1163 return a.m_impl != b.m_impl; | 1167 return a.m_impl != b.m_impl; | 
| 1164 } | 1168 } | 
| 1165 | 1169 | 
| 1166 } // namespace WTF | 1170 } // namespace WTF | 
| 1167 | 1171 | 
| 1168 #include "wtf/HashIterators.h" | 1172 #include "wtf/HashIterators.h" | 
| 1169 | 1173 | 
| 1170 #endif // WTF_HashTable_h | 1174 #endif // WTF_HashTable_h | 
| OLD | NEW |