Title: [261179] trunk
Revision
261179
Author
mark....@apple.com
Date
2020-05-05 10:08:29 -0700 (Tue, 05 May 2020)

Log Message

Allow Bitmap to use up to a UCPURegister word size for internal bit storage.
https://bugs.webkit.org/show_bug.cgi?id=211328
<rdar://problem/62755865>

Reviewed by Yusuke Suzuki.

Source/_javascript_Core:

* assembler/CPU.h:

Source/WTF:

1. Moved the definition of CPURegister and UCPURegister down into WTF.
   Added CPU(REGISTER64) and CPU(REGISTER32) for determining what size a CPU
   general purpose register is.

2. Updated Bitmap so that it will automatically choose the minimal required
   word size for the number of bits it needs to store.  This means the Bitmap
   can automatically choose a WordType from uint8_t up to UCPURegister.
   Previously, the WordType is always uint32_t by default.

   This should improve perf with use of Bitmap on 64-bit platforms.  The size
   optimization is necessary to prevent bloat on 64-bit platforms which would have
   resulted if we simply set the default to always be UCPURegister.

3. Added a check in findRunOfZeros() for handling the edge case where the
   requested runLength exceeds the bitmapSize.

4. Fixed a bug in count() that was unnecessarily casting the bits to unsigned
   instead of just using the Bitmap WordType.  As a result, when using a WordType
   of uint64_t, it was discarding bits from the count.

5. Fixed invert() to leave the bits beyond bitmapSize untouched.
   Fixed isFull() to ignore the bits beyond bitmapSize.

   By fixing invert() to leave those bits as 0, isEmpty() and hash() will
   continue to work.  Otherwise, inverting those bits will cause isEmpty() to
   always fail, and hash()'s result may be different for the same set of bit
   values within bitmapSize.

   isFull(), on the other hand, checks for set bits in the words.  Since there
   may be 0 valued bits beyond bitmapSize, isFull() needs to be fixed to ignore
   those.

* WTF.xcodeproj/project.pbxproj:
* wtf/Bitmap.h:
(WTF::WordType>::invert):
(WTF::WordType>::findRunOfZeros const):
(WTF::WordType>::count const):
(WTF::WordType>::isFull const):
* wtf/CMakeLists.txt:
* wtf/PlatformCPU.h:
* wtf/PlatformUse.h:
* wtf/StdIntExtras.h: Copied from Source/WTF/wtf/StdIntExtras.h.

Tools:

Added API tests for WTF::Bitmap to make sure that Bitmap is behaving correctly.
Since Bitmap is used in critical infrastructure like the GC, it is important to
ensure that there are no latent bugs.

* TestWebKitAPI/CMakeLists.txt:
* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WTF/Bitmap.cpp: Added.
(TestWebKitAPI::countBits):
(TestWebKitAPI::testBitmapSize):
(TestWebKitAPI::testBitmapConstructedEmpty):
(TestWebKitAPI::testBitmapSetGet):
(TestWebKitAPI::testBitmapTestAndSet):
(TestWebKitAPI::testBitmapTestAndClear):
(TestWebKitAPI::testBitmapConcurrentTestAndSet):
(TestWebKitAPI::testBitmapConcurrentTestAndClear):
(TestWebKitAPI::testBitmapClear):
(TestWebKitAPI::testBitmapClearAll):
(TestWebKitAPI::testBitmapInvert):
(TestWebKitAPI::testBitmapFindRunOfZeros):
(TestWebKitAPI::testBitmapCount):
(TestWebKitAPI::testBitmapIsEmpty):
(TestWebKitAPI::testBitmapIsFull):
(TestWebKitAPI::testBitmapMerge):
(TestWebKitAPI::testBitmapFilter):
(TestWebKitAPI::testBitmapExclude):
(TestWebKitAPI::testBitmapConcurrentFilter):
(TestWebKitAPI::testBitmapSubsumes):
(TestWebKitAPI::testBitmapForEachSetBit):
(TestWebKitAPI::testBitmapFindBit):
(TestWebKitAPI::testBitmapIteration):
(TestWebKitAPI::testBitmapMergeAndClear):
(TestWebKitAPI::testBitmapSetAndClear):
(TestWebKitAPI::testBitmapOperatorEqual):
(TestWebKitAPI::testBitmapOperatorNotEqual):
(TestWebKitAPI::testBitmapHash):
(TestWebKitAPI::TEST):

LayoutTests:

editing/undo-manager/undo-manager-delete-stale-undo-items.html exposed a bug in
this patch.  However, when a failure occurs, this test runs perpetually until it
times out.  There's no need to do this.  After a finite number of GC cycles,
unreachable objects should be collected.  This is especially so because
GCController.collect() does a synchronous full GC.

Added a cap of 10 GC tries, and fail out if the test does not see the expected
result.  This allows the test to fail fast and avoid the costly time out.

* editing/undo-manager/undo-manager-delete-stale-undo-items.html:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (261178 => 261179)


--- trunk/LayoutTests/ChangeLog	2020-05-05 16:52:24 UTC (rev 261178)
+++ trunk/LayoutTests/ChangeLog	2020-05-05 17:08:29 UTC (rev 261179)
@@ -1,3 +1,22 @@
+2020-05-05  Mark Lam  <mark....@apple.com>
+
+        Allow Bitmap to use up to a UCPURegister word size for internal bit storage.
+        https://bugs.webkit.org/show_bug.cgi?id=211328
+        <rdar://problem/62755865>
+
+        Reviewed by Yusuke Suzuki.
+
+        editing/undo-manager/undo-manager-delete-stale-undo-items.html exposed a bug in
+        this patch.  However, when a failure occurs, this test runs perpetually until it
+        times out.  There's no need to do this.  After a finite number of GC cycles,
+        unreachable objects should be collected.  This is especially so because
+        GCController.collect() does a synchronous full GC.
+
+        Added a cap of 10 GC tries, and fail out if the test does not see the expected
+        result.  This allows the test to fail fast and avoid the costly time out.
+
+        * editing/undo-manager/undo-manager-delete-stale-undo-items.html:
+
 2020-05-05  Megan Gardner  <megan_gard...@apple.com>
 
         Style is not applied when changed on the first line of a new mail message.

Modified: trunk/LayoutTests/editing/undo-manager/undo-manager-delete-stale-undo-items.html (261178 => 261179)


--- trunk/LayoutTests/editing/undo-manager/undo-manager-delete-stale-undo-items.html	2020-05-05 16:52:24 UTC (rev 261178)
+++ trunk/LayoutTests/editing/undo-manager/undo-manager-delete-stale-undo-items.html	2020-05-05 17:08:29 UTC (rev 261179)
@@ -48,9 +48,12 @@
             // handlers are not properly relinquished once they're no longer needed.
             const minimumNumberOfWrappersToCollectBeforePassing = 3 * undoItemCount - 300;
             objectCountAfterClearingUndoStack = objectCountBeforeClearingUndoStack;
+            var tries = 0;
             while (objectCountBeforeClearingUndoStack - objectCountAfterClearingUndoStack < minimumNumberOfWrappersToCollectBeforePassing) {
                 await new Promise(resolve => setTimeout(resolve, 100));
                 objectCountAfterClearingUndoStack = objectCountAfterSimulatingMemoryPressureAndGarbageCollection();
+                if (tries++ > 10)
+                    break;
             }
 
             shouldBeGreaterThanOrEqual("objectCountBeforeClearingUndoStack - objectCountAfterClearingUndoStack", `${minimumNumberOfWrappersToCollectBeforePassing}`);

Modified: trunk/Source/_javascript_Core/ChangeLog (261178 => 261179)


--- trunk/Source/_javascript_Core/ChangeLog	2020-05-05 16:52:24 UTC (rev 261178)
+++ trunk/Source/_javascript_Core/ChangeLog	2020-05-05 17:08:29 UTC (rev 261179)
@@ -1,3 +1,13 @@
+2020-05-05  Mark Lam  <mark....@apple.com>
+
+        Allow Bitmap to use up to a UCPURegister word size for internal bit storage.
+        https://bugs.webkit.org/show_bug.cgi?id=211328
+        <rdar://problem/62755865>
+
+        Reviewed by Yusuke Suzuki.
+
+        * assembler/CPU.h:
+
 2020-05-05  Keith Miller  <keith_mil...@apple.com>
 
         iterator_open should remap the symbolIterator argument correctly when inlined.

Modified: trunk/Source/_javascript_Core/assembler/CPU.h (261178 => 261179)


--- trunk/Source/_javascript_Core/assembler/CPU.h	2020-05-05 16:52:24 UTC (rev 261178)
+++ trunk/Source/_javascript_Core/assembler/CPU.h	2020-05-05 17:08:29 UTC (rev 261179)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008-2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-2020 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,17 +27,10 @@
 
 #include "Options.h"
 #include <wtf/NumberOfCores.h>
