Unreviewed, rolling out r202136.
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 21 Jun 2016 00:24:32 +0000 (00:24 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 21 Jun 2016 00:24:32 +0000 (00:24 +0000)
https://bugs.webkit.org/show_bug.cgi?id=158932

JSBench wasn't regressed by r202002 and r202111 on iOS after
all (Requested by rniwa_ on #webkit).

Reverted changeset:

"Unreviewed, rolling out r202002 and r202111."
https://bugs.webkit.org/show_bug.cgi?id=158638
http://trac.webkit.org/changeset/202136

Patch by Commit Queue <commit-queue@webkit.org> on 2016-06-20

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@202254 268f45cc-cd09-0410-ab3c-d52691b4dbfc

12 files changed:
Source/WTF/ChangeLog
Source/WTF/wtf/GetPtr.h
Source/WTF/wtf/HashFunctions.h
Source/WTF/wtf/HashMap.h
Source/WTF/wtf/HashSet.h
Source/WTF/wtf/HashTable.h
Source/WTF/wtf/HashTraits.h
Source/WTF/wtf/Ref.h
Source/WTF/wtf/RefPtr.h
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp
Tools/TestWebKitAPI/Tests/WTF/HashSet.cpp

index 17b41f3..c5a464c 100644 (file)
@@ -1,3 +1,17 @@
+2016-06-20  Commit Queue  <commit-queue@webkit.org>
+
+        Unreviewed, rolling out r202136.
+        https://bugs.webkit.org/show_bug.cgi?id=158932
+
+        JSBench wasn't regressed by r202002 and r202111 on iOS after
+        all (Requested by rniwa_ on #webkit).
+
+        Reverted changeset:
+
+        "Unreviewed, rolling out r202002 and r202111."
+        https://bugs.webkit.org/show_bug.cgi?id=158638
+        http://trac.webkit.org/changeset/202136
+
 2016-06-17  Chris Dumez  <cdumez@apple.com>
 
         Optimize parseCacheHeader() by using StringView
index 4fc5ff6..78107cb 100644 (file)
@@ -25,6 +25,9 @@
 
 namespace WTF {
 
+enum HashTableDeletedValueType { HashTableDeletedValue };
+enum HashTableEmptyValueType { HashTableEmptyValue };
+
 template <typename T> inline T* getPtr(T* p) { return p; }
 
 template <typename T> struct IsSmartPtr {
index c4097ad..462f19a 100644 (file)
@@ -149,6 +149,10 @@ namespace WTF {
     template<typename T> struct PtrHash : PtrHashBase<T, IsSmartPtr<T>::value> {
     };
 
+    template<typename P> struct PtrHash<Ref<P>> : PtrHashBase<Ref<P>, IsSmartPtr<Ref<P>>::value> {
+        static const bool safeToCompareToEmptyOrDeleted = false;
+    };
+
     // default hash function for each type
 
     template<typename T> struct DefaultHash;
@@ -194,6 +198,8 @@ namespace WTF {
 
     template<typename P> struct DefaultHash<P*> { typedef PtrHash<P*> Hash; };
     template<typename P> struct DefaultHash<RefPtr<P>> { typedef PtrHash<RefPtr<P>> Hash; };
+    template<typename P> struct DefaultHash<Ref<P>> { typedef PtrHash<Ref<P>> Hash; };
+
     template<typename P, typename Deleter> struct DefaultHash<std::unique_ptr<P, Deleter>> { typedef PtrHash<std::unique_ptr<P, Deleter>> Hash; };
 
     // make IntPairHash the default hash function for pairs of (at most) 32-bit integers.
index 2c734f3..06179d9 100644 (file)
@@ -54,6 +54,7 @@ public:
 
 private:
     typedef typename MappedTraits::PeekType MappedPeekType;
+    typedef typename MappedTraits::TakeType MappedTakeType;
 
     typedef HashArg HashFunctions;
 
@@ -130,7 +131,7 @@ public:
     void removeIf(const Functor& functor);
     void clear();
 
-    MappedType take(const KeyType&); // efficient combination of get with remove
+    MappedTakeType take(const KeyType&); // efficient combination of get with remove
 
     // An alternate version of find() that finds the object by hashing and comparing
     // with some other type, to avoid the cost of type conversion. HashTranslator
@@ -156,7 +157,7 @@ public:
     template<typename K = KeyType> typename std::enable_if<IsSmartPtr<K>::value, MappedPeekType>::type inlineGet(typename GetPtrHelper<K>::PtrType) const;
     template<typename K = KeyType> typename std::enable_if<IsSmartPtr<K>::value, MappedPeekType>::type get(typename GetPtrHelper<K>::PtrType) const;
     template<typename K = KeyType> typename std::enable_if<IsSmartPtr<K>::value, bool>::type remove(typename GetPtrHelper<K>::PtrType);
-    template<typename K = KeyType> typename std::enable_if<IsSmartPtr<K>::value, MappedType>::type take(typename GetPtrHelper<K>::PtrType);
+    template<typename K = KeyType> typename std::enable_if<IsSmartPtr<K>::value, MappedTakeType>::type take(typename GetPtrHelper<K>::PtrType);
 
     void checkConsistency() const;
 
@@ -181,8 +182,8 @@ struct HashMapTranslator {
     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 V> static void translate(T& location, U&& key, V&& mapped)
     {
-        location.key = std::forward<U>(key);
-        location.value = std::forward<V>(mapped);
+        ValueTraits::KeyTraits::assignToEmpty(location.key, std::forward<U>(key));
+        ValueTraits::ValueTraits::assignToEmpty(location.value, std::forward<V>(mapped));
     }
 };
 
@@ -192,8 +193,8 @@ struct HashMapEnsureTranslator {
     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();
+        ValueTraits::KeyTraits::assignToEmpty(location.key, std::forward<U>(key));
+        ValueTraits::ValueTraits::assignToEmpty(location.value, functor());
     }
 };
 
@@ -434,12 +435,12 @@ inline void HashMap<T, U, V, W, X>::clear()
 }
 
 template<typename T, typename U, typename V, typename W, typename MappedTraits>
-auto HashMap<T, U, V, W, MappedTraits>::take(const KeyType& key) -> MappedType
+auto HashMap<T, U, V, W, MappedTraits>::take(const KeyType& key) -> MappedTakeType
 {
     iterator it = find(key);
     if (it == end())
-        return MappedTraits::emptyValue();
-    MappedType value = WTFMove(it->value);
+        return MappedTraits::take(MappedTraits::emptyValue());
+    auto value = MappedTraits::take(WTFMove(it->value));
     remove(it);
     return value;
 }
@@ -491,12 +492,12 @@ inline auto HashMap<T, U, V, W, X>::remove(typename GetPtrHelper<K>::PtrType key
 
 template<typename T, typename U, typename V, typename W, typename X>
 template<typename K>
-inline auto HashMap<T, U, V, W, X>::take(typename GetPtrHelper<K>::PtrType key) -> typename std::enable_if<IsSmartPtr<K>::value, MappedType>::type
+inline auto HashMap<T, U, V, W, X>::take(typename GetPtrHelper<K>::PtrType key) -> typename std::enable_if<IsSmartPtr<K>::value, MappedTakeType>::type
 {
     iterator it = find(key);
     if (it == end())
-        return MappedTraits::emptyValue();
-    MappedType value = WTFMove(it->value);
+        return MappedTraits::take(MappedTraits::emptyValue());
+    auto value = MappedTraits::take(WTFMove(it->value));
     remove(it);
     return value;
 }
index c9a2fc1..cf1f942 100644 (file)
@@ -38,6 +38,7 @@ namespace WTF {
     private:
         typedef HashArg HashFunctions;
         typedef TraitsArg ValueTraits;
+        typedef typename ValueTraits::TakeType TakeType;
 
     public:
         typedef typename ValueTraits::TraitType ValueType;
@@ -105,15 +106,15 @@ namespace WTF {
         void removeIf(const Functor&);
         void clear();
 
-        ValueType take(const ValueType&);
-        ValueType take(iterator);
-        ValueType takeAny();
+        TakeType take(const ValueType&);
+        TakeType take(iterator);
+        TakeType takeAny();
 
         // Overloads for smart pointer values that take the raw pointer type as the parameter.
         template<typename V = ValueType> typename std::enable_if<IsSmartPtr<V>::value, iterator>::type find(typename GetPtrHelper<V>::PtrType) const;
         template<typename V = ValueType> typename std::enable_if<IsSmartPtr<V>::value, bool>::type contains(typename GetPtrHelper<V>::PtrType) const;
         template<typename V = ValueType> typename std::enable_if<IsSmartPtr<V>::value, bool>::type remove(typename GetPtrHelper<V>::PtrType);
-        template<typename V = ValueType> typename std::enable_if<IsSmartPtr<V>::value, ValueType>::type take(typename GetPtrHelper<V>::PtrType);
+        template<typename V = ValueType> typename std::enable_if<IsSmartPtr<V>::value, TakeType>::type take(typename GetPtrHelper<V>::PtrType);
 
         static bool isValidValue(const ValueType&);
 
@@ -128,11 +129,14 @@ namespace WTF {
         template<typename T> static const T& extract(const T& t) { return t; }
     };
 
-    template<typename HashFunctions>
+    template<typename ValueTraits, typename HashFunctions>
     struct HashSetTranslator {
         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 V> static void translate(T& location, U&&, V&& value) { location = std::forward<V>(value); }
+        template<typename T, typename U, typename V> static void translate(T& location, U&&, V&& value)
+        { 
+            ValueTraits::assignToEmpty(location, std::forward<V>(value));
+        }
     };
 
     template<typename Translator>
@@ -266,24 +270,24 @@ namespace WTF {
     }
 
     template<typename T, typename U, typename V>
-    inline auto HashSet<T, U, V>::take(iterator it) -> ValueType
+    inline auto HashSet<T, U, V>::take(iterator it) -> TakeType
     {
         if (it == end())
-            return ValueTraits::emptyValue();
+            return ValueTraits::take(ValueTraits::emptyValue());
 
-        ValueType result = WTFMove(const_cast<ValueType&>(*it));
+        auto result = ValueTraits::take(WTFMove(const_cast<ValueType&>(*it)));
         remove(it);
         return result;
     }
 
     template<typename T, typename U, typename V>
-    inline auto HashSet<T, U, V>::take(const ValueType& value) -> ValueType
+    inline auto HashSet<T, U, V>::take(const ValueType& value) -> TakeType
     {
         return take(find(value));
     }
 
     template<typename T, typename U, typename V>
-    inline auto HashSet<T, U, V>::takeAny() -> ValueType
+    inline auto HashSet<T, U, V>::takeAny() -> TakeType
     {
         return take(begin());
     }
@@ -292,14 +296,14 @@ namespace WTF {
     template<typename V>
     inline auto HashSet<Value, HashFunctions, Traits>::find(typename GetPtrHelper<V>::PtrType value) const -> typename std::enable_if<IsSmartPtr<V>::value, iterator>::type
     {
-        return m_impl.template find<HashSetTranslator<HashFunctions>>(value);
+        return m_impl.template find<HashSetTranslator<Traits, HashFunctions>>(value);
     }
 
     template<typename Value, typename HashFunctions, typename Traits>
     template<typename V>
     inline auto HashSet<Value, HashFunctions, Traits>::contains(typename GetPtrHelper<V>::PtrType value) const -> typename std::enable_if<IsSmartPtr<V>::value, bool>::type
     {
-        return m_impl.template contains<HashSetTranslator<HashFunctions>>(value);
+        return m_impl.template contains<HashSetTranslator<Traits, HashFunctions>>(value);
     }
 
     template<typename Value, typename HashFunctions, typename Traits>
@@ -311,7 +315,7 @@ namespace WTF {
 
     template<typename Value, typename HashFunctions, typename Traits>
     template<typename V>
-    inline auto HashSet<Value, HashFunctions, Traits>::take(typename GetPtrHelper<V>::PtrType value) -> typename std::enable_if<IsSmartPtr<V>::value, ValueType>::type
+    inline auto HashSet<Value, HashFunctions, Traits>::take(typename GetPtrHelper<V>::PtrType value) -> typename std::enable_if<IsSmartPtr<V>::value, TakeType>::type
     {
         return take(find(value));
     }
index 712022d..2e59771 100644 (file)
@@ -279,11 +279,14 @@ namespace WTF {
         const_iterator m_iterator;
     };
 
-    template<typename HashFunctions> class IdentityHashTranslator {
+    template<typename ValueTraits, typename HashFunctions> class IdentityHashTranslator {
     public:
         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 V> static void translate(T& location, const U&, V&& value) { location = std::forward<V>(value); }
+        template<typename T, typename U, typename V> static void translate(T& location, const U&, V&& value)
+        { 
+            ValueTraits::assignToEmpty(location, std::forward<V>(value)); 
+        }
     };
 
     template<typename IteratorType> struct HashTableAddResult {
@@ -303,7 +306,7 @@ namespace WTF {
         typedef Traits ValueTraits;
         typedef Key KeyType;
         typedef Value ValueType;
-        typedef IdentityHashTranslator<HashFunctions> IdentityTranslatorType;
+        typedef IdentityHashTranslator<ValueTraits, HashFunctions> IdentityTranslatorType;
         typedef HashTableAddResult<iterator> AddResult;
 
 #if DUMP_HASHTABLE_STATS_PER_TABLE
index 2affe31..eb04847 100644 (file)
 #ifndef WTF_HashTraits_h
 #define WTF_HashTraits_h
 
+#include <limits>
+#include <utility>
 #include <wtf/HashFunctions.h>
+#include <wtf/Optional.h>
 #include <wtf/StdLibExtras.h>
-#include <utility>
-#include <limits>
 
 namespace WTF {
 
@@ -61,9 +62,18 @@ template<typename T> struct GenericHashTraits : GenericHashTraitsBase<std::is_in
 
     static T emptyValue() { return T(); }
 
+    template<typename U, typename V> 
+    static void assignToEmpty(U& emptyValue, V&& value)
+    { 
+        emptyValue = std::forward<V>(value);
+    }
+
     // Type for return value of functions that do not transfer ownership, such as get.
     typedef T PeekType;
     template<typename U> static U&& peek(U&& value) { return std::forward<U>(value); }
+
+    typedef T TakeType;
+    template<typename U> static TakeType take(U&& value) { return std::forward<U>(value); }
 };
 
 template<typename T> struct HashTraits : GenericHashTraits<T> { };
@@ -165,6 +175,23 @@ template<typename P> struct HashTraits<RefPtr<P>> : SimpleClassHashTraits<RefPtr
     }
 };
 
+template<typename P> struct HashTraits<Ref<P>> : SimpleClassHashTraits<Ref<P>> {
+    static const bool emptyValueIsZero = true;
+    static Ref<P> emptyValue() { return HashTableEmptyValue; }
+
+    static const bool hasIsEmptyValueFunction = true;
+    static bool isEmptyValue(const Ref<P>& value) { return value.isHashTableEmptyValue(); }
+
+    static void assignToEmpty(Ref<P>& emptyValue, Ref<P>&& newValue) { ASSERT(isEmptyValue(emptyValue)); emptyValue.assignToHashTableEmptyValue(WTFMove(newValue)); }
+
+    typedef P* PeekType;
+    static PeekType peek(const Ref<P>& value) { return const_cast<PeekType>(value.ptrAllowingHashTableEmptyValue()); }
+    static PeekType peek(P* value) { return value; }
+
+    typedef Optional<Ref<P>> TakeType;
+    static TakeType take(Ref<P>&& value) { return isEmptyValue(value) ? Nullopt : Optional<Ref<P>>(WTFMove(value)); }
+};
+
 template<> struct HashTraits<String> : SimpleClassHashTraits<String> {
     static const bool hasIsEmptyValueFunction = true;
     static bool isEmptyValue(const String&);
index 7e45e67..bd632db 100644 (file)
@@ -114,6 +114,25 @@ public:
         return *this;
     }
 
+    // Hash table deleted/empty values, which are only constructed and never copied or destroyed.
+    Ref(HashTableDeletedValueType) : m_ptr(hashTableDeletedValue()) { }
+    bool isHashTableDeletedValue() const { return m_ptr == hashTableDeletedValue(); }
+    static T* hashTableDeletedValue() { return reinterpret_cast<T*>(-1); }
+
+    Ref(HashTableEmptyValueType) : m_ptr(hashTableEmptyValue()) { }
+    bool isHashTableEmptyValue() const { return m_ptr == hashTableEmptyValue(); }
+    static T* hashTableEmptyValue() { return nullptr; }
+
+    const T* ptrAllowingHashTableEmptyValue() const { ASSERT(m_ptr || isHashTableEmptyValue()); return m_ptr; }
+    T* ptrAllowingHashTableEmptyValue() { ASSERT(m_ptr || isHashTableEmptyValue()); return m_ptr; }
+
+    void assignToHashTableEmptyValue(Ref&& reference)
+    {
+        ASSERT(m_ptr == hashTableEmptyValue());
+        m_ptr = &reference.leakRef();
+        ASSERT(m_ptr);
+    }
+
     const T* operator->() const { ASSERT(m_ptr); return m_ptr; }
     T* operator->() { ASSERT(m_ptr); return m_ptr; }
 
@@ -186,12 +205,16 @@ struct GetPtrHelper<Ref<T>> {
     static T* getPtr(const Ref<T>& p) { return const_cast<T*>(p.ptr()); }
 };
 
+template <typename T> 
+struct IsSmartPtr<Ref<T>> {
+    static const bool value = true;
+};
+
 template<typename T>
 inline Ref<T> adoptRef(T& reference)
 {
     adopted(&reference);
     return Ref<T>(reference, Ref<T>::Adopt);
-
 }
 
 template<typename ExpectedType, typename ArgType> inline bool is(Ref<ArgType>& source)
index a8cb6c9..7d0a452 100644 (file)
@@ -34,8 +34,6 @@ namespace WTF {
 template<typename T> class RefPtr;
 template<typename T> RefPtr<T> adoptRef(T*);
 
-enum HashTableDeletedValueType { HashTableDeletedValue };
-
 template<typename T> class RefPtr {
     WTF_MAKE_FAST_ALLOCATED;
 public:
index 0cb84c1..e7fdda6 100644 (file)
@@ -1,3 +1,17 @@
+2016-06-20  Commit Queue  <commit-queue@webkit.org>
+
+        Unreviewed, rolling out r202136.
+        https://bugs.webkit.org/show_bug.cgi?id=158932
+
+        JSBench wasn't regressed by r202002 and r202111 on iOS after
+        all (Requested by rniwa_ on #webkit).
+
+        Reverted changeset:
+
+        "Unreviewed, rolling out r202002 and r202111."
+        https://bugs.webkit.org/show_bug.cgi?id=158638
+        http://trac.webkit.org/changeset/202136
+
 2016-06-20  Keith Rollin  <krollin@apple.com>
 
         Remove RefPtr::release() and change calls sites to use WTFMove()
index 08a414d..7973a7b 100644 (file)
@@ -701,4 +701,196 @@ TEST(WTF_HashMap, RefPtrNotZeroedBeforeDeref)
     EXPECT_EQ(observer->count, 0u);
 }
 
+TEST(WTF_HashMap, Ref_Key)
+{
+    {
+        HashMap<Ref<RefLogger>, int> map;
+
+        RefLogger a("a");
+        Ref<RefLogger> ref(a);
+        map.add(WTFMove(ref), 1);
+    }
+
+    ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+    {
+        HashMap<Ref<RefLogger>, int> map;
+
+        RefLogger a("a");
+        Ref<RefLogger> ref(a);
+        map.set(WTFMove(ref), 1);
+    }
+
+    ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+    {
+        HashMap<Ref<RefLogger>, int> map;
+
+        RefLogger a("a");
+        Ref<RefLogger> refA(a);
+        map.add(WTFMove(refA), 1);
+
+        Ref<RefLogger> refA2(a);
+        map.set(WTFMove(refA2), 1);
+    }
+
+    ASSERT_STREQ("ref(a) ref(a) deref(a) deref(a) ", takeLogStr().c_str());
+
+    {
+        HashMap<Ref<RefLogger>, int> map;
+
+        RefLogger a("a");
+        Ref<RefLogger> ref(a);
+        map.ensure(WTFMove(ref), []() { 
+            return 1; 
+        });
+    }
+
+    ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+    {
+        HashMap<Ref<RefLogger>, int> map;
+
+        RefLogger a("a");
+        Ref<RefLogger> ref(a);
+        map.add(WTFMove(ref), 1);
+        
+        auto it = map.find(&a);
+        ASSERT_TRUE(it != map.end());
+        
+        ASSERT_EQ(it->key.ptr(), &a);
+        ASSERT_EQ(it->value, 1);
+    }
+
+    ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+    {
+        HashMap<Ref<RefLogger>, int> map;
+
+        RefLogger a("a");
+        Ref<RefLogger> ref(a);
+        map.add(WTFMove(ref), 1);
+
+        map.remove(&a);
+    }
+
+    ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+    {
+        HashMap<Ref<RefLogger>, int> map;
+
+        RefLogger a("a");
+        Ref<RefLogger> ref(a);
+        map.add(WTFMove(ref), 1);
+
+        int i = map.take(&a);
+        ASSERT_EQ(i, 1);
+    }
+
+    ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+TEST(WTF_HashMap, Ref_Value)
+{
+    {
+        HashMap<int, Ref<RefLogger>> map;
+
+        RefLogger a("a");
+        Ref<RefLogger> ref(a);
+        map.add(1, WTFMove(ref));
+    }
+
+    ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+    {
+        HashMap<int, Ref<RefLogger>> map;
+
+        RefLogger a("a");
+        Ref<RefLogger> ref(a);
+        map.set(1, WTFMove(ref));
+    }
+
+    ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+    {
+        HashMap<int, Ref<RefLogger>> map;
+
+        RefLogger a("a");
+        Ref<RefLogger> refA(a);
+        map.add(1, WTFMove(refA));
+
+        RefLogger b("b");
+        Ref<RefLogger> refB(b);
+        map.set(1, WTFMove(refB));
+    }
+
+    ASSERT_STREQ("ref(a) ref(b) deref(a) deref(b) ", takeLogStr().c_str());
+
+    {
+        HashMap<int, Ref<RefLogger>> map;
+
+        RefLogger a("a");
+        Ref<RefLogger> ref(a);
+        map.add(1, WTFMove(ref));
+        
+        auto aGet = map.get(1);
+        ASSERT_EQ(aGet, &a);
+    }
+
+    ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+    {
+        HashMap<int, Ref<RefLogger>> map;
+        
+        auto emptyGet = map.get(1);
+        ASSERT_TRUE(emptyGet == nullptr);
+    }
+
+    {
+        HashMap<int, Ref<RefLogger>> map;
+
+        RefLogger a("a");
+        Ref<RefLogger> ref(a);
+        map.add(1, WTFMove(ref));
+        
+        auto aOut = map.take(1);
+        ASSERT_TRUE(static_cast<bool>(aOut));
+        ASSERT_EQ(&a, aOut.value().ptr());
+    }
+
+    ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+    {
+        HashMap<int, Ref<RefLogger>> map;
+        
+        auto emptyTake = map.take(1);
+        ASSERT_FALSE(static_cast<bool>(emptyTake));
+    }
+
+    {
+        HashMap<int, Ref<RefLogger>> map;
+
+        RefLogger a("a");
+        Ref<RefLogger> ref(a);
+        map.add(1, WTFMove(ref));
+        map.remove(1);
+    }
+
+    ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+    {
+        HashMap<int, Ref<RefLogger>> map;
+
+        RefLogger a("a");
+        map.ensure(1, [&]() { 
+            Ref<RefLogger> ref(a);
+            return ref; 
+        });
+    }
+
+    ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
+
+
 } // namespace TestWebKitAPI
index 1d6ffc0..6b81300 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "Counters.h"
 #include "MoveOnly.h"
+#include "RefLogger.h"
 #include <wtf/HashSet.h>
 #include <wtf/RefPtr.h>
 
@@ -348,5 +349,84 @@ TEST(WTF_HashSet, UniquePtrNotZeroedBeforeDestructor)
     EXPECT_TRUE(observedBucket == observerAddress || observedBucket == reinterpret_cast<const DestructorObserver*>(-1));
 }
 
+TEST(WTF_HashSet, Ref)
+{
+    {
+        HashSet<Ref<RefLogger>> set;
+
+        RefLogger a("a");
+        Ref<RefLogger> ref(a);
+        set.add(WTFMove(ref));
+    }
+
+    ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+    {
+        HashSet<Ref<RefLogger>> set;
+
+        RefLogger a("a");
+        Ref<RefLogger> ref(a);
+        set.add(ref.copyRef());
+    }
+
+    ASSERT_STREQ("ref(a) ref(a) deref(a) deref(a) ", takeLogStr().c_str());
+
+    {
+        HashSet<Ref<RefLogger>> set;
+
+        RefLogger a("a");
+        Ref<RefLogger> ref(a);
+        set.add(WTFMove(ref));
+        set.remove(&a);
+    }
+
+    ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+    {
+        HashSet<Ref<RefLogger>> set;
+
+        RefLogger a("a");
+        Ref<RefLogger> ref(a);
+        set.add(WTFMove(ref));
+
+        auto aOut = set.take(&a);
+        ASSERT_TRUE(static_cast<bool>(aOut));
+        ASSERT_EQ(&a, aOut.value().ptr());
+    }
+
+    ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+    {
+        HashSet<Ref<RefLogger>> set;
+
+        RefLogger a("a");
+        Ref<RefLogger> ref(a);
+        set.add(WTFMove(ref));
+
+        auto aOut = set.takeAny();
+        ASSERT_TRUE(static_cast<bool>(aOut));
+        ASSERT_EQ(&a, aOut.value().ptr());
+    }
+
+    ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+    {
+        HashSet<Ref<RefLogger>> set;
+        auto emptyTake = set.takeAny();
+        ASSERT_FALSE(static_cast<bool>(emptyTake));
+    }
+
+    {
+        HashSet<Ref<RefLogger>> set;
+
+        RefLogger a("a");
+        Ref<RefLogger> ref(a);
+        set.add(WTFMove(ref));
+        
+        ASSERT_TRUE(set.contains(&a));
+    }
+
+    ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
 
 } // namespace TestWebKitAPI