Title: [202002] trunk
Revision
202002
Author
[email protected]
Date
2016-06-13 13:06:22 -0700 (Mon, 13 Jun 2016)

Log Message

Make HashMap and HashSet work with Refs
https://bugs.webkit.org/show_bug.cgi?id=158638

Patch by Sam Weinig <[email protected]> on 2016-06-13
Reviewed by Darin Adler.

Source/WTF:

* wtf/GetPtr.h:
Move HashTableDeletedValueType and HashTableEmptyValueType here, as they are now shared
by more than one smart pointer. This file should probably be renamed to something else
at some point to indicate that it contains helpers for pointer and ref related functionality.

* wtf/HashFunctions.h:
Add a DefaultHash for Refs. Customize the PtrHash to indicate that it is not safe to compare
to empty or deleted Refs.

* wtf/HashMap.h:
(WTF::HashMapTranslator::equal):
(WTF::HashMapTranslator::translate):
(WTF::HashMapEnsureTranslator::equal):
(WTF::HashMapEnsureTranslator::translate):
* wtf/HashSet.h:
(WTF::IdentityExtractor::extract):
(WTF::HashSetTranslator::hash):
(WTF::HashSetTranslator::equal):
(WTF::HashSetTranslator::translate):
* wtf/HashTable.h:
(WTF::IdentityHashTranslator::hash):
(WTF::IdentityHashTranslator::equal):
(WTF::IdentityHashTranslator::translate):
Use the new assignToEmpty trait function to allow uninitialized Ref's to be safely assigned to.

* wtf/HashTraits.h:
(WTF::HashTraits<Ref<P>>::emptyValue):
(WTF::HashTraits<Ref<P>>::isEmptyValue):
(WTF::HashTraits<Ref<P>>::assignToEmpty):
(WTF::HashTraits<Ref<P>>::peek):
(WTF::HashTraits<Ref<P>>::customDeleteBucket):
Add custom HashTraits for Ref. Also, introduce a new trait function, assignToEmpty, for use
in translation assignments. This is necessary since the default assignment operator for Ref
will not allow assignment to the empty Ref, which we need to do here.

* wtf/Ref.h:
(WTF::Ref::operator=):
(WTF::Ref::Ref):
(WTF::Ref::isHashTableDeletedValue):
(WTF::Ref::hashTableDeletedValue):
(WTF::Ref::isHashTableEmptyValue):
(WTF::Ref::hashTableEmptyValue):
Add explicit constructors/predicates for making deleted/empty Refs.

(WTF::Ref::assignToHashTableEmptyValue):
Add a special function that allows assignment to an empty Ref, which the
assignment operator does not.

(WTF::IsSmartPtr):
Add an IsSmartPtr override to indicate that Ref is a smart pointer.

* wtf/RefPtr.h:
Move HashTableDeletedValueType to GetPtr.h.

Tools:

* TestWebKitAPI/Tests/WTF/HashMap.cpp:
(TestWebKitAPI::TEST):
* TestWebKitAPI/Tests/WTF/HashSet.cpp:
(TestWebKitAPI::TEST):
Add tests for using Refs in HashMaps (both as key and value) and HashSets.

Modified Paths

Diff

Modified: trunk/Source/WTF/ChangeLog (202001 => 202002)