+#include <wtf/StdIntExtras.h>
 
 namespace JSC {
 
-#if USE(JSVALUE64)
-using CPURegister = int64_t;
-using UCPURegister = uint64_t;
-#else
-using CPURegister = int32_t;
-using UCPURegister = uint32_t;
-#endif
-
 using UCPUStrictInt32 = UCPURegister;
 
 constexpr bool isARMv7IDIVSupported()

Modified: trunk/Source/WTF/ChangeLog (261178 => 261179)


--- trunk/Source/WTF/ChangeLog	2020-05-05 16:52:24 UTC (rev 261178)
+++ trunk/Source/WTF/ChangeLog	2020-05-05 17:08:29 UTC (rev 261179)
@@ -1,3 +1,54 @@
+2020-05-05  Mark Lam  <mark....@apple.com>
+
+        Allow Bitmap to use up to a UCPURegister word size for internal bit storage.
+        https://bugs.webkit.org/show_bug.cgi?id=211328
+        <rdar://problem/62755865>
+
+        Reviewed by Yusuke Suzuki.
+
+        1. Moved the definition of CPURegister and UCPURegister down into WTF.
+           Added CPU(REGISTER64) and CPU(REGISTER32) for determining what size a CPU
+           general purpose register is.
+
+        2. Updated Bitmap so that it will automatically choose the minimal required
+           word size for the number of bits it needs to store.  This means the Bitmap
+           can automatically choose a WordType from uint8_t up to UCPURegister.
+           Previously, the WordType is always uint32_t by default.
+
+           This should improve perf with use of Bitmap on 64-bit platforms.  The size
+           optimization is necessary to prevent bloat on 64-bit platforms which would have
+           resulted if we simply set the default to always be UCPURegister.
+
+        3. Added a check in findRunOfZeros() for handling the edge case where the
+           requested runLength exceeds the bitmapSize.
+
+        4. Fixed a bug in count() that was unnecessarily casting the bits to unsigned
+           instead of just using the Bitmap WordType.  As a result, when using a WordType
+           of uint64_t, it was discarding bits from the count.
+
+        5. Fixed invert() to leave the bits beyond bitmapSize untouched.
+           Fixed isFull() to ignore the bits beyond bitmapSize.
+
+           By fixing invert() to leave those bits as 0, isEmpty() and hash() will
+           continue to work.  Otherwise, inverting those bits will cause isEmpty() to
+           always fail, and hash()'s result may be different for the same set of bit
+           values within bitmapSize.
+
+           isFull(), on the other hand, checks for set bits in the words.  Since there
+           may be 0 valued bits beyond bitmapSize, isFull() needs to be fixed to ignore
+           those.
+
+        * WTF.xcodeproj/project.pbxproj:
+        * wtf/Bitmap.h:
+        (WTF::WordType>::invert):
+        (WTF::WordType>::findRunOfZeros const):
+        (WTF::WordType>::count const):
+        (WTF::WordType>::isFull const):
+        * wtf/CMakeLists.txt:
+        * wtf/PlatformCPU.h:
+        * wtf/PlatformUse.h:
+        * wtf/StdIntExtras.h: Copied from Source/WTF/wtf/StdIntExtras.h.
+
 2020-05-05  Darin Adler  <da...@apple.com>
 
         Remove now-unneeded USE(COREMEDIA) and USE(VIDEOTOOLBOX)

Modified: trunk/Source/WTF/WTF.xcodeproj/project.pbxproj (261178 => 261179)


--- trunk/Source/WTF/WTF.xcodeproj/project.pbxproj	2020-05-05 16:52:24 UTC (rev 261178)
+++ trunk/Source/WTF/WTF.xcodeproj/project.pbxproj	2020-05-05 17:08:29 UTC (rev 261179)
@@ -749,6 +749,7 @@
 		FE8225301B2A1E5B00BA68FD /* NakedPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NakedPtr.h; sourceTree = "<group>"; };
 		FE86A8741E59440200111BBF /* ForbidHeapAllocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ForbidHeapAllocation.h; sourceTree = "<group>"; };
 		FE8925AF1D00DAEC0046907E /* Indenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Indenter.h; sourceTree = "<group>"; };
+		FE97F6A8245CE5DD00C63FC6 /* StdIntExtras.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StdIntExtras.h; sourceTree = "<group>"; };
 		FEB6B035201BE0B600B958C1 /* PointerPreparations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PointerPreparations.h; sourceTree = "<group>"; };
 		FEDACD3B1630F83F00C69634 /* StackStats.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StackStats.cpp; sourceTree = "<group>"; };
 		FEDACD3C1630F83F00C69634 /* StackStats.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StackStats.h; sourceTree = "<group>"; };
@@ -1232,6 +1233,7 @@
 				FEDACD3C1630F83F00C69634 /* StackStats.h */,
 				313EDEC9778E49C9BEA91CFC /* StackTrace.cpp */,
 				EF7D6CD59D8642A8A0DA86AD /* StackTrace.h */,
+				FE97F6A8245CE5DD00C63FC6 /* StdIntExtras.h */,
 				A8A47311151A825B004123FF /* StdLibExtras.h */,
 				FF0A436588954F3CB07DBECA /* StdList.h */,
 				391BD6BA4D164FD294F9A93D /* StdMap.h */,

Modified: trunk/Source/WTF/wtf/Bitmap.h (261178 => 261179)


--- trunk/Source/WTF/wtf/Bitmap.h	2020-05-05 16:52:24 UTC (rev 261178)
+++ trunk/Source/WTF/wtf/Bitmap.h	2020-05-05 17:08:29 UTC (rev 261179)
@@ -22,17 +22,21 @@
 #include <array>
 #include <wtf/Atomics.h>
 #include <wtf/HashFunctions.h>
+#include <wtf/StdIntExtras.h>
 #include <wtf/StdLibExtras.h>
-#include <stdint.h>
 #include <string.h>
+#include <type_traits>
 
 namespace WTF {
 
-template<size_t bitmapSize, typename WordType = uint32_t>
+template<size_t size>
+using BitmapWordType = std::conditional_t<(size <= 32 && sizeof(UCPURegister) > sizeof(uint32_t)), uint32_t, UCPURegister>;
+
+template<size_t bitmapSize, typename WordType = BitmapWordType<bitmapSize>>
 class Bitmap final {
     WTF_MAKE_FAST_ALLOCATED;
     
-    static_assert(sizeof(WordType) <= sizeof(unsigned), "WordType must not be bigger than unsigned");
+    static_assert(sizeof(WordType) <= sizeof(UCPURegister), "WordType must not be bigger than the CPU atomic word size");
 public:
     constexpr Bitmap();
 
@@ -230,6 +234,11 @@
 {
     for (size_t i = 0; i < words; ++i)
         bits[i] = ~bits[i];
+    if constexpr (!!(bitmapSize % wordSize)) {
+        constexpr size_t remainingBits = bitmapSize % wordSize;
+        constexpr WordType mask = (static_cast<WordType>(1) << remainingBits) - 1;
+        bits[words - 1] &= mask;
+    }
 }
 
 template<size_t bitmapSize, typename WordType>
@@ -246,6 +255,9 @@
     if (!runLength) 
         runLength = 1; 
      
+    if (runLength > bitmapSize)
+        return -1;
+
     for (size_t i = 0; i <= (bitmapSize - runLength) ; i++) {
         bool found = true; 
         for (size_t j = i; j <= (i + runLength - 1) ; j++) { 
@@ -269,7 +281,7 @@
             ++result;
     }
     for (size_t i = start / wordSize; i < words; ++i)
-        result += WTF::bitCount(static_cast<unsigned>(bits[i]));
+        result += WTF::bitCount(bits[i]);
     return result;
 }
 
@@ -286,8 +298,17 @@
 inline size_t Bitmap<bitmapSize, WordType>::isFull() const
 {
     for (size_t i = 0; i < words; ++i)
-        if (~bits[i])
+        if (~bits[i]) {
+            if constexpr (!!(bitmapSize % wordSize)) {
+                if (i == words - 1) {
+                    constexpr size_t remainingBits = bitmapSize % wordSize;
+                    constexpr WordType mask = (static_cast<WordType>(1) << remainingBits) - 1;
+                    if ((bits[i] & mask) == mask)
+                        return true;
+                }
+            }
             return false;
+        }
     return true;
 }
 

Modified: trunk/Source/WTF/wtf/CMakeLists.txt (261178 => 261179)


--- trunk/Source/WTF/wtf/CMakeLists.txt	2020-05-05 16:52:24 UTC (rev 261178)
+++ trunk/Source/WTF/wtf/CMakeLists.txt	2020-05-05 17:08:29 UTC (rev 261179)
@@ -238,6 +238,7 @@
     StackShotProfiler.h
     StackStats.h
     StackTrace.h
+    StdIntExtras.h
     StdLibExtras.h
     StdList.h
     StdMap.h

Modified: trunk/Source/WTF/wtf/PlatformCPU.h (261178 => 261179)


--- trunk/Source/WTF/wtf/PlatformCPU.h	2020-05-05 16:52:24 UTC (rev 261178)
+++ trunk/Source/WTF/wtf/PlatformCPU.h	2020-05-05 17:08:29 UTC (rev 261179)
@@ -311,6 +311,15 @@
 #endif
 #endif
 
+/* CPU general purpose register width. */
+#if !defined(WTF_CPU_REGISTER64) && !defined(WTF_CPU_REGISTER32)
+#if CPU(ADDRESS64) || CPU(ARM64)
+#define WTF_CPU_REGISTER64 1
+#else
+#define WTF_CPU_REGISTER32 1
+#endif
+#endif
+
 /* CPU(BIG_ENDIAN) or CPU(MIDDLE_ENDIAN) or neither, as appropriate. */
 
 #if COMPILER(GCC_COMPATIBLE)

Modified: trunk/Source/WTF/wtf/PlatformUse.h (261178 => 261179)


--- trunk/Source/WTF/wtf/PlatformUse.h	2020-05-05 16:52:24 UTC (rev 261178)
+++ trunk/Source/WTF/wtf/PlatformUse.h	2020-05-05 17:08:29 UTC (rev 261179)
@@ -131,13 +131,11 @@
 #define USE_SYSTEM_MALLOC 1
 #endif
 
-#if !defined(USE_JSVALUE64) && !defined(USE_JSVALUE32_64)
-#if CPU(ADDRESS64) || CPU(ARM64)
+#if CPU(REGISTER64)
 #define USE_JSVALUE64 1
 #else
 #define USE_JSVALUE32_64 1
 #endif
-#endif /* !defined(USE_JSVALUE64) && !defined(USE_JSVALUE32_64) */
 
 #if USE(JSVALUE64)
 #define USE_BIGINT32 1

Added: trunk/Source/WTF/wtf/StdIntExtras.h (0 => 261179)


--- trunk/Source/WTF/wtf/StdIntExtras.h	                        (rev 0)
+++ trunk/Source/WTF/wtf/StdIntExtras.h	2020-05-05 17:08:29 UTC (rev 261179)
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 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. ``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
+ * 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+namespace WTF {
+
+#if CPU(REGISTER64)
+using CPURegister = int64_t;
+using UCPURegister = uint64_t;
+#else
+using CPURegister = int32_t;
+using UCPURegister = uint32_t;
+#endif
+
+} // namespace WTF
+
+using WTF::CPURegister;
+using WTF::UCPURegister;

Modified: trunk/Tools/ChangeLog (261178 => 261179)


--- trunk/Tools/ChangeLog	2020-05-05 16:52:24 UTC (rev 261178)
+++ trunk/Tools/ChangeLog	2020-05-05 17:08:29 UTC (rev 261179)
@@ -1,3 +1,48 @@
+2020-05-05  Mark Lam  <mark....@apple.com>
+
+        Allow Bitmap to use up to a UCPURegister word size for internal bit storage.
+        https://bugs.webkit.org/show_bug.cgi?id=211328
+        <rdar://problem/62755865>
+
+        Reviewed by Yusuke Suzuki.
+
+        Added API tests for WTF::Bitmap to make sure that Bitmap is behaving correctly.
+        Since Bitmap is used in critical infrastructure like the GC, it is important to
+        ensure that there are no latent bugs.
+
+        * TestWebKitAPI/CMakeLists.txt:
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WTF/Bitmap.cpp: Added.
+        (TestWebKitAPI::countBits):
+        (TestWebKitAPI::testBitmapSize):
+        (TestWebKitAPI::testBitmapConstructedEmpty):
+        (TestWebKitAPI::testBitmapSetGet):
+        (TestWebKitAPI::testBitmapTestAndSet):
+        (TestWebKitAPI::testBitmapTestAndClear):
+        (TestWebKitAPI::testBitmapConcurrentTestAndSet):
+        (TestWebKitAPI::testBitmapConcurrentTestAndClear):
+        (TestWebKitAPI::testBitmapClear):
+        (TestWebKitAPI::testBitmapClearAll):
+        (TestWebKitAPI::testBitmapInvert):
+        (TestWebKitAPI::testBitmapFindRunOfZeros):
+        (TestWebKitAPI::testBitmapCount):
+        (TestWebKitAPI::testBitmapIsEmpty):
+        (TestWebKitAPI::testBitmapIsFull):
+        (TestWebKitAPI::testBitmapMerge):
+        (TestWebKitAPI::testBitmapFilter):
+        (TestWebKitAPI::testBitmapExclude):
+        (TestWebKitAPI::testBitmapConcurrentFilter):
+        (TestWebKitAPI::testBitmapSubsumes):
+        (TestWebKitAPI::testBitmapForEachSetBit):
+        (TestWebKitAPI::testBitmapFindBit):
+        (TestWebKitAPI::testBitmapIteration):
+        (TestWebKitAPI::testBitmapMergeAndClear):
+        (TestWebKitAPI::testBitmapSetAndClear):
+        (TestWebKitAPI::testBitmapOperatorEqual):
+        (TestWebKitAPI::testBitmapOperatorNotEqual):
+        (TestWebKitAPI::testBitmapHash):
+        (TestWebKitAPI::TEST):
+
 2020-05-05  Alexey Shvayka  <shvaikal...@gmail.com>
 
         Object.prototype.toString is not spec-perfect

Modified: trunk/Tools/TestWebKitAPI/CMakeLists.txt (261178 => 261179)


--- trunk/Tools/TestWebKitAPI/CMakeLists.txt	2020-05-05 16:52:24 UTC (rev 261178)
+++ trunk/Tools/TestWebKitAPI/CMakeLists.txt	2020-05-05 17:08:29 UTC (rev 261179)
@@ -26,6 +26,7 @@
     WTFStringUtilities.cpp
 
     Tests/WTF/AtomString.cpp
+    Tests/WTF/Bitmap.cpp
     Tests/WTF/BloomFilter.cpp
     Tests/WTF/BumpPointerAllocator.cpp
     Tests/WTF/CString.cpp

Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (261178 => 261179)


--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2020-05-05 16:52:24 UTC (rev 261178)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2020-05-05 17:08:29 UTC (rev 261179)
@@ -1139,6 +1139,7 @@
 		F6B7BE9717469B96008A3445 /* associate-form-controls.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F6B7BE9617469B7E008A3445 /* associate-form-controls.html */; };
 		F6F49C6B15545CA70007F39D /* DOMWindowExtensionNoCache_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6F49C6615545C8D0007F39D /* DOMWindowExtensionNoCache_Bundle.cpp */; };
 		F6FDDDD614241C6F004F1729 /* push-state.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F6FDDDD514241C48004F1729 /* push-state.html */; };
