Skip to content
Snippets Groups Projects
Select Git revision
  • wk2/unstable default
  • fix-raspi-issues-v2-oracular
  • fix-raspi-issues-v2-noble
  • fix-raspi-issues-v2
  • fix-raspi-issues
  • wpe/unstable
  • wpewebkit-2.44
  • berto/wk2/bookworm
  • berto/wk2/bullseye
  • webkitgtk-2.44
  • wk2/experimental
  • wpewebkit-2.42
  • webkitgtk-2.42
  • webkitgtk-2.40
  • wpewebkit-2.40
  • buster
  • webkitgtk-2.38
  • wpewebkit-2.38
  • wpewebkit-2.36
  • webkitgtk-2.36
  • wpe/debian/2.44.1-1
  • wpe/upstream/2.44.1
  • debian/2.44.1-1
  • upstream/2.44.1
  • debian/2.44.0-2
  • debian/2.44.0-1
  • upstream/2.44.0
  • debian/2.43.4-2
  • debian/2.42.5-2
  • wpe/debian/2.42.5-1.2
  • wpe/debian/2.42.5-2_exp
  • wpe/debian/2.42.5-1.1
  • debian/2.42.5-1_deb11u1
  • debian/2.42.5-1_deb12u1
  • wpe/debian/2.42.5-1
  • wpe/upstream/2.42.5
  • debian/2.42.5-1
  • upstream/2.42.5
  • debian/2.43.4-1
  • upstream/2.43.4
40 results

HashSet.cpp

