Title: [196716] trunk
Revision
196716
Author
[email protected]
Date
2016-02-17 13:17:00 -0800 (Wed, 17 Feb 2016)

Log Message

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.

Source/WTF:

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):

Tools:

* TestWebKitAPI/Tests/WTF/HashMap.cpp:
Add tests for HashMap::ensure.

Modified Paths

Diff

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/ChangeLog (196715 => 196716)


--- trunk/Tools/ChangeLog	2016-02-17 20:42:55 UTC (rev 196715)
+++ trunk/Tools/ChangeLog	2016-02-17 21:17:00 UTC (rev 196716)
@@ -1,3 +1,13 @@
+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.
+
+        * TestWebKitAPI/Tests/WTF/HashMap.cpp:
+        Add tests for HashMap::ensure.
+
 2016-02-17  Nan Wang  <[email protected]>
 
         AX: Implement sentence related text marker functions using TextIterator

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
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to