+		FE2D9474245EB2F400E48135 /* Bitmap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE2D9473245EB2DF00E48135 /* Bitmap.cpp */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -2802,6 +2803,7 @@
 		F6F49C6715545C8D0007F39D /* DOMWindowExtensionNoCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DOMWindowExtensionNoCache.cpp; sourceTree = "<group>"; };
 		F6FDDDD214241AD4004F1729 /* PrivateBrowsingPushStateNoHistoryCallback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PrivateBrowsingPushStateNoHistoryCallback.cpp; sourceTree = "<group>"; };
 		F6FDDDD514241C48004F1729 /* push-state.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "push-state.html"; sourceTree = "<group>"; };
+		FE2D9473245EB2DF00E48135 /* Bitmap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Bitmap.cpp; sourceTree = "<group>"; };
 		FEB6F74E1B2BA44E009E4922 /* NakedPtr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NakedPtr.cpp; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
@@ -3949,6 +3951,7 @@
 				7CBBA07519BB8A0900BBF025 /* darwin */,
 				BC029B1A1486B23800817DA9 /* ns */,
 				26F1B44215CA434F00D1E4BF /* AtomString.cpp */,
+				FE2D9473245EB2DF00E48135 /* Bitmap.cpp */,
 				E40019301ACE9B5C001B0A2A /* BloomFilter.cpp */,
 				0451A5A6235E438E009DF945 /* BumpPointerAllocator.cpp */,
 				A7A966DA140ECCC8005EF9B4 /* CheckedArithmeticOperations.cpp */,
@@ -4699,6 +4702,7 @@
 				E38D65CB23A45FAA0063D69A /* PackedRefPtr.cpp in Sources */,
 				7C83DF591D0A590C00FEBCF3 /* ParkingLot.cpp in Sources */,
 				53EC25411E96FD87000831B9 /* PriorityQueue.cpp in Sources */,
+				FE2D9474245EB2F400E48135 /* Bitmap.cpp in Sources */,
 				7C83DF131D0A590C00FEBCF3 /* RedBlackTree.cpp in Sources */,
 				7C83DF141D0A590C00FEBCF3 /* Ref.cpp in Sources */,
 				7C83DF151D0A590C00FEBCF3 /* RefCounter.cpp in Sources */,

Added: trunk/Tools/TestWebKitAPI/Tests/WTF/Bitmap.cpp (0 => 261179)


