haikuwebkit/Source/WTF/wtf/RobinHoodHashTable.h

934 lines
39 KiB
C
Raw Permalink Normal View History

[WTF] Introduce RobinHoodHashTable https://bugs.webkit.org/show_bug.cgi?id=223895 Reviewed by Fil Pizlo. Source/JavaScriptCore: * builtins/BuiltinNames.cpp: (JSC::lookUpPrivateNameImpl): (JSC::lookUpWellKnownSymbolImpl): * builtins/BuiltinNames.h: * bytecode/BytecodeIntrinsicRegistry.h: * runtime/Identifier.h: * runtime/IntlCollator.cpp: (JSC::IntlCollator::initializeCollator): (JSC::IntlCollator::checkICULocaleInvariants): * runtime/IntlCollator.h: * runtime/IntlDateTimeFormat.cpp: (JSC::IntlDateTimeFormat::initializeDateTimeFormat): * runtime/IntlDateTimeFormatConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/IntlDisplayNames.cpp: (JSC::IntlDisplayNames::initializeDisplayNames): * runtime/IntlDisplayNamesConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/IntlListFormat.cpp: (JSC::IntlListFormat::initializeListFormat): * runtime/IntlListFormatConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/IntlNumberFormat.cpp: (JSC::IntlNumberFormat::initializeNumberFormat): * runtime/IntlNumberFormatConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/IntlObject.cpp: (JSC::addScriptlessLocaleIfNeeded): (JSC::intlAvailableLocales): (JSC::intlCollatorAvailableLocales): (JSC::intlSegmenterAvailableLocales): (JSC::bestAvailableLocale): (JSC::lookupMatcher): (JSC::bestFitMatcher): (JSC::resolveLocale): (JSC::lookupSupportedLocales): (JSC::bestFitSupportedLocales): (JSC::supportedLocales): * runtime/IntlObject.h: (JSC::intlDateTimeFormatAvailableLocales): (JSC::intlDisplayNamesAvailableLocales): (JSC::intlNumberFormatAvailableLocales): (JSC::intlPluralRulesAvailableLocales): (JSC::intlRelativeTimeFormatAvailableLocales): (JSC::intlListFormatAvailableLocales): * runtime/IntlPluralRules.cpp: (JSC::IntlPluralRules::initializePluralRules): * runtime/IntlPluralRulesConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/IntlRelativeTimeFormat.cpp: (JSC::IntlRelativeTimeFormat::initializeRelativeTimeFormat): * runtime/IntlRelativeTimeFormatConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/IntlSegmenter.cpp: (JSC::IntlSegmenter::initializeSegmenter): * runtime/IntlSegmenterConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/RegExpCache.h: * runtime/RegExpKey.h: Source/WebCore: * Modules/mediacapabilities/MediaCapabilities.cpp: (WebCore::bucketMIMETypes): * accessibility/AccessibilityObject.cpp: (WebCore::AccessibilityObject::popupValue const): * dom/Element.cpp: (WebCore::canAttachAuthorShadowRoot): * dom/QualifiedName.h: * dom/make_names.pl: (printNamesHeaderFile): (printFactoryCppFile): (printWrapperFactoryCppFile): * editing/FormatBlockCommand.cpp: (WebCore::isElementForFormatBlock): * editing/RemoveFormatCommand.cpp: (WebCore::isElementForRemoveFormatCommand): * editing/ReplaceSelectionCommand.cpp: (WebCore::isProhibitedParagraphChild): * html/Autofill.cpp: (WebCore::fieldNameMap): * html/HTMLDocument.cpp: (WebCore::HTMLDocument::isCaseSensitiveAttribute): * html/HTMLObjectElement.cpp: (WebCore::preventsParentObjectFromExposure): * html/parser/HTMLTreeBuilder.cpp: (WebCore::createCaseMap): (WebCore::adjustSVGTagNameCase): (WebCore::adjustAttributes): (WebCore::createForeignAttributesMap): (WebCore::adjustForeignAttributes): (WebCore::addNamesWithPrefix): Deleted. * page/DebugPageOverlays.cpp: (WebCore::touchEventRegionColors): (WebCore::NonFastScrollableRegionOverlay::drawRect): * page/PerformanceUserTiming.cpp: (WebCore::restrictedMarkNamesToNavigationTimingFunctionMap): * platform/cocoa/MIMETypeRegistryCocoa.mm: (WebCore::extensionsForMIMETypeMap): * platform/graphics/FontCascade.cpp: (WebCore::useBackslashAsYenSignForFamily): (WebCore::FontCascade::hasValidAverageCharWidth const): * platform/graphics/avfoundation/CDMFairPlayStreaming.cpp: (WebCore::validInitDataTypes): * platform/graphics/cg/UTIRegistry.cpp: (WebCore::defaultSupportedImageTypes): * platform/graphics/cg/UTIRegistry.h: * platform/graphics/cocoa/HEVCUtilitiesCocoa.mm: (WebCore::codecTypeForDoViCodecString): * platform/graphics/cocoa/SourceBufferParserWebM.cpp: (WebCore::SourceBufferParserWebM::supportedVideoCodecs): (WebCore::SourceBufferParserWebM::supportedAudioCodecs): * platform/graphics/cocoa/SourceBufferParserWebM.h: * rendering/svg/SVGResources.cpp: (WebCore::clipperFilterMaskerTags): (WebCore::markerTags): (WebCore::fillAndStrokeTags): (WebCore::chainableResourceTags): * style/StyleAdjuster.cpp: (WebCore::Style::hasEffectiveDisplayNoneForDisplayContents): * svg/SVGAnimationElement.cpp: (WebCore::SVGAnimationElement::isSupportedAttribute): * svg/SVGElement.cpp: (WebCore::createAttributeNameToCSSPropertyIDMap): (WebCore::SVGElement::animatableAttributeForName): (WebCore::SVGElement::cssPropertyIdForSVGAttributeName): * svg/SVGTests.cpp: (WebCore::SVGTests::addSupportedAttributes): * svg/SVGTests.h: * svg/SVGUseElement.cpp: (WebCore::createAllowedElementSet): (WebCore::isDisallowedElement): * svg/animation/SVGSMILElement.cpp: (WebCore::SVGSMILElement::isSupportedAttribute): * xml/XPathFunctions.cpp: (WebCore::XPath::createFunctionMap): * xml/XPathParser.cpp: (WebCore::XPath::createAxisNamesMap): Source/WebKit: * NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp: (WebKit::ObservedDomainsTableSchemaV1Alternate): (WebKit::expectedUnattributedColumns): (WebKit::expectedAttributedColumns): (WebKit::createTableQueries): * Platform/IPC/ArgumentCoders.h: * Shared/Cocoa/DefaultWebBrowserChecks.mm: (WebKit::getAppBoundDomainsTesting): * Shared/WebPreferencesStore.cpp: (WebKit::WebPreferencesStore::decode): * Shared/WebPreferencesStore.h: * UIProcess/Cocoa/WebProcessProxyCocoa.mm: (WebKit::WebProcessProxy::platformPathsWithAssumedReadAccess): * UIProcess/WebProcessProxy.cpp: (WebKit::WebProcessProxy::platformPathsWithAssumedReadAccess): * UIProcess/WebProcessProxy.h: Source/WTF: This patch implements RobinHoodHashTable[1]. We don't use it as a default hashtable since it has different performance v.s. memory-saving characteristics, and this patch's goal is not tackling on making this default. Rather, the goal of this patch is introducing it to non-performance sensitive area quickly so that we can save memory. RobinHoodHashTable more frequently computes hash value compared to HashTable, so this is not drop-in replacement for the existing one. But still, this is useful since we know that "while there are many small HashTables and they holds much memory, there are super large HashTables and they holds almost same amount of memory while they are a few.". This patch's goal is applying this RobinHoodHashTable to these "large, but a few" singleton tables. RobinHoodHashTable maintains distance-from-initial-bucket (DIB) small by adjusting existing entries when inserting. When inserting, if we found that the existing entry has less DIB than the current inserting entry's DIB, then we swap entries, and insert the existing entry to the other place. This is giving some good DIB from rich entry to poor entry (that's why it is called RobinHood Hashing), and making average DIB lower. And this algorithm adds good invariant that, when looking up an entry, and we found that existing entry has smaller DIB, then we can stop searching in the middle of the chain since we know that we should swap entries when this happened when inserting. These two tricks maintain HashTable performance even under significantly high load factor: 90% load-factor just works. 95% load-factor regress adding performance, but still it does not become catastrophic compared to normal open-addressing HashTable. We introduce RobinHoodHashTable, and adding several kinds of tables based on load-factors. 1. MemoryCompactLookupOnlyRobinHoodHashSet / HashMap This has 95% load-factor. This is suitable for sets and maps which is mostly-constant: constructing once, and looking up repeatedly. In WebKit, there are so many this kind of tables e.g. singleton HashMap for various kinds of things. We can use this super high load-factor table so that we can save memory even while we are maintains fast HashTable lookup. 2. MemoryCompactRobinHoodHashSet / HashMap This has 90% load-factor. It just works, and we can try using it if sets and maps are significantly performance intensive. 3. FastRobinHoodHashSet / HashMap This has 75% load-factor. This is still good compared to HashSet and HashMap since they are using 50% load-factor for large sized tables. This has very slightly performance regressed compared to 50% load-factor large HashSet and HashMap, but if that is not performance intensive (e.g. AtomStringTable is one of the most performance intensive table), this is good. In this patch, we replace many singleton HashSet / HashMap with RobinHoodHashTable. [1]: https://www.sebastiansylvan.com/post/robin-hood-hashing-should-be-your-default-hash-table-implementation/ * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Forward.h: * wtf/HashMap.h: (WTF::Y>::swap): (WTF::Y>::size const): (WTF::Y>::capacity const): (WTF::Y>::isEmpty const): (WTF::Y>::begin): (WTF::Y>::end): (WTF::Y>::begin const): (WTF::Y>::end const): (WTF::Y>::find): (WTF::Y>::find const): (WTF::Y>::contains const): (WTF::Y>::get const): (WTF::Y>::inlineGet const): (WTF::TableTraitsArg>::inlineSet): (WTF::TableTraitsArg>::inlineAdd): (WTF::TableTraitsArg>::inlineEnsure): (WTF::TableTraitsArg>::set): (WTF::TableTraitsArg>::add): (WTF::TableTraitsArg>::fastAdd): (WTF::TableTraitsArg>::ensure): (WTF::Y>::remove): (WTF::Y>::removeIf): (WTF::Y>::clear): (WTF::Y>::take): (WTF::Y>::checkConsistency const): (WTF::Y>::isValidKey): (WTF::operator==): (WTF::operator!=): (WTF::X>::swap): Deleted. (WTF::X>::size const): Deleted. (WTF::X>::capacity const): Deleted. (WTF::X>::isEmpty const): Deleted. (WTF::X>::begin): Deleted. (WTF::X>::end): Deleted. (WTF::X>::begin const): Deleted. (WTF::X>::end const): Deleted. (WTF::X>::find): Deleted. (WTF::X>::find const): Deleted. (WTF::X>::contains const): Deleted. (WTF::X>::get const): Deleted. (WTF::X>::inlineGet const): Deleted. (WTF::MappedTraitsArg>::inlineSet): Deleted. (WTF::MappedTraitsArg>::inlineAdd): Deleted. (WTF::MappedTraitsArg>::inlineEnsure): Deleted. (WTF::MappedTraitsArg>::set): Deleted. (WTF::MappedTraitsArg>::add): Deleted. (WTF::MappedTraitsArg>::fastAdd): Deleted. (WTF::MappedTraitsArg>::ensure): Deleted. (WTF::MappedTraits>::get const): Deleted. (WTF::MappedTraits>::inlineGet const): Deleted. (WTF::X>::remove): Deleted. (WTF::X>::removeIf): Deleted. (WTF::X>::clear): Deleted. (WTF::MappedTraits>::take): Deleted. (WTF::X>::take): Deleted. (WTF::X>::checkConsistency const): Deleted. (WTF::X>::isValidKey): Deleted. * wtf/HashSet.h: (WTF::W>::swap): (WTF::W>::size const): (WTF::W>::capacity const): (WTF::W>::isEmpty const): (WTF::W>::begin const): (WTF::W>::end const): (WTF::W>::find const): (WTF::W>::contains const): (WTF::TableTraits>::find const): (WTF::TableTraits>::contains const): (WTF::TableTraits>::ensure): (WTF::W>::add): (WTF::W>::addVoid): (WTF::TableTraits>::add): (WTF::W>::remove): (WTF::W>::removeIf): (WTF::W>::clear): (WTF::W>::take): (WTF::W>::takeAny): (WTF::TableTraits>::remove): (WTF::TableTraits>::take): (WTF::W>::isValidValue): (WTF::= const): (WTF::W>::checkConsistency const): (WTF::V>::swap): Deleted. (WTF::V>::size const): Deleted. (WTF::V>::capacity const): Deleted. (WTF::V>::isEmpty const): Deleted. (WTF::V>::begin const): Deleted. (WTF::V>::end const): Deleted. (WTF::V>::find const): Deleted. (WTF::V>::contains const): Deleted. (WTF::Traits>::find const): Deleted. (WTF::Traits>::contains const): Deleted. (WTF::Traits>::ensure): Deleted. (WTF::V>::add): Deleted. (WTF::V>::addVoid): Deleted. (WTF::Traits>::add): Deleted. (WTF::V>::remove): Deleted. (WTF::V>::removeIf): Deleted. (WTF::V>::clear): Deleted. (WTF::V>::take): Deleted. (WTF::V>::takeAny): Deleted. (WTF::Traits>::remove): Deleted. (WTF::Traits>::take): Deleted. (WTF::V>::isValidValue): Deleted. (WTF::V>::checkConsistency const): Deleted. * wtf/HashTable.h: (WTF::addIterator): (WTF::removeIterator): (WTF::invalidateIterators): (WTF::HashTable::~HashTable): (WTF::HashTable::random): (WTF::KeyTraits>::inlineLookup): (WTF::KeyTraits>::lookupForWriting): (WTF::KeyTraits>::fullLookupForWriting): (WTF::KeyTraits>::addUniqueForInitialization): (WTF::KeyTraits>::add): (WTF::KeyTraits>::addPassingHashCode): (WTF::KeyTraits>::removeAndInvalidateWithoutEntryConsistencyCheck): (WTF::KeyTraits>::removeAndInvalidate): (WTF::KeyTraits>::clear): (WTF::KeyTraits>::swap): (WTF::KeyTraits>::HashTable): (WTF::HashTable::invalidateIterators): Deleted. (WTF::KeyTraits>::invalidateIterators): Deleted. * wtf/RobinHoodHashMap.h: Added. * wtf/RobinHoodHashSet.h: Added. * wtf/RobinHoodHashTable.h: Added. (WTF::RobinHoodHashTable::~RobinHoodHashTable): (WTF::RobinHoodHashTable::begin): (WTF::RobinHoodHashTable::end): (WTF::RobinHoodHashTable::begin const): (WTF::RobinHoodHashTable::end const): (WTF::RobinHoodHashTable::random): (WTF::RobinHoodHashTable::random const): (WTF::RobinHoodHashTable::size const): (WTF::RobinHoodHashTable::capacity const): (WTF::RobinHoodHashTable::isEmpty const): (WTF::RobinHoodHashTable::reserveInitialCapacity): (WTF::RobinHoodHashTable::add): (WTF::RobinHoodHashTable::find): (WTF::RobinHoodHashTable::find const): (WTF::RobinHoodHashTable::contains const): (WTF::RobinHoodHashTable::isEmptyBucket): (WTF::RobinHoodHashTable::isEmptyOrDeletedBucket): (WTF::RobinHoodHashTable::lookup): (WTF::RobinHoodHashTable::checkTableConsistency): (WTF::RobinHoodHashTable::internalCheckTableConsistency const): (WTF::RobinHoodHashTable::internalCheckTableConsistencyExceptSize const): (WTF::RobinHoodHashTable::internalCheckTableConsistencyExceptSize): (WTF::RobinHoodHashTable::internalCheckTableConsistency): (WTF::RobinHoodHashTable::shouldExpand): (WTF::RobinHoodHashTable::computeTableHash): (WTF::RobinHoodHashTable::shouldExpand const): (WTF::RobinHoodHashTable::shouldShrink const): (WTF::RobinHoodHashTable::shrink): (WTF::RobinHoodHashTable::deleteBucket): (WTF::RobinHoodHashTable::desiredIndex): (WTF::RobinHoodHashTable::probeDistance): (WTF::RobinHoodHashTable::makeIterator): (WTF::RobinHoodHashTable::makeConstIterator const): (WTF::RobinHoodHashTable::makeKnownGoodIterator): (WTF::RobinHoodHashTable::makeKnownGoodConstIterator const): (WTF::RobinHoodHashTable::checkTableConsistencyExceptSize): (WTF::RobinHoodHashTable::tableSize const): (WTF::RobinHoodHashTable::tableSizeMask const): (WTF::RobinHoodHashTable::keyCount const): (WTF::RobinHoodHashTable::tableHash const): (WTF::SizePolicy>::checkKey): (WTF::SizePolicy>::lookup): (WTF::SizePolicy>::inlineLookup): (WTF::SizePolicy>::initializeBucket): (WTF::SizePolicy>::add): (WTF::SizePolicy>::maintainProbeDistanceForAdd): (WTF::SizePolicy>::addPassingHashCode): (WTF::SizePolicy>::reinsert): (WTF::SizePolicy>::find): (WTF::SizePolicy>::find const): (WTF::SizePolicy>::contains const): (WTF::SizePolicy>::removeAndInvalidateWithoutEntryConsistencyCheck): (WTF::SizePolicy>::removeAndInvalidate): (WTF::SizePolicy>::remove): (WTF::SizePolicy>::removeWithoutEntryConsistencyCheck): (WTF::SizePolicy>::allocateTable): (WTF::SizePolicy>::deallocateTable): (WTF::SizePolicy>::expand): (WTF::SizePolicy>::computeBestTableSize): (WTF::SizePolicy>::shrinkToBestSize): (WTF::SizePolicy>::rehash): (WTF::SizePolicy>::clear): (WTF::SizePolicy>::RobinHoodHashTable): (WTF::SizePolicy>::swap): (WTF::=): (WTF::SizePolicy>::checkTableConsistency const): (WTF::SizePolicy>::checkTableConsistencyExceptSize const): * wtf/text/AtomStringHash.h: * wtf/text/AtomStringImpl.cpp: * wtf/text/AtomStringTable.cpp: (WTF::AtomStringTable::~AtomStringTable): * wtf/text/AtomStringTable.h: (WTF::AtomStringTable::table): * wtf/text/StringHash.h: Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/DeletedAddressOfOperator.h: * TestWebKitAPI/Tests/WTF/HashMap.cpp: (TestWebKitAPI::testMovingUsingEnsure): (TestWebKitAPI::testMovingUsingAdd): * TestWebKitAPI/Tests/WTF/HashSet.cpp: (TestWebKitAPI::generateTestCapacityUpToSize<0>): (TestWebKitAPI::generateTestCapacityUpToSize): * TestWebKitAPI/Tests/WTF/MoveOnly.h: * TestWebKitAPI/Tests/WTF/RobinHoodHashMap.cpp: Copied from Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp. (TestWebKitAPI::TEST): (TestWebKitAPI::bucketForKey): (TestWebKitAPI::ZeroHash::hash): (TestWebKitAPI::ObjectWithRefLogger::ObjectWithRefLogger): (TestWebKitAPI::testMovingUsingEnsure): (TestWebKitAPI::testMovingUsingAdd): (TestWebKitAPI::DerefObserver::ref): (TestWebKitAPI::DerefObserver::deref): (TestWebKitAPI::TestObjectWithCustomDestructor::TestObjectWithCustomDestructor): (TestWebKitAPI::TestObjectWithCustomDestructor::~TestObjectWithCustomDestructor): * TestWebKitAPI/Tests/WTF/RobinHoodHashSet.cpp: Copied from Tools/TestWebKitAPI/Tests/WTF/HashSet.cpp. (TestWebKitAPI::capacityForSize): (TestWebKitAPI::testInitialCapacity): (TestWebKitAPI::generateTestCapacityUpToSize<0>): (TestWebKitAPI::generateTestCapacityUpToSize): (TestWebKitAPI::TEST): (TestWebKitAPI::DerefObserver::ref): (TestWebKitAPI::DerefObserver::deref): Canonical link: https://commits.webkit.org/236073@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@275410 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2021-04-02 08:33:32 +00:00
/*
* Copyright (C) 2021 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright 2018 The Rust Project Developers.
*
* Permission is hereby granted, free of charge, to any
* person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without
* limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software
* is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice
* shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
* SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include <wtf/HashTable.h>
namespace WTF {
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
class RobinHoodHashTable;
// 95% load factor. This a bit regress "insertion" performance, while it keeps lookup performance sane.
// RobinHoodHashTable can work with 95% load factor because of maintained probe distance.
struct MemoryCompactLookupOnlyRobinHoodHashTableSizePolicy {
static constexpr unsigned maxLoadNumerator = 19;
static constexpr unsigned maxLoadDenominator = 20;
static constexpr unsigned minLoad = 6;
};
// 90% load factor. RobinHoodHashTable can work with such a high load-factor.
// Observed performance is slightly worse than HashTable (75% for small table, 50% for large table).
struct MemoryCompactRobinHoodHashTableSizePolicy {
static constexpr unsigned maxLoadNumerator = 9;
static constexpr unsigned maxLoadDenominator = 10;
static constexpr unsigned minLoad = 6;
};
// 75% load factor, this maintains the performance same to HashTable, still the load factor
// is higher (HashTable uses 75% for small table, 50 for large table).
struct FastRobinHoodHashTableSizePolicy {
static constexpr unsigned maxLoadNumerator = 3;
static constexpr unsigned maxLoadDenominator = 4;
static constexpr unsigned minLoad = 6;
};
// RobinHood HashTable has several limitations compared to usual HashTable, that's why this is not a default one.
// RobinHood HashTable computes hash much more frequently. This means that the Key should cache computed hash.
// But our default HashTable does not cache hash value because of memory usage. This design means that Key type
// should have hash value intrusively (e.g. WTF::String holds hash value internally).
//
// If the above requirements meet your use case, then you can try RobinHood HashTable.
// The largest benefit is that we can use significantly high load-factor (90% - 95%)!
//
// The algorithm is RobinHood-Hashing + backward shift deletion, described in [1,2].
//
// Naive RobinHoodHashTable has some cases which cause O(N^2) when iterating it and inserting it to some new RobinHoodHashTable
// without reserving capacity and this is because of high load-factor and exposed hash-ordering at iteration[3]. To mitigate it,
// we calculate hash for each table, and do XOR with the hash value to make hash-ordering different for each table.
//
// [1]: https://codecapsule.com/2013/11/11/robin-hood-hashing/
// [2]: https://codecapsule.com/2013/11/17/robin-hood-hashing-backward-shift-deletion/
// [3]: https://accidentallyquadratic.tumblr.com/post/153545455987/rust-hash-iteration-reinsertion
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
class RobinHoodHashTable {
public:
using HashTableType = RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>;
using iterator = HashTableIterator<HashTableType, Key, Value, Extractor, HashFunctions, Traits, KeyTraits>;
using const_iterator = HashTableConstIterator<HashTableType, Key, Value, Extractor, HashFunctions, Traits, KeyTraits>;
using ValueTraits = Traits;
using KeyType = Key;
using ValueType = Value;
using IdentityTranslatorType = IdentityHashTranslator<ValueTraits, HashFunctions>;
using AddResult = HashTableAddResult<iterator>;
static constexpr unsigned probeDistanceThreshold = 128;
static_assert(!KeyTraits::hasIsReleasedWeakValueFunction);
static_assert(HashFunctions::hasHashInValue);
RobinHoodHashTable() = default;
~RobinHoodHashTable()
{
invalidateIterators(this);
if (m_table)
deallocateTable(m_table, tableSize());
}
RobinHoodHashTable(const RobinHoodHashTable&);
void swap(RobinHoodHashTable&);
RobinHoodHashTable& operator=(const RobinHoodHashTable&);
RobinHoodHashTable(RobinHoodHashTable&&);
RobinHoodHashTable& operator=(RobinHoodHashTable&&);
// When the hash table is empty, just return the same iterator for end as for begin.
// This is more efficient because we don't have to skip all the empty and deleted
// buckets, and iterating an empty table is a common case that's worth optimizing.
iterator begin() { return isEmpty() ? end() : makeIterator(m_table); }
iterator end() { return makeKnownGoodIterator(m_table + tableSize()); }
const_iterator begin() const { return isEmpty() ? end() : makeConstIterator(m_table); }
const_iterator end() const { return makeKnownGoodConstIterator(m_table + tableSize()); }
iterator random()
{
if (isEmpty())
return end();
while (true) {
auto& bucket = m_table[weakRandomUint32() & tableSizeMask()];
if (!isEmptyBucket(bucket))
return makeKnownGoodIterator(&bucket);
}
}
const_iterator random() const { return static_cast<const_iterator>(const_cast<RobinHoodHashTable*>(this)->random()); }
unsigned size() const { return keyCount(); }
unsigned capacity() const { return tableSize(); }
bool isEmpty() const { return !keyCount(); }
void reserveInitialCapacity(unsigned keyCount)
{
ASSERT(!m_table);
ASSERT(!tableSize());
unsigned minimumTableSize = KeyTraits::minimumTableSize;
unsigned newTableSize = std::max(minimumTableSize, computeBestTableSize(keyCount));
m_table = allocateTable(newTableSize);
m_tableSize = newTableSize;
m_keyCount = 0;
m_tableHash = computeTableHash(m_table);
m_willExpand = false;
internalCheckTableConsistency();
}
AddResult add(const ValueType& value) { return add<IdentityTranslatorType>(Extractor::extract(value), value); }
AddResult add(ValueType&& value) { return add<IdentityTranslatorType>(Extractor::extract(value), WTFMove(value)); }
// A special version of add() that finds the object by hashing and comparing
// with some other type, to avoid the cost of type conversion if the object is already
// in the table.
template<typename HashTranslator, typename T, typename Extra> AddResult add(T&& key, Extra&&);
template<typename HashTranslator, typename T, typename Extra> AddResult addPassingHashCode(T&& key, Extra&&);
iterator find(const KeyType& key) { return find<IdentityTranslatorType>(key); }
const_iterator find(const KeyType& key) const { return find<IdentityTranslatorType>(key); }
bool contains(const KeyType& key) const { return contains<IdentityTranslatorType>(key); }
template<typename HashTranslator, typename T> iterator find(const T&);
template<typename HashTranslator, typename T> const_iterator find(const T&) const;
template<typename HashTranslator, typename T> bool contains(const T&) const;
void remove(const KeyType&);
void remove(iterator);
void removeWithoutEntryConsistencyCheck(iterator);
void removeWithoutEntryConsistencyCheck(const_iterator);
void clear();
static bool isEmptyBucket(const ValueType& value) { return isHashTraitsEmptyValue<KeyTraits>(Extractor::extract(value)); }
static bool isEmptyOrDeletedBucket(const ValueType& value) { return isEmptyBucket(value); }
ValueType* lookup(const Key& key) { return lookup<IdentityTranslatorType>(key); }
template<typename HashTranslator, typename T> ValueType* lookup(const T&);
template<typename HashTranslator, typename T> ValueType* inlineLookup(const T&);
#if ASSERT_ENABLED
void checkTableConsistency() const;
#else
static void checkTableConsistency() { }
#endif
#if CHECK_HASHTABLE_CONSISTENCY
void internalCheckTableConsistency() const { checkTableConsistency(); }
void internalCheckTableConsistencyExceptSize() const { checkTableConsistencyExceptSize(); }
#else
static void internalCheckTableConsistencyExceptSize() { }
static void internalCheckTableConsistency() { }
#endif
static constexpr bool shouldExpand(uint64_t keyCount, uint64_t tableSize)
{
return keyCount * maxLoadDenominator >= tableSize * maxLoadNumerator;
}
private:
static ValueType* allocateTable(unsigned size);
static void deallocateTable(ValueType* table, unsigned size);
using LookupType = std::pair<ValueType*, bool>;
template<typename HashTranslator, typename T> void checkKey(const T&);
void maintainProbeDistanceForAdd(ValueType&&, unsigned index, unsigned distance, unsigned size, unsigned sizeMask, unsigned tableHash);
void removeAndInvalidateWithoutEntryConsistencyCheck(ValueType*);
void removeAndInvalidate(ValueType*);
void remove(ValueType*);
static unsigned computeTableHash(ValueType* table) { return DefaultHash<ValueType*>::hash(table); }
static constexpr unsigned computeBestTableSize(unsigned keyCount);
bool shouldExpand() const
{
unsigned keyCount = this->keyCount();
unsigned tableSize = this->tableSize();
if (shouldExpand(keyCount, tableSize))
return true;
// If probe-length exceeds probeDistanceThreshold, and 50%~ is filled, expand the table.
return m_willExpand && keyCount * 2 >= tableSize;
}
bool shouldShrink() const { return keyCount() * minLoad < tableSize() && tableSize() > KeyTraits::minimumTableSize; }
void expand();
void shrink() { rehash(tableSize() / 2); }
void shrinkToBestSize();
void rehash(unsigned newTableSize);
void reinsert(ValueType&&);
static void initializeBucket(ValueType& bucket);
static void deleteBucket(ValueType& bucket) { hashTraitsDeleteBucket<Traits>(bucket); }
static constexpr unsigned desiredIndex(unsigned hash, unsigned sizeMask)
{
return hash & sizeMask;
}
static constexpr unsigned probeDistance(unsigned hash, unsigned index, unsigned size, unsigned sizeMask)
{
return (index + size - desiredIndex(hash, sizeMask)) & sizeMask;
}
iterator makeIterator(ValueType* pos) { return iterator(this, pos, m_table + tableSize()); }
const_iterator makeConstIterator(ValueType* pos) const { return const_iterator(this, pos, m_table + tableSize()); }
iterator makeKnownGoodIterator(ValueType* pos) { return iterator(this, pos, m_table + tableSize(), HashItemKnownGood); }
const_iterator makeKnownGoodConstIterator(ValueType* pos) const { return const_iterator(this, pos, m_table + tableSize(), HashItemKnownGood); }
#if ASSERT_ENABLED
void checkTableConsistencyExceptSize() const;
#else
static void checkTableConsistencyExceptSize() { }
#endif
static constexpr unsigned maxLoadNumerator = SizePolicy::maxLoadNumerator;
static constexpr unsigned maxLoadDenominator = SizePolicy::maxLoadDenominator;
static constexpr unsigned minLoad = SizePolicy::minLoad;
unsigned tableSize() const { return m_tableSize; }
unsigned tableSizeMask() const { return m_tableSize - 1; }
unsigned keyCount() const { return m_keyCount; }
unsigned tableHash() const { return m_tableHash; }
ValueType* m_table { nullptr };
unsigned m_tableSize { 0 };
unsigned m_keyCount { 0 };
unsigned m_tableHash { 0 };
bool m_willExpand { false };
#if CHECK_HASHTABLE_ITERATORS
public:
// All access to m_iterators should be guarded with m_mutex.
mutable const_iterator* m_iterators { nullptr };
// Use std::unique_ptr so HashTable can still be memmove'd or memcpy'ed.
mutable std::unique_ptr<Lock> m_mutex { makeUnique<Lock>() };
#endif
};
#if !ASSERT_ENABLED
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
template<typename HashTranslator, typename T>
inline void RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::checkKey(const T&)
{
}
#else // ASSERT_ENABLED
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
template<typename HashTranslator, typename T>
void RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::checkKey(const T& key)
{
if (!HashFunctions::safeToCompareToEmptyOrDeleted)
return;
ASSERT(!HashTranslator::equal(KeyTraits::emptyValue(), key));
typename std::aligned_storage<sizeof(ValueType), std::alignment_of<ValueType>::value>::type deletedValueBuffer;
ValueType* deletedValuePtr = reinterpret_cast_ptr<ValueType*>(&deletedValueBuffer);
ValueType& deletedValue = *deletedValuePtr;
Traits::constructDeletedValue(deletedValue);
ASSERT(!HashTranslator::equal(Extractor::extract(deletedValue), key));
}
#endif // ASSERT_ENABLED
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
template<typename HashTranslator, typename T>
inline auto RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::lookup(const T& key) -> ValueType*
{
return inlineLookup<HashTranslator>(key);
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
template<typename HashTranslator, typename T>
ALWAYS_INLINE auto RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::inlineLookup(const T& key) -> ValueType*
{
checkKey<HashTranslator>(key);
ValueType* table = m_table;
if (!table)
return nullptr;
unsigned size = tableSize();
unsigned sizeMask = tableSizeMask();
unsigned tableHash = this->tableHash();
unsigned hash = HashTranslator::hash(key) ^ tableHash;
unsigned index = desiredIndex(hash, sizeMask);
unsigned distance = 0;
while (true) {
ValueType* entry = m_table + index;
if (isEmptyBucket(*entry))
return nullptr;
// RobinHoodHashTable maintains this invariant so that we can stop
// probing when distance exceeds probing distance of the existing entry.
auto& entryKey = Extractor::extract(*entry);
unsigned entryHash = IdentityTranslatorType::hash(entryKey) ^ tableHash;
if (distance > probeDistance(entryHash, index, size, sizeMask))
return nullptr;
if (entryHash == hash && HashTranslator::equal(entryKey, key))
return entry;
index = (index + 1) & sizeMask;
++distance;
}
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
inline void RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::initializeBucket(ValueType& bucket)
{
HashTableBucketInitializer<Traits::emptyValueIsZero>::template initialize<Traits>(bucket);
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
template<typename HashTranslator, typename T, typename Extra>
ALWAYS_INLINE auto RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::add(T&& key, Extra&& extra) -> AddResult
{
checkKey<HashTranslator>(key);
invalidateIterators(this);
// We should expand before potentially inserting an entry. If we expand a table after inserting an entry,
// we need to re-look up entry from the table since the inserted entry position is not stable during rehasing.
if (shouldExpand())
expand();
internalCheckTableConsistency();
ASSERT(m_table);
unsigned size = tableSize();
unsigned sizeMask = tableSizeMask();
unsigned tableHash = this->tableHash();
unsigned hash = HashTranslator::hash(key) ^ tableHash;
unsigned index = desiredIndex(hash, sizeMask);
unsigned distance = 0;
ValueType* entry = nullptr;
while (true) {
entry = m_table + index;
if (isEmptyBucket(*entry)) {
if (distance >= probeDistanceThreshold)
m_willExpand = true;
HashTranslator::translate(*entry, std::forward<T>(key), std::forward<Extra>(extra));
break;
}
auto& entryKey = Extractor::extract(*entry);
unsigned entryHash = IdentityTranslatorType::hash(entryKey) ^ tableHash;
unsigned entryDistance = probeDistance(entryHash, index, size, sizeMask);
if (distance > entryDistance) {
if (distance >= probeDistanceThreshold)
m_willExpand = true;
// Start swapping existing entry to maintain probe-distance invariant.
ValueType existingEntry = WTFMove(*entry);
entry->~ValueType();
initializeBucket(*entry);
HashTranslator::translate(*entry, std::forward<T>(key), std::forward<Extra>(extra));
maintainProbeDistanceForAdd(WTFMove(existingEntry), index, entryDistance, size, sizeMask, tableHash);
break;
}
if (entryHash == hash && HashTranslator::equal(entryKey, key))
return AddResult(makeKnownGoodIterator(entry), false);
index = (index + 1) & sizeMask;
++distance;
}
m_keyCount += 1;
internalCheckTableConsistency();
return AddResult(makeKnownGoodIterator(entry), true);
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
ALWAYS_INLINE void RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::maintainProbeDistanceForAdd(ValueType&& value, unsigned index, unsigned distance, unsigned size, unsigned sizeMask, unsigned tableHash)
{
using std::swap; // For C++ ADL.
index = (index + 1) & sizeMask;
++distance;
while (true) {
ValueType* entry = m_table + index;
if (isEmptyBucket(*entry)) {
ValueTraits::assignToEmpty(*entry, WTFMove(value));
return;
}
unsigned entryHash = IdentityTranslatorType::hash(Extractor::extract(*entry)) ^ tableHash;
unsigned entryDistance = probeDistance(entryHash, index, size, sizeMask);
if (distance > entryDistance) {
swap(value, *entry);
distance = entryDistance;
}
index = (index + 1) & sizeMask;
++distance;
}
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
template<typename HashTranslator, typename T, typename Extra>
inline auto RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::addPassingHashCode(T&& key, Extra&& extra) -> AddResult
{
checkKey<HashTranslator>(key);
invalidateIterators(this);
// We should expand before potentially inserting an entry. If we expand a table after inserting an entry,
// we need to re-look up entry from the table since the inserted entry position is not stable during rehasing.
if (shouldExpand())
expand();
internalCheckTableConsistency();
ASSERT(m_table);
unsigned size = tableSize();
unsigned sizeMask = tableSizeMask();
unsigned tableHash = this->tableHash();
unsigned originalHash = HashTranslator::hash(key);
unsigned hash = originalHash ^ tableHash;
[WTF] Introduce RobinHoodHashTable https://bugs.webkit.org/show_bug.cgi?id=223895 Reviewed by Fil Pizlo. Source/JavaScriptCore: * builtins/BuiltinNames.cpp: (JSC::lookUpPrivateNameImpl): (JSC::lookUpWellKnownSymbolImpl): * builtins/BuiltinNames.h: * bytecode/BytecodeIntrinsicRegistry.h: * runtime/Identifier.h: * runtime/IntlCollator.cpp: (JSC::IntlCollator::initializeCollator): (JSC::IntlCollator::checkICULocaleInvariants): * runtime/IntlCollator.h: * runtime/IntlDateTimeFormat.cpp: (JSC::IntlDateTimeFormat::initializeDateTimeFormat): * runtime/IntlDateTimeFormatConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/IntlDisplayNames.cpp: (JSC::IntlDisplayNames::initializeDisplayNames): * runtime/IntlDisplayNamesConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/IntlListFormat.cpp: (JSC::IntlListFormat::initializeListFormat): * runtime/IntlListFormatConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/IntlNumberFormat.cpp: (JSC::IntlNumberFormat::initializeNumberFormat): * runtime/IntlNumberFormatConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/IntlObject.cpp: (JSC::addScriptlessLocaleIfNeeded): (JSC::intlAvailableLocales): (JSC::intlCollatorAvailableLocales): (JSC::intlSegmenterAvailableLocales): (JSC::bestAvailableLocale): (JSC::lookupMatcher): (JSC::bestFitMatcher): (JSC::resolveLocale): (JSC::lookupSupportedLocales): (JSC::bestFitSupportedLocales): (JSC::supportedLocales): * runtime/IntlObject.h: (JSC::intlDateTimeFormatAvailableLocales): (JSC::intlDisplayNamesAvailableLocales): (JSC::intlNumberFormatAvailableLocales): (JSC::intlPluralRulesAvailableLocales): (JSC::intlRelativeTimeFormatAvailableLocales): (JSC::intlListFormatAvailableLocales): * runtime/IntlPluralRules.cpp: (JSC::IntlPluralRules::initializePluralRules): * runtime/IntlPluralRulesConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/IntlRelativeTimeFormat.cpp: (JSC::IntlRelativeTimeFormat::initializeRelativeTimeFormat): * runtime/IntlRelativeTimeFormatConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/IntlSegmenter.cpp: (JSC::IntlSegmenter::initializeSegmenter): * runtime/IntlSegmenterConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/RegExpCache.h: * runtime/RegExpKey.h: Source/WebCore: * Modules/mediacapabilities/MediaCapabilities.cpp: (WebCore::bucketMIMETypes): * accessibility/AccessibilityObject.cpp: (WebCore::AccessibilityObject::popupValue const): * dom/Element.cpp: (WebCore::canAttachAuthorShadowRoot): * dom/QualifiedName.h: * dom/make_names.pl: (printNamesHeaderFile): (printFactoryCppFile): (printWrapperFactoryCppFile): * editing/FormatBlockCommand.cpp: (WebCore::isElementForFormatBlock): * editing/RemoveFormatCommand.cpp: (WebCore::isElementForRemoveFormatCommand): * editing/ReplaceSelectionCommand.cpp: (WebCore::isProhibitedParagraphChild): * html/Autofill.cpp: (WebCore::fieldNameMap): * html/HTMLDocument.cpp: (WebCore::HTMLDocument::isCaseSensitiveAttribute): * html/HTMLObjectElement.cpp: (WebCore::preventsParentObjectFromExposure): * html/parser/HTMLTreeBuilder.cpp: (WebCore::createCaseMap): (WebCore::adjustSVGTagNameCase): (WebCore::adjustAttributes): (WebCore::createForeignAttributesMap): (WebCore::adjustForeignAttributes): (WebCore::addNamesWithPrefix): Deleted. * page/DebugPageOverlays.cpp: (WebCore::touchEventRegionColors): (WebCore::NonFastScrollableRegionOverlay::drawRect): * page/PerformanceUserTiming.cpp: (WebCore::restrictedMarkNamesToNavigationTimingFunctionMap): * platform/cocoa/MIMETypeRegistryCocoa.mm: (WebCore::extensionsForMIMETypeMap): * platform/graphics/FontCascade.cpp: (WebCore::useBackslashAsYenSignForFamily): (WebCore::FontCascade::hasValidAverageCharWidth const): * platform/graphics/avfoundation/CDMFairPlayStreaming.cpp: (WebCore::validInitDataTypes): * platform/graphics/cg/UTIRegistry.cpp: (WebCore::defaultSupportedImageTypes): * platform/graphics/cg/UTIRegistry.h: * platform/graphics/cocoa/HEVCUtilitiesCocoa.mm: (WebCore::codecTypeForDoViCodecString): * platform/graphics/cocoa/SourceBufferParserWebM.cpp: (WebCore::SourceBufferParserWebM::supportedVideoCodecs): (WebCore::SourceBufferParserWebM::supportedAudioCodecs): * platform/graphics/cocoa/SourceBufferParserWebM.h: * rendering/svg/SVGResources.cpp: (WebCore::clipperFilterMaskerTags): (WebCore::markerTags): (WebCore::fillAndStrokeTags): (WebCore::chainableResourceTags): * style/StyleAdjuster.cpp: (WebCore::Style::hasEffectiveDisplayNoneForDisplayContents): * svg/SVGAnimationElement.cpp: (WebCore::SVGAnimationElement::isSupportedAttribute): * svg/SVGElement.cpp: (WebCore::createAttributeNameToCSSPropertyIDMap): (WebCore::SVGElement::animatableAttributeForName): (WebCore::SVGElement::cssPropertyIdForSVGAttributeName): * svg/SVGTests.cpp: (WebCore::SVGTests::addSupportedAttributes): * svg/SVGTests.h: * svg/SVGUseElement.cpp: (WebCore::createAllowedElementSet): (WebCore::isDisallowedElement): * svg/animation/SVGSMILElement.cpp: (WebCore::SVGSMILElement::isSupportedAttribute): * xml/XPathFunctions.cpp: (WebCore::XPath::createFunctionMap): * xml/XPathParser.cpp: (WebCore::XPath::createAxisNamesMap): Source/WebKit: * NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp: (WebKit::ObservedDomainsTableSchemaV1Alternate): (WebKit::expectedUnattributedColumns): (WebKit::expectedAttributedColumns): (WebKit::createTableQueries): * Platform/IPC/ArgumentCoders.h: * Shared/Cocoa/DefaultWebBrowserChecks.mm: (WebKit::getAppBoundDomainsTesting): * Shared/WebPreferencesStore.cpp: (WebKit::WebPreferencesStore::decode): * Shared/WebPreferencesStore.h: * UIProcess/Cocoa/WebProcessProxyCocoa.mm: (WebKit::WebProcessProxy::platformPathsWithAssumedReadAccess): * UIProcess/WebProcessProxy.cpp: (WebKit::WebProcessProxy::platformPathsWithAssumedReadAccess): * UIProcess/WebProcessProxy.h: Source/WTF: This patch implements RobinHoodHashTable[1]. We don't use it as a default hashtable since it has different performance v.s. memory-saving characteristics, and this patch's goal is not tackling on making this default. Rather, the goal of this patch is introducing it to non-performance sensitive area quickly so that we can save memory. RobinHoodHashTable more frequently computes hash value compared to HashTable, so this is not drop-in replacement for the existing one. But still, this is useful since we know that "while there are many small HashTables and they holds much memory, there are super large HashTables and they holds almost same amount of memory while they are a few.". This patch's goal is applying this RobinHoodHashTable to these "large, but a few" singleton tables. RobinHoodHashTable maintains distance-from-initial-bucket (DIB) small by adjusting existing entries when inserting. When inserting, if we found that the existing entry has less DIB than the current inserting entry's DIB, then we swap entries, and insert the existing entry to the other place. This is giving some good DIB from rich entry to poor entry (that's why it is called RobinHood Hashing), and making average DIB lower. And this algorithm adds good invariant that, when looking up an entry, and we found that existing entry has smaller DIB, then we can stop searching in the middle of the chain since we know that we should swap entries when this happened when inserting. These two tricks maintain HashTable performance even under significantly high load factor: 90% load-factor just works. 95% load-factor regress adding performance, but still it does not become catastrophic compared to normal open-addressing HashTable. We introduce RobinHoodHashTable, and adding several kinds of tables based on load-factors. 1. MemoryCompactLookupOnlyRobinHoodHashSet / HashMap This has 95% load-factor. This is suitable for sets and maps which is mostly-constant: constructing once, and looking up repeatedly. In WebKit, there are so many this kind of tables e.g. singleton HashMap for various kinds of things. We can use this super high load-factor table so that we can save memory even while we are maintains fast HashTable lookup. 2. MemoryCompactRobinHoodHashSet / HashMap This has 90% load-factor. It just works, and we can try using it if sets and maps are significantly performance intensive. 3. FastRobinHoodHashSet / HashMap This has 75% load-factor. This is still good compared to HashSet and HashMap since they are using 50% load-factor for large sized tables. This has very slightly performance regressed compared to 50% load-factor large HashSet and HashMap, but if that is not performance intensive (e.g. AtomStringTable is one of the most performance intensive table), this is good. In this patch, we replace many singleton HashSet / HashMap with RobinHoodHashTable. [1]: https://www.sebastiansylvan.com/post/robin-hood-hashing-should-be-your-default-hash-table-implementation/ * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Forward.h: * wtf/HashMap.h: (WTF::Y>::swap): (WTF::Y>::size const): (WTF::Y>::capacity const): (WTF::Y>::isEmpty const): (WTF::Y>::begin): (WTF::Y>::end): (WTF::Y>::begin const): (WTF::Y>::end const): (WTF::Y>::find): (WTF::Y>::find const): (WTF::Y>::contains const): (WTF::Y>::get const): (WTF::Y>::inlineGet const): (WTF::TableTraitsArg>::inlineSet): (WTF::TableTraitsArg>::inlineAdd): (WTF::TableTraitsArg>::inlineEnsure): (WTF::TableTraitsArg>::set): (WTF::TableTraitsArg>::add): (WTF::TableTraitsArg>::fastAdd): (WTF::TableTraitsArg>::ensure): (WTF::Y>::remove): (WTF::Y>::removeIf): (WTF::Y>::clear): (WTF::Y>::take): (WTF::Y>::checkConsistency const): (WTF::Y>::isValidKey): (WTF::operator==): (WTF::operator!=): (WTF::X>::swap): Deleted. (WTF::X>::size const): Deleted. (WTF::X>::capacity const): Deleted. (WTF::X>::isEmpty const): Deleted. (WTF::X>::begin): Deleted. (WTF::X>::end): Deleted. (WTF::X>::begin const): Deleted. (WTF::X>::end const): Deleted. (WTF::X>::find): Deleted. (WTF::X>::find const): Deleted. (WTF::X>::contains const): Deleted. (WTF::X>::get const): Deleted. (WTF::X>::inlineGet const): Deleted. (WTF::MappedTraitsArg>::inlineSet): Deleted. (WTF::MappedTraitsArg>::inlineAdd): Deleted. (WTF::MappedTraitsArg>::inlineEnsure): Deleted. (WTF::MappedTraitsArg>::set): Deleted. (WTF::MappedTraitsArg>::add): Deleted. (WTF::MappedTraitsArg>::fastAdd): Deleted. (WTF::MappedTraitsArg>::ensure): Deleted. (WTF::MappedTraits>::get const): Deleted. (WTF::MappedTraits>::inlineGet const): Deleted. (WTF::X>::remove): Deleted. (WTF::X>::removeIf): Deleted. (WTF::X>::clear): Deleted. (WTF::MappedTraits>::take): Deleted. (WTF::X>::take): Deleted. (WTF::X>::checkConsistency const): Deleted. (WTF::X>::isValidKey): Deleted. * wtf/HashSet.h: (WTF::W>::swap): (WTF::W>::size const): (WTF::W>::capacity const): (WTF::W>::isEmpty const): (WTF::W>::begin const): (WTF::W>::end const): (WTF::W>::find const): (WTF::W>::contains const): (WTF::TableTraits>::find const): (WTF::TableTraits>::contains const): (WTF::TableTraits>::ensure): (WTF::W>::add): (WTF::W>::addVoid): (WTF::TableTraits>::add): (WTF::W>::remove): (WTF::W>::removeIf): (WTF::W>::clear): (WTF::W>::take): (WTF::W>::takeAny): (WTF::TableTraits>::remove): (WTF::TableTraits>::take): (WTF::W>::isValidValue): (WTF::= const): (WTF::W>::checkConsistency const): (WTF::V>::swap): Deleted. (WTF::V>::size const): Deleted. (WTF::V>::capacity const): Deleted. (WTF::V>::isEmpty const): Deleted. (WTF::V>::begin const): Deleted. (WTF::V>::end const): Deleted. (WTF::V>::find const): Deleted. (WTF::V>::contains const): Deleted. (WTF::Traits>::find const): Deleted. (WTF::Traits>::contains const): Deleted. (WTF::Traits>::ensure): Deleted. (WTF::V>::add): Deleted. (WTF::V>::addVoid): Deleted. (WTF::Traits>::add): Deleted. (WTF::V>::remove): Deleted. (WTF::V>::removeIf): Deleted. (WTF::V>::clear): Deleted. (WTF::V>::take): Deleted. (WTF::V>::takeAny): Deleted. (WTF::Traits>::remove): Deleted. (WTF::Traits>::take): Deleted. (WTF::V>::isValidValue): Deleted. (WTF::V>::checkConsistency const): Deleted. * wtf/HashTable.h: (WTF::addIterator): (WTF::removeIterator): (WTF::invalidateIterators): (WTF::HashTable::~HashTable): (WTF::HashTable::random): (WTF::KeyTraits>::inlineLookup): (WTF::KeyTraits>::lookupForWriting): (WTF::KeyTraits>::fullLookupForWriting): (WTF::KeyTraits>::addUniqueForInitialization): (WTF::KeyTraits>::add): (WTF::KeyTraits>::addPassingHashCode): (WTF::KeyTraits>::removeAndInvalidateWithoutEntryConsistencyCheck): (WTF::KeyTraits>::removeAndInvalidate): (WTF::KeyTraits>::clear): (WTF::KeyTraits>::swap): (WTF::KeyTraits>::HashTable): (WTF::HashTable::invalidateIterators): Deleted. (WTF::KeyTraits>::invalidateIterators): Deleted. * wtf/RobinHoodHashMap.h: Added. * wtf/RobinHoodHashSet.h: Added. * wtf/RobinHoodHashTable.h: Added. (WTF::RobinHoodHashTable::~RobinHoodHashTable): (WTF::RobinHoodHashTable::begin): (WTF::RobinHoodHashTable::end): (WTF::RobinHoodHashTable::begin const): (WTF::RobinHoodHashTable::end const): (WTF::RobinHoodHashTable::random): (WTF::RobinHoodHashTable::random const): (WTF::RobinHoodHashTable::size const): (WTF::RobinHoodHashTable::capacity const): (WTF::RobinHoodHashTable::isEmpty const): (WTF::RobinHoodHashTable::reserveInitialCapacity): (WTF::RobinHoodHashTable::add): (WTF::RobinHoodHashTable::find): (WTF::RobinHoodHashTable::find const): (WTF::RobinHoodHashTable::contains const): (WTF::RobinHoodHashTable::isEmptyBucket): (WTF::RobinHoodHashTable::isEmptyOrDeletedBucket): (WTF::RobinHoodHashTable::lookup): (WTF::RobinHoodHashTable::checkTableConsistency): (WTF::RobinHoodHashTable::internalCheckTableConsistency const): (WTF::RobinHoodHashTable::internalCheckTableConsistencyExceptSize const): (WTF::RobinHoodHashTable::internalCheckTableConsistencyExceptSize): (WTF::RobinHoodHashTable::internalCheckTableConsistency): (WTF::RobinHoodHashTable::shouldExpand): (WTF::RobinHoodHashTable::computeTableHash): (WTF::RobinHoodHashTable::shouldExpand const): (WTF::RobinHoodHashTable::shouldShrink const): (WTF::RobinHoodHashTable::shrink): (WTF::RobinHoodHashTable::deleteBucket): (WTF::RobinHoodHashTable::desiredIndex): (WTF::RobinHoodHashTable::probeDistance): (WTF::RobinHoodHashTable::makeIterator): (WTF::RobinHoodHashTable::makeConstIterator const): (WTF::RobinHoodHashTable::makeKnownGoodIterator): (WTF::RobinHoodHashTable::makeKnownGoodConstIterator const): (WTF::RobinHoodHashTable::checkTableConsistencyExceptSize): (WTF::RobinHoodHashTable::tableSize const): (WTF::RobinHoodHashTable::tableSizeMask const): (WTF::RobinHoodHashTable::keyCount const): (WTF::RobinHoodHashTable::tableHash const): (WTF::SizePolicy>::checkKey): (WTF::SizePolicy>::lookup): (WTF::SizePolicy>::inlineLookup): (WTF::SizePolicy>::initializeBucket): (WTF::SizePolicy>::add): (WTF::SizePolicy>::maintainProbeDistanceForAdd): (WTF::SizePolicy>::addPassingHashCode): (WTF::SizePolicy>::reinsert): (WTF::SizePolicy>::find): (WTF::SizePolicy>::find const): (WTF::SizePolicy>::contains const): (WTF::SizePolicy>::removeAndInvalidateWithoutEntryConsistencyCheck): (WTF::SizePolicy>::removeAndInvalidate): (WTF::SizePolicy>::remove): (WTF::SizePolicy>::removeWithoutEntryConsistencyCheck): (WTF::SizePolicy>::allocateTable): (WTF::SizePolicy>::deallocateTable): (WTF::SizePolicy>::expand): (WTF::SizePolicy>::computeBestTableSize): (WTF::SizePolicy>::shrinkToBestSize): (WTF::SizePolicy>::rehash): (WTF::SizePolicy>::clear): (WTF::SizePolicy>::RobinHoodHashTable): (WTF::SizePolicy>::swap): (WTF::=): (WTF::SizePolicy>::checkTableConsistency const): (WTF::SizePolicy>::checkTableConsistencyExceptSize const): * wtf/text/AtomStringHash.h: * wtf/text/AtomStringImpl.cpp: * wtf/text/AtomStringTable.cpp: (WTF::AtomStringTable::~AtomStringTable): * wtf/text/AtomStringTable.h: (WTF::AtomStringTable::table): * wtf/text/StringHash.h: Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/DeletedAddressOfOperator.h: * TestWebKitAPI/Tests/WTF/HashMap.cpp: (TestWebKitAPI::testMovingUsingEnsure): (TestWebKitAPI::testMovingUsingAdd): * TestWebKitAPI/Tests/WTF/HashSet.cpp: (TestWebKitAPI::generateTestCapacityUpToSize<0>): (TestWebKitAPI::generateTestCapacityUpToSize): * TestWebKitAPI/Tests/WTF/MoveOnly.h: * TestWebKitAPI/Tests/WTF/RobinHoodHashMap.cpp: Copied from Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp. (TestWebKitAPI::TEST): (TestWebKitAPI::bucketForKey): (TestWebKitAPI::ZeroHash::hash): (TestWebKitAPI::ObjectWithRefLogger::ObjectWithRefLogger): (TestWebKitAPI::testMovingUsingEnsure): (TestWebKitAPI::testMovingUsingAdd): (TestWebKitAPI::DerefObserver::ref): (TestWebKitAPI::DerefObserver::deref): (TestWebKitAPI::TestObjectWithCustomDestructor::TestObjectWithCustomDestructor): (TestWebKitAPI::TestObjectWithCustomDestructor::~TestObjectWithCustomDestructor): * TestWebKitAPI/Tests/WTF/RobinHoodHashSet.cpp: Copied from Tools/TestWebKitAPI/Tests/WTF/HashSet.cpp. (TestWebKitAPI::capacityForSize): (TestWebKitAPI::testInitialCapacity): (TestWebKitAPI::generateTestCapacityUpToSize<0>): (TestWebKitAPI::generateTestCapacityUpToSize): (TestWebKitAPI::TEST): (TestWebKitAPI::DerefObserver::ref): (TestWebKitAPI::DerefObserver::deref): Canonical link: https://commits.webkit.org/236073@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@275410 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2021-04-02 08:33:32 +00:00
unsigned index = desiredIndex(hash, sizeMask);
unsigned distance = 0;
ValueType* entry = nullptr;
while (true) {
entry = m_table + index;
if (isEmptyBucket(*entry)) {
if (distance >= probeDistanceThreshold)
m_willExpand = true;
HashTranslator::translate(*entry, std::forward<T>(key), std::forward<Extra>(extra), originalHash);
[WTF] Introduce RobinHoodHashTable https://bugs.webkit.org/show_bug.cgi?id=223895 Reviewed by Fil Pizlo. Source/JavaScriptCore: * builtins/BuiltinNames.cpp: (JSC::lookUpPrivateNameImpl): (JSC::lookUpWellKnownSymbolImpl): * builtins/BuiltinNames.h: * bytecode/BytecodeIntrinsicRegistry.h: * runtime/Identifier.h: * runtime/IntlCollator.cpp: (JSC::IntlCollator::initializeCollator): (JSC::IntlCollator::checkICULocaleInvariants): * runtime/IntlCollator.h: * runtime/IntlDateTimeFormat.cpp: (JSC::IntlDateTimeFormat::initializeDateTimeFormat): * runtime/IntlDateTimeFormatConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/IntlDisplayNames.cpp: (JSC::IntlDisplayNames::initializeDisplayNames): * runtime/IntlDisplayNamesConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/IntlListFormat.cpp: (JSC::IntlListFormat::initializeListFormat): * runtime/IntlListFormatConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/IntlNumberFormat.cpp: (JSC::IntlNumberFormat::initializeNumberFormat): * runtime/IntlNumberFormatConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/IntlObject.cpp: (JSC::addScriptlessLocaleIfNeeded): (JSC::intlAvailableLocales): (JSC::intlCollatorAvailableLocales): (JSC::intlSegmenterAvailableLocales): (JSC::bestAvailableLocale): (JSC::lookupMatcher): (JSC::bestFitMatcher): (JSC::resolveLocale): (JSC::lookupSupportedLocales): (JSC::bestFitSupportedLocales): (JSC::supportedLocales): * runtime/IntlObject.h: (JSC::intlDateTimeFormatAvailableLocales): (JSC::intlDisplayNamesAvailableLocales): (JSC::intlNumberFormatAvailableLocales): (JSC::intlPluralRulesAvailableLocales): (JSC::intlRelativeTimeFormatAvailableLocales): (JSC::intlListFormatAvailableLocales): * runtime/IntlPluralRules.cpp: (JSC::IntlPluralRules::initializePluralRules): * runtime/IntlPluralRulesConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/IntlRelativeTimeFormat.cpp: (JSC::IntlRelativeTimeFormat::initializeRelativeTimeFormat): * runtime/IntlRelativeTimeFormatConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/IntlSegmenter.cpp: (JSC::IntlSegmenter::initializeSegmenter): * runtime/IntlSegmenterConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/RegExpCache.h: * runtime/RegExpKey.h: Source/WebCore: * Modules/mediacapabilities/MediaCapabilities.cpp: (WebCore::bucketMIMETypes): * accessibility/AccessibilityObject.cpp: (WebCore::AccessibilityObject::popupValue const): * dom/Element.cpp: (WebCore::canAttachAuthorShadowRoot): * dom/QualifiedName.h: * dom/make_names.pl: (printNamesHeaderFile): (printFactoryCppFile): (printWrapperFactoryCppFile): * editing/FormatBlockCommand.cpp: (WebCore::isElementForFormatBlock): * editing/RemoveFormatCommand.cpp: (WebCore::isElementForRemoveFormatCommand): * editing/ReplaceSelectionCommand.cpp: (WebCore::isProhibitedParagraphChild): * html/Autofill.cpp: (WebCore::fieldNameMap): * html/HTMLDocument.cpp: (WebCore::HTMLDocument::isCaseSensitiveAttribute): * html/HTMLObjectElement.cpp: (WebCore::preventsParentObjectFromExposure): * html/parser/HTMLTreeBuilder.cpp: (WebCore::createCaseMap): (WebCore::adjustSVGTagNameCase): (WebCore::adjustAttributes): (WebCore::createForeignAttributesMap): (WebCore::adjustForeignAttributes): (WebCore::addNamesWithPrefix): Deleted. * page/DebugPageOverlays.cpp: (WebCore::touchEventRegionColors): (WebCore::NonFastScrollableRegionOverlay::drawRect): * page/PerformanceUserTiming.cpp: (WebCore::restrictedMarkNamesToNavigationTimingFunctionMap): * platform/cocoa/MIMETypeRegistryCocoa.mm: (WebCore::extensionsForMIMETypeMap): * platform/graphics/FontCascade.cpp: (WebCore::useBackslashAsYenSignForFamily): (WebCore::FontCascade::hasValidAverageCharWidth const): * platform/graphics/avfoundation/CDMFairPlayStreaming.cpp: (WebCore::validInitDataTypes): * platform/graphics/cg/UTIRegistry.cpp: (WebCore::defaultSupportedImageTypes): * platform/graphics/cg/UTIRegistry.h: * platform/graphics/cocoa/HEVCUtilitiesCocoa.mm: (WebCore::codecTypeForDoViCodecString): * platform/graphics/cocoa/SourceBufferParserWebM.cpp: (WebCore::SourceBufferParserWebM::supportedVideoCodecs): (WebCore::SourceBufferParserWebM::supportedAudioCodecs): * platform/graphics/cocoa/SourceBufferParserWebM.h: * rendering/svg/SVGResources.cpp: (WebCore::clipperFilterMaskerTags): (WebCore::markerTags): (WebCore::fillAndStrokeTags): (WebCore::chainableResourceTags): * style/StyleAdjuster.cpp: (WebCore::Style::hasEffectiveDisplayNoneForDisplayContents): * svg/SVGAnimationElement.cpp: (WebCore::SVGAnimationElement::isSupportedAttribute): * svg/SVGElement.cpp: (WebCore::createAttributeNameToCSSPropertyIDMap): (WebCore::SVGElement::animatableAttributeForName): (WebCore::SVGElement::cssPropertyIdForSVGAttributeName): * svg/SVGTests.cpp: (WebCore::SVGTests::addSupportedAttributes): * svg/SVGTests.h: * svg/SVGUseElement.cpp: (WebCore::createAllowedElementSet): (WebCore::isDisallowedElement): * svg/animation/SVGSMILElement.cpp: (WebCore::SVGSMILElement::isSupportedAttribute): * xml/XPathFunctions.cpp: (WebCore::XPath::createFunctionMap): * xml/XPathParser.cpp: (WebCore::XPath::createAxisNamesMap): Source/WebKit: * NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp: (WebKit::ObservedDomainsTableSchemaV1Alternate): (WebKit::expectedUnattributedColumns): (WebKit::expectedAttributedColumns): (WebKit::createTableQueries): * Platform/IPC/ArgumentCoders.h: * Shared/Cocoa/DefaultWebBrowserChecks.mm: (WebKit::getAppBoundDomainsTesting): * Shared/WebPreferencesStore.cpp: (WebKit::WebPreferencesStore::decode): * Shared/WebPreferencesStore.h: * UIProcess/Cocoa/WebProcessProxyCocoa.mm: (WebKit::WebProcessProxy::platformPathsWithAssumedReadAccess): * UIProcess/WebProcessProxy.cpp: (WebKit::WebProcessProxy::platformPathsWithAssumedReadAccess): * UIProcess/WebProcessProxy.h: Source/WTF: This patch implements RobinHoodHashTable[1]. We don't use it as a default hashtable since it has different performance v.s. memory-saving characteristics, and this patch's goal is not tackling on making this default. Rather, the goal of this patch is introducing it to non-performance sensitive area quickly so that we can save memory. RobinHoodHashTable more frequently computes hash value compared to HashTable, so this is not drop-in replacement for the existing one. But still, this is useful since we know that "while there are many small HashTables and they holds much memory, there are super large HashTables and they holds almost same amount of memory while they are a few.". This patch's goal is applying this RobinHoodHashTable to these "large, but a few" singleton tables. RobinHoodHashTable maintains distance-from-initial-bucket (DIB) small by adjusting existing entries when inserting. When inserting, if we found that the existing entry has less DIB than the current inserting entry's DIB, then we swap entries, and insert the existing entry to the other place. This is giving some good DIB from rich entry to poor entry (that's why it is called RobinHood Hashing), and making average DIB lower. And this algorithm adds good invariant that, when looking up an entry, and we found that existing entry has smaller DIB, then we can stop searching in the middle of the chain since we know that we should swap entries when this happened when inserting. These two tricks maintain HashTable performance even under significantly high load factor: 90% load-factor just works. 95% load-factor regress adding performance, but still it does not become catastrophic compared to normal open-addressing HashTable. We introduce RobinHoodHashTable, and adding several kinds of tables based on load-factors. 1. MemoryCompactLookupOnlyRobinHoodHashSet / HashMap This has 95% load-factor. This is suitable for sets and maps which is mostly-constant: constructing once, and looking up repeatedly. In WebKit, there are so many this kind of tables e.g. singleton HashMap for various kinds of things. We can use this super high load-factor table so that we can save memory even while we are maintains fast HashTable lookup. 2. MemoryCompactRobinHoodHashSet / HashMap This has 90% load-factor. It just works, and we can try using it if sets and maps are significantly performance intensive. 3. FastRobinHoodHashSet / HashMap This has 75% load-factor. This is still good compared to HashSet and HashMap since they are using 50% load-factor for large sized tables. This has very slightly performance regressed compared to 50% load-factor large HashSet and HashMap, but if that is not performance intensive (e.g. AtomStringTable is one of the most performance intensive table), this is good. In this patch, we replace many singleton HashSet / HashMap with RobinHoodHashTable. [1]: https://www.sebastiansylvan.com/post/robin-hood-hashing-should-be-your-default-hash-table-implementation/ * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Forward.h: * wtf/HashMap.h: (WTF::Y>::swap): (WTF::Y>::size const): (WTF::Y>::capacity const): (WTF::Y>::isEmpty const): (WTF::Y>::begin): (WTF::Y>::end): (WTF::Y>::begin const): (WTF::Y>::end const): (WTF::Y>::find): (WTF::Y>::find const): (WTF::Y>::contains const): (WTF::Y>::get const): (WTF::Y>::inlineGet const): (WTF::TableTraitsArg>::inlineSet): (WTF::TableTraitsArg>::inlineAdd): (WTF::TableTraitsArg>::inlineEnsure): (WTF::TableTraitsArg>::set): (WTF::TableTraitsArg>::add): (WTF::TableTraitsArg>::fastAdd): (WTF::TableTraitsArg>::ensure): (WTF::Y>::remove): (WTF::Y>::removeIf): (WTF::Y>::clear): (WTF::Y>::take): (WTF::Y>::checkConsistency const): (WTF::Y>::isValidKey): (WTF::operator==): (WTF::operator!=): (WTF::X>::swap): Deleted. (WTF::X>::size const): Deleted. (WTF::X>::capacity const): Deleted. (WTF::X>::isEmpty const): Deleted. (WTF::X>::begin): Deleted. (WTF::X>::end): Deleted. (WTF::X>::begin const): Deleted. (WTF::X>::end const): Deleted. (WTF::X>::find): Deleted. (WTF::X>::find const): Deleted. (WTF::X>::contains const): Deleted. (WTF::X>::get const): Deleted. (WTF::X>::inlineGet const): Deleted. (WTF::MappedTraitsArg>::inlineSet): Deleted. (WTF::MappedTraitsArg>::inlineAdd): Deleted. (WTF::MappedTraitsArg>::inlineEnsure): Deleted. (WTF::MappedTraitsArg>::set): Deleted. (WTF::MappedTraitsArg>::add): Deleted. (WTF::MappedTraitsArg>::fastAdd): Deleted. (WTF::MappedTraitsArg>::ensure): Deleted. (WTF::MappedTraits>::get const): Deleted. (WTF::MappedTraits>::inlineGet const): Deleted. (WTF::X>::remove): Deleted. (WTF::X>::removeIf): Deleted. (WTF::X>::clear): Deleted. (WTF::MappedTraits>::take): Deleted. (WTF::X>::take): Deleted. (WTF::X>::checkConsistency const): Deleted. (WTF::X>::isValidKey): Deleted. * wtf/HashSet.h: (WTF::W>::swap): (WTF::W>::size const): (WTF::W>::capacity const): (WTF::W>::isEmpty const): (WTF::W>::begin const): (WTF::W>::end const): (WTF::W>::find const): (WTF::W>::contains const): (WTF::TableTraits>::find const): (WTF::TableTraits>::contains const): (WTF::TableTraits>::ensure): (WTF::W>::add): (WTF::W>::addVoid): (WTF::TableTraits>::add): (WTF::W>::remove): (WTF::W>::removeIf): (WTF::W>::clear): (WTF::W>::take): (WTF::W>::takeAny): (WTF::TableTraits>::remove): (WTF::TableTraits>::take): (WTF::W>::isValidValue): (WTF::= const): (WTF::W>::checkConsistency const): (WTF::V>::swap): Deleted. (WTF::V>::size const): Deleted. (WTF::V>::capacity const): Deleted. (WTF::V>::isEmpty const): Deleted. (WTF::V>::begin const): Deleted. (WTF::V>::end const): Deleted. (WTF::V>::find const): Deleted. (WTF::V>::contains const): Deleted. (WTF::Traits>::find const): Deleted. (WTF::Traits>::contains const): Deleted. (WTF::Traits>::ensure): Deleted. (WTF::V>::add): Deleted. (WTF::V>::addVoid): Deleted. (WTF::Traits>::add): Deleted. (WTF::V>::remove): Deleted. (WTF::V>::removeIf): Deleted. (WTF::V>::clear): Deleted. (WTF::V>::take): Deleted. (WTF::V>::takeAny): Deleted. (WTF::Traits>::remove): Deleted. (WTF::Traits>::take): Deleted. (WTF::V>::isValidValue): Deleted. (WTF::V>::checkConsistency const): Deleted. * wtf/HashTable.h: (WTF::addIterator): (WTF::removeIterator): (WTF::invalidateIterators): (WTF::HashTable::~HashTable): (WTF::HashTable::random): (WTF::KeyTraits>::inlineLookup): (WTF::KeyTraits>::lookupForWriting): (WTF::KeyTraits>::fullLookupForWriting): (WTF::KeyTraits>::addUniqueForInitialization): (WTF::KeyTraits>::add): (WTF::KeyTraits>::addPassingHashCode): (WTF::KeyTraits>::removeAndInvalidateWithoutEntryConsistencyCheck): (WTF::KeyTraits>::removeAndInvalidate): (WTF::KeyTraits>::clear): (WTF::KeyTraits>::swap): (WTF::KeyTraits>::HashTable): (WTF::HashTable::invalidateIterators): Deleted. (WTF::KeyTraits>::invalidateIterators): Deleted. * wtf/RobinHoodHashMap.h: Added. * wtf/RobinHoodHashSet.h: Added. * wtf/RobinHoodHashTable.h: Added. (WTF::RobinHoodHashTable::~RobinHoodHashTable): (WTF::RobinHoodHashTable::begin): (WTF::RobinHoodHashTable::end): (WTF::RobinHoodHashTable::begin const): (WTF::RobinHoodHashTable::end const): (WTF::RobinHoodHashTable::random): (WTF::RobinHoodHashTable::random const): (WTF::RobinHoodHashTable::size const): (WTF::RobinHoodHashTable::capacity const): (WTF::RobinHoodHashTable::isEmpty const): (WTF::RobinHoodHashTable::reserveInitialCapacity): (WTF::RobinHoodHashTable::add): (WTF::RobinHoodHashTable::find): (WTF::RobinHoodHashTable::find const): (WTF::RobinHoodHashTable::contains const): (WTF::RobinHoodHashTable::isEmptyBucket): (WTF::RobinHoodHashTable::isEmptyOrDeletedBucket): (WTF::RobinHoodHashTable::lookup): (WTF::RobinHoodHashTable::checkTableConsistency): (WTF::RobinHoodHashTable::internalCheckTableConsistency const): (WTF::RobinHoodHashTable::internalCheckTableConsistencyExceptSize const): (WTF::RobinHoodHashTable::internalCheckTableConsistencyExceptSize): (WTF::RobinHoodHashTable::internalCheckTableConsistency): (WTF::RobinHoodHashTable::shouldExpand): (WTF::RobinHoodHashTable::computeTableHash): (WTF::RobinHoodHashTable::shouldExpand const): (WTF::RobinHoodHashTable::shouldShrink const): (WTF::RobinHoodHashTable::shrink): (WTF::RobinHoodHashTable::deleteBucket): (WTF::RobinHoodHashTable::desiredIndex): (WTF::RobinHoodHashTable::probeDistance): (WTF::RobinHoodHashTable::makeIterator): (WTF::RobinHoodHashTable::makeConstIterator const): (WTF::RobinHoodHashTable::makeKnownGoodIterator): (WTF::RobinHoodHashTable::makeKnownGoodConstIterator const): (WTF::RobinHoodHashTable::checkTableConsistencyExceptSize): (WTF::RobinHoodHashTable::tableSize const): (WTF::RobinHoodHashTable::tableSizeMask const): (WTF::RobinHoodHashTable::keyCount const): (WTF::RobinHoodHashTable::tableHash const): (WTF::SizePolicy>::checkKey): (WTF::SizePolicy>::lookup): (WTF::SizePolicy>::inlineLookup): (WTF::SizePolicy>::initializeBucket): (WTF::SizePolicy>::add): (WTF::SizePolicy>::maintainProbeDistanceForAdd): (WTF::SizePolicy>::addPassingHashCode): (WTF::SizePolicy>::reinsert): (WTF::SizePolicy>::find): (WTF::SizePolicy>::find const): (WTF::SizePolicy>::contains const): (WTF::SizePolicy>::removeAndInvalidateWithoutEntryConsistencyCheck): (WTF::SizePolicy>::removeAndInvalidate): (WTF::SizePolicy>::remove): (WTF::SizePolicy>::removeWithoutEntryConsistencyCheck): (WTF::SizePolicy>::allocateTable): (WTF::SizePolicy>::deallocateTable): (WTF::SizePolicy>::expand): (WTF::SizePolicy>::computeBestTableSize): (WTF::SizePolicy>::shrinkToBestSize): (WTF::SizePolicy>::rehash): (WTF::SizePolicy>::clear): (WTF::SizePolicy>::RobinHoodHashTable): (WTF::SizePolicy>::swap): (WTF::=): (WTF::SizePolicy>::checkTableConsistency const): (WTF::SizePolicy>::checkTableConsistencyExceptSize const): * wtf/text/AtomStringHash.h: * wtf/text/AtomStringImpl.cpp: * wtf/text/AtomStringTable.cpp: (WTF::AtomStringTable::~AtomStringTable): * wtf/text/AtomStringTable.h: (WTF::AtomStringTable::table): * wtf/text/StringHash.h: Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/DeletedAddressOfOperator.h: * TestWebKitAPI/Tests/WTF/HashMap.cpp: (TestWebKitAPI::testMovingUsingEnsure): (TestWebKitAPI::testMovingUsingAdd): * TestWebKitAPI/Tests/WTF/HashSet.cpp: (TestWebKitAPI::generateTestCapacityUpToSize<0>): (TestWebKitAPI::generateTestCapacityUpToSize): * TestWebKitAPI/Tests/WTF/MoveOnly.h: * TestWebKitAPI/Tests/WTF/RobinHoodHashMap.cpp: Copied from Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp. (TestWebKitAPI::TEST): (TestWebKitAPI::bucketForKey): (TestWebKitAPI::ZeroHash::hash): (TestWebKitAPI::ObjectWithRefLogger::ObjectWithRefLogger): (TestWebKitAPI::testMovingUsingEnsure): (TestWebKitAPI::testMovingUsingAdd): (TestWebKitAPI::DerefObserver::ref): (TestWebKitAPI::DerefObserver::deref): (TestWebKitAPI::TestObjectWithCustomDestructor::TestObjectWithCustomDestructor): (TestWebKitAPI::TestObjectWithCustomDestructor::~TestObjectWithCustomDestructor): * TestWebKitAPI/Tests/WTF/RobinHoodHashSet.cpp: Copied from Tools/TestWebKitAPI/Tests/WTF/HashSet.cpp. (TestWebKitAPI::capacityForSize): (TestWebKitAPI::testInitialCapacity): (TestWebKitAPI::generateTestCapacityUpToSize<0>): (TestWebKitAPI::generateTestCapacityUpToSize): (TestWebKitAPI::TEST): (TestWebKitAPI::DerefObserver::ref): (TestWebKitAPI::DerefObserver::deref): Canonical link: https://commits.webkit.org/236073@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@275410 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2021-04-02 08:33:32 +00:00
break;
}
auto& entryKey = Extractor::extract(*entry);
unsigned entryHash = IdentityTranslatorType::hash(entryKey) ^ tableHash;
unsigned entryDistance = probeDistance(entryHash, index, size, sizeMask);
if (distance > entryDistance) {
if (distance >= probeDistanceThreshold)
m_willExpand = true;
// Start swapping existing entry to maintain probe-distance invariant.
ValueType existingEntry = WTFMove(*entry);
entry->~ValueType();
initializeBucket(*entry);
HashTranslator::translate(*entry, std::forward<T>(key), std::forward<Extra>(extra), originalHash);
[WTF] Introduce RobinHoodHashTable https://bugs.webkit.org/show_bug.cgi?id=223895 Reviewed by Fil Pizlo. Source/JavaScriptCore: * builtins/BuiltinNames.cpp: (JSC::lookUpPrivateNameImpl): (JSC::lookUpWellKnownSymbolImpl): * builtins/BuiltinNames.h: * bytecode/BytecodeIntrinsicRegistry.h: * runtime/Identifier.h: * runtime/IntlCollator.cpp: (JSC::IntlCollator::initializeCollator): (JSC::IntlCollator::checkICULocaleInvariants): * runtime/IntlCollator.h: * runtime/IntlDateTimeFormat.cpp: (JSC::IntlDateTimeFormat::initializeDateTimeFormat): * runtime/IntlDateTimeFormatConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/IntlDisplayNames.cpp: (JSC::IntlDisplayNames::initializeDisplayNames): * runtime/IntlDisplayNamesConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/IntlListFormat.cpp: (JSC::IntlListFormat::initializeListFormat): * runtime/IntlListFormatConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/IntlNumberFormat.cpp: (JSC::IntlNumberFormat::initializeNumberFormat): * runtime/IntlNumberFormatConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/IntlObject.cpp: (JSC::addScriptlessLocaleIfNeeded): (JSC::intlAvailableLocales): (JSC::intlCollatorAvailableLocales): (JSC::intlSegmenterAvailableLocales): (JSC::bestAvailableLocale): (JSC::lookupMatcher): (JSC::bestFitMatcher): (JSC::resolveLocale): (JSC::lookupSupportedLocales): (JSC::bestFitSupportedLocales): (JSC::supportedLocales): * runtime/IntlObject.h: (JSC::intlDateTimeFormatAvailableLocales): (JSC::intlDisplayNamesAvailableLocales): (JSC::intlNumberFormatAvailableLocales): (JSC::intlPluralRulesAvailableLocales): (JSC::intlRelativeTimeFormatAvailableLocales): (JSC::intlListFormatAvailableLocales): * runtime/IntlPluralRules.cpp: (JSC::IntlPluralRules::initializePluralRules): * runtime/IntlPluralRulesConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/IntlRelativeTimeFormat.cpp: (JSC::IntlRelativeTimeFormat::initializeRelativeTimeFormat): * runtime/IntlRelativeTimeFormatConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/IntlSegmenter.cpp: (JSC::IntlSegmenter::initializeSegmenter): * runtime/IntlSegmenterConstructor.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): * runtime/RegExpCache.h: * runtime/RegExpKey.h: Source/WebCore: * Modules/mediacapabilities/MediaCapabilities.cpp: (WebCore::bucketMIMETypes): * accessibility/AccessibilityObject.cpp: (WebCore::AccessibilityObject::popupValue const): * dom/Element.cpp: (WebCore::canAttachAuthorShadowRoot): * dom/QualifiedName.h: * dom/make_names.pl: (printNamesHeaderFile): (printFactoryCppFile): (printWrapperFactoryCppFile): * editing/FormatBlockCommand.cpp: (WebCore::isElementForFormatBlock): * editing/RemoveFormatCommand.cpp: (WebCore::isElementForRemoveFormatCommand): * editing/ReplaceSelectionCommand.cpp: (WebCore::isProhibitedParagraphChild): * html/Autofill.cpp: (WebCore::fieldNameMap): * html/HTMLDocument.cpp: (WebCore::HTMLDocument::isCaseSensitiveAttribute): * html/HTMLObjectElement.cpp: (WebCore::preventsParentObjectFromExposure): * html/parser/HTMLTreeBuilder.cpp: (WebCore::createCaseMap): (WebCore::adjustSVGTagNameCase): (WebCore::adjustAttributes): (WebCore::createForeignAttributesMap): (WebCore::adjustForeignAttributes): (WebCore::addNamesWithPrefix): Deleted. * page/DebugPageOverlays.cpp: (WebCore::touchEventRegionColors): (WebCore::NonFastScrollableRegionOverlay::drawRect): * page/PerformanceUserTiming.cpp: (WebCore::restrictedMarkNamesToNavigationTimingFunctionMap): * platform/cocoa/MIMETypeRegistryCocoa.mm: (WebCore::extensionsForMIMETypeMap): * platform/graphics/FontCascade.cpp: (WebCore::useBackslashAsYenSignForFamily): (WebCore::FontCascade::hasValidAverageCharWidth const): * platform/graphics/avfoundation/CDMFairPlayStreaming.cpp: (WebCore::validInitDataTypes): * platform/graphics/cg/UTIRegistry.cpp: (WebCore::defaultSupportedImageTypes): * platform/graphics/cg/UTIRegistry.h: * platform/graphics/cocoa/HEVCUtilitiesCocoa.mm: (WebCore::codecTypeForDoViCodecString): * platform/graphics/cocoa/SourceBufferParserWebM.cpp: (WebCore::SourceBufferParserWebM::supportedVideoCodecs): (WebCore::SourceBufferParserWebM::supportedAudioCodecs): * platform/graphics/cocoa/SourceBufferParserWebM.h: * rendering/svg/SVGResources.cpp: (WebCore::clipperFilterMaskerTags): (WebCore::markerTags): (WebCore::fillAndStrokeTags): (WebCore::chainableResourceTags): * style/StyleAdjuster.cpp: (WebCore::Style::hasEffectiveDisplayNoneForDisplayContents): * svg/SVGAnimationElement.cpp: (WebCore::SVGAnimationElement::isSupportedAttribute): * svg/SVGElement.cpp: (WebCore::createAttributeNameToCSSPropertyIDMap): (WebCore::SVGElement::animatableAttributeForName): (WebCore::SVGElement::cssPropertyIdForSVGAttributeName): * svg/SVGTests.cpp: (WebCore::SVGTests::addSupportedAttributes): * svg/SVGTests.h: * svg/SVGUseElement.cpp: (WebCore::createAllowedElementSet): (WebCore::isDisallowedElement): * svg/animation/SVGSMILElement.cpp: (WebCore::SVGSMILElement::isSupportedAttribute): * xml/XPathFunctions.cpp: (WebCore::XPath::createFunctionMap): * xml/XPathParser.cpp: (WebCore::XPath::createAxisNamesMap): Source/WebKit: * NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp: (WebKit::ObservedDomainsTableSchemaV1Alternate): (WebKit::expectedUnattributedColumns): (WebKit::expectedAttributedColumns): (WebKit::createTableQueries): * Platform/IPC/ArgumentCoders.h: * Shared/Cocoa/DefaultWebBrowserChecks.mm: (WebKit::getAppBoundDomainsTesting): * Shared/WebPreferencesStore.cpp: (WebKit::WebPreferencesStore::decode): * Shared/WebPreferencesStore.h: * UIProcess/Cocoa/WebProcessProxyCocoa.mm: (WebKit::WebProcessProxy::platformPathsWithAssumedReadAccess): * UIProcess/WebProcessProxy.cpp: (WebKit::WebProcessProxy::platformPathsWithAssumedReadAccess): * UIProcess/WebProcessProxy.h: Source/WTF: This patch implements RobinHoodHashTable[1]. We don't use it as a default hashtable since it has different performance v.s. memory-saving characteristics, and this patch's goal is not tackling on making this default. Rather, the goal of this patch is introducing it to non-performance sensitive area quickly so that we can save memory. RobinHoodHashTable more frequently computes hash value compared to HashTable, so this is not drop-in replacement for the existing one. But still, this is useful since we know that "while there are many small HashTables and they holds much memory, there are super large HashTables and they holds almost same amount of memory while they are a few.". This patch's goal is applying this RobinHoodHashTable to these "large, but a few" singleton tables. RobinHoodHashTable maintains distance-from-initial-bucket (DIB) small by adjusting existing entries when inserting. When inserting, if we found that the existing entry has less DIB than the current inserting entry's DIB, then we swap entries, and insert the existing entry to the other place. This is giving some good DIB from rich entry to poor entry (that's why it is called RobinHood Hashing), and making average DIB lower. And this algorithm adds good invariant that, when looking up an entry, and we found that existing entry has smaller DIB, then we can stop searching in the middle of the chain since we know that we should swap entries when this happened when inserting. These two tricks maintain HashTable performance even under significantly high load factor: 90% load-factor just works. 95% load-factor regress adding performance, but still it does not become catastrophic compared to normal open-addressing HashTable. We introduce RobinHoodHashTable, and adding several kinds of tables based on load-factors. 1. MemoryCompactLookupOnlyRobinHoodHashSet / HashMap This has 95% load-factor. This is suitable for sets and maps which is mostly-constant: constructing once, and looking up repeatedly. In WebKit, there are so many this kind of tables e.g. singleton HashMap for various kinds of things. We can use this super high load-factor table so that we can save memory even while we are maintains fast HashTable lookup. 2. MemoryCompactRobinHoodHashSet / HashMap This has 90% load-factor. It just works, and we can try using it if sets and maps are significantly performance intensive. 3. FastRobinHoodHashSet / HashMap This has 75% load-factor. This is still good compared to HashSet and HashMap since they are using 50% load-factor for large sized tables. This has very slightly performance regressed compared to 50% load-factor large HashSet and HashMap, but if that is not performance intensive (e.g. AtomStringTable is one of the most performance intensive table), this is good. In this patch, we replace many singleton HashSet / HashMap with RobinHoodHashTable. [1]: https://www.sebastiansylvan.com/post/robin-hood-hashing-should-be-your-default-hash-table-implementation/ * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/Forward.h: * wtf/HashMap.h: (WTF::Y>::swap): (WTF::Y>::size const): (WTF::Y>::capacity const): (WTF::Y>::isEmpty const): (WTF::Y>::begin): (WTF::Y>::end): (WTF::Y>::begin const): (WTF::Y>::end const): (WTF::Y>::find): (WTF::Y>::find const): (WTF::Y>::contains const): (WTF::Y>::get const): (WTF::Y>::inlineGet const): (WTF::TableTraitsArg>::inlineSet): (WTF::TableTraitsArg>::inlineAdd): (WTF::TableTraitsArg>::inlineEnsure): (WTF::TableTraitsArg>::set): (WTF::TableTraitsArg>::add): (WTF::TableTraitsArg>::fastAdd): (WTF::TableTraitsArg>::ensure): (WTF::Y>::remove): (WTF::Y>::removeIf): (WTF::Y>::clear): (WTF::Y>::take): (WTF::Y>::checkConsistency const): (WTF::Y>::isValidKey): (WTF::operator==): (WTF::operator!=): (WTF::X>::swap): Deleted. (WTF::X>::size const): Deleted. (WTF::X>::capacity const): Deleted. (WTF::X>::isEmpty const): Deleted. (WTF::X>::begin): Deleted. (WTF::X>::end): Deleted. (WTF::X>::begin const): Deleted. (WTF::X>::end const): Deleted. (WTF::X>::find): Deleted. (WTF::X>::find const): Deleted. (WTF::X>::contains const): Deleted. (WTF::X>::get const): Deleted. (WTF::X>::inlineGet const): Deleted. (WTF::MappedTraitsArg>::inlineSet): Deleted. (WTF::MappedTraitsArg>::inlineAdd): Deleted. (WTF::MappedTraitsArg>::inlineEnsure): Deleted. (WTF::MappedTraitsArg>::set): Deleted. (WTF::MappedTraitsArg>::add): Deleted. (WTF::MappedTraitsArg>::fastAdd): Deleted. (WTF::MappedTraitsArg>::ensure): Deleted. (WTF::MappedTraits>::get const): Deleted. (WTF::MappedTraits>::inlineGet const): Deleted. (WTF::X>::remove): Deleted. (WTF::X>::removeIf): Deleted. (WTF::X>::clear): Deleted. (WTF::MappedTraits>::take): Deleted. (WTF::X>::take): Deleted. (WTF::X>::checkConsistency const): Deleted. (WTF::X>::isValidKey): Deleted. * wtf/HashSet.h: (WTF::W>::swap): (WTF::W>::size const): (WTF::W>::capacity const): (WTF::W>::isEmpty const): (WTF::W>::begin const): (WTF::W>::end const): (WTF::W>::find const): (WTF::W>::contains const): (WTF::TableTraits>::find const): (WTF::TableTraits>::contains const): (WTF::TableTraits>::ensure): (WTF::W>::add): (WTF::W>::addVoid): (WTF::TableTraits>::add): (WTF::W>::remove): (WTF::W>::removeIf): (WTF::W>::clear): (WTF::W>::take): (WTF::W>::takeAny): (WTF::TableTraits>::remove): (WTF::TableTraits>::take): (WTF::W>::isValidValue): (WTF::= const): (WTF::W>::checkConsistency const): (WTF::V>::swap): Deleted. (WTF::V>::size const): Deleted. (WTF::V>::capacity const): Deleted. (WTF::V>::isEmpty const): Deleted. (WTF::V>::begin const): Deleted. (WTF::V>::end const): Deleted. (WTF::V>::find const): Deleted. (WTF::V>::contains const): Deleted. (WTF::Traits>::find const): Deleted. (WTF::Traits>::contains const): Deleted. (WTF::Traits>::ensure): Deleted. (WTF::V>::add): Deleted. (WTF::V>::addVoid): Deleted. (WTF::Traits>::add): Deleted. (WTF::V>::remove): Deleted. (WTF::V>::removeIf): Deleted. (WTF::V>::clear): Deleted. (WTF::V>::take): Deleted. (WTF::V>::takeAny): Deleted. (WTF::Traits>::remove): Deleted. (WTF::Traits>::take): Deleted. (WTF::V>::isValidValue): Deleted. (WTF::V>::checkConsistency const): Deleted. * wtf/HashTable.h: (WTF::addIterator): (WTF::removeIterator): (WTF::invalidateIterators): (WTF::HashTable::~HashTable): (WTF::HashTable::random): (WTF::KeyTraits>::inlineLookup): (WTF::KeyTraits>::lookupForWriting): (WTF::KeyTraits>::fullLookupForWriting): (WTF::KeyTraits>::addUniqueForInitialization): (WTF::KeyTraits>::add): (WTF::KeyTraits>::addPassingHashCode): (WTF::KeyTraits>::removeAndInvalidateWithoutEntryConsistencyCheck): (WTF::KeyTraits>::removeAndInvalidate): (WTF::KeyTraits>::clear): (WTF::KeyTraits>::swap): (WTF::KeyTraits>::HashTable): (WTF::HashTable::invalidateIterators): Deleted. (WTF::KeyTraits>::invalidateIterators): Deleted. * wtf/RobinHoodHashMap.h: Added. * wtf/RobinHoodHashSet.h: Added. * wtf/RobinHoodHashTable.h: Added. (WTF::RobinHoodHashTable::~RobinHoodHashTable): (WTF::RobinHoodHashTable::begin): (WTF::RobinHoodHashTable::end): (WTF::RobinHoodHashTable::begin const): (WTF::RobinHoodHashTable::end const): (WTF::RobinHoodHashTable::random): (WTF::RobinHoodHashTable::random const): (WTF::RobinHoodHashTable::size const): (WTF::RobinHoodHashTable::capacity const): (WTF::RobinHoodHashTable::isEmpty const): (WTF::RobinHoodHashTable::reserveInitialCapacity): (WTF::RobinHoodHashTable::add): (WTF::RobinHoodHashTable::find): (WTF::RobinHoodHashTable::find const): (WTF::RobinHoodHashTable::contains const): (WTF::RobinHoodHashTable::isEmptyBucket): (WTF::RobinHoodHashTable::isEmptyOrDeletedBucket): (WTF::RobinHoodHashTable::lookup): (WTF::RobinHoodHashTable::checkTableConsistency): (WTF::RobinHoodHashTable::internalCheckTableConsistency const): (WTF::RobinHoodHashTable::internalCheckTableConsistencyExceptSize const): (WTF::RobinHoodHashTable::internalCheckTableConsistencyExceptSize): (WTF::RobinHoodHashTable::internalCheckTableConsistency): (WTF::RobinHoodHashTable::shouldExpand): (WTF::RobinHoodHashTable::computeTableHash): (WTF::RobinHoodHashTable::shouldExpand const): (WTF::RobinHoodHashTable::shouldShrink const): (WTF::RobinHoodHashTable::shrink): (WTF::RobinHoodHashTable::deleteBucket): (WTF::RobinHoodHashTable::desiredIndex): (WTF::RobinHoodHashTable::probeDistance): (WTF::RobinHoodHashTable::makeIterator): (WTF::RobinHoodHashTable::makeConstIterator const): (WTF::RobinHoodHashTable::makeKnownGoodIterator): (WTF::RobinHoodHashTable::makeKnownGoodConstIterator const): (WTF::RobinHoodHashTable::checkTableConsistencyExceptSize): (WTF::RobinHoodHashTable::tableSize const): (WTF::RobinHoodHashTable::tableSizeMask const): (WTF::RobinHoodHashTable::keyCount const): (WTF::RobinHoodHashTable::tableHash const): (WTF::SizePolicy>::checkKey): (WTF::SizePolicy>::lookup): (WTF::SizePolicy>::inlineLookup): (WTF::SizePolicy>::initializeBucket): (WTF::SizePolicy>::add): (WTF::SizePolicy>::maintainProbeDistanceForAdd): (WTF::SizePolicy>::addPassingHashCode): (WTF::SizePolicy>::reinsert): (WTF::SizePolicy>::find): (WTF::SizePolicy>::find const): (WTF::SizePolicy>::contains const): (WTF::SizePolicy>::removeAndInvalidateWithoutEntryConsistencyCheck): (WTF::SizePolicy>::removeAndInvalidate): (WTF::SizePolicy>::remove): (WTF::SizePolicy>::removeWithoutEntryConsistencyCheck): (WTF::SizePolicy>::allocateTable): (WTF::SizePolicy>::deallocateTable): (WTF::SizePolicy>::expand): (WTF::SizePolicy>::computeBestTableSize): (WTF::SizePolicy>::shrinkToBestSize): (WTF::SizePolicy>::rehash): (WTF::SizePolicy>::clear): (WTF::SizePolicy>::RobinHoodHashTable): (WTF::SizePolicy>::swap): (WTF::=): (WTF::SizePolicy>::checkTableConsistency const): (WTF::SizePolicy>::checkTableConsistencyExceptSize const): * wtf/text/AtomStringHash.h: * wtf/text/AtomStringImpl.cpp: * wtf/text/AtomStringTable.cpp: (WTF::AtomStringTable::~AtomStringTable): * wtf/text/AtomStringTable.h: (WTF::AtomStringTable::table): * wtf/text/StringHash.h: Tools: * TestWebKitAPI/CMakeLists.txt: * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: * TestWebKitAPI/Tests/WTF/DeletedAddressOfOperator.h: * TestWebKitAPI/Tests/WTF/HashMap.cpp: (TestWebKitAPI::testMovingUsingEnsure): (TestWebKitAPI::testMovingUsingAdd): * TestWebKitAPI/Tests/WTF/HashSet.cpp: (TestWebKitAPI::generateTestCapacityUpToSize<0>): (TestWebKitAPI::generateTestCapacityUpToSize): * TestWebKitAPI/Tests/WTF/MoveOnly.h: * TestWebKitAPI/Tests/WTF/RobinHoodHashMap.cpp: Copied from Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp. (TestWebKitAPI::TEST): (TestWebKitAPI::bucketForKey): (TestWebKitAPI::ZeroHash::hash): (TestWebKitAPI::ObjectWithRefLogger::ObjectWithRefLogger): (TestWebKitAPI::testMovingUsingEnsure): (TestWebKitAPI::testMovingUsingAdd): (TestWebKitAPI::DerefObserver::ref): (TestWebKitAPI::DerefObserver::deref): (TestWebKitAPI::TestObjectWithCustomDestructor::TestObjectWithCustomDestructor): (TestWebKitAPI::TestObjectWithCustomDestructor::~TestObjectWithCustomDestructor): * TestWebKitAPI/Tests/WTF/RobinHoodHashSet.cpp: Copied from Tools/TestWebKitAPI/Tests/WTF/HashSet.cpp. (TestWebKitAPI::capacityForSize): (TestWebKitAPI::testInitialCapacity): (TestWebKitAPI::generateTestCapacityUpToSize<0>): (TestWebKitAPI::generateTestCapacityUpToSize): (TestWebKitAPI::TEST): (TestWebKitAPI::DerefObserver::ref): (TestWebKitAPI::DerefObserver::deref): Canonical link: https://commits.webkit.org/236073@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@275410 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2021-04-02 08:33:32 +00:00
maintainProbeDistanceForAdd(WTFMove(existingEntry), index, entryDistance, size, sizeMask, tableHash);
break;
}
if (entryHash == hash && HashTranslator::equal(entryKey, key))
return AddResult(makeKnownGoodIterator(entry), false);
index = (index + 1) & sizeMask;
++distance;
}
m_keyCount += 1;
internalCheckTableConsistency();
return AddResult(makeKnownGoodIterator(entry), true);
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
inline void RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::reinsert(ValueType&& value)
{
using std::swap; // For C++ ADL.
unsigned size = tableSize();
unsigned sizeMask = tableSizeMask();
unsigned tableHash = this->tableHash();
unsigned hash = IdentityTranslatorType::hash(Extractor::extract(value)) ^ tableHash;
unsigned index = desiredIndex(hash, sizeMask);
unsigned distance = 0;
while (true) {
ValueType* entry = m_table + index;
if (isEmptyBucket(*entry)) {
ValueTraits::assignToEmpty(*entry, WTFMove(value));
return;
}
unsigned entryHash = IdentityTranslatorType::hash(Extractor::extract(*entry)) ^ tableHash;
unsigned entryDistance = probeDistance(entryHash, index, size, sizeMask);
if (distance > entryDistance) {
swap(value, *entry);
distance = entryDistance;
}
index = (index + 1) & sizeMask;
++distance;
}
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
template <typename HashTranslator, typename T>
auto RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::find(const T& key) -> iterator
{
if (!m_table)
return end();
ValueType* entry = lookup<HashTranslator>(key);
if (!entry)
return end();
return makeKnownGoodIterator(entry);
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
template <typename HashTranslator, typename T>
auto RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::find(const T& key) const -> const_iterator
{
if (!m_table)
return end();
ValueType* entry = const_cast<RobinHoodHashTable*>(this)->lookup<HashTranslator>(key);
if (!entry)
return end();
return makeKnownGoodConstIterator(entry);
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
template <typename HashTranslator, typename T>
bool RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::contains(const T& key) const
{
if (!m_table)
return false;
return const_cast<RobinHoodHashTable*>(this)->lookup<HashTranslator>(key);
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
void RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::removeAndInvalidateWithoutEntryConsistencyCheck(ValueType* pos)
{
invalidateIterators(this);
remove(pos);
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
void RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::removeAndInvalidate(ValueType* pos)
{
invalidateIterators(this);
internalCheckTableConsistency();
remove(pos);
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
void RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::remove(ValueType* pos)
{
// This is removal via "backward-shift-deletion". This basically shift existing entries to removed empty entry place so that we make
// the table as if no removal happened so far. This decreases distance-to-initial-bucket (DIB) of the subsequent entries by 1. This maintains
// DIB of the table low and relatively constant even if we have many removals, compared to using tombstones.
// https://codecapsule.com/2013/11/17/robin-hood-hashing-backward-shift-deletion/
deleteBucket(*pos);
initializeBucket(*pos);
m_keyCount -= 1;
unsigned size = tableSize();
unsigned sizeMask = tableSizeMask();
unsigned tableHash = this->tableHash();
unsigned indexPrevious = pos - m_table;
unsigned index = (indexPrevious + 1) & sizeMask;
while (true) {
Value* previousEntry = m_table + indexPrevious;
Value* entry = m_table + index;
if (isEmptyBucket(*entry))
break;
ASSERT(isEmptyBucket(*previousEntry));
auto& entryKey = Extractor::extract(*entry);
unsigned entryHash = IdentityTranslatorType::hash(entryKey) ^ tableHash;
if (!probeDistance(entryHash, index, size, sizeMask))
break;
ValueTraits::assignToEmpty(*previousEntry, WTFMove(*entry));
entry->~ValueType();
initializeBucket(*entry);
indexPrevious = index;
index = (index + 1) & sizeMask;
}
if (shouldShrink())
shrink();
internalCheckTableConsistency();
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
inline void RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::remove(iterator it)
{
if (it == end())
return;
removeAndInvalidate(const_cast<ValueType*>(it.m_iterator.m_position));
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
inline void RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::removeWithoutEntryConsistencyCheck(iterator it)
{
if (it == end())
return;
removeAndInvalidateWithoutEntryConsistencyCheck(const_cast<ValueType*>(it.m_iterator.m_position));
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
inline void RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::removeWithoutEntryConsistencyCheck(const_iterator it)
{
if (it == end())
return;
removeAndInvalidateWithoutEntryConsistencyCheck(const_cast<ValueType*>(it.m_position));
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
inline void RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::remove(const KeyType& key)
{
remove(find(key));
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
auto RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::allocateTable(unsigned size) -> ValueType*
{
// would use a template member function with explicit specializations here, but
// gcc doesn't appear to support that
if constexpr (Traits::emptyValueIsZero)
return reinterpret_cast_ptr<ValueType*>(static_cast<char*>(HashTableMalloc::zeroedMalloc(size * sizeof(ValueType))));
ValueType* result = reinterpret_cast_ptr<ValueType*>(static_cast<char*>(HashTableMalloc::malloc(size * sizeof(ValueType))));
for (unsigned i = 0; i < size; i++)
initializeBucket(result[i]);
return result;
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
void RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::deallocateTable(ValueType* table, unsigned size)
{
for (unsigned i = 0; i < size; ++i)
table[i].~ValueType();
HashTableMalloc::free(reinterpret_cast<char*>(table));
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
void RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::expand()
{
unsigned newSize;
unsigned oldSize = tableSize();
if (!oldSize)
newSize = KeyTraits::minimumTableSize;
else
newSize = oldSize * 2;
rehash(newSize);
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
constexpr unsigned RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::computeBestTableSize(unsigned keyCount)
{
unsigned bestTableSize = WTF::roundUpToPowerOfTwo(keyCount);
if (shouldExpand(keyCount, bestTableSize))
bestTableSize *= 2;
auto aboveThresholdForEagerExpansion = [](double loadFactor, unsigned keyCount, unsigned tableSize)
{
// Here is the rationale behind this calculation, using 3/4 load-factor.
// With maxLoad at 3/4 and minLoad at 1/6, our average load is 11/24.
// If we are getting half-way between 11/24 and 3/4, we double the size
// to avoid being too close to loadMax and bring the ratio close to 11/24. This
// give us a load in the bounds [9/24, 15/24).
double maxLoadRatio = loadFactor;
double minLoadRatio = 1.0 / minLoad;
double averageLoadRatio = (maxLoadRatio + minLoadRatio) / 2;
double halfWayBetweenAverageAndMaxLoadRatio = (averageLoadRatio + maxLoadRatio) / 2;
return keyCount >= tableSize * halfWayBetweenAverageAndMaxLoadRatio;
};
constexpr double loadFactor = static_cast<double>(maxLoadNumerator) / maxLoadDenominator;
if (aboveThresholdForEagerExpansion(loadFactor, keyCount, bestTableSize))
bestTableSize *= 2;
unsigned minimumTableSize = KeyTraits::minimumTableSize;
return std::max(bestTableSize, minimumTableSize);
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
void RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::shrinkToBestSize()
{
unsigned minimumTableSize = KeyTraits::minimumTableSize;
rehash(std::max(minimumTableSize, computeBestTableSize(keyCount())));
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
void RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::rehash(unsigned newTableSize)
{
internalCheckTableConsistencyExceptSize();
unsigned oldTableSize = tableSize();
ValueType* oldTable = m_table;
m_table = allocateTable(newTableSize);
m_tableSize = newTableSize;
m_tableHash = computeTableHash(m_table);
m_willExpand = false;
for (unsigned i = 0; i < oldTableSize; ++i) {
auto* oldEntry = oldTable + i;
if (!isEmptyBucket(*oldEntry))
reinsert(WTFMove(*oldEntry));
oldEntry->~ValueType();
}
if (oldTable)
HashTableMalloc::free(reinterpret_cast<char*>(oldTable));
internalCheckTableConsistency();
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
void RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::clear()
{
invalidateIterators(this);
if (!m_table)
return;
unsigned oldTableSize = tableSize();
m_tableSize = 0;
m_keyCount = 0;
m_tableHash = 0;
m_willExpand = false;
deallocateTable(std::exchange(m_table, nullptr), oldTableSize);
internalCheckTableConsistency();
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::RobinHoodHashTable(const RobinHoodHashTable& other)
{
if (!other.m_tableSize || !other.m_keyCount)
return;
m_table = allocateTable(other.m_tableSize);
m_tableSize = other.m_tableSize;
m_keyCount = other.m_keyCount;
m_tableHash = computeTableHash(m_table);
m_willExpand = other.m_willExpand;
for (unsigned index = 0; index < other.m_tableSize; ++index) {
ValueType& otherEntry = other.m_table[index];
if (!isEmptyBucket(otherEntry)) {
ValueType entry(otherEntry);
reinsert(WTFMove(entry));
}
}
internalCheckTableConsistency();
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
void RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::swap(RobinHoodHashTable& other)
{
using std::swap; // For C++ ADL.
invalidateIterators(this);
invalidateIterators(&other);
swap(m_table, other.m_table);
swap(m_tableSize, other.m_tableSize);
swap(m_keyCount, other.m_keyCount);
swap(m_tableHash, other.m_tableHash);
swap(m_willExpand, other.m_willExpand);
internalCheckTableConsistency();
other.internalCheckTableConsistency();
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
auto RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::operator=(const RobinHoodHashTable& other) -> RobinHoodHashTable&
{
RobinHoodHashTable tmp(other);
swap(tmp);
return *this;
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
inline RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::RobinHoodHashTable(RobinHoodHashTable&& other)
{
invalidateIterators(&other);
m_table = std::exchange(other.m_table, nullptr);
m_tableSize = std::exchange(other.m_tableSize, 0);
m_keyCount = std::exchange(other.m_keyCount, 0);
m_tableHash = std::exchange(other.m_tableHash, 0);
m_willExpand = std::exchange(other.m_willExpand, false);
internalCheckTableConsistency();
other.internalCheckTableConsistency();
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
inline auto RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::operator=(RobinHoodHashTable&& other) -> RobinHoodHashTable&
{
RobinHoodHashTable temp(WTFMove(other));
swap(temp);
return *this;
}
#if ASSERT_ENABLED
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
void RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::checkTableConsistency() const
{
checkTableConsistencyExceptSize();
}
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename SizePolicy>
void RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, SizePolicy>::checkTableConsistencyExceptSize() const
{
if (!m_table)
return;
unsigned count = 0;
unsigned tableSize = this->tableSize();
for (unsigned i = 0; i < tableSize; ++i) {
ValueType* entry = m_table + i;
if (isEmptyBucket(*entry))
continue;
auto& key = Extractor::extract(*entry);
const_iterator it = find(key);
ASSERT(entry == it.m_position);
++count;
ValueCheck<Key>::checkConsistency(key);
}
ASSERT(count == keyCount());
ASSERT(this->tableSize() >= KeyTraits::minimumTableSize);
ASSERT(tableSizeMask());
ASSERT(this->tableSize() == tableSizeMask() + 1);
}
#endif // ASSERT_ENABLED
struct MemoryCompactLookupOnlyRobinHoodHashTableTraits {
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
using TableType = RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, MemoryCompactLookupOnlyRobinHoodHashTableSizePolicy>;
};
struct MemoryCompactRobinHoodHashTableTraits {
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
using TableType = RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, MemoryCompactRobinHoodHashTableSizePolicy>;
};
struct FastRobinHoodHashTableTraits {
template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
using TableType = RobinHoodHashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, FastRobinHoodHashTableSizePolicy>;
};
} // namespace WTF