2017-03-14 21:37:41 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2017 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. ``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
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <wtf/DataLog.h>
|
|
|
|
#include <wtf/HashMap.h>
|
|
|
|
#include <wtf/LoggingHashID.h>
|
2020-05-08 15:39:39 +00:00
|
|
|
#include <wtf/LoggingHashTraits.h>
|
2017-03-14 21:37:41 +00:00
|
|
|
|
|
|
|
namespace WTF {
|
|
|
|
|
|
|
|
template<
|
|
|
|
const char* typeArguments,
|
2020-07-17 00:33:37 +00:00
|
|
|
typename KeyArg, typename MappedArg, typename HashArg = DefaultHash<KeyArg>,
|
2017-03-14 21:37:41 +00:00
|
|
|
typename KeyTraitsArg = HashTraits<KeyArg>, typename MappedTraitsArg = HashTraits<MappedArg>,
|
|
|
|
typename LoggingKeyTraits = LoggingHashKeyTraits<KeyArg>,
|
|
|
|
typename LoggingValueTraits = LoggingHashValueTraits<MappedArg>>
|
|
|
|
class LoggingHashMap final {
|
|
|
|
WTF_MAKE_FAST_ALLOCATED;
|
|
|
|
|
|
|
|
public:
|
|
|
|
typedef WTF::HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg> HashMap;
|
|
|
|
|
|
|
|
typedef typename HashMap::KeyType KeyType;
|
|
|
|
typedef typename HashMap::MappedType MappedType;
|
|
|
|
typedef typename HashMap::KeyValuePairType KeyValuePairType;
|
|
|
|
|
|
|
|
typedef typename HashMap::iterator iterator;
|
|
|
|
typedef typename HashMap::const_iterator const_iterator;
|
|
|
|
typedef typename HashMap::AddResult AddResult;
|
|
|
|
|
2020-05-08 15:39:39 +00:00
|
|
|
private:
|
|
|
|
typedef typename HashMap::MappedTraits::PeekType MappedPeekType;
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
2017-03-14 21:37:41 +00:00
|
|
|
LoggingHashMap()
|
|
|
|
{
|
|
|
|
dataLog("auto* ", m_id, " = new HashMap<", typeArguments, ">();\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
~LoggingHashMap()
|
|
|
|
{
|
|
|
|
dataLog("delete ", m_id, ";\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
LoggingHashMap(const LoggingHashMap& other)
|
|
|
|
: m_map(other.m_map)
|
|
|
|
{
|
|
|
|
dataLog("auto* ", m_id, " = new HashMap(*", other.m_id, ");");
|
|
|
|
}
|
|
|
|
|
|
|
|
LoggingHashMap(LoggingHashMap&& other)
|
|
|
|
: m_map(other.m_map)
|
|
|
|
{
|
|
|
|
dataLog("auto* ", m_id, " = new HashMap(WTFMove(*", other.m_id, "));");
|
|
|
|
}
|
|
|
|
|
|
|
|
LoggingHashMap& operator=(const LoggingHashMap& other)
|
|
|
|
{
|
|
|
|
dataLog("*", m_id, " = *", other.m_id, ";\n");
|
|
|
|
m_map = other.m_map;
|
|
|
|
}
|
|
|
|
|
|
|
|
LoggingHashMap& operator=(LoggingHashMap&& other)
|
|
|
|
{
|
|
|
|
dataLog("*", m_id, " = WTFMove(*", other.m_id, ");\n");
|
|
|
|
m_map = WTFMove(other.m_map);
|
|
|
|
}
|
|
|
|
|
|
|
|
void swap(LoggingHashMap& other)
|
|
|
|
{
|
|
|
|
dataLog(m_id, "->swap(*", RawPointer(&other), ");\n");
|
|
|
|
m_map.swap(other.m_map);
|
|
|
|
}
|
|
|
|
|
|
|
|
// A bunch of stuff does not get logged.
|
|
|
|
unsigned size() const { return m_map.size(); }
|
|
|
|
unsigned capacity() const { return m_map.capacity(); }
|
|
|
|
bool isEmpty() const { return m_map.isEmpty(); }
|
|
|
|
|
|
|
|
iterator begin() { return m_map.begin(); }
|
|
|
|
iterator end() { return m_map.end(); }
|
|
|
|
const_iterator begin() const { return m_map.begin(); }
|
|
|
|
const_iterator end() const { return m_map.end(); }
|
2018-10-25 17:41:35 +00:00
|
|
|
|
|
|
|
iterator random() { return m_map.random(); }
|
|
|
|
const_iterator random() const { return m_map.random(); }
|
2017-03-14 21:37:41 +00:00
|
|
|
|
|
|
|
auto keys() { return m_map.keys(); }
|
2020-05-08 15:39:39 +00:00
|
|
|
auto keys() const { return m_map.keys(); }
|
2017-03-14 21:37:41 +00:00
|
|
|
auto values() { return m_map.values(); }
|
2020-05-08 15:39:39 +00:00
|
|
|
auto values() const { return m_map.values(); }
|
2017-03-14 21:37:41 +00:00
|
|
|
|
|
|
|
iterator find(const KeyType& key)
|
|
|
|
{
|
|
|
|
StringPrintStream string;
|
|
|
|
string.print("{\n");
|
|
|
|
string.print(" auto iter = ", m_id, "->find(");
|
|
|
|
LoggingKeyTraits::print(string, key);
|
|
|
|
string.print(");\n");
|
|
|
|
iterator result = m_map.find(key);
|
|
|
|
if (result == m_map.end())
|
|
|
|
string.print(" RELEASE_ASSERT(iter == ", m_id, "->end());\n");
|
|
|
|
else
|
|
|
|
string.print(" RELEASE_ASSERT(iter != ", m_id, "->end());\n");
|
|
|
|
string.print("}\n");
|
|
|
|
dataLog(string.toCString());
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
const_iterator find(const KeyType& key) const
|
|
|
|
{
|
|
|
|
StringPrintStream string;
|
|
|
|
string.print("{\n");
|
|
|
|
string.print(" auto iter = ", m_id, "->find(");
|
|
|
|
LoggingKeyTraits::print(string, key);
|
|
|
|
string.print(");\n");
|
|
|
|
const_iterator result = m_map.find(key);
|
|
|
|
if (result == m_map.end())
|
|
|
|
string.print(" RELEASE_ASSERT(iter == ", m_id, "->end());\n");
|
|
|
|
else
|
|
|
|
string.print(" RELEASE_ASSERT(iter != ", m_id, "->end());\n");
|
|
|
|
string.print("}\n");
|
|
|
|
dataLog(string.toCString());
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool contains(const KeyType& key) const
|
|
|
|
{
|
|
|
|
return find(key) != end();
|
|
|
|
}
|
|
|
|
|
|
|
|
MappedPeekType get(const KeyType& key) const
|
|
|
|
{
|
|
|
|
find(key);
|
|
|
|
return m_map.get(key);
|
|
|
|
}
|
|
|
|
|
[DFG] Optimize WeakMap::get by adding intrinsic and fixup
https://bugs.webkit.org/show_bug.cgi?id=176010
Reviewed by Filip Pizlo.
JSTests:
* microbenchmarks/weak-map-key.js: Added.
(assert):
(objectKey):
(let.start.Date.now):
Source/JavaScriptCore:
It reveals that Ember.js consumes 3.8% of execution time for WeakMap#get.
It is used for meta property for objects (see peekMeta function in Ember.js).
This patch optimizes WeakMap#get.
1. We use inlineGet to inline WeakMap#get operation in the native function.
Since this native function itself is very small, we should inline HashMap#get
entirely in this function.
2. We add JSWeakMapType and JSWeakSetType. This allows us to perform `isJSWeakMap()`
very fast. And this patch wires this to DFG and FTL to add WeakMapObjectUse and WeakSetObjectUse
to drop unnecessary type checking. We add fixup rules for WeakMapGet DFG node by using WeakMapObjectUse,
ObjectUse, and Int32Use.
3. We add intrinsic for WeakMap#get, and handle it in DFG and FTL. We use MapHash to
calculate hash value for the key's Object and use this hash value to look up value from
JSWeakMap's HashMap. Currently, we just call the operationWeakMapGet function in DFG and FTL.
It is worth considering that implementing this operation entirely in JIT, like GetMapBucket.
But anyway, the current one already optimizes the performance, so we leave this for the subsequent
patches.
We currently do not implement any other intrinsics (like, WeakMap#has, WeakSet) because they are
not used in Ember.js right now.
This patch optimizes WeakMap#get by 50%.
baseline patched
weak-map-key 88.6456+-3.9564 ^ 59.1502+-2.2406 ^ definitely 1.4987x faster
* bytecode/DirectEvalCodeCache.h:
(JSC::DirectEvalCodeCache::tryGet):
* bytecode/SpeculatedType.cpp:
(JSC::dumpSpeculation):
(JSC::speculationFromClassInfo):
(JSC::speculationFromJSType):
(JSC::speculationFromString):
* bytecode/SpeculatedType.h:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsicCall):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGHeapLocation.cpp:
(WTF::printInternal):
* dfg/DFGHeapLocation.h:
* dfg/DFGNode.h:
(JSC::DFG::Node::hasHeapPrediction):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::SafeToExecuteEdge::operator()):
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::speculateWeakMapObject):
(JSC::DFG::SpeculativeJIT::speculateWeakSetObject):
(JSC::DFG::SpeculativeJIT::speculate):
(JSC::DFG::SpeculativeJIT::compileWeakMapGet):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGUseKind.cpp:
(WTF::printInternal):
* dfg/DFGUseKind.h:
(JSC::DFG::typeFilterFor):
(JSC::DFG::isCell):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileWeakMapGet):
(JSC::FTL::DFG::LowerDFGToB3::lowWeakMapObject):
(JSC::FTL::DFG::LowerDFGToB3::lowWeakSetObject):
(JSC::FTL::DFG::LowerDFGToB3::speculate):
(JSC::FTL::DFG::LowerDFGToB3::speculateWeakMapObject):
(JSC::FTL::DFG::LowerDFGToB3::speculateWeakSetObject):
* jit/JITOperations.h:
* runtime/HashMapImpl.h:
(JSC::WeakMapHash::hash):
(JSC::WeakMapHash::equal):
* runtime/Intrinsic.cpp:
(JSC::intrinsicName):
* runtime/Intrinsic.h:
* runtime/JSType.h:
* runtime/JSWeakMap.h:
(JSC::isJSWeakMap):
* runtime/JSWeakSet.h:
(JSC::isJSWeakSet):
* runtime/WeakMapBase.cpp:
(JSC::WeakMapBase::get):
* runtime/WeakMapBase.h:
(JSC::WeakMapBase::HashTranslator::hash):
(JSC::WeakMapBase::HashTranslator::equal):
(JSC::WeakMapBase::inlineGet):
* runtime/WeakMapPrototype.cpp:
(JSC::WeakMapPrototype::finishCreation):
(JSC::getWeakMap):
(JSC::protoFuncWeakMapGet):
* runtime/WeakSetPrototype.cpp:
(JSC::getWeakSet):
Source/WebCore:
* platform/network/curl/CurlJobManager.cpp:
(WebCore::CurlJobList::finishJobs):
Source/WTF:
Add inlineGet method with HashTranslator.
* wtf/HashMap.h:
(WTF::X>::inlineGet const):
(WTF::MappedTraits>::inlineGet const):
(WTF::MappedTraits>::fastGet const): Deleted.
* wtf/LoggingHashMap.h:
Canonical link: https://commits.webkit.org/193297@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@221959 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-09-13 07:02:13 +00:00
|
|
|
MappedPeekType inlineGet(const KeyType& key) const
|
2017-03-14 21:37:41 +00:00
|
|
|
{
|
|
|
|
find(key);
|
[DFG] Optimize WeakMap::get by adding intrinsic and fixup
https://bugs.webkit.org/show_bug.cgi?id=176010
Reviewed by Filip Pizlo.
JSTests:
* microbenchmarks/weak-map-key.js: Added.
(assert):
(objectKey):
(let.start.Date.now):
Source/JavaScriptCore:
It reveals that Ember.js consumes 3.8% of execution time for WeakMap#get.
It is used for meta property for objects (see peekMeta function in Ember.js).
This patch optimizes WeakMap#get.
1. We use inlineGet to inline WeakMap#get operation in the native function.
Since this native function itself is very small, we should inline HashMap#get
entirely in this function.
2. We add JSWeakMapType and JSWeakSetType. This allows us to perform `isJSWeakMap()`
very fast. And this patch wires this to DFG and FTL to add WeakMapObjectUse and WeakSetObjectUse
to drop unnecessary type checking. We add fixup rules for WeakMapGet DFG node by using WeakMapObjectUse,
ObjectUse, and Int32Use.
3. We add intrinsic for WeakMap#get, and handle it in DFG and FTL. We use MapHash to
calculate hash value for the key's Object and use this hash value to look up value from
JSWeakMap's HashMap. Currently, we just call the operationWeakMapGet function in DFG and FTL.
It is worth considering that implementing this operation entirely in JIT, like GetMapBucket.
But anyway, the current one already optimizes the performance, so we leave this for the subsequent
patches.
We currently do not implement any other intrinsics (like, WeakMap#has, WeakSet) because they are
not used in Ember.js right now.
This patch optimizes WeakMap#get by 50%.
baseline patched
weak-map-key 88.6456+-3.9564 ^ 59.1502+-2.2406 ^ definitely 1.4987x faster
* bytecode/DirectEvalCodeCache.h:
(JSC::DirectEvalCodeCache::tryGet):
* bytecode/SpeculatedType.cpp:
(JSC::dumpSpeculation):
(JSC::speculationFromClassInfo):
(JSC::speculationFromJSType):
(JSC::speculationFromString):
* bytecode/SpeculatedType.h:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsicCall):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGHeapLocation.cpp:
(WTF::printInternal):
* dfg/DFGHeapLocation.h:
* dfg/DFGNode.h:
(JSC::DFG::Node::hasHeapPrediction):
* dfg/DFGNodeType.h:
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::SafeToExecuteEdge::operator()):
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::speculateWeakMapObject):
(JSC::DFG::SpeculativeJIT::speculateWeakSetObject):
(JSC::DFG::SpeculativeJIT::speculate):
(JSC::DFG::SpeculativeJIT::compileWeakMapGet):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::callOperation):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGUseKind.cpp:
(WTF::printInternal):
* dfg/DFGUseKind.h:
(JSC::DFG::typeFilterFor):
(JSC::DFG::isCell):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileWeakMapGet):
(JSC::FTL::DFG::LowerDFGToB3::lowWeakMapObject):
(JSC::FTL::DFG::LowerDFGToB3::lowWeakSetObject):
(JSC::FTL::DFG::LowerDFGToB3::speculate):
(JSC::FTL::DFG::LowerDFGToB3::speculateWeakMapObject):
(JSC::FTL::DFG::LowerDFGToB3::speculateWeakSetObject):
* jit/JITOperations.h:
* runtime/HashMapImpl.h:
(JSC::WeakMapHash::hash):
(JSC::WeakMapHash::equal):
* runtime/Intrinsic.cpp:
(JSC::intrinsicName):
* runtime/Intrinsic.h:
* runtime/JSType.h:
* runtime/JSWeakMap.h:
(JSC::isJSWeakMap):
* runtime/JSWeakSet.h:
(JSC::isJSWeakSet):
* runtime/WeakMapBase.cpp:
(JSC::WeakMapBase::get):
* runtime/WeakMapBase.h:
(JSC::WeakMapBase::HashTranslator::hash):
(JSC::WeakMapBase::HashTranslator::equal):
(JSC::WeakMapBase::inlineGet):
* runtime/WeakMapPrototype.cpp:
(JSC::WeakMapPrototype::finishCreation):
(JSC::getWeakMap):
(JSC::protoFuncWeakMapGet):
* runtime/WeakSetPrototype.cpp:
(JSC::getWeakSet):
Source/WebCore:
* platform/network/curl/CurlJobManager.cpp:
(WebCore::CurlJobList::finishJobs):
Source/WTF:
Add inlineGet method with HashTranslator.
* wtf/HashMap.h:
(WTF::X>::inlineGet const):
(WTF::MappedTraits>::inlineGet const):
(WTF::MappedTraits>::fastGet const): Deleted.
* wtf/LoggingHashMap.h:
Canonical link: https://commits.webkit.org/193297@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@221959 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-09-13 07:02:13 +00:00
|
|
|
return m_map.inlineGet(key);
|
2017-03-14 21:37:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename PassedType>
|
|
|
|
AddResult set(const KeyType& key, PassedType&& passedValue)
|
|
|
|
{
|
|
|
|
StringPrintStream string;
|
|
|
|
string.print(m_id, "->set(");
|
|
|
|
LoggingKeyTraits::print(string, key);
|
|
|
|
string.print(", ");
|
|
|
|
LoggingValueTraits::print(string, passedValue);
|
|
|
|
string.print(");\n");
|
|
|
|
dataLog(string.toCString());
|
|
|
|
return set(key, std::forward<PassedType>(passedValue));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename PassedType>
|
|
|
|
AddResult set(KeyType&& key, PassedType&& passedValue)
|
|
|
|
{
|
|
|
|
StringPrintStream string;
|
|
|
|
string.print(m_id, "->set(");
|
|
|
|
LoggingKeyTraits::print(string, key);
|
|
|
|
string.print(", ");
|
|
|
|
LoggingValueTraits::print(string, passedValue);
|
|
|
|
string.print(");\n");
|
|
|
|
dataLog(string.toCString());
|
|
|
|
return set(WTFMove(key), std::forward<PassedType>(passedValue));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename PassedType>
|
|
|
|
AddResult add(const KeyType& key, PassedType&& passedValue)
|
|
|
|
{
|
|
|
|
StringPrintStream string;
|
|
|
|
string.print(m_id, "->add(");
|
|
|
|
LoggingKeyTraits::print(string, key);
|
|
|
|
string.print(", ");
|
|
|
|
LoggingValueTraits::print(string, passedValue);
|
|
|
|
string.print(");\n");
|
|
|
|
dataLog(string.toCString());
|
|
|
|
return add(key, std::forward<PassedType>(passedValue));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename PassedType>
|
|
|
|
AddResult add(KeyType&& key, PassedType&& passedValue)
|
|
|
|
{
|
|
|
|
StringPrintStream string;
|
|
|
|
string.print(m_id, "->add(");
|
|
|
|
LoggingKeyTraits::print(string, key);
|
|
|
|
string.print(", ");
|
|
|
|
LoggingValueTraits::print(string, passedValue);
|
|
|
|
string.print(");\n");
|
|
|
|
dataLog(string.toCString());
|
|
|
|
return add(WTFMove(key), std::forward<PassedType>(passedValue));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename PassedType>
|
|
|
|
AddResult fastAdd(const KeyType& key, PassedType&& passedValue)
|
|
|
|
{
|
|
|
|
return add(key, std::forward<PassedType>(passedValue));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename PassedType>
|
|
|
|
AddResult fastAdd(KeyType&& key, PassedType&& passedValue)
|
|
|
|
{
|
|
|
|
return add(WTFMove(key), std::forward<PassedType>(passedValue));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Func>
|
|
|
|
AddResult ensure(const KeyType& key, Func&& func)
|
|
|
|
{
|
|
|
|
StringPrintStream string;
|
|
|
|
string.print(m_id, "->ensure(");
|
|
|
|
LoggingKeyTraits::print(string, key);
|
|
|
|
string.print(", ");
|
|
|
|
string.print("[] () { return ");
|
|
|
|
bool didCallFunctor = false;
|
|
|
|
auto result = m_map.ensure(
|
|
|
|
key,
|
|
|
|
[&] () {
|
|
|
|
didCallFunctor = true;
|
|
|
|
auto result = func();
|
|
|
|
LoggingValueTraits::print(string, result);
|
|
|
|
return result;
|
|
|
|
});
|
|
|
|
if (!didCallFunctor)
|
|
|
|
LoggingValueTraits::print(string, MappedTraitsArg::emptyValue());
|
|
|
|
string.print("; });\n");
|
|
|
|
dataLog(string.toCString());
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename Func>
|
|
|
|
AddResult ensure(KeyType&& key, Func&& func)
|
|
|
|
{
|
|
|
|
StringPrintStream string;
|
|
|
|
string.print(m_id, "->ensure(");
|
|
|
|
LoggingKeyTraits::print(string, key);
|
|
|
|
string.print(", ");
|
|
|
|
string.print("[] () { return ");
|
|
|
|
bool didCallFunctor = false;
|
|
|
|
auto result = m_map.ensure(
|
|
|
|
WTFMove(key),
|
|
|
|
[&] () {
|
|
|
|
didCallFunctor = true;
|
|
|
|
auto result = func();
|
|
|
|
LoggingValueTraits::print(string, result);
|
|
|
|
return result;
|
|
|
|
});
|
|
|
|
if (!didCallFunctor)
|
|
|
|
LoggingValueTraits::print(string, MappedTraitsArg::emptyValue());
|
|
|
|
string.print("; });\n");
|
|
|
|
dataLog(string.toCString());
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool remove(const KeyType& key)
|
|
|
|
{
|
|
|
|
StringPrintStream string;
|
|
|
|
string.print(m_id, "->remove(");
|
|
|
|
LoggingKeyTraits::print(string, key);
|
|
|
|
string.print(");\n");
|
|
|
|
dataLog(string.toCString());
|
|
|
|
return m_map.remove(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool remove(iterator iter)
|
|
|
|
{
|
|
|
|
// FIXME: It would be nice if we could do better than this.
|
|
|
|
if (iter == end())
|
|
|
|
return false;
|
|
|
|
return remove(iter->key);
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Implement removeIf().
|
|
|
|
|
|
|
|
void clear()
|
|
|
|
{
|
|
|
|
dataLog(m_id, "->clear();\n");
|
|
|
|
m_map.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Implement the no-convert overloads.
|
|
|
|
|
|
|
|
private:
|
|
|
|
HashMap m_map;
|
|
|
|
LoggingHashID m_id;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace WTF
|
|
|
|
|
|
|
|
using WTF::LoggingHashMap;
|