Blame
  • Forked from WebKit / webkit
    279 commits behind the upstream repository.
    user avatar
    Alberto Garcia authored
    3909133a
    History
    HashSet.cpp 22.33 KiB
    /*
     * Copyright (C) 2012-2017 Apple Inc. All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     * 1. Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     * 2. Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
     * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     * THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    #include "config.h"
    
    #include "Counters.h"
    #include "DeletedAddressOfOperator.h"
    #include "MoveOnly.h"
    #include "RefLogger.h"
    #include "Test.h"
    #include <functional>
    #include <wtf/HashSet.h>
    #include <wtf/RefPtr.h>
    #include <wtf/text/StringConcatenateNumbers.h>
    #include <wtf/text/StringHash.h>
    
    namespace TestWebKitAPI {
    
    template<int initialCapacity>
    struct InitialCapacityTestHashTraits : public WTF::UnsignedWithZeroKeyHashTraits<int> {
        static const int minimumTableSize = initialCapacity;
    };
    
    template<unsigned size>
    void testInitialCapacity()
    {
        const unsigned initialCapacity = WTF::HashTableCapacityForSize<size>::value;
        HashSet<int, DefaultHash<int>, InitialCapacityTestHashTraits<initialCapacity> > testSet;
    
        // Initial capacity is null.
        ASSERT_EQ(0u, testSet.capacity());
    
        // Adding items up to size should never change the capacity.
        for (size_t i = 0; i < size; ++i) {
            testSet.add(i);
            ASSERT_EQ(initialCapacity, static_cast<unsigned>(testSet.capacity()));
        }
    
        // Adding items up to less than 3/4 of the capacity should not change the capacity.
        unsigned capacityLimit = initialCapacity * 3 / 4 - 1;
        for (size_t i = size; i < capacityLimit; ++i) {
            testSet.add(i);
            ASSERT_EQ(initialCapacity, static_cast<unsigned>(testSet.capacity()));
        }
    
        // Adding one more item increase the capacity.
        testSet.add(initialCapacity);
        EXPECT_GT(static_cast<unsigned>(testSet.capacity()), initialCapacity);
    }
    
    template<unsigned size> inline void generateTestCapacityUpToSize();
    template<> inline void generateTestCapacityUpToSize<0>()
    {
    }
    template<unsigned size> inline void generateTestCapacityUpToSize()
    {
        generateTestCapacityUpToSize<size - 1>();
        testInitialCapacity<size>();
    }
    
    TEST(WTF_HashSet, InitialCapacity)
    {
        generateTestCapacityUpToSize<128>();
    }
    
    TEST(WTF_HashSet, MoveOnly)
    {
        HashSet<MoveOnly> hashSet;
    
        for (size_t i = 0; i < 100; ++i) {
            MoveOnly moveOnly(i + 1);
            hashSet.add(WTFMove(moveOnly));
        }
    
        for (size_t i = 0; i < 100; ++i)
            EXPECT_TRUE(hashSet.contains(MoveOnly(i + 1)));
    
        for (size_t i = 0; i < 100; ++i)
            EXPECT_TRUE(hashSet.remove(MoveOnly(i + 1)));
    
        EXPECT_TRUE(hashSet.isEmpty());
    
        for (size_t i = 0; i < 100; ++i)
            hashSet.add(MoveOnly(i + 1));
    
        for (size_t i = 0; i < 100; ++i)
            EXPECT_TRUE(hashSet.take(MoveOnly(i + 1)) == MoveOnly(i + 1));
    
        EXPECT_TRUE(hashSet.isEmpty());
    
        for (size_t i = 0; i < 100; ++i)
            hashSet.add(MoveOnly(i + 1));
    
        HashSet<MoveOnly> secondSet;
    
        for (size_t i = 0; i < 100; ++i)
            secondSet.add(hashSet.takeAny());
    
        EXPECT_TRUE(hashSet.isEmpty());
    
        for (size_t i = 0; i < 100; ++i)
            EXPECT_TRUE(secondSet.contains(MoveOnly(i + 1)));
    }
    
    
    TEST(WTF_HashSet, UniquePtrKey)
    {
        ConstructorDestructorCounter::TestingScope scope;
    
        HashSet<std::unique_ptr<ConstructorDestructorCounter>> set;
    
        auto uniquePtr = makeUnique<ConstructorDestructorCounter>();
        set.add(WTFMove(uniquePtr));
    
        EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
        EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
    
        set.clear();
    
        EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
        EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount);
    }
    
    TEST(WTF_HashSet, UniquePtrKey_FindUsingRawPointer)
    {
        HashSet<std::unique_ptr<int>> set;
    
        auto uniquePtr = makeUniqueWithoutFastMallocCheck<int>(5);
        int* ptr = uniquePtr.get();
        set.add(WTFMove(uniquePtr));
    
        auto it = set.find(ptr);
        ASSERT_TRUE(it != set.end());
        EXPECT_EQ(ptr, it->get());
        EXPECT_EQ(5, *it->get());
    }
    
    TEST(WTF_HashSet, UniquePtrKey_ContainsUsingRawPointer)
    {
        HashSet<std::unique_ptr<int>> set;
    
        auto uniquePtr = makeUniqueWithoutFastMallocCheck<int>(5);
        int* ptr = uniquePtr.get();
        set.add(WTFMove(uniquePtr));
    
        EXPECT_EQ(true, set.contains(ptr));
    }
    
    TEST(WTF_HashSet, UniquePtrKey_RemoveUsingRawPointer)
    {
        ConstructorDestructorCounter::TestingScope scope;
    
        HashSet<std::unique_ptr<ConstructorDestructorCounter>> set;
    #if !CHECK_HASHTABLE_ITERATORS &&!DUMP_HASHTABLE_STATS_PER_TABLE
        static_assert(sizeof(set) == sizeof(void*));
    #endif
    
        auto uniquePtr = makeUnique<ConstructorDestructorCounter>();
        ConstructorDestructorCounter* ptr = uniquePtr.get();
        set.add(WTFMove(uniquePtr));
    
        EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
        EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
    
        bool result = set.remove(ptr);
        EXPECT_EQ(true, result);
    
        EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
        EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount);
    }
    
    TEST(WTF_HashSet, UniquePtrKey_TakeUsingRawPointer)
    {
        ConstructorDestructorCounter::TestingScope scope;
    
        HashSet<std::unique_ptr<ConstructorDestructorCounter>> set;
    
        auto uniquePtr = makeUnique<ConstructorDestructorCounter>();
        ConstructorDestructorCounter* ptr = uniquePtr.get();
        set.add(WTFMove(uniquePtr));
    
        EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
        EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
    
        auto result = set.take(ptr);
        EXPECT_EQ(ptr, result.get());
    
        EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
        EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);
        
        result = nullptr;
    
        EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
        EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount);
    }
    
    TEST(WTF_HashSet, CopyEmpty)
    {
        {
            HashSet<unsigned> foo;
            HashSet<unsigned> bar(foo);
    
            EXPECT_EQ(0u, bar.capacity());
            EXPECT_EQ(0u, bar.size());
        }
        {
            HashSet<unsigned> foo({ 1, 5, 64, 42 });
            EXPECT_EQ(4u, foo.size());
            foo.remove(1);
            foo.remove(5);
            foo.remove(42);
            foo.remove(64);
            HashSet<unsigned> bar(foo);
    
            EXPECT_EQ(0u, bar.capacity());
            EXPECT_EQ(0u, bar.size());
        }
    }
    
    TEST(WTF_HashSet, CopyAllocateAtLeastMinimumCapacity)
    {
        HashSet<unsigned> foo({ 42 });
        EXPECT_EQ(1u, foo.size());
        HashSet<unsigned> bar(foo);
    
        EXPECT_EQ(8u, bar.capacity());
        EXPECT_EQ(1u, bar.size());
    }
    
    TEST(WTF_HashSet, CopyCapacityIsNotOnBoundary)
    {
        // Starting at 4 because the minimum size is 8.
        // With a size of 8, a medium load can be up to 3.3333->3.
        // Adding 1 to 3 would reach max load.
        // While correct, that's not really what we care about here.
        for (unsigned size = 4; size < 100; ++size) {
            HashSet<unsigned> source;
            for (unsigned i = 1; i < size + 1; ++i)
                source.add(i);
    
            HashSet<unsigned> copy1(source);
            HashSet<unsigned> copy2(source);
            HashSet<unsigned> copy3(source);
    
            EXPECT_EQ(size, copy1.size());
            EXPECT_EQ(size, copy2.size());
            EXPECT_EQ(size, copy3.size());
            for (unsigned i = 1; i < size + 1; ++i) {
                EXPECT_TRUE(copy1.contains(i));
                EXPECT_TRUE(copy2.contains(i));
                EXPECT_TRUE(copy3.contains(i));
            }
            EXPECT_FALSE(copy1.contains(size + 2));
            EXPECT_FALSE(copy2.contains(size + 2));
            EXPECT_FALSE(copy3.contains(size + 2));
    
            EXPECT_TRUE(copy2.remove(1));
            EXPECT_EQ(copy1.capacity(), copy2.capacity());
            EXPECT_FALSE(copy2.contains(1));
    
            EXPECT_TRUE(copy3.add(size + 2).isNewEntry);
            EXPECT_EQ(copy1.capacity(), copy3.capacity());
            EXPECT_TRUE(copy3.contains(size + 2));
        }
    }
    
    struct DerefObserver {
        WTF_MAKE_STRUCT_FAST_ALLOCATED;
        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 };
    };
    
    TEST(WTF_HashSet, RefPtrNotZeroedBeforeDeref)
    {
        auto observer = makeUniqueWithoutRefCountedCheck<DerefObserver>();
    
        HashSet<RefPtr<DerefObserver>> set;
        set.add(adoptRef(observer.get()));
    
        auto iterator = set.find(observer.get());
        EXPECT_TRUE(iterator != set.end());
    
        observer->bucketAddress = iterator.get();
    
        EXPECT_TRUE(observer->observedBucket == nullptr);
        EXPECT_TRUE(set.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>::PtrTraits::hashTableDeletedValue());
        EXPECT_EQ(observer->count, 0u);
    }
    
    
    TEST(WTF_HashSet, UniquePtrNotZeroedBeforeDestructor)
    {
        struct DestructorObserver {
            ~DestructorObserver()
            {
                observe();
            }
            std::function<void()> observe;
        };
    
        const std::unique_ptr<DestructorObserver>* bucketAddress = nullptr;
        const DestructorObserver* observedBucket = nullptr;
        std::unique_ptr<DestructorObserver> observer(new DestructorObserver { [&]() {
            observedBucket = bucketAddress->get();
        }});
    
        const DestructorObserver* observerAddress = observer.get();
    
        HashSet<std::unique_ptr<DestructorObserver>> set;
        auto addResult = set.add(WTFMove(observer));
    
        EXPECT_TRUE(addResult.isNewEntry);
        EXPECT_TRUE(observedBucket == nullptr);
    
        bucketAddress = addResult.iterator.get();
    
        EXPECT_TRUE(observedBucket == nullptr);
        EXPECT_TRUE(set.remove(*addResult.iterator));
    
        EXPECT_TRUE(observedBucket == observerAddress || observedBucket == reinterpret_cast<const DestructorObserver*>(-1));
    }
    
    TEST(WTF_HashSet, Ref)
    {
        {
            RefLogger a("a");
    
            HashSet<Ref<RefLogger>> set;
    
            Ref<RefLogger> ref(a);
            set.add(WTFMove(ref));
        }
    
        ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
    
        {
            RefLogger a("a");
    
            HashSet<Ref<RefLogger>> set;
    
            Ref<RefLogger> ref(a);
            set.add(ref.copyRef());
        }
    
        ASSERT_STREQ("ref(a) ref(a) deref(a) deref(a) ", takeLogStr().c_str());
    
        {
            RefLogger a("a");
    
            HashSet<Ref<RefLogger>> set;
    
            Ref<RefLogger> ref(a);
            set.add(WTFMove(ref));
            set.remove(&a);
        }
    
        ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
    
        {
            RefLogger a("a");
    
            HashSet<Ref<RefLogger>> set;
    
            Ref<RefLogger> ref(a);
            set.add(WTFMove(ref));
    
            auto aOut = set.take(&a);
            ASSERT_TRUE(static_cast<bool>(aOut));
            ASSERT_EQ(&a, aOut.get());
        }
    
        ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
    
        {
            RefLogger a("a");
    
            HashSet<Ref<RefLogger>> set;
    
            Ref<RefLogger> ref(a);
            set.add(WTFMove(ref));
    
            auto aOut = set.takeAny();
            ASSERT_TRUE(static_cast<bool>(aOut));
            ASSERT_EQ(&a, aOut.get());
        }
    
        ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
    
        {
            HashSet<Ref<RefLogger>> set;
            auto emptyTake = set.takeAny();
            ASSERT_FALSE(static_cast<bool>(emptyTake));
        }
    
        {
            RefLogger a("a");
    
            HashSet<Ref<RefLogger>> set;
    
            Ref<RefLogger> ref(a);
            set.add(WTFMove(ref));
            
            ASSERT_TRUE(set.contains(&a));
        }
    
        ASSERT_STREQ("ref(a) deref(a) ", takeLogStr().c_str());
    
        {
            HashSet<Ref<RefLogger>> set;
            for (int i = 0; i < 64; ++i) {
                // FIXME: All of these RefLogger objects leak. No big deal for a test I guess.
                Ref<RefLogger> ref = adoptRef(*new RefLogger("a"));
                auto* pointer = ref.ptr();
                set.add(WTFMove(ref));
                ASSERT_TRUE(set.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());
    
        {
            RefLogger a("a");
    
            HashSet<Ref<RefLogger>> set;
            Ref<RefLogger> ref(a);
            set.add(WTFMove(ref));
            HashSet<Ref<RefLogger>> set2(set);
        }
        ASSERT_STREQ("ref(a) ref(a) deref(a) deref(a) ", takeLogStr().c_str());
    }
    
    TEST(WTF_HashSet, DeletedAddressOfOperator)
    {
        HashSet<DeletedAddressOfOperator> set1;
        set1.add(10);
    
        set1.remove(10);
    }
    
    TEST(WTF_HashSet, RemoveRandom)
    {
        HashSet<unsigned> set1 { 1, 2, 3 };
        set1.remove(set1.random());
        set1.remove(set1.random());
        set1.remove(set1.random());
        ASSERT_TRUE(set1.isEmpty());
    }
    
    TEST(WTF_HashSet, RemoveIf)
    {
        HashSet<unsigned> set1 { 1, 2, 3, 4, 5 };
        ASSERT_EQ(set1.size(), 5u);
        set1.removeIf([] (unsigned item) { return item % 2;  });
        set1.checkConsistency();
        ASSERT_TRUE(!set1.contains(1));
        ASSERT_TRUE(set1.contains(2));
        ASSERT_TRUE(!set1.contains(3));
        ASSERT_TRUE(set1.contains(4));
        ASSERT_TRUE(!set1.contains(5));
        ASSERT_EQ(set1.size(), 2u);
    }
    
    TEST(WTF_HashSet, RemoveIfShrinkToBestSize)
    {
        HashSet<unsigned> set1;
        set1.add(1);
        unsigned originalCapacity = set1.capacity();
        while (set1.capacity() < originalCapacity * 4)
            set1.add(set1.size() + 1);
        set1.removeIf([] (unsigned item) { return item != 1; });
        set1.checkConsistency();
        ASSERT_EQ(set1.size(), 1u);
        ASSERT_EQ(set1.capacity(), originalCapacity);
    
        set1.clear();
        set1.checkConsistency();
        while (set1.capacity() < originalCapacity * 8)
            set1.add(set1.size() + 1);
        set1.removeIf([originalCapacity] (unsigned item) { return item >= originalCapacity / 2; });
        set1.checkConsistency();
        ASSERT_EQ(set1.size(), originalCapacity / 2 - 1);
        ASSERT_EQ(set1.capacity(), originalCapacity);
    }
    
    TEST(WTF_HashSet, ReserveInitialCapacity)
    {
        HashSet<String> set;
        EXPECT_EQ(0u, set.size());
        EXPECT_EQ(0u, set.capacity());
    
        set.reserveInitialCapacity(9999);
        EXPECT_EQ(0u, set.size());
        EXPECT_EQ(32768u, set.capacity());
    
        for (int i = 0; i < 9999; ++i)
            set.add(makeString("foo", i));
        EXPECT_EQ(9999u, set.size());
        EXPECT_EQ(32768u, set.capacity());
        EXPECT_TRUE(set.contains("foo3"_str));
    
        for (int i = 0; i < 9999; ++i)
            set.add(makeString("excess", i));
        EXPECT_EQ(9999u + 9999u, set.size());
        EXPECT_EQ(32768u + 32768u, set.capacity());
    
        for (int i = 0; i < 9999; ++i)
            EXPECT_TRUE(set.remove(makeString("foo", i)));
        EXPECT_EQ(9999u, set.size());
        EXPECT_EQ(32768u, set.capacity());
    
        for (int i = 0; i < 9999; ++i)
            EXPECT_TRUE(set.remove(makeString("excess", i)));
        EXPECT_EQ(0u, set.size());
        EXPECT_EQ(8u, set.capacity());
    
        HashSet<String> set2;
        set2.reserveInitialCapacity(9999);
        EXPECT_FALSE(set2.remove("foo1"_s));
    
        for (int i = 0; i < 2000; ++i)
            set2.add(makeString("foo", i));
        EXPECT_EQ(2000u, set2.size());
        EXPECT_EQ(32768u, set2.capacity());
    
        for (int i = 0; i < 2000; ++i)
            EXPECT_TRUE(set2.remove(makeString("foo", i)));
        EXPECT_EQ(0u, set2.size());
        EXPECT_EQ(8u, set2.capacity());
    }
    
    TEST(WTF_HashSet, UnionWith)
    {
        HashSet<int> emptySet;
        HashSet<int> set1 { 1, 2, 3 };
        HashSet<int> set2 { 2, 3, 4 };
        HashSet<int> set3 { 1, 2, 3, 4 };
        Vector<int> sequence { 2, 3, 4 };
    
        {
            auto result = emptySet.unionWith(set1);
            EXPECT_EQ(result, set1);
        }
    
        {
            auto result = set1.unionWith(emptySet);
            EXPECT_EQ(result, set1);
        }
    
        {
            auto result = emptySet.unionWith(emptySet);
            EXPECT_EQ(result, emptySet);
        }
    
        {
            auto result = set1.unionWith(set1);
            EXPECT_EQ(result, set1);
        }
    
        {
            auto result = set1.unionWith(set2);
            EXPECT_EQ(result, set3);
        }
    
        {
            auto result = set2.unionWith(set1);
            EXPECT_EQ(result, set3);
        }
    
        {
            auto result = set1.unionWith(sequence);
            EXPECT_EQ(result, set3);
        }
    }
    
    TEST(WTF_HashSet, FormUnion)
    {
        HashSet<int> emptySet;
        HashSet<int> set1 { 1, 2, 3 };
        HashSet<int> set2 { 2, 3, 4 };
        HashSet<int> set3 { 1, 2, 3, 4 };
        Vector<int> sequence { 2, 3, 4 };
    
        {
            auto result = emptySet;
            result.formUnion(set1);
            EXPECT_EQ(result, set1);
        }
    
        {
            auto result = set1;
            result.formUnion(emptySet);
            EXPECT_EQ(result, set1);
        }
    
        {
            auto result = emptySet;
            result.formUnion(emptySet);
            EXPECT_EQ(result, emptySet);
        }
    
        {
            auto result = set1;
            result.formUnion(set1);
            EXPECT_EQ(result, set1);
        }
    
        {
            auto result = set1;
            result.formUnion(set2);
            EXPECT_EQ(result, set3);
        }
    
        {
            auto result = set2;
            result.formUnion(set1);
            EXPECT_EQ(result, set3);
        }
    
        {
            auto result = set1;
            result.formUnion(sequence);
            EXPECT_EQ(result, set3);
        }
    }
    
    TEST(WTF_HashSet, IntersectionWith)
    {
        HashSet<int> emptySet;
        HashSet<int> set1 { 1, 2, 3 };
        HashSet<int> set2 { 2, 3, 4 };
        HashSet<int> set3 { 2, 3 };
        Vector<int> sequence { 2, 3, 4 };
    
        {
            auto result = emptySet.intersectionWith(set1);
            EXPECT_EQ(result, emptySet);
        }
    
        {
            auto result = set1.intersectionWith(emptySet);
            EXPECT_EQ(result, emptySet);
        }
    
        {
            auto result = emptySet.intersectionWith(emptySet);
            EXPECT_EQ(result, emptySet);
        }
    
        {
            auto result = set1.intersectionWith(set1);
            EXPECT_EQ(result, set1);
        }
    
        {
            auto result = set1.intersectionWith(set2);
            EXPECT_EQ(result, set3);
        }
    
        {
            auto result = set2.intersectionWith(set1);
            EXPECT_EQ(result, set3);
        }
    
        {
            auto result = set1.intersectionWith(sequence);
            EXPECT_EQ(result, set3);
        }
    }
    
    TEST(WTF_HashSet, FormIntersection)
    {
        HashSet<int> emptySet;
        HashSet<int> set1 { 1, 2, 3 };
        HashSet<int> set2 { 2, 3, 4 };
        HashSet<int> set3 { 2, 3 };
        Vector<int> sequence { 2, 3, 4 };
    
        {
            auto result = emptySet;
            result.formIntersection(set1);
            EXPECT_EQ(result, emptySet);
        }
    
        {
            auto result = set1;
            result.formIntersection(emptySet);
            EXPECT_EQ(result, emptySet);
        }
    
        {
            auto result = emptySet;
            result.formIntersection(emptySet);
            EXPECT_EQ(result, emptySet);
        }
    
        {
            auto result = set1;
            result.formIntersection(set1);
            EXPECT_EQ(result, set1);
        }
    
        {
            auto result = set1;
            result.formIntersection(set2);
            EXPECT_EQ(result, set3);
        }
    
        {
            auto result = set2;
            result.formIntersection(set1);
            EXPECT_EQ(result, set3);
        }
    
        {
            auto result = set1;
            result.formIntersection(sequence);
            EXPECT_EQ(result, set3);
        }
    }
    
    TEST(WTF_HashSet, SymmetricDifferenceWith)
    {
        HashSet<int> emptySet;
        HashSet<int> set1 { 1, 2, 3 };
        HashSet<int> set2 { 2, 3, 4 };
        HashSet<int> set3 { 1, 4 };
        Vector<int> sequence { 2, 3, 4 };
    
        {
            auto result = emptySet.symmetricDifferenceWith(set1);
            EXPECT_EQ(result, set1);
        }
    
        {
            auto result = set1.symmetricDifferenceWith(emptySet);
            EXPECT_EQ(result, set1);
        }
    
        {
            auto result = emptySet.symmetricDifferenceWith(emptySet);
            EXPECT_EQ(result, emptySet);
        }
    
        {
            auto result = set1.symmetricDifferenceWith(set1);
            EXPECT_EQ(result, emptySet);
        }
    
        {
            auto result = set1.symmetricDifferenceWith(set2);
            EXPECT_EQ(result, set3);
        }
    
        {
            auto result = set2.symmetricDifferenceWith(set1);
            EXPECT_EQ(result, set3);
        }
    
        {
            auto result = set1.symmetricDifferenceWith(sequence);
            EXPECT_EQ(result, set3);
        }
    }
    
    TEST(WTF_HashSet, FormSymmetricDifference)
    {
        HashSet<int> emptySet;
        HashSet<int> set1 { 1, 2, 3 };
        HashSet<int> set2 { 2, 3, 4 };
        HashSet<int> set3 { 1, 4 };
        Vector<int> sequence { 2, 3, 4 };
    
        {
            auto result = emptySet;
            result.formSymmetricDifference(set1);
            EXPECT_EQ(result, set1);
        }
    
        {
            auto result = set1;
            result.formSymmetricDifference(emptySet);
            EXPECT_EQ(result, set1);
        }
    
        {
            auto result = emptySet;
            result.formSymmetricDifference(emptySet);
            EXPECT_EQ(result, emptySet);
        }
    
        {
            auto result = set1;
            result.formSymmetricDifference(set1);
            EXPECT_EQ(result, emptySet);
        }
    
        {
            auto result = set1;
            result.formSymmetricDifference(set2);
            EXPECT_EQ(result, set3);
        }
    
        {
            auto result = set2;
            result.formSymmetricDifference(set1);
            EXPECT_EQ(result, set3);
        }
    
        {
            auto result = set1;
            result.formSymmetricDifference(sequence);
            EXPECT_EQ(result, set3);
        }
    }
    
    } // namespace TestWebKitAPI