Modified: trunk/Source/WTF/ChangeLog (196715 => 196716)
--- trunk/Source/WTF/ChangeLog 2016-02-17 20:42:55 UTC (rev 196715)
+++ trunk/Source/WTF/ChangeLog 2016-02-17 21:17:00 UTC (rev 196716)
@@ -1,3 +1,47 @@
+2016-02-16 Sam Weinig <[email protected]>
+
+ Add an ensure function on HashMap that takes a key and a function to make the lazy value initialization idiom easier
+ https://bugs.webkit.org/show_bug.cgi?id=134857
+
+ Reviewed by Geoffrey Garen.
+
+ The current idiom for adding a value to a HashMap if the key is not already present, to allow for not
+ unnecessarily constructing the new value if it won't be used, is:
+
+ {
+ auto result = map.add(key, Value());
+ if (!result.isNewEntry)
+ return result.iterator->value;
+
+ result.iterator->value = createNewValue();
+ return result.iterator->value;
+ }
+
+ or sometimes
+
+ {
+ auto& value = map.add(key, Value()).iterator->value;
+ if (!value)
+ value = createNewValue();
+ return value;
+ }
+
+ With this patch, you can now use the new function HashMap::ensure(key, functor). This will allow us to
+ change to using the following idiom:
+
+ {
+ return map.ensure(key, [] { return createNewValue(); });
+ }
+
+ The passed in functor will only be called if the key is not already present in the HashMap.
+
+ * wtf/HashMap.h:
+ (WTF::HashMapTranslator::translate):
+ (WTF::HashMapEnsureTranslator::hash):
+ (WTF::HashMapEnsureTranslator::equal):
+ (WTF::HashMapEnsureTranslator::translate):
+ (WTF::HashMapTranslatorAdapter::hash):
+
2016-02-16 Filip Pizlo <[email protected]>
FTL_USES_B3 should be unconditionally true
Modified: trunk/Source/WTF/wtf/HashMap.h (196715 => 196716)
--- trunk/Source/WTF/wtf/HashMap.h 2016-02-17 20:42:55 UTC (rev 196715)
+++ trunk/Source/WTF/wtf/HashMap.h 2016-02-17 21:17:00 UTC (rev 196716)
@@ -118,6 +118,9 @@
template<typename V> AddResult fastAdd(const KeyType&, V&&);
template<typename V> AddResult fastAdd(KeyType&&, V&&);
+ template<typename Functor> MappedType& ensure(const KeyType&, const Functor&);
+ template<typename Functor> MappedType& ensure(KeyType&&, const Functor&);
+
bool remove(const KeyType&);
bool remove(iterator);
template<typename Functor>
@@ -163,6 +166,9 @@
template<typename K, typename V>
AddResult inlineAdd(K&&, V&&);
+ template<typename K, typename F>
+ MappedType& inlineEnsure(K&&, const F&);
+
HashTableType m_impl;
};
@@ -177,6 +183,17 @@
}
};
+template<typename ValueTraits, typename HashFunctions>
+struct HashMapEnsureTranslator {
+ template<typename T> static unsigned hash(const T& key) { return HashFunctions::hash(key); }
+ template<typename T, typename U> static bool equal(const T& a, const U& b) { return HashFunctions::equal(a, b); }
+ template<typename T, typename U, typename Functor> static void translate(T& location, U&& key, const Functor& functor)
+ {
+ location.key = std::forward<U>(key);
+ location.value = functor();
+ }
+};
+
template<typename ValueTraits, typename Translator>
struct HashMapTranslatorAdapter {
template<typename T> static unsigned hash(const T& key) { return Translator::hash(key); }
@@ -297,6 +314,13 @@
}
template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg>
+template<typename K, typename F>
+ALWAYS_INLINE auto HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>::inlineEnsure(K&& key, const F& functor) -> MappedType&
+{
+ return m_impl.template add<HashMapEnsureTranslator<KeyValuePairTraits, HashFunctions>>(std::forward<K>(key), functor).iterator->value;
+}
+
+template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg>
template<typename T>
auto HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>::set(const KeyType& key, T&& mapped) -> AddResult
{
@@ -345,6 +369,20 @@
return inlineAdd(WTFMove(key), std::forward<T>(mapped));
}
+template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg>
+template<typename Functor>
+auto HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>::ensure(const KeyType& key, const Functor& functor) -> MappedType&
+{
+ return inlineEnsure(key, functor);
+}
+
+template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg>
+template<typename Functor>
+auto HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>::ensure(KeyType&& key, const Functor& functor) -> MappedType&
+{
+ return inlineEnsure(WTFMove(key), functor);
+}
+
template<typename T, typename U, typename V, typename W, typename MappedTraits>
auto HashMap<T, U, V, W, MappedTraits>::get(const KeyType& key) const -> MappedPeekType
{
Modified: trunk/Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp (196715 => 196716)
--- trunk/Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp 2016-02-17 20:42:55 UTC (rev 196715)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp 2016-02-17 21:17:00 UTC (rev 196716)
@@ -508,4 +508,54 @@
EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
}
+TEST(WTF_HashMap, Ensure)
+{
+ HashMap<unsigned, unsigned> map;
+ {
+ auto value = map.ensure(1, [] { return 1; });
+ EXPECT_EQ(1u, value);
+ value = map.ensure(1, [] { return 2; });
+ EXPECT_EQ(1u, value);
+ }
+}
+
+TEST(WTF_HashMap, Ensure_MoveOnlyValues)
+{
+ HashMap<unsigned, MoveOnly> moveOnlyValues;
+ {
+ auto& value = moveOnlyValues.ensure(1, [] { return MoveOnly(1); });
+ EXPECT_EQ(1u, value.value());
+ auto& value2 = moveOnlyValues.ensure(1, [] { return MoveOnly(2); });
+ EXPECT_EQ(1u, value2.value());
+ }
+}
+
+TEST(WTF_HashMap, Ensure_UniquePointer)
+{
+ HashMap<unsigned, std::unique_ptr<unsigned>> map;
+ {
+ auto& value = map.ensure(1, [] { return std::make_unique<unsigned>(1); });
+ EXPECT_EQ(1u, *map.get(1));
+ EXPECT_EQ(1u, *value.get());
+ auto& value2 = map.ensure(1, [] { return std::make_unique<unsigned>(2); });
+ EXPECT_EQ(1u, *map.get(1));
+ EXPECT_EQ(1u, *value2.get());
+ }
+}
+
+TEST(WTF_HashMap, Ensure_RefPtr)
+{
+ HashMap<unsigned, RefPtr<RefLogger>> map;
+
+ {
+ DerivedRefLogger a("a");
+
+ map.ensure(1, [&] { return RefPtr<RefLogger>(&a); });
+ EXPECT_STREQ("ref(a) ", takeLogStr().c_str());
+
+ map.ensure(1, [&] { return RefPtr<RefLogger>(&a); });
+ EXPECT_STREQ("", takeLogStr().c_str());
+ }
+}
+
} // namespace TestWebKitAPI