--- trunk/Source/WTF/ChangeLog	2016-06-13 19:47:38 UTC (rev 202001)
+++ trunk/Source/WTF/ChangeLog	2016-06-13 20:06:22 UTC (rev 202002)
@@ -1,3 +1,64 @@
+2016-06-13  Sam Weinig  <[email protected]>
+
+        Make HashMap and HashSet work with Refs
+        https://bugs.webkit.org/show_bug.cgi?id=158638
+
+        Reviewed by Darin Adler.
+
+        * wtf/GetPtr.h:
+        Move HashTableDeletedValueType and HashTableEmptyValueType here, as they are now shared
+        by more than one smart pointer. This file should probably be renamed to something else
+        at some point to indicate that it contains helpers for pointer and ref related functionality.
+
+        * wtf/HashFunctions.h:
+        Add a DefaultHash for Refs. Customize the PtrHash to indicate that it is not safe to compare
+        to empty or deleted Refs.
+
+        * wtf/HashMap.h:
+        (WTF::HashMapTranslator::equal):
+        (WTF::HashMapTranslator::translate):
+        (WTF::HashMapEnsureTranslator::equal):
+        (WTF::HashMapEnsureTranslator::translate):
+        * wtf/HashSet.h:
+        (WTF::IdentityExtractor::extract):
+        (WTF::HashSetTranslator::hash):
+        (WTF::HashSetTranslator::equal):
+        (WTF::HashSetTranslator::translate):
+        * wtf/HashTable.h:
+        (WTF::IdentityHashTranslator::hash):
+        (WTF::IdentityHashTranslator::equal):
+        (WTF::IdentityHashTranslator::translate):
+        Use the new assignToEmpty trait function to allow uninitialized Ref's to be safely assigned to.
+
+        * wtf/HashTraits.h:
+        (WTF::HashTraits<Ref<P>>::emptyValue):
+        (WTF::HashTraits<Ref<P>>::isEmptyValue):
+        (WTF::HashTraits<Ref<P>>::assignToEmpty):
+        (WTF::HashTraits<Ref<P>>::peek):
+        (WTF::HashTraits<Ref<P>>::customDeleteBucket):
+        Add custom HashTraits for Ref. Also, introduce a new trait function, assignToEmpty, for use
+        in translation assignments. This is necessary since the default assignment operator for Ref
+        will not allow assignment to the empty Ref, which we need to do here.
+
+        * wtf/Ref.h:
+        (WTF::Ref::operator=):
+        (WTF::Ref::Ref):
+        (WTF::Ref::isHashTableDeletedValue):
+        (WTF::Ref::hashTableDeletedValue):
+        (WTF::Ref::isHashTableEmptyValue):
+        (WTF::Ref::hashTableEmptyValue):
+        Add explicit constructors/predicates for making deleted/empty Refs.
+
+        (WTF::Ref::assignToHashTableEmptyValue):
+        Add a special function that allows assignment to an empty Ref, which the
+        assignment operator does not.
+        
+        (WTF::IsSmartPtr):
+        Add an IsSmartPtr override to indicate that Ref is a smart pointer.
+
+        * wtf/RefPtr.h:
+        Move HashTableDeletedValueType to GetPtr.h.
+
 2016-06-13  Fujii Hironori  <[email protected]>
 
         Stack overflow at RefPtr::release on Windows port since r201782

Modified: trunk/Source/WTF/wtf/GetPtr.h (202001 => 202002)


--- trunk/Source/WTF/wtf/GetPtr.h	2016-06-13 19:47:38 UTC (rev 202001)
+++ trunk/Source/WTF/wtf/GetPtr.h	2016-06-13 20:06:22 UTC (rev 202002)
@@ -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 {

Modified: trunk/Source/WTF/wtf/HashFunctions.h (202001 => 202002)


--- trunk/Source/WTF/wtf/HashFunctions.h	2016-06-13 19:47:38 UTC (rev 202001)
+++ trunk/Source/WTF/wtf/HashFunctions.h	2016-06-13 20:06:22 UTC (rev 202002)
@@ -149,6 +149,10 @@
     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 @@
 
     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.

Modified: trunk/Source/WTF/wtf/HashMap.h (202001 => 202002)


--- trunk/Source/WTF/wtf/HashMap.h	2016-06-13 19:47:38 UTC (rev 202001)
+++ trunk/Source/WTF/wtf/HashMap.h	2016-06-13 20:06:22 UTC (rev 202002)
@@ -181,8 +181,8 @@
     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 +192,8 @@
     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());
     }
 };
 

Modified: trunk/Source/WTF/wtf/HashSet.h (202001 => 202002)


--- trunk/Source/WTF/wtf/HashSet.h	2016-06-13 19:47:38 UTC (rev 202001)
+++ trunk/Source/WTF/wtf/HashSet.h	2016-06-13 20:06:22 UTC (rev 202002)
@@ -128,11 +128,14 @@
         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>
@@ -292,14 +295,14 @@
     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>

Modified: trunk/Source/WTF/wtf/HashTable.h (202001 => 202002)


--- trunk/Source/WTF/wtf/HashTable.h	2016-06-13 19:47:38 UTC (rev 202001)
+++ trunk/Source/WTF/wtf/HashTable.h	2016-06-13 20:06:22 UTC (rev 202002)
@@ -279,11 +279,14 @@
         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 @@
         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

Modified: trunk/Source/WTF/wtf/HashTraits.h (202001 => 202002)


--- trunk/Source/WTF/wtf/HashTraits.h	2016-06-13 19:47:38 UTC (rev 202001)
+++ trunk/Source/WTF/wtf/HashTraits.h	2016-06-13 20:06:22 UTC (rev 202002)
@@ -43,6 +43,12 @@
     // for cases like String that need them.
     static const bool hasIsEmptyValueFunction = false;
 