--- trunk/Tools/TestWebKitAPI/Tests/WTF/Bitmap.cpp	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/Bitmap.cpp	2020-05-05 17:08:29 UTC (rev 261179)
@@ -0,0 +1,1115 @@
+/*
+ * Copyright (C) 2020 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 <wtf/Bitmap.h>
+
+namespace TestWebKitAPI {
+
+constexpr size_t size = 128;
+constexpr size_t smallSize = 9;
+constexpr size_t zeroSize = 0;
+
+static constexpr bool expectedBits1[size] = {
+    false, false, true,  false,  false, false, false, false,
+    false, false, false, false,  false, false, false, true,
+    false, true,  false, false,  false, false, true,  false,
+    false, false, true,  false,  false, false, true,  true,
+    true,  false, false, false,  false, true,  false, false,
+    true,  false, false, false,  false, true,  false, true,
+    false, false, false, false,  false, true,  true,  false,
+    false, true,  false, false,  false, true,  true,  true,
+    false, false, true,  false,  true,  false, false, false,
+    false, false, true,  false,  true,  false, false, true,
+    true,  false, false, false,  true,  false, true,  false,
+    false, false, false, false,  true,  false, true,  true,
+    false, false, false, false,  true,  true,  false, false,
+    false, true,  false, false,  true,  true,  false, true,
+    false, true,  false, false,  true,  true,  true,  false,
+    false, false, true,  false,  true,  true,  true,  true,
+};
+
+static constexpr bool expectedBits2[size] = {
+    false, true,  false, true,   false, false, false, false,
+    false, false, false, true,   false, false, false, true,
+    false, false, false, true,   false, false, true,  false,
+    false, false, false, true,   false, false, true,  true,
+    true,  false, false, true,   false, true,  false, false,
+    false, false, false, true,   false, true,  false, true,
+    false, false, false, true,   false, true,  true,  false,
+    false, false, true,  true,   false, true,  true,  true,
+    false, true,  false, true,   true,  false, false, false,
+    false, true,  false, true,   true,  false, false, true,
+    false, false, false, true,   true,  false, true,  false,
+    false, false, true,  true,   true,  false, true,  true,
+    true,  false, false, true,   true,  true,  false, false,
+    false, false, true,  true,   true,  true,  false, true,
+    true,  false, false, true,   true,  true,  true,  false,
+    false, true,  false, true,   true,  true,  true,  true,
+};
+
+constexpr size_t countBits(const bool boolArray[], size_t size)
+{
+    size_t result = 0;
+    for (size_t i = 0; i < size; ++i) {
+        if (boolArray[i])
+            result++;
+    }
+    return result;
+}
+
+constexpr size_t expectedNumberOfSetBits1 = countBits(expectedBits1, size);
+constexpr size_t expectedNumberOfSetBits2 = countBits(expectedBits2, size);
+
+#define DECLARE_BITMAPS_FOR_TEST() \
+    Bitmap<size, WordType> bitmap0; /* All bits will remain cleared. */ \
+    Bitmap<size, WordType> bitmap1; /* Will hold values specified in expectedBits1. */ \
+    Bitmap<size, WordType> bitmap2; /* Will hold values specified in expectedBits2. */ \
+    Bitmap<size, WordType> bitmap3; /* Same as bitmap2. */ \
+    Bitmap<size, WordType> bitmapFilled; \
+    Bitmap<smallSize, WordType> bitmapSmallZeroed; \
+    Bitmap<smallSize, WordType> bitmapSmallFilled;
+
+#define DECLARE_AND_INIT_BITMAPS_FOR_TEST() \
+    DECLARE_BITMAPS_FOR_TEST() \
+    for (size_t i = 0; i < size; ++i) { \
+        bitmap1.set(i, expectedBits1[i]); \
+        bitmap2.set(i, expectedBits2[i]); \
+        bitmap3.set(i, expectedBits2[i]); \
+        bitmapFilled.set(i); \
+    } \
+    for (size_t i = 0; i < smallSize; ++i) \
+        bitmapSmallFilled.set(i);
+
+template<typename WordType>
+void testBitmapSize()
+{
+    DECLARE_BITMAPS_FOR_TEST();
+
+    auto verifySize = [=] (auto& bitmap, size_t expectedSize, size_t notExpectedSize) {
+        EXPECT_EQ(bitmap.size(), expectedSize);
+        EXPECT_NE(bitmap.size(), notExpectedSize);
+    };
+
+    verifySize(bitmap0, size, smallSize);
+    verifySize(bitmap1, size, smallSize);
+    verifySize(bitmap2, size, smallSize);
+    verifySize(bitmap3, size, smallSize);
+    verifySize(bitmapFilled, size, smallSize);
+    verifySize(bitmapSmallZeroed, smallSize, size);
+    verifySize(bitmapSmallFilled, smallSize, size);
+}
+
+template<typename WordType>
+void testBitmapConstructedEmpty()
+{
+    DECLARE_BITMAPS_FOR_TEST();
+
+    // Verify that the default constructor initializes all bits to 0.
+    auto verifyIsEmpty = [=] (const auto& bitmap) {
+        EXPECT_TRUE(bitmap.isEmpty());
+        EXPECT_EQ(bitmap.count(), zeroSize);
+        for (size_t i = 0; i < bitmap.size(); ++i)
+            EXPECT_FALSE(bitmap.get(i));
+    };
+
+    verifyIsEmpty(bitmap0);
+    verifyIsEmpty(bitmap1);
+    verifyIsEmpty(bitmap2);
+    verifyIsEmpty(bitmap3);
+    verifyIsEmpty(bitmapFilled);
+    verifyIsEmpty(bitmapSmallZeroed);
+    verifyIsEmpty(bitmapSmallFilled);
+}
+
+template<typename WordType>
+void testBitmapSetGet()
+{
+    DECLARE_AND_INIT_BITMAPS_FOR_TEST();
+
+    auto verifyIsEmpty = [=] (const auto& bitmap) {
+        EXPECT_TRUE(bitmap.isEmpty());
+        EXPECT_EQ(bitmap.count(), zeroSize);
+        for (size_t i = 0; i < bitmap.size(); ++i)
+            EXPECT_FALSE(bitmap.get(i));
+    };
+
+    for (size_t i = 0; i < size; ++i)
+        EXPECT_EQ(bitmap1.get(i), expectedBits1[i]);
+
+    for (size_t i = 0; i < size; ++i) {
+        EXPECT_EQ(bitmap2.get(i), expectedBits2[i]);
+        EXPECT_EQ(bitmap3.get(i), expectedBits2[i]);
+    }
+    for (size_t i = 0; i < size; ++i)
+        EXPECT_EQ(bitmap2.get(i), bitmap3.get(i));
+
+    for (size_t i = 0; i < size; ++i)
+        EXPECT_TRUE(bitmapFilled.get(i));
+
+    for (size_t i = 0; i < smallSize; ++i)
+        EXPECT_TRUE(bitmapSmallFilled.get(i));
+
+    // Verify that there is no out of bounds write from the above set operations.
+    verifyIsEmpty(bitmap0);
+    verifyIsEmpty(bitmapSmallZeroed);
+}
+
+template<typename WordType>
+void testBitmapTestAndSet()
+{
+    DECLARE_AND_INIT_BITMAPS_FOR_TEST();
+
+    ASSERT_FALSE(bitmap1.isFull());
+    for (size_t i = 0; i < size; ++i)
+        ASSERT_EQ(bitmap1.get(i), expectedBits1[i]);
+    for (size_t i = 0; i < size; ++i)
+        ASSERT_EQ(bitmap1.testAndSet(i), expectedBits1[i]);
+    ASSERT_TRUE(bitmap1.isFull());
+
+    ASSERT_FALSE(bitmapSmallZeroed.isFull());
+    ASSERT_TRUE(bitmapSmallZeroed.isEmpty());
+    for (size_t i = 0; i < smallSize; ++i)
+        ASSERT_FALSE(bitmapSmallZeroed.testAndSet(i));
+    ASSERT_TRUE(bitmapSmallZeroed.isFull());
+}
+
+template<typename WordType>
+void testBitmapTestAndClear()
+{
+    DECLARE_AND_INIT_BITMAPS_FOR_TEST();
+
+    ASSERT_FALSE(bitmap1.isEmpty());
+    for (size_t i = 0; i < size; ++i)
+        ASSERT_EQ(bitmap1.get(i), expectedBits1[i]);
+    for (size_t i = 0; i < size; ++i)
+        ASSERT_EQ(bitmap1.testAndClear(i), expectedBits1[i]);
+    ASSERT_TRUE(bitmap1.isEmpty());
+
+    ASSERT_FALSE(bitmapSmallFilled.isEmpty());
+    ASSERT_TRUE(bitmapSmallFilled.isFull());
+    for (size_t i = 0; i < smallSize; ++i)
+        ASSERT_TRUE(bitmapSmallFilled.testAndClear(i));
+    ASSERT_TRUE(bitmapSmallFilled.isEmpty());
+}
+
+template<typename WordType>
+void testBitmapConcurrentTestAndSet()
+{
+    DECLARE_AND_INIT_BITMAPS_FOR_TEST();
+
+    // FIXME: the following does not test the concurrent part. It only ensures that
+    // the TestAndSet part of the operation is working.
+    ASSERT_FALSE(bitmap1.isFull());
+    for (size_t i = 0; i < size; ++i)
+        ASSERT_EQ(bitmap1.get(i), expectedBits1[i]);
+    for (size_t i = 0; i < size; ++i)
+        ASSERT_EQ(bitmap1.testAndSet(i), expectedBits1[i]);
+    ASSERT_TRUE(bitmap1.isFull());
+
+    ASSERT_FALSE(bitmapSmallZeroed.isFull());
+    ASSERT_TRUE(bitmapSmallZeroed.isEmpty());
+    for (size_t i = 0; i < smallSize; ++i)
+        ASSERT_FALSE(bitmapSmallZeroed.testAndSet(i));
+    ASSERT_TRUE(bitmapSmallZeroed.isFull());
+}
+
+template<typename WordType>
+void testBitmapConcurrentTestAndClear()
+{
+    DECLARE_AND_INIT_BITMAPS_FOR_TEST();
+
+    // FIXME: the following does not test the concurrent part. It only ensures that
+    // the TestAndClear part of the operation is working.
+    ASSERT_FALSE(bitmap1.isEmpty());
+    for (size_t i = 0; i < size; ++i)
+        ASSERT_EQ(bitmap1.get(i), expectedBits1[i]);
+    for (size_t i = 0; i < size; ++i)
+        ASSERT_EQ(bitmap1.testAndClear(i), expectedBits1[i]);
+    ASSERT_TRUE(bitmap1.isEmpty());
+
+    ASSERT_FALSE(bitmapSmallFilled.isEmpty());
+    ASSERT_TRUE(bitmapSmallFilled.isFull());
+    for (size_t i = 0; i < smallSize; ++i)
+        ASSERT_TRUE(bitmapSmallFilled.testAndClear(i));
+    ASSERT_TRUE(bitmapSmallFilled.isEmpty());
+}
+
+template<typename WordType>
+void testBitmapClear()
+{
+    DECLARE_AND_INIT_BITMAPS_FOR_TEST();
+
+    ASSERT_TRUE(bitmapFilled.isFull());
+    for (size_t i = 0; i < size; ++i) {
+        if (!expectedBits1[i])
+            bitmapFilled.clear(i);
+    }
+    ASSERT_EQ(bitmapFilled, bitmap1);
+}
+
+template<typename WordType>
+void testBitmapClearAll()
+{
+    DECLARE_AND_INIT_BITMAPS_FOR_TEST();
+
+    auto verifyIsEmpty = [=] (const auto& bitmap) {
+        EXPECT_TRUE(bitmap.isEmpty());
+        EXPECT_EQ(bitmap.count(), zeroSize);
+        for (size_t i = 0; i < bitmap.size(); ++i)
+            EXPECT_FALSE(bitmap.get(i));
+    };
+
+    auto verifyIsFull = [=] (const auto& bitmap) {
+        EXPECT_TRUE(bitmap.isFull());
+        for (size_t i = 0; i < bitmap.size(); ++i)
+            EXPECT_TRUE(bitmap.get(i));
+    };
+
+    EXPECT_FALSE(bitmap1.isEmpty());
+    bitmap1.clearAll();
+    verifyIsEmpty(bitmap1);
+    verifyIsFull(bitmapFilled);
+    verifyIsFull(bitmapSmallFilled);
+
+    EXPECT_FALSE(bitmap2.isEmpty());
+    bitmap2.clearAll();
+    verifyIsEmpty(bitmap1);
+    verifyIsEmpty(bitmap2);
+    verifyIsFull(bitmapFilled);
+    verifyIsFull(bitmapSmallFilled);
+
+    EXPECT_FALSE(bitmap3.isEmpty());
+    bitmap3.clearAll();
+    verifyIsEmpty(bitmap1);
+    verifyIsEmpty(bitmap2);
+    verifyIsEmpty(bitmap3);
+    verifyIsFull(bitmapFilled);
+    verifyIsFull(bitmapSmallFilled);
+}
+
+template<typename WordType>
+void testBitmapInvert()
+{
+    DECLARE_AND_INIT_BITMAPS_FOR_TEST();
+
+    auto verifyInvert = [=] (auto& bitmap) {
+        ASSERT_TRUE(bitmap.isFull());
+        ASSERT_FALSE(bitmap.isEmpty());
+        bitmap.invert();
+        ASSERT_FALSE(bitmap.isFull());
+        ASSERT_TRUE(bitmap.isEmpty());
+        bitmap.invert();
+        ASSERT_TRUE(bitmap.isFull());
+        ASSERT_FALSE(bitmap.isEmpty());
+    };
+
+    verifyInvert(bitmapFilled);
+    verifyInvert(bitmapSmallFilled);
+
+    for (size_t i = 0; i < size; ++i)
+        ASSERT_EQ(bitmap1.get(i), expectedBits1[i]);
+    bitmap1.invert();
+    for (size_t i = 0; i < size; ++i)
+        ASSERT_EQ(bitmap1.get(i), !expectedBits1[i]);
+    bitmap1.invert();
+    for (size_t i = 0; i < size; ++i)
+        ASSERT_EQ(bitmap1.get(i), expectedBits1[i]);
+}
+
+template<typename WordType>
+void testBitmapFindRunOfZeros()
+{
+    DECLARE_AND_INIT_BITMAPS_FOR_TEST();
+
+    const int64_t bitmap1RunsOfZeros[15] = {
+        0, 0, 0, 3, 3,
+        3, 3, 3, 3, 3,
+        3, 3, 3, -1, -1
+    };
+
+    const int64_t bitmap2RunsOfZeros[15] = {
+        0, 0, 4, 4, 4,
+        4, 4, 4, -1, -1,
+        -1, -1, -1, -1, -1,
+    };
+
+    Bitmap<smallSize, WordType> smallTemp;
+    smallTemp.set(1, true); // bits low to high are: 0100 0000 0
+
+    const int64_t smallTempRunsOfZeros[15] = {
+        0, 0, 2, 2, 2,
+        2, 2, 2, -1, -1,
+        -1, -1, -1, -1, -1
+    };
+
+    for (size_t runLength = 0; runLength < 15; ++runLength) {
+        ASSERT_EQ(bitmap0.findRunOfZeros(runLength), 0ll);
+        ASSERT_EQ(bitmap1.findRunOfZeros(runLength), bitmap1RunsOfZeros[runLength]);
+        ASSERT_EQ(bitmap2.findRunOfZeros(runLength), bitmap2RunsOfZeros[runLength]);
+        ASSERT_EQ(bitmapFilled.findRunOfZeros(runLength), -1ll);
+
+        if (runLength <= smallSize)
+            ASSERT_EQ(bitmapSmallZeroed.findRunOfZeros(runLength), 0ll);
+        else
+            ASSERT_EQ(bitmapSmallZeroed.findRunOfZeros(runLength), -1ll);
+
+        ASSERT_EQ(bitmapSmallFilled.findRunOfZeros(runLength), -1ll);
+
+        ASSERT_EQ(smallTemp.findRunOfZeros(runLength), smallTempRunsOfZeros[runLength]);
+    }
+}
+
+template<typename WordType>
+void testBitmapCount()
+{
+    DECLARE_AND_INIT_BITMAPS_FOR_TEST();
+
+    EXPECT_EQ(bitmap0.count(), zeroSize);
+    EXPECT_EQ(bitmap1.count(), expectedNumberOfSetBits1);
+    EXPECT_EQ(bitmap2.count(), expectedNumberOfSetBits2);
+    EXPECT_EQ(bitmap3.count(), expectedNumberOfSetBits2);
+    EXPECT_EQ(bitmapFilled.count(), size);
+    EXPECT_EQ(bitmapSmallZeroed.count(), zeroSize);
+    EXPECT_EQ(bitmapSmallFilled.count(), smallSize);
+}
+
+template<typename WordType>
+void testBitmapIsEmpty()
+{
+    DECLARE_AND_INIT_BITMAPS_FOR_TEST();
+
+    EXPECT_TRUE(bitmap0.isEmpty());
+    EXPECT_FALSE(bitmap1.isEmpty());
+    EXPECT_FALSE(bitmap2.isEmpty());
+    EXPECT_FALSE(bitmap3.isEmpty());
+    EXPECT_FALSE(bitmapFilled.isEmpty());
+    EXPECT_TRUE(bitmapSmallZeroed.isEmpty());
+    EXPECT_FALSE(bitmapSmallFilled.isEmpty());
+
+    auto verifyIsEmpty = [=] (const auto& bitmap) {
+        EXPECT_TRUE(bitmap.isEmpty());
+        EXPECT_EQ(bitmap.count(), zeroSize);
+        for (size_t i = 0; i < bitmap.size(); ++i)
+            EXPECT_FALSE(bitmap.get(i));
+    };
+
+    verifyIsEmpty(bitmap0);
+    verifyIsEmpty(bitmapSmallZeroed);
+}
+
+template<typename WordType>
+void testBitmapIsFull()
+{
+    DECLARE_AND_INIT_BITMAPS_FOR_TEST();
+
+    EXPECT_FALSE(bitmap0.isFull());
+    EXPECT_FALSE(bitmap1.isFull());
+    EXPECT_FALSE(bitmap2.isFull());
+    EXPECT_FALSE(bitmap3.isFull());
+    EXPECT_TRUE(bitmapFilled.isFull());
+    EXPECT_FALSE(bitmapSmallZeroed.isFull());
+    EXPECT_TRUE(bitmapSmallFilled.isFull());
+
+    auto verifyIsFull = [=] (auto& bitmap) {
+        EXPECT_TRUE(bitmap.isFull());
+        for (size_t i = 0; i < bitmap.size(); ++i)
+            EXPECT_TRUE(bitmap.get(i));
+    };
+
+    verifyIsFull(bitmapFilled);
+    verifyIsFull(bitmapSmallFilled);
+}
+
+template<typename WordType>
+void testBitmapMerge()
+{
+    DECLARE_AND_INIT_BITMAPS_FOR_TEST();
+
+    ASSERT_TRUE(bitmap0.isEmpty());
+    ASSERT_EQ(bitmap2, bitmap3);
+    bitmap2.merge(bitmap0);
+    ASSERT_EQ(bitmap2, bitmap3);
+    
+    ASSERT_NE(bitmap1, bitmap2);
+    ASSERT_NE(bitmap1, bitmap3);
+    ASSERT_EQ(bitmap2, bitmap3);
+    bitmap3.merge(bitmap1);
+    ASSERT_NE(bitmap2, bitmap3);
+    for (size_t i = 0; i < size; ++i) {
+        bool expectedBit = expectedBits2[i] | expectedBits1[i];
+        ASSERT_EQ(bitmap3.get(i), expectedBit);
+    }
+
+    ASSERT_TRUE(bitmapFilled.isFull());
+    ASSERT_TRUE(bitmap0.isEmpty());
+    bitmapFilled.merge(bitmap0);
+    ASSERT_TRUE(bitmapFilled.isFull());
+    ASSERT_TRUE(bitmap0.isEmpty());
+
+    bitmap0.merge(bitmap1);
+    ASSERT_EQ(bitmap0, bitmap1);
+
+    bitmap1.merge(bitmapFilled);
+    ASSERT_EQ(bitmap1, bitmapFilled);
+
+    ASSERT_TRUE(bitmapSmallZeroed.isEmpty());
+    ASSERT_TRUE(bitmapSmallFilled.isFull());
+    bitmapSmallZeroed.merge(bitmapSmallFilled);
+    ASSERT_FALSE(bitmapSmallZeroed.isEmpty());
+    ASSERT_TRUE(bitmapSmallZeroed.isFull());
+    ASSERT_TRUE(bitmapSmallFilled.isFull());
+    
+    bitmapSmallZeroed.clearAll();
+    ASSERT_TRUE(bitmapSmallZeroed.isEmpty());
+    ASSERT_TRUE(bitmapSmallFilled.isFull());
+    bitmapSmallFilled.merge(bitmapSmallZeroed);
+    ASSERT_TRUE(bitmapSmallFilled.isFull());
+    ASSERT_TRUE(bitmapSmallZeroed.isEmpty());
+}
+
+template<typename WordType>
+void testBitmapFilter()
+{
+    DECLARE_AND_INIT_BITMAPS_FOR_TEST();
+
+    ASSERT_TRUE(bitmapFilled.isFull());
+    ASSERT_EQ(bitmap2, bitmap3);
+    bitmap2.filter(bitmapFilled);
+    ASSERT_EQ(bitmap2, bitmap3);
+    
+    ASSERT_NE(bitmap1, bitmap2);
+    ASSERT_NE(bitmap1, bitmap3);
+    ASSERT_EQ(bitmap2, bitmap3);
+    bitmap3.filter(bitmap1);
+    ASSERT_NE(bitmap2, bitmap3);
+    for (size_t i = 0; i < size; ++i) {
+        bool expectedBit = expectedBits2[i] & expectedBits1[i];
+        ASSERT_EQ(bitmap3.get(i), expectedBit);
+    }
+
+    ASSERT_TRUE(bitmap0.isEmpty());
+    bitmap2.filter(bitmap0);
+    ASSERT_EQ(bitmap2, bitmap0);
+
+    ASSERT_TRUE(bitmap0.isEmpty());
+    bitmap0.filter(bitmap1);
+    ASSERT_TRUE(bitmap0.isEmpty());
+
+    ASSERT_TRUE(bitmapFilled.isFull());
+    bitmapFilled.filter(bitmap1);
+    ASSERT_EQ(bitmapFilled, bitmap1);
+
+    ASSERT_TRUE(bitmapSmallZeroed.isEmpty());
+    ASSERT_TRUE(bitmapSmallFilled.isFull());
+    bitmapSmallZeroed.filter(bitmapSmallFilled);
+    ASSERT_TRUE(bitmapSmallZeroed.isEmpty());
+    ASSERT_FALSE(bitmapSmallZeroed.isFull());
+    ASSERT_TRUE(bitmapSmallFilled.isFull());
+    
+    bitmapSmallFilled.filter(bitmapSmallZeroed);
+    ASSERT_FALSE(bitmapSmallFilled.isFull());
+    ASSERT_TRUE(bitmapSmallFilled.isEmpty());
+    ASSERT_TRUE(bitmapSmallZeroed.isEmpty());
+}
+
+template<typename WordType>
+void testBitmapExclude()
+{
+    DECLARE_AND_INIT_BITMAPS_FOR_TEST();
+
+    ASSERT_TRUE(bitmap0.isEmpty());
+    ASSERT_EQ(bitmap2, bitmap3);
+    bitmap2.exclude(bitmap0);
+    ASSERT_EQ(bitmap2, bitmap3);
+    
+    ASSERT_NE(bitmap1, bitmap2);
+    ASSERT_NE(bitmap1, bitmap3);
+    ASSERT_EQ(bitmap2, bitmap3);
+    bitmap3.exclude(bitmap1);
+    ASSERT_NE(bitmap2, bitmap3);
+    for (size_t i = 0; i < size; ++i) {
+        bool expectedBit = expectedBits2[i] & !expectedBits1[i];
+        ASSERT_EQ(bitmap3.get(i), expectedBit);
+    }
+
+    ASSERT_TRUE(bitmap0.isEmpty());
+    ASSERT_TRUE(bitmapFilled.isFull());
+    bitmap2.exclude(bitmapFilled);
+    ASSERT_EQ(bitmap2, bitmap0);
+
+    ASSERT_TRUE(bitmapFilled.isFull());
+    bitmapFilled.exclude(bitmap1);
+    bitmap1.invert();
+    ASSERT_EQ(bitmapFilled, bitmap1);
+
+    ASSERT_TRUE(bitmapSmallZeroed.isEmpty());
+    ASSERT_TRUE(bitmapSmallFilled.isFull());
+    bitmapSmallZeroed.exclude(bitmapSmallFilled);
+    ASSERT_TRUE(bitmapSmallZeroed.isEmpty());
+    ASSERT_FALSE(bitmapSmallZeroed.isFull());
+    ASSERT_TRUE(bitmapSmallFilled.isFull());
+    
+    bitmapSmallFilled.exclude(bitmapSmallZeroed);
+    ASSERT_TRUE(bitmapSmallFilled.isFull());
+    ASSERT_TRUE(bitmapSmallZeroed.isEmpty());
+
+    bitmapSmallFilled.exclude(bitmapSmallFilled);
+    ASSERT_FALSE(bitmapSmallFilled.isFull());
+    ASSERT_TRUE(bitmapSmallFilled.isEmpty());
+}
+
+template<typename WordType>
+void testBitmapConcurrentFilter()
+{
+    DECLARE_AND_INIT_BITMAPS_FOR_TEST();
+
+    // FIXME: the following does not test the concurrent part. It only ensures that
+    // the Filter part of the operation is working.
+    ASSERT_TRUE(bitmapFilled.isFull());
+    ASSERT_EQ(bitmap2, bitmap3);
+    bitmap2.concurrentFilter(bitmapFilled);
+    ASSERT_EQ(bitmap2, bitmap3);
+    
+    ASSERT_NE(bitmap1, bitmap2);
+    ASSERT_NE(bitmap1, bitmap3);
+    ASSERT_EQ(bitmap2, bitmap3);
+    bitmap3.concurrentFilter(bitmap1);
+    ASSERT_NE(bitmap2, bitmap3);
+    for (size_t i = 0; i < size; ++i) {
+        bool expectedBit = expectedBits2[i] & expectedBits1[i];
+        ASSERT_EQ(bitmap3.get(i), expectedBit);
+    }
+
+    ASSERT_TRUE(bitmap0.isEmpty());
+    bitmap2.concurrentFilter(bitmap0);
+    ASSERT_EQ(bitmap2, bitmap0);
+
+    ASSERT_TRUE(bitmap0.isEmpty());
+    bitmap0.concurrentFilter(bitmap1);
+    ASSERT_TRUE(bitmap0.isEmpty());
+
+    ASSERT_TRUE(bitmapFilled.isFull());
+    bitmapFilled.concurrentFilter(bitmap1);
+    ASSERT_EQ(bitmapFilled, bitmap1);
+
+    ASSERT_TRUE(bitmapSmallZeroed.isEmpty());
+    ASSERT_TRUE(bitmapSmallFilled.isFull());
+    bitmapSmallZeroed.concurrentFilter(bitmapSmallFilled);
+    ASSERT_TRUE(bitmapSmallZeroed.isEmpty());
+    ASSERT_FALSE(bitmapSmallZeroed.isFull());
+    ASSERT_TRUE(bitmapSmallFilled.isFull());
+    
+    bitmapSmallFilled.concurrentFilter(bitmapSmallZeroed);
+    ASSERT_FALSE(bitmapSmallFilled.isFull());
+    ASSERT_TRUE(bitmapSmallFilled.isEmpty());
+    ASSERT_TRUE(bitmapSmallZeroed.isEmpty());
+}
+
+template<typename WordType>
+void testBitmapSubsumes()
+{
+    DECLARE_AND_INIT_BITMAPS_FOR_TEST();
+
+    ASSERT_TRUE(bitmap0.isEmpty());
+    ASSERT_TRUE(bitmapFilled.isFull());
+    ASSERT_EQ(bitmap2, bitmap3);
+
+    ASSERT_TRUE(bitmap0.subsumes(bitmap0));
+    ASSERT_FALSE(bitmap0.subsumes(bitmap1));
+    ASSERT_FALSE(bitmap0.subsumes(bitmap2));
+    ASSERT_FALSE(bitmap0.subsumes(bitmap3));
+    ASSERT_FALSE(bitmap0.subsumes(bitmapFilled));
+
+    ASSERT_TRUE(bitmap1.subsumes(bitmap0));
+    ASSERT_TRUE(bitmap1.subsumes(bitmap1));
+    ASSERT_FALSE(bitmap1.subsumes(bitmap2));
+    ASSERT_FALSE(bitmap1.subsumes(bitmap3));
+    ASSERT_FALSE(bitmap1.subsumes(bitmapFilled));
+
+    ASSERT_TRUE(bitmap2.subsumes(bitmap0));
+    ASSERT_FALSE(bitmap2.subsumes(bitmap1));
+    ASSERT_TRUE(bitmap2.subsumes(bitmap2));
+    ASSERT_TRUE(bitmap2.subsumes(bitmap3));
+    ASSERT_FALSE(bitmap2.subsumes(bitmapFilled));
+
+    ASSERT_TRUE(bitmap3.subsumes(bitmap0));
+    ASSERT_FALSE(bitmap3.subsumes(bitmap1));
+    ASSERT_TRUE(bitmap3.subsumes(bitmap2));
+    ASSERT_TRUE(bitmap3.subsumes(bitmap3));
+    ASSERT_FALSE(bitmap3.subsumes(bitmapFilled));
+
+    ASSERT_TRUE(bitmapFilled.subsumes(bitmap0));
+    ASSERT_TRUE(bitmapFilled.subsumes(bitmap1));
+    ASSERT_TRUE(bitmapFilled.subsumes(bitmap2));
+    ASSERT_TRUE(bitmapFilled.subsumes(bitmap3));
+    ASSERT_TRUE(bitmapFilled.subsumes(bitmapFilled));
+
+    ASSERT_TRUE(bitmapSmallFilled.subsumes(bitmapSmallFilled));
+    ASSERT_TRUE(bitmapSmallFilled.subsumes(bitmapSmallZeroed));
+
+    ASSERT_FALSE(bitmapSmallZeroed.subsumes(bitmapSmallFilled));
+    ASSERT_TRUE(bitmapSmallZeroed.subsumes(bitmapSmallZeroed));
+}
+
+template<typename WordType>
+void testBitmapForEachSetBit()
+{
+    DECLARE_AND_INIT_BITMAPS_FOR_TEST();
+
+    size_t count = 0;
+    ASSERT_TRUE(bitmap0.isEmpty());
+    bitmap0.forEachSetBit([&] (size_t i) {
+        constexpr bool notReached = false;
+        ASSERT_TRUE(notReached);
+        count++;
+    });
+    ASSERT_EQ(count, zeroSize);
+
+    count = 0;
+    bitmap1.forEachSetBit([&] (size_t i) {
+        ASSERT_TRUE(bitmap1.get(i));
+        ASSERT_EQ(bitmap1.get(i), expectedBits1[i]);
+        count++;
+    });
+    ASSERT_EQ(count, expectedNumberOfSetBits1);
+
+    count = 0;
+    ASSERT_TRUE(bitmapFilled.isFull());
+    bitmapFilled.forEachSetBit([&] (size_t i) {
+        ASSERT_TRUE(bitmapFilled.get(i));
+        count++;
+    });
+    ASSERT_EQ(count, size);
+
+    count = 0;
+    ASSERT_TRUE(bitmapSmallZeroed.isEmpty());
+    bitmapSmallZeroed.forEachSetBit([&] (size_t i) {
+        constexpr bool notReached = false;
+        ASSERT_TRUE(notReached);
+        count++;
+    });
+    ASSERT_EQ(count, zeroSize);
+
+    count = 0;
+    ASSERT_TRUE(bitmapSmallFilled.isFull());
+    bitmapSmallFilled.forEachSetBit([&] (size_t i) {
+        ASSERT_TRUE(bitmapSmallFilled.get(i));
+        count++;
+    });
+    ASSERT_EQ(count, smallSize);
+}
+
+template<typename WordType>
+void testBitmapFindBit()
+{
+    DECLARE_AND_INIT_BITMAPS_FOR_TEST();
+
+    auto findExpectedBit = [=] (auto expectedBits, size_t startIndex, bool value) -> size_t {
+        for (auto index = startIndex; index < size; ++index) {
+            if (expectedBits[index] == value)
+                return index;
+        }
+        return startIndex;
+    };
+    
+    for (size_t i = 1, lastIndex = 1; i < size; lastIndex = i, i += lastIndex) {
+        ASSERT_EQ(bitmap1.findBit(i, true), findExpectedBit(expectedBits1, i, true));
+        ASSERT_EQ(bitmap1.findBit(i, false), findExpectedBit(expectedBits1, i, false));
+        ASSERT_EQ(bitmap2.findBit(i, true), findExpectedBit(expectedBits2, i, true));
+        ASSERT_EQ(bitmap2.findBit(i, false), findExpectedBit(expectedBits2, i, false));
+
+        ASSERT_EQ(bitmap2.findBit(i, true), bitmap3.findBit(i, true));
+        ASSERT_EQ(bitmap2.findBit(i, false), bitmap3.findBit(i, false));
+    }
+
+    ASSERT_EQ(bitmap0.findBit(0, false), zeroSize);
+    ASSERT_EQ(bitmap0.findBit(10, false), static_cast<size_t>(10));
+    ASSERT_EQ(bitmap0.findBit(size - 1, false), size-1);
+    ASSERT_EQ(bitmap0.findBit(size, false), size);
+    ASSERT_EQ(bitmap0.findBit(size + 1, false), size);
+
+    ASSERT_EQ(bitmap0.findBit(0, true), size);
+    ASSERT_EQ(bitmap0.findBit(10, true), size);
+    ASSERT_EQ(bitmap0.findBit(size - 1, true), size);
+    ASSERT_EQ(bitmap0.findBit(size, true), size);
+    ASSERT_EQ(bitmap0.findBit(size + 1, true), size);
+
+    ASSERT_EQ(bitmapFilled.findBit(0, false), size);
+    ASSERT_EQ(bitmapFilled.findBit(10, false), size);
+    ASSERT_EQ(bitmapFilled.findBit(size - 1, false), size);
+    ASSERT_EQ(bitmapFilled.findBit(size, false), size);
+    ASSERT_EQ(bitmapFilled.findBit(size + 1, false), size);
+
+    ASSERT_EQ(bitmapFilled.findBit(0, true), zeroSize);
+    ASSERT_EQ(bitmapFilled.findBit(10, true), static_cast<size_t>(10));
+    ASSERT_EQ(bitmapFilled.findBit(size - 1, true), size-1);
+    ASSERT_EQ(bitmapFilled.findBit(size, true), size);
+    ASSERT_EQ(bitmapFilled.findBit(size + 1, true), size);
+}
+
+template<typename WordType>
+void testBitmapIteration()
+{
+    DECLARE_AND_INIT_BITMAPS_FOR_TEST();
+
+    auto computeSetBitsCount = [=] (auto& bitmap) -> size_t {
+        size_t count = 0;
+        for (auto bitIndex : bitmap) {
+            UNUSED_PARAM(bitIndex);
+            count++;
+        }
+        return count;
+    };
+
+    EXPECT_EQ(computeSetBitsCount(bitmap0), zeroSize);
+    EXPECT_EQ(computeSetBitsCount(bitmap1), expectedNumberOfSetBits1);
+    EXPECT_EQ(computeSetBitsCount(bitmap2), expectedNumberOfSetBits2);
+    EXPECT_EQ(computeSetBitsCount(bitmap3), expectedNumberOfSetBits2);
+    EXPECT_EQ(computeSetBitsCount(bitmapFilled), size);
+    EXPECT_EQ(computeSetBitsCount(bitmapSmallZeroed), zeroSize);
+    EXPECT_EQ(computeSetBitsCount(bitmapSmallFilled), smallSize);
+
+    auto verifySetBits = [=] (auto& bitmap, auto& expectedBits) {
+        for (auto bitIndex : bitmap) {
+            EXPECT_TRUE(bitmap.get(bitIndex));
+            EXPECT_EQ(bitmap.get(bitIndex), expectedBits[bitIndex]);
+        }
+    };
+
+    verifySetBits(bitmap1, expectedBits1);
+    verifySetBits(bitmap2, expectedBits2);
+    verifySetBits(bitmap3, expectedBits2);
+
+    auto verifyBitsAllSet = [=] (auto& bitmap) {
+        size_t lastBitIndex = 0;
+        for (auto bitIndex : bitmap) {
+            EXPECT_TRUE(bitmap.get(bitIndex));
+            if (bitIndex)
+                EXPECT_EQ(bitIndex, lastBitIndex + 1);
+            lastBitIndex = bitIndex;
+        }
+    };
+
+    verifyBitsAllSet(bitmapFilled);
+    verifyBitsAllSet(bitmapSmallFilled);
+}
+
+template<typename WordType>
+void testBitmapMergeAndClear()
+{
+    DECLARE_AND_INIT_BITMAPS_FOR_TEST();
+
+    Bitmap<size, WordType> temp;
+    Bitmap<size, WordType> savedBitmap1;
+
+    ASSERT_FALSE(bitmap2.isEmpty());
+
+    savedBitmap1.merge(bitmap1);
+    ASSERT_EQ(savedBitmap1, bitmap1);
+    
+    ASSERT_NE(bitmap1, bitmap2);
+    ASSERT_NE(bitmap1, bitmap3);
+    ASSERT_EQ(bitmap3, bitmap2);
+    bitmap1.mergeAndClear(bitmap3);
+    ASSERT_NE(bitmap1, bitmap2);
+    ASSERT_NE(bitmap1, savedBitmap1);
+    ASSERT_TRUE(bitmap3.isEmpty());
+    for (size_t i = 0; i < size; ++i) {
+        bool expectedBit = expectedBits1[i] | expectedBits2[i];
+        ASSERT_EQ(bitmap1.get(i), expectedBit);
+    }
+
+    bitmap3.merge(bitmap2); // restore bitmap3
+    ASSERT_EQ(bitmap3, bitmap2);
+
+    ASSERT_TRUE(temp.isEmpty());
+    temp.mergeAndClear(bitmap3);
+    ASSERT_FALSE(temp.isEmpty());
+    ASSERT_EQ(temp, bitmap2);
+    ASSERT_TRUE(bitmap3.isEmpty());
+
+    Bitmap<size, WordType> savedBitmapFilled;
+    savedBitmapFilled.merge(bitmapFilled);
+
+    temp.clearAll();
+    ASSERT_TRUE(temp.isEmpty());
+    ASSERT_FALSE(temp.isFull());
+    ASSERT_FALSE(bitmapFilled.isEmpty());
+    ASSERT_TRUE(bitmapFilled.isFull());
+    temp.mergeAndClear(bitmapFilled);
+    ASSERT_FALSE(temp.isEmpty());
+    ASSERT_TRUE(temp.isFull());
+    ASSERT_TRUE(bitmapFilled.isEmpty());
+    ASSERT_FALSE(bitmapFilled.isFull());
+
+    bitmap3.merge(bitmap2); // restore bitmap3
+    ASSERT_EQ(bitmap3, bitmap2);
+    bitmapFilled.merge(savedBitmapFilled); // restore bitmapFilled
+    ASSERT_TRUE(bitmapFilled.isFull());
+
+    ASSERT_TRUE(temp.isFull());
+    temp.mergeAndClear(bitmap3);
+    ASSERT_TRUE(temp.isFull());
+    ASSERT_EQ(temp, bitmapFilled);
+    ASSERT_TRUE(bitmap3.isEmpty());
+
+    Bitmap<smallSize, WordType> smallTemp;
+
+    smallTemp.merge(bitmapSmallFilled);
+    ASSERT_TRUE(smallTemp.isFull());
+    ASSERT_TRUE(bitmapSmallZeroed.isEmpty());
+    smallTemp.mergeAndClear(bitmapSmallZeroed);
+    ASSERT_TRUE(smallTemp.isFull());
+    ASSERT_FALSE(smallTemp.isEmpty());
+    ASSERT_TRUE(bitmapSmallZeroed.isEmpty());
+
+    smallTemp.clearAll();
+    ASSERT_TRUE(bitmapSmallFilled.isFull());
+    ASSERT_TRUE(smallTemp.isEmpty());
+    smallTemp.mergeAndClear(bitmapSmallFilled);
+    ASSERT_TRUE(smallTemp.isFull());
+    ASSERT_TRUE(bitmapSmallFilled.isEmpty());
+}
+
+template<typename WordType>
+void testBitmapSetAndClear()
+{
+    DECLARE_AND_INIT_BITMAPS_FOR_TEST();
+
+    Bitmap<size, WordType> temp;
+    Bitmap<size, WordType> savedBitmap1;
+
+    ASSERT_FALSE(bitmap2.isEmpty());
+
+    savedBitmap1.merge(bitmap1);
+    ASSERT_EQ(savedBitmap1, bitmap1);
+    
+    ASSERT_NE(bitmap1, bitmap2);
+    ASSERT_NE(bitmap1, bitmap3);
+    ASSERT_EQ(bitmap3, bitmap2);
+    bitmap1.setAndClear(bitmap3);
+    ASSERT_EQ(bitmap1, bitmap2);
+    ASSERT_NE(bitmap1, savedBitmap1);
+    ASSERT_TRUE(bitmap3.isEmpty());
+
+    bitmap3.merge(bitmap2); // restore bitmap3
+    ASSERT_EQ(bitmap3, bitmap2);
+
+    ASSERT_TRUE(temp.isEmpty());
+    temp.setAndClear(bitmap3);
+    ASSERT_FALSE(temp.isEmpty());
+    ASSERT_EQ(temp, bitmap2);
+    ASSERT_TRUE(bitmap3.isEmpty());
+
+    temp.clearAll();
+    ASSERT_TRUE(temp.isEmpty());
+    ASSERT_FALSE(temp.isFull());
+    ASSERT_FALSE(bitmapFilled.isEmpty());
+    ASSERT_TRUE(bitmapFilled.isFull());
+    temp.setAndClear(bitmapFilled);
+    ASSERT_FALSE(temp.isEmpty());
+    ASSERT_TRUE(temp.isFull());
+    ASSERT_TRUE(bitmapFilled.isEmpty());
+    ASSERT_FALSE(bitmapFilled.isFull());
+
+    bitmap3.merge(bitmap2); // restore bitmap3
+    ASSERT_EQ(bitmap3, bitmap2);
+
+    ASSERT_TRUE(temp.isFull());
+    temp.setAndClear(bitmap3);
+    ASSERT_FALSE(temp.isFull());
+    ASSERT_EQ(temp, bitmap2);
+    ASSERT_TRUE(bitmap3.isEmpty());
+
+    Bitmap<smallSize, WordType> smallTemp;
+
+    smallTemp.merge(bitmapSmallFilled);
+    ASSERT_TRUE(smallTemp.isFull());
+    ASSERT_TRUE(bitmapSmallZeroed.isEmpty());
+    smallTemp.setAndClear(bitmapSmallZeroed);
+    ASSERT_TRUE(smallTemp.isEmpty());
+    ASSERT_TRUE(bitmapSmallZeroed.isEmpty());
+    
+    ASSERT_TRUE(bitmapSmallFilled.isFull());
+    ASSERT_TRUE(smallTemp.isEmpty());
+    smallTemp.setAndClear(bitmapSmallFilled);
+    ASSERT_TRUE(smallTemp.isFull());
+    ASSERT_TRUE(bitmapSmallFilled.isEmpty());
+}
+
+template<typename WordType>
+void testBitmapOperatorEqual()
+{
+    DECLARE_AND_INIT_BITMAPS_FOR_TEST();
+
+    EXPECT_TRUE(bitmap0 == bitmap0);
+    EXPECT_FALSE(bitmap0 == bitmap1);
+    EXPECT_TRUE(bitmap1 == bitmap1);
+    EXPECT_FALSE(bitmap1 == bitmap2);
+    EXPECT_FALSE(bitmap1 == bitmap3);
+    EXPECT_TRUE(bitmap2 == bitmap3);
+    EXPECT_FALSE(bitmapFilled == bitmap1);
+    EXPECT_FALSE(bitmapSmallZeroed == bitmapSmallFilled);
+}
+
+template<typename WordType>
+void testBitmapOperatorNotEqual()
+{
+    DECLARE_AND_INIT_BITMAPS_FOR_TEST();
+
+    EXPECT_FALSE(bitmap0 != bitmap0);
+    EXPECT_TRUE(bitmap0 != bitmap1);
+    EXPECT_FALSE(bitmap1 != bitmap1);
+    EXPECT_TRUE(bitmap1 != bitmap2);
+    EXPECT_TRUE(bitmap1 != bitmap3);
+    EXPECT_FALSE(bitmap2 != bitmap3);
+    EXPECT_TRUE(bitmapFilled != bitmap1);
+    EXPECT_TRUE(bitmapSmallZeroed != bitmapSmallFilled);
+}
+
+template<typename WordType>
+void testBitmapHash()
+{
+    DECLARE_AND_INIT_BITMAPS_FOR_TEST();
+
+    constexpr unsigned wordSize = sizeof(WordType) * 8;
+    constexpr size_t words = (size + wordSize - 1) / wordSize;
+
+    auto expectedBitmap0Hash = [=] () -> unsigned {
+        unsigned result = 0;
+        WordType zeroWord = 0;
+        for (size_t i = 0; i < words; ++i)
+            result ^= IntHash<WordType>::hash(zeroWord);
+        return result;
+    };
+
+    auto expectedBitmapFilledHash = [=] () -> unsigned {
+        unsigned result = 0;
+        WordType filledWord = static_cast<WordType>(-1);
+        for (size_t i = 0; i < words; ++i)
+            result ^= IntHash<WordType>::hash(filledWord);
+        return result;
+    };
+
+    ASSERT_EQ(bitmap0.hash(), expectedBitmap0Hash());
+    ASSERT_EQ(bitmapFilled.hash(), expectedBitmapFilledHash());
+
+    auto expectedHash = [=] (auto expectedBits, size_t size) {
+        unsigned result = 0;
+        for (size_t i = 0; i < size;) {
+            WordType word = 0;
+            for (size_t j = 0; j < wordSize && i < size; ++i, ++j)
+                word |= static_cast<WordType>(!!expectedBits[i]) << j;
+            result ^= IntHash<WordType>::hash(word);
+        }
+        return result;
+    };
+
+    ASSERT_EQ(bitmap1.hash(), expectedHash(expectedBits1, size));
+    ASSERT_EQ(bitmap2.hash(), expectedHash(expectedBits2, size));
+
+    static constexpr bool expectedSmallBits[smallSize] = {
+        true,  false, false, true,  false,  false, false, true,
+        true,
+    };
+    Bitmap<smallSize, WordType> temp1;
+    Bitmap<smallSize, WordType> temp2;
+
+    auto initTemp = [&] (auto& bitmap) {
+        for (size_t i = 0; i < smallSize; ++i)
+            bitmap.set(i, expectedSmallBits[i]);
+    };
+
+    initTemp(temp1);
+    ASSERT_EQ(temp1.hash(), expectedHash(expectedSmallBits, smallSize));
+
+    temp2.invert();
+    initTemp(temp2);
+    ASSERT_EQ(temp2.hash(), expectedHash(expectedSmallBits, smallSize));
+    ASSERT_EQ(temp2.hash(), temp1.hash());
+}
+
+TEST(WTF_Bitmap, Size_uint32_t) { testBitmapSize<uint32_t>(); }
+TEST(WTF_Bitmap, ConstructedEmpty_uint32_t) { testBitmapConstructedEmpty<uint32_t>(); }
+TEST(WTF_Bitmap, SetGet_uint32_t) { testBitmapSetGet<uint32_t>(); }
+TEST(WTF_Bitmap, TestAndSet_uint32_t) { testBitmapTestAndSet<uint32_t>(); }
+TEST(WTF_Bitmap, TestAndClear_uint32_t) { testBitmapTestAndClear<uint32_t>(); }
+TEST(WTF_Bitmap, ConcurrentTestAndSet_uint32_t) { testBitmapConcurrentTestAndSet<uint32_t>(); }
+TEST(WTF_Bitmap, ConcurrentTestAndClear_uint32_t) { testBitmapConcurrentTestAndClear<uint32_t>(); }
+TEST(WTF_Bitmap, Clear_uint32_t) { testBitmapClear<uint32_t>(); }
+TEST(WTF_Bitmap, ClearAll_uint32_t) { testBitmapClearAll<uint32_t>(); }
+TEST(WTF_Bitmap, Invert_uint32_t) { testBitmapInvert<uint32_t>(); }
+TEST(WTF_Bitmap, FindRunOfZeros_uint32_t) { testBitmapFindRunOfZeros<uint32_t>(); }
+TEST(WTF_Bitmap, Count_uint32_t) { testBitmapCount<uint32_t>(); }
+TEST(WTF_Bitmap, IsEmpty_uint32_t) { testBitmapIsEmpty<uint32_t>(); }
+TEST(WTF_Bitmap, IsFull_uint32_t) { testBitmapIsFull<uint32_t>(); }
+TEST(WTF_Bitmap, Merge_uint32_t) { testBitmapMerge<uint32_t>(); }
+TEST(WTF_Bitmap, Filter_uint32_t) { testBitmapFilter<uint32_t>(); }
+TEST(WTF_Bitmap, Exclude_uint32_t) { testBitmapExclude<uint32_t>(); }
+TEST(WTF_Bitmap, ConcurrentFilter_uint32_t) { testBitmapConcurrentFilter<uint32_t>(); }
+TEST(WTF_Bitmap, Subsumes_uint32_t) { testBitmapSubsumes<uint32_t>(); }
+TEST(WTF_Bitmap, ForEachSetBit_uint32_t) { testBitmapForEachSetBit<uint32_t>(); }
+TEST(WTF_Bitmap, FindBit_uint32_t) { testBitmapFindBit<uint32_t>(); }
+TEST(WTF_Bitmap, Iteration_uint32_t) { testBitmapIteration<uint32_t>(); }
+TEST(WTF_Bitmap, MergeAndClear_uint32_t) { testBitmapMergeAndClear<uint32_t>(); }
+TEST(WTF_Bitmap, SetAndClear_uint32_t) { testBitmapSetAndClear<uint32_t>(); }
+TEST(WTF_Bitmap, OperatorEqualAccess_uint32_t) { testBitmapOperatorEqual<uint32_t>(); }
+TEST(WTF_Bitmap, OperatorNotEqualAccess_uint32_t) { testBitmapOperatorNotEqual<uint32_t>(); }
+TEST(WTF_Bitmap, Hash_uint32_t) { testBitmapHash<uint32_t>(); }
+
+#if CPU(REGISTER64)
+
+TEST(WTF_Bitmap, Size_uint64_t) { testBitmapSize<uint64_t>(); }
+TEST(WTF_Bitmap, ConstructedEmpty_uint64_t) { testBitmapConstructedEmpty<uint64_t>(); }
+TEST(WTF_Bitmap, SetGet_uint64_t) { testBitmapSetGet<uint64_t>(); }
+TEST(WTF_Bitmap, TestAndSet_uint64_t) { testBitmapTestAndSet<uint64_t>(); }
+TEST(WTF_Bitmap, TestAndClear_uint64_t) { testBitmapTestAndClear<uint64_t>(); }
+TEST(WTF_Bitmap, ConcurrentTestAndSet_uint64_t) { testBitmapConcurrentTestAndSet<uint64_t>(); }
+TEST(WTF_Bitmap, ConcurrentTestAndClear_uint64_t) { testBitmapConcurrentTestAndClear<uint64_t>(); }
+TEST(WTF_Bitmap, Clear_uint64_t) { testBitmapClear<uint64_t>(); }
+TEST(WTF_Bitmap, ClearAll_uint64_t) { testBitmapClearAll<uint64_t>(); }
+TEST(WTF_Bitmap, Invert_uint64_t) { testBitmapInvert<uint64_t>(); }
+TEST(WTF_Bitmap, FindRunOfZeros_uint64_t) { testBitmapFindRunOfZeros<uint64_t>(); }
+TEST(WTF_Bitmap, Count_uint64_t) { testBitmapCount<uint64_t>(); }
+TEST(WTF_Bitmap, IsEmpty_uint64_t) { testBitmapIsEmpty<uint64_t>(); }
+TEST(WTF_Bitmap, IsFull_uint64_t) { testBitmapIsFull<uint64_t>(); }
+TEST(WTF_Bitmap, Merge_uint64_t) { testBitmapMerge<uint64_t>(); }
+TEST(WTF_Bitmap, Filter_uint64_t) { testBitmapFilter<uint64_t>(); }
+TEST(WTF_Bitmap, Exclude_uint64_t) { testBitmapExclude<uint64_t>(); }
+TEST(WTF_Bitmap, ConcurrentFilter_uint64_t) { testBitmapConcurrentFilter<uint64_t>(); }
+TEST(WTF_Bitmap, Subsumes_uint64_t) { testBitmapSubsumes<uint64_t>(); }
+TEST(WTF_Bitmap, ForEachSetBit_uint64_t) { testBitmapForEachSetBit<uint64_t>(); }
+TEST(WTF_Bitmap, FindBit_uint64_t) { testBitmapFindBit<uint64_t>(); }
+TEST(WTF_Bitmap, Iteration_uint64_t) { testBitmapIteration<uint64_t>(); }
+TEST(WTF_Bitmap, MergeAndClear_uint64_t) { testBitmapMergeAndClear<uint64_t>(); }
+TEST(WTF_Bitmap, SetAndClear_uint64_t) { testBitmapSetAndClear<uint64_t>(); }
+TEST(WTF_Bitmap, OperatorEqualAccess_uint64_t) { testBitmapOperatorEqual<uint64_t>(); }
+TEST(WTF_Bitmap, OperatorNotEqualAccess_uint64_t) { testBitmapOperatorNotEqual<uint64_t>(); }
+TEST(WTF_Bitmap, Hash_uint64_t) { testBitmapHash<uint64_t>(); }
+
+#endif // CPU(REGISTER64)
+
+} // namespace TestWebKitAPI
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to