diff options
Diffstat (limited to 'Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp')
-rw-r--r-- | Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp | 780 |
1 files changed, 777 insertions, 3 deletions
diff --git a/Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp b/Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp index d03fb9594..222f23c5c 100644 --- a/Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp +++ b/Tools/TestWebKitAPI/Tests/WTF/HashMap.cpp @@ -25,9 +25,14 @@ #include "config.h" +#include "Counters.h" +#include "DeletedAddressOfOperator.h" #include "MoveOnly.h" +#include "RefLogger.h" +#include "Test.h" #include <string> #include <wtf/HashMap.h> +#include <wtf/Ref.h> #include <wtf/text/StringHash.h> namespace TestWebKitAPI { @@ -90,7 +95,7 @@ TEST(WTF_HashMap, MoveOnlyValues) for (size_t i = 0; i < 100; ++i) { MoveOnly moveOnly(i + 1); - moveOnlyValues.set(i + 1, std::move(moveOnly)); + moveOnlyValues.set(i + 1, WTFMove(moveOnly)); } for (size_t i = 0; i < 100; ++i) { @@ -113,7 +118,7 @@ TEST(WTF_HashMap, MoveOnlyKeys) for (size_t i = 0; i < 100; ++i) { MoveOnly moveOnly(i + 1); - moveOnlyKeys.set(std::move(moveOnly), i + 1); + moveOnlyKeys.set(WTFMove(moveOnly), i + 1); } for (size_t i = 0; i < 100; ++i) { @@ -139,7 +144,7 @@ TEST(WTF_HashMap, InitializerList) { 4, "four" }, }; - EXPECT_EQ(4, map.size()); + EXPECT_EQ(4u, map.size()); EXPECT_EQ("one", map.get(1)); EXPECT_EQ("two", map.get(2)); @@ -148,4 +153,773 @@ TEST(WTF_HashMap, InitializerList) EXPECT_EQ(std::string(), map.get(5)); } +TEST(WTF_HashMap, EfficientGetter) +{ + HashMap<unsigned, CopyMoveCounter> map; + map.set(1, CopyMoveCounter()); + + { + CopyMoveCounter::TestingScope scope; + map.get(1); + EXPECT_EQ(0U, CopyMoveCounter::constructionCount); + EXPECT_EQ(1U, CopyMoveCounter::copyCount); + EXPECT_EQ(0U, CopyMoveCounter::moveCount); + } + + { + CopyMoveCounter::TestingScope scope; + map.get(2); + EXPECT_EQ(1U, CopyMoveCounter::constructionCount); + EXPECT_EQ(0U, CopyMoveCounter::copyCount); + EXPECT_EQ(1U, CopyMoveCounter::moveCount); + } +} + +TEST(WTF_HashMap, UniquePtrKey) +{ + ConstructorDestructorCounter::TestingScope scope; + + HashMap<std::unique_ptr<ConstructorDestructorCounter>, int> map; + + auto uniquePtr = std::make_unique<ConstructorDestructorCounter>(); + map.add(WTFMove(uniquePtr), 2); + + EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount); + EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount); + + map.clear(); + + EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount); + EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount); +} + +TEST(WTF_HashMap, UniquePtrKey_CustomDeleter) +{ + ConstructorDestructorCounter::TestingScope constructorDestructorCounterScope; + DeleterCounter<ConstructorDestructorCounter>::TestingScope deleterCounterScope; + + HashMap<std::unique_ptr<ConstructorDestructorCounter, DeleterCounter<ConstructorDestructorCounter>>, int> map; + + std::unique_ptr<ConstructorDestructorCounter, DeleterCounter<ConstructorDestructorCounter>> uniquePtr(new ConstructorDestructorCounter(), DeleterCounter<ConstructorDestructorCounter>()); + map.add(WTFMove(uniquePtr), 2); + + EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount); + EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount); + + EXPECT_EQ(0u, DeleterCounter<ConstructorDestructorCounter>::deleterCount()); + + map.clear(); + + EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount); + EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount); + + EXPECT_EQ(1u, DeleterCounter<ConstructorDestructorCounter>::deleterCount()); +} + +TEST(WTF_HashMap, UniquePtrKey_FindUsingRawPointer) +{ + HashMap<std::unique_ptr<int>, int> map; + + auto uniquePtr = std::make_unique<int>(5); + int* ptr = uniquePtr.get(); + map.add(WTFMove(uniquePtr), 2); + + auto it = map.find(ptr); + ASSERT_TRUE(it != map.end()); + EXPECT_EQ(ptr, it->key.get()); + EXPECT_EQ(2, it->value); +} + +TEST(WTF_HashMap, UniquePtrKey_ContainsUsingRawPointer) +{ + HashMap<std::unique_ptr<int>, int> map; + + auto uniquePtr = std::make_unique<int>(5); + int* ptr = uniquePtr.get(); + map.add(WTFMove(uniquePtr), 2); + + EXPECT_EQ(true, map.contains(ptr)); +} + +TEST(WTF_HashMap, UniquePtrKey_GetUsingRawPointer) +{ + HashMap<std::unique_ptr<int>, int> map; + + auto uniquePtr = std::make_unique<int>(5); + int* ptr = uniquePtr.get(); + map.add(WTFMove(uniquePtr), 2); + + int value = map.get(ptr); + EXPECT_EQ(2, value); +} + +TEST(WTF_HashMap, UniquePtrKey_RemoveUsingRawPointer) +{ + ConstructorDestructorCounter::TestingScope scope; + + HashMap<std::unique_ptr<ConstructorDestructorCounter>, int> map; + + auto uniquePtr = std::make_unique<ConstructorDestructorCounter>(); + ConstructorDestructorCounter* ptr = uniquePtr.get(); + map.add(WTFMove(uniquePtr), 2); + + EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount); + EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount); + + bool result = map.remove(ptr); + EXPECT_EQ(true, result); + + EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount); + EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount); +} + +TEST(WTF_HashMap, UniquePtrKey_TakeUsingRawPointer) +{ + ConstructorDestructorCounter::TestingScope scope; + + HashMap<std::unique_ptr<ConstructorDestructorCounter>, int> map; + + auto uniquePtr = std::make_unique<ConstructorDestructorCounter>(); + ConstructorDestructorCounter* ptr = uniquePtr.get(); + map.add(WTFMove(uniquePtr), 2); + + EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount); + EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount); + + int result = map.take(ptr); + EXPECT_EQ(2, result); + + EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount); + EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount); +} + +TEST(WTF_HashMap, RefPtrKey_Add) +{ + HashMap<RefPtr<RefLogger>, int> map; + + DerivedRefLogger a("a"); + RefPtr<RefLogger> ptr(&a); + map.add(ptr, 0); + + ASSERT_STREQ("ref(a) ref(a) ", takeLogStr().c_str()); +} + +TEST(WTF_HashMap, RefPtrKey_AddUsingRelease) +{ + HashMap<RefPtr<RefLogger>, int> map; + + DerivedRefLogger a("a"); + RefPtr<RefLogger> ptr(&a); + map.add(WTFMove(ptr), 0); + + EXPECT_STREQ("ref(a) ", takeLogStr().c_str()); +} + +TEST(WTF_HashMap, RefPtrKey_AddUsingMove) +{ + HashMap<RefPtr<RefLogger>, int> map; + + DerivedRefLogger a("a"); + RefPtr<RefLogger> ptr(&a); + map.add(WTFMove(ptr), 0); + + EXPECT_STREQ("ref(a) ", takeLogStr().c_str()); +} + +TEST(WTF_HashMap, RefPtrKey_AddUsingRaw) +{ + HashMap<RefPtr<RefLogger>, int> map; + + DerivedRefLogger a("a"); + RefPtr<RefLogger> ptr(&a); + map.add(ptr.get(), 0); + + EXPECT_STREQ("ref(a) ref(a) ", takeLogStr().c_str()); +} + +TEST(WTF_HashMap, RefPtrKey_AddKeyAlreadyPresent) +{ + HashMap<RefPtr<RefLogger>, int> map; + + DerivedRefLogger a("a"); + + { + RefPtr<RefLogger> ptr(&a); + map.add(ptr, 0); + } + + EXPECT_STREQ("ref(a) ref(a) deref(a) ", takeLogStr().c_str()); + + { + RefPtr<RefLogger> ptr2(&a); + auto addResult = map.add(ptr2, 0); + EXPECT_FALSE(addResult.isNewEntry); + } + + EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); +} + +TEST(WTF_HashMap, RefPtrKey_AddUsingReleaseKeyAlreadyPresent) +{ + HashMap<RefPtr<RefLogger>, int> map; + + DerivedRefLogger a("a"); + + { + RefPtr<RefLogger> ptr(&a); + map.add(ptr, 0); + } + + EXPECT_STREQ("ref(a) ref(a) deref(a) ", takeLogStr().c_str()); + + { + RefPtr<RefLogger> ptr2(&a); + auto addResult = map.add(WTFMove(ptr2), 0); + EXPECT_FALSE(addResult.isNewEntry); + } + + EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); +} + +TEST(WTF_HashMap, RefPtrKey_AddUsingMoveKeyAlreadyPresent) +{ + HashMap<RefPtr<RefLogger>, int> map; + + DerivedRefLogger a("a"); + + { + RefPtr<RefLogger> ptr(&a); + map.add(ptr, 0); + } + + EXPECT_STREQ("ref(a) ref(a) deref(a) ", takeLogStr().c_str()); + + { + RefPtr<RefLogger> ptr2(&a); + auto addResult = map.add(WTFMove(ptr2), 0); + EXPECT_FALSE(addResult.isNewEntry); + } + + EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); +} + +TEST(WTF_HashMap, RefPtrKey_Set) +{ + HashMap<RefPtr<RefLogger>, int> map; + + DerivedRefLogger a("a"); + RefPtr<RefLogger> ptr(&a); + map.set(ptr, 0); + + ASSERT_STREQ("ref(a) ref(a) ", takeLogStr().c_str()); +} + +TEST(WTF_HashMap, RefPtrKey_SetUsingRelease) +{ + HashMap<RefPtr<RefLogger>, int> map; + + DerivedRefLogger a("a"); + RefPtr<RefLogger> ptr(&a); + map.set(WTFMove(ptr), 0); + + EXPECT_STREQ("ref(a) ", takeLogStr().c_str()); +} + + +TEST(WTF_HashMap, RefPtrKey_SetUsingMove) +{ + HashMap<RefPtr<RefLogger>, int> map; + + DerivedRefLogger a("a"); + RefPtr<RefLogger> ptr(&a); + map.set(WTFMove(ptr), 0); + + EXPECT_STREQ("ref(a) ", takeLogStr().c_str()); +} + +TEST(WTF_HashMap, RefPtrKey_SetUsingRaw) +{ + HashMap<RefPtr<RefLogger>, int> map; + + DerivedRefLogger a("a"); + RefPtr<RefLogger> ptr(&a); + map.set(ptr.get(), 0); + + EXPECT_STREQ("ref(a) ref(a) ", takeLogStr().c_str()); +} + +TEST(WTF_HashMap, RefPtrKey_SetKeyAlreadyPresent) +{ + HashMap<RefPtr<RefLogger>, int> map; + + DerivedRefLogger a("a"); + + RefPtr<RefLogger> ptr(&a); + map.set(ptr, 0); + + EXPECT_STREQ("ref(a) ref(a) ", takeLogStr().c_str()); + + { + RefPtr<RefLogger> ptr2(&a); + auto addResult = map.set(ptr2, 1); + EXPECT_FALSE(addResult.isNewEntry); + EXPECT_EQ(1, map.get(ptr.get())); + } + + EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); +} + +TEST(WTF_HashMap, RefPtrKey_SetUsingReleaseKeyAlreadyPresent) +{ + HashMap<RefPtr<RefLogger>, int> map; + + DerivedRefLogger a("a"); + + RefPtr<RefLogger> ptr(&a); + map.set(ptr, 0); + + EXPECT_STREQ("ref(a) ref(a) ", takeLogStr().c_str()); + + { + RefPtr<RefLogger> ptr2(&a); + auto addResult = map.set(WTFMove(ptr2), 1); + EXPECT_FALSE(addResult.isNewEntry); + EXPECT_EQ(1, map.get(ptr.get())); + } + + EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); +} + +TEST(WTF_HashMap, RefPtrKey_SetUsingMoveKeyAlreadyPresent) +{ + HashMap<RefPtr<RefLogger>, int> map; + + DerivedRefLogger a("a"); + + RefPtr<RefLogger> ptr(&a); + map.set(ptr, 0); + + EXPECT_STREQ("ref(a) ref(a) ", takeLogStr().c_str()); + + { + RefPtr<RefLogger> ptr2(&a); + auto addResult = map.set(WTFMove(ptr2), 1); + EXPECT_FALSE(addResult.isNewEntry); + EXPECT_EQ(1, map.get(ptr.get())); + } + + EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); +} + +TEST(WTF_HashMap, Ensure) +{ + HashMap<unsigned, unsigned> map; + { + auto addResult = map.ensure(1, [] { return 1; }); + EXPECT_EQ(1u, addResult.iterator->value); + EXPECT_EQ(1u, addResult.iterator->key); + EXPECT_TRUE(addResult.isNewEntry); + auto addResult2 = map.ensure(1, [] { return 2; }); + EXPECT_EQ(1u, addResult2.iterator->value); + EXPECT_EQ(1u, addResult2.iterator->key); + EXPECT_FALSE(addResult2.isNewEntry); + } +} + +TEST(WTF_HashMap, Ensure_MoveOnlyValues) +{ + HashMap<unsigned, MoveOnly> moveOnlyValues; + { + auto addResult = moveOnlyValues.ensure(1, [] { return MoveOnly(1); }); + EXPECT_EQ(1u, addResult.iterator->value.value()); + EXPECT_EQ(1u, addResult.iterator->key); + EXPECT_TRUE(addResult.isNewEntry); + auto addResult2 = moveOnlyValues.ensure(1, [] { return MoveOnly(2); }); + EXPECT_EQ(1u, addResult2.iterator->value.value()); + EXPECT_EQ(1u, addResult2.iterator->key); + EXPECT_FALSE(addResult2.isNewEntry); + } +} + +TEST(WTF_HashMap, Ensure_UniquePointer) +{ + HashMap<unsigned, std::unique_ptr<unsigned>> map; + { + auto addResult = map.ensure(1, [] { return std::make_unique<unsigned>(1); }); + EXPECT_EQ(1u, *map.get(1)); + EXPECT_EQ(1u, *addResult.iterator->value.get()); + EXPECT_EQ(1u, addResult.iterator->key); + EXPECT_TRUE(addResult.isNewEntry); + auto addResult2 = map.ensure(1, [] { return std::make_unique<unsigned>(2); }); + EXPECT_EQ(1u, *map.get(1)); + EXPECT_EQ(1u, *addResult2.iterator->value.get()); + EXPECT_EQ(1u, addResult2.iterator->key); + EXPECT_FALSE(addResult2.isNewEntry); + } +} + +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()); + } +} + +class ObjectWithRefLogger { +public: + ObjectWithRefLogger(Ref<RefLogger>&& logger) + : m_logger(WTFMove(logger)) + { + } + + Ref<RefLogger> m_logger; +}; + + +void testMovingUsingEnsure(Ref<RefLogger>&& logger) +{ + HashMap<unsigned, std::unique_ptr<ObjectWithRefLogger>> map; + + map.ensure(1, [&] { return std::make_unique<ObjectWithRefLogger>(WTFMove(logger)); }); +} + +void testMovingUsingAdd(Ref<RefLogger>&& logger) +{ + HashMap<unsigned, std::unique_ptr<ObjectWithRefLogger>> map; + + auto& slot = map.add(1, nullptr).iterator->value; + slot = std::make_unique<ObjectWithRefLogger>(WTFMove(logger)); +} + +TEST(WTF_HashMap, Ensure_LambdasCapturingByReference) +{ + { + DerivedRefLogger a("a"); + Ref<RefLogger> ref(a); + testMovingUsingEnsure(WTFMove(ref)); + + EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); + } + + { + DerivedRefLogger a("a"); + Ref<RefLogger> ref(a); + testMovingUsingAdd(WTFMove(ref)); + + EXPECT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); + } +} + + +TEST(WTF_HashMap, ValueIsDestructedOnRemove) +{ + struct DestructorObserver { + DestructorObserver() = default; + + DestructorObserver(bool* destructed) + : destructed(destructed) + { + } + + ~DestructorObserver() + { + if (destructed) + *destructed = true; + } + + DestructorObserver(DestructorObserver&& other) + : destructed(other.destructed) + { + other.destructed = nullptr; + } + + DestructorObserver& operator=(DestructorObserver&& other) + { + destructed = other.destructed; + other.destructed = nullptr; + return *this; + } + + bool* destructed { nullptr }; + }; + + HashMap<int, DestructorObserver> map; + + bool destructed = false; + map.add(5, DestructorObserver { &destructed }); + + EXPECT_FALSE(destructed); + + bool removeResult = map.remove(5); + + EXPECT_TRUE(removeResult); + EXPECT_TRUE(destructed); +} + +TEST(WTF_HashMap, RefPtrNotZeroedBeforeDeref) +{ + struct DerefObserver { + NEVER_INLINE void ref() + { + ++count; + } + NEVER_INLINE void deref() + { + --count; + observedBucket = bucketAddress->get(); + } + unsigned count { 1 }; + const RefPtr<DerefObserver>* bucketAddress { nullptr }; + const DerefObserver* observedBucket { nullptr }; + }; + + auto observer = std::make_unique<DerefObserver>(); + + HashMap<RefPtr<DerefObserver>, int> map; + map.add(adoptRef(observer.get()), 5); + + auto iterator = map.find(observer.get()); + EXPECT_TRUE(iterator != map.end()); + + observer->bucketAddress = &iterator->key; + + EXPECT_TRUE(observer->observedBucket == nullptr); + EXPECT_TRUE(map.remove(observer.get())); + + // It if fine to either leave the old value intact at deletion or already set it to the deleted + // value. + // A zero would be a incorrect outcome as it would mean we nulled the bucket before an opaque + // call. + EXPECT_TRUE(observer->observedBucket == observer.get() || observer->observedBucket == RefPtr<DerefObserver>::hashTableDeletedValue()); + 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()); + + { + HashMap<Ref<RefLogger>, int> map; + for (int i = 0; i < 64; ++i) { + Ref<RefLogger> ref = adoptRef(*new RefLogger("a")); + auto* pointer = ref.ptr(); + map.add(WTFMove(ref), i + 1); + ASSERT_TRUE(map.contains(pointer)); + } + } + + ASSERT_STREQ("deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(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, [&]() mutable { + Ref<RefLogger> ref(a); + return ref; + }); + } + + ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str()); + + { + HashMap<int, Ref<RefLogger>> map; + for (int i = 0; i < 64; ++i) { + Ref<RefLogger> ref = adoptRef(*new RefLogger("a")); + map.add(i + 1, WTFMove(ref)); + ASSERT_TRUE(map.contains(i + 1)); + } + } + + ASSERT_STREQ("deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) deref(a) ", takeLogStr().c_str()); +} + +TEST(WTF_HashMap, DeletedAddressOfOperator) +{ + HashMap<int, DeletedAddressOfOperator> map1; + for (auto& value : map1.values()) + (void)value; +} + } // namespace TestWebKitAPI |