+    template<typename U, typename V> 
+    static void assignToEmpty(U& emptyValue, V&& value)
+    { 
+        emptyValue = std::forward<V>(value);
+    }
+
     // The starting table size. Can be overridden when we know beforehand that
     // a hash table will have at least N entries.
     static const unsigned minimumTableSize = 8;
@@ -165,6 +171,32 @@
     }
 };
 
+template<typename P> struct HashTraits<Ref<P>> : SimpleClassHashTraits<Ref<P>> {
+    static const bool emptyValueIsZero = true;
+    static Ref<P> emptyValue() { return Ref<P>(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.ptr()); }
+    static PeekType peek(P* value) { return value; }
+
+    static void customDeleteBucket(Ref<P>& value)
+    {
+        // See unique_ptr's customDeleteBucket() for an explanation.
+        ASSERT(!SimpleClassHashTraits<Ref<P>>::isDeletedValue(value));
+        auto valueToBeDestroyed = WTFMove(value);
+        SimpleClassHashTraits<Ref<P>>::constructDeletedValue(value);
+    }
+};
+
 template<> struct HashTraits<String> : SimpleClassHashTraits<String> {
     static const bool hasIsEmptyValueFunction = true;
     static bool isEmptyValue(const String&);

Modified: trunk/Source/WTF/wtf/Ref.h (202001 => 202002)


--- trunk/Source/WTF/wtf/Ref.h	2016-06-13 19:47:38 UTC (rev 202001)
+++ trunk/Source/WTF/wtf/Ref.h	2016-06-13 20:06:22 UTC (rev 202002)
@@ -114,6 +114,22 @@
         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; }
+
+    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 +202,16 @@
     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)

Modified: trunk/Source/WTF/wtf/RefPtr.h (202001 => 202002)


--- trunk/Source/WTF/wtf/RefPtr.h	2016-06-13 19:47:38 UTC (rev 202001)
+++ trunk/Source/WTF/wtf/RefPtr.h	2016-06-13 20:06:22 UTC (rev 202002)
@@ -34,8 +34,6 @@
 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:

Modified: trunk/Tools/ChangeLog (202001 => 202002)


--- trunk/Tools/ChangeLog	2016-06-13 19:47:38 UTC (rev 202001)
+++ trunk/Tools/ChangeLog	2016-06-13 20:06:22 UTC (rev 202002)
@@ -1,3 +1,16 @@
+2016-06-13  Sam Weinig  <[email protected]>
+
+        Make HashMap and HashSet work with Refs
+        https://bugs.webkit.org/show_bug.cgi?id=158638
+
+        Reviewed by Darin Adler.
+
+        * TestWebKitAPI/Tests/WTF/HashMap.cpp:
+        (TestWebKitAPI::TEST):
+        * TestWebKitAPI/Tests/WTF/HashSet.cpp:
+        (TestWebKitAPI::TEST):
+        Add tests for using Refs in HashMaps (both as key and value) and HashSets.
+
 2016-06-13  Mark Lam  <[email protected]>
 
         Add a mechanism for collecting LLINT stats.

Modified: trunk/Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp (202001 => 202002)


--- trunk/Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp	2016-06-13 19:47:38 UTC (rev 202001)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp	2016-06-13 20:06:22 UTC (rev 202002)
@@ -701,4 +701,179 @@
     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));
+        
+        ASSERT_EQ(map.get(1), &a);
+    }
+
+    ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+    {
+        HashMap<int, Ref<RefLogger>> map;
+
+        RefLogger a("a");
+        Ref<RefLogger> ref(a);
+        map.add(1, WTFMove(ref));
+        
+        Ref<RefLogger> aOut = map.take(1);
+    }
+
+    ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+
+    {
+        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

Modified: trunk/Tools/TestWebKitAPI/Tests/WTF/HashSet.cpp (202001 => 202002)


--- trunk/Tools/TestWebKitAPI/Tests/WTF/HashSet.cpp	2016-06-13 19:47:38 UTC (rev 202001)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/HashSet.cpp	2016-06-13 20:06:22 UTC (rev 202002)
@@ -27,6 +27,7 @@
 
 #include "Counters.h"
 #include "MoveOnly.h"
+#include "RefLogger.h"
 #include <wtf/HashSet.h>
 #include <wtf/RefPtr.h>
 
@@ -348,5 +349,50 @@
     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));
+        
+        ASSERT_TRUE(set.contains(&a));
+    }
+
+    ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
+}
+
 } // namespace TestWebKitAPI
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to