Add support for CompactPointerTuple<..., OptionSet<...>>
https://bugs.webkit.org/show_bug.cgi?id=201316

Reviewed by Yusuke Suzuki.

Source/WebCore:

Use the new CompactPointerTuple capability to replace CompactPointerTuple<RenderObject*, uint8_t>
with CompactPointerTuple<RenderObject*, OptionSet<ElementStyleFlag>> in Node.h.

* dom/Node.h:
(WebCore::Node::hasStyleFlag const):
(WebCore::Node::setStyleFlag):
(WebCore::Node::clearStyleFlags):
Update code now that we support CompactPointerTuple<..., OptionSet<...>>.

Source/WTF:

Support using an OptionSet<> for the byte value portion of a CompactPointerTuple so that
you can encode both a pointer and 8-bit bitmask in a type-safe way. Another benefit of
supporting OptionSet<> is that we have a LLDB pretty-printer for it so this makes it easy
to see the set flags in such a CompactPointerTuple.

* wtf/CompactPointerTuple.h:

Tools:

Add a test to ensure we encode and decode a compact pointer tuple correctly when an uint8_t and
a OptionSet<> as the byte value portion of the tuple.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WTF/CompactPointerTuple.cpp: Added.
(TestWebKitAPI::TEST):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@250930 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WTF/ChangeLog b/Source/WTF/ChangeLog
index c05c0b3..01f617d 100644
--- a/Source/WTF/ChangeLog
+++ b/Source/WTF/ChangeLog
@@ -1,3 +1,17 @@
+2019-10-09  Daniel Bates  <dabates@apple.com>
+
+        Add support for CompactPointerTuple<..., OptionSet<...>>
+        https://bugs.webkit.org/show_bug.cgi?id=201316
+
+        Reviewed by Yusuke Suzuki.
+
+        Support using an OptionSet<> for the byte value portion of a CompactPointerTuple so that
+        you can encode both a pointer and 8-bit bitmask in a type-safe way. Another benefit of
+        supporting OptionSet<> is that we have a LLDB pretty-printer for it so this makes it easy
+        to see the set flags in such a CompactPointerTuple.
+
+        * wtf/CompactPointerTuple.h:
+
 2019-10-08  Robin Morisset  <rmorisset@apple.com>
 
         dataLogIf should be ALWAYS_INLINE
diff --git a/Source/WTF/wtf/CompactPointerTuple.h b/Source/WTF/wtf/CompactPointerTuple.h
index a7ff73e..f2e942f 100644
--- a/Source/WTF/wtf/CompactPointerTuple.h
+++ b/Source/WTF/wtf/CompactPointerTuple.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2018 Yusuke Suzuki <utatane.tea@gmail.com>.
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -26,21 +27,35 @@
 #pragma once
 
 #include <type_traits>
+#include <wtf/OptionSet.h>
 #include <wtf/StdLibExtras.h>
 
 namespace WTF {
 
+template <typename T>
+struct IsOptionSet : public std::integral_constant<bool, WTF::IsTemplate<std::decay_t<T>, OptionSet>::value> { };
+
+template<typename T> struct ByteValueTypeAdapter {
+    static constexpr uint8_t toByte(T value) { return value; }
+    static constexpr T fromByte(uint8_t value) { return static_cast<T>(value); }
+};
+
+template<typename U> struct ByteValueTypeAdapter<OptionSet<U>> {
+    static constexpr uint8_t toByte(OptionSet<U> value) { return value.toRaw(); }
+    static constexpr OptionSet<U> fromByte(uint8_t value) { return OptionSet<U>::fromRaw(value); }
+};
+
 // The goal of this class is folding a pointer and 1 byte value into 8 bytes in both 32bit and 64bit architectures.
 // 32bit architecture just has a pair of byte and pointer, which should be 8 bytes.
 // In 64bit, we use the upper 5 bits and lower 3 bits (zero due to alignment) since these bits are safe to use even
 // with 5-level page tables where the effective pointer width is 57bits.
-template<typename PointerType, typename Type>
+template<typename PointerType, typename Type, typename Adapter = ByteValueTypeAdapter<Type>>
 class CompactPointerTuple final {
     WTF_MAKE_FAST_ALLOCATED;
 public:
     static_assert(sizeof(Type) == 1, "");
     static_assert(std::is_pointer<PointerType>::value, "");
-    static_assert(std::is_integral<Type>::value || std::is_enum<Type>::value, "");
+    static_assert(std::is_integral<Type>::value || std::is_enum<Type>::value || IsOptionSet<Type>::value, "");
 
     CompactPointerTuple() = default;
 
@@ -62,7 +77,7 @@
     static constexpr uint64_t pointerMask = ~typeMask;
 
     CompactPointerTuple(PointerType pointer, Type type)
-        : m_data(bitwise_cast<uint64_t>(pointer) | encodeType(static_cast<uint8_t>(type)))
+        : m_data { bitwise_cast<uint64_t>(pointer) | encodeType(Adapter::toByte(type)) }
     {
         ASSERT((bitwise_cast<uint64_t>(pointer) & 0b111) == 0x0);
     }
@@ -75,7 +90,7 @@
         m_data = CompactPointerTuple(pointer, type()).m_data;
     }
 
-    Type type() const { return static_cast<Type>(decodeType(m_data)); }
+    Type type() const { return Adapter::fromByte(decodeType(m_data)); }
     void setType(Type type)
     {
         m_data = CompactPointerTuple(pointer(), type).m_data;
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 65e9e2b..1a1ca3e 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,19 @@
+2019-10-09  Daniel Bates  <dabates@apple.com>
+
+        Add support for CompactPointerTuple<..., OptionSet<...>>
+        https://bugs.webkit.org/show_bug.cgi?id=201316
+
+        Reviewed by Yusuke Suzuki.
+
+        Use the new CompactPointerTuple capability to replace CompactPointerTuple<RenderObject*, uint8_t>
+        with CompactPointerTuple<RenderObject*, OptionSet<ElementStyleFlag>> in Node.h.
+
+        * dom/Node.h:
+        (WebCore::Node::hasStyleFlag const):
+        (WebCore::Node::setStyleFlag):
+        (WebCore::Node::clearStyleFlags):
+        Update code now that we support CompactPointerTuple<..., OptionSet<...>>.
+
 2019-10-09  Zalan Bujtas  <zalan@apple.com>
 
         RunResolver::rangeForRendererWithOffsets should check for range end
diff --git a/Source/WebCore/dom/Node.h b/Source/WebCore/dom/Node.h
index 04aba13..8e0f665 100644
--- a/Source/WebCore/dom/Node.h
+++ b/Source/WebCore/dom/Node.h
@@ -36,6 +36,7 @@
 #include <wtf/IsoMalloc.h>
 #include <wtf/ListHashSet.h>
 #include <wtf/MainThread.h>
+#include <wtf/OptionSet.h>
 #include <wtf/URLHash.h>
 
 // This needs to be here because Document.h also depends on it.
@@ -615,9 +616,9 @@
         ChildrenAffectedByPropertyBasedBackwardPositionalRules = 1 << 7,
     };
 
-    bool hasStyleFlag(ElementStyleFlag state) const { return m_rendererWithStyleFlags.type() & static_cast<uint8_t>(state); }
-    void setStyleFlag(ElementStyleFlag state) { m_rendererWithStyleFlags.setType(m_rendererWithStyleFlags.type() | static_cast<uint8_t>(state)); }
-    void clearStyleFlags() { m_rendererWithStyleFlags.setType(0); }
+    bool hasStyleFlag(ElementStyleFlag state) const { return m_rendererWithStyleFlags.type().contains(state); }
+    void setStyleFlag(ElementStyleFlag state) { m_rendererWithStyleFlags.setType(m_rendererWithStyleFlags.type() | state); }
+    void clearStyleFlags() { m_rendererWithStyleFlags.setType(OptionSet<ElementStyleFlag>()); }
 
     virtual void addSubresourceAttributeURLs(ListHashSet<URL>&) const { }
 
@@ -675,7 +676,7 @@
     TreeScope* m_treeScope { nullptr };
     Node* m_previous { nullptr };
     Node* m_next { nullptr };
-    CompactPointerTuple<RenderObject*, uint8_t> m_rendererWithStyleFlags;
+    CompactPointerTuple<RenderObject*, OptionSet<ElementStyleFlag>> m_rendererWithStyleFlags;
     std::unique_ptr<NodeRareData, NodeRareDataDeleter> m_rareData;
 };
 
diff --git a/Tools/ChangeLog b/Tools/ChangeLog
index fef2576..46cdeaa 100644
--- a/Tools/ChangeLog
+++ b/Tools/ChangeLog
@@ -1,3 +1,17 @@
+2019-10-09  Daniel Bates  <dabates@apple.com>
+
+        Add support for CompactPointerTuple<..., OptionSet<...>>
+        https://bugs.webkit.org/show_bug.cgi?id=201316
+
+        Reviewed by Yusuke Suzuki.
+
+        Add a test to ensure we encode and decode a compact pointer tuple correctly when an uint8_t and
+        a OptionSet<> as the byte value portion of the tuple.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WTF/CompactPointerTuple.cpp: Added.
+        (TestWebKitAPI::TEST):
+
 2019-10-09  Jonathan Bedard  <jbedard@apple.com>
 
         results.webkit.org: Increase default limit for test results
diff --git a/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
index 3a6675c..92de553 100644
--- a/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
+++ b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
@@ -926,6 +926,7 @@
 		CE6E81A020A6935F00E2C80F /* SetTimeoutFunction.mm in Sources */ = {isa = PBXBuildFile; fileRef = CE6E819F20A6935F00E2C80F /* SetTimeoutFunction.mm */; };
 		CE6E81A420A933D500E2C80F /* set-timeout-function.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = CE6E81A320A933B800E2C80F /* set-timeout-function.html */; };
 		CE78705F2107AB980053AC67 /* MoveOnlyLifecycleLogger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CE78705D2107AB8C0053AC67 /* MoveOnlyLifecycleLogger.cpp */; };
+		CE9B07F2231889E300A09BC7 /* CompactPointerTuple.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CE9B07F1231889E300A09BC7 /* CompactPointerTuple.cpp */; };
 		CEA6CF2819CCF69D0064F5A7 /* open-and-close-window.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = CEA6CF2719CCF69D0064F5A7 /* open-and-close-window.html */; };
 		CEA7F57D2089624B0078EF6E /* DidResignInputElementStrongPasswordAppearance.mm in Sources */ = {isa = PBXBuildFile; fileRef = CEA7F57B20895F5B0078EF6E /* DidResignInputElementStrongPasswordAppearance.mm */; };
 		CEBABD491B71687C0051210A /* should-open-external-schemes.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = CEBABD481B71687C0051210A /* should-open-external-schemes.html */; };
@@ -2401,6 +2402,7 @@
 		CE6E81A320A933B800E2C80F /* set-timeout-function.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = "set-timeout-function.html"; path = "ios/set-timeout-function.html"; sourceTree = SOURCE_ROOT; };
 		CE78705C2107AB8C0053AC67 /* MoveOnlyLifecycleLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MoveOnlyLifecycleLogger.h; sourceTree = "<group>"; };
 		CE78705D2107AB8C0053AC67 /* MoveOnlyLifecycleLogger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MoveOnlyLifecycleLogger.cpp; sourceTree = "<group>"; };
+		CE9B07F1231889E300A09BC7 /* CompactPointerTuple.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CompactPointerTuple.cpp; sourceTree = "<group>"; };
 		CEA6CF2219CCF5BD0064F5A7 /* OpenAndCloseWindow.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = OpenAndCloseWindow.mm; sourceTree = "<group>"; };
 		CEA6CF2719CCF69D0064F5A7 /* open-and-close-window.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "open-and-close-window.html"; sourceTree = "<group>"; };
 		CEA7F57B20895F5B0078EF6E /* DidResignInputElementStrongPasswordAppearance.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = DidResignInputElementStrongPasswordAppearance.mm; sourceTree = "<group>"; };
@@ -3617,6 +3619,7 @@
 				26F1B44215CA434F00D1E4BF /* AtomString.cpp */,
 				E40019301ACE9B5C001B0A2A /* BloomFilter.cpp */,
 				A7A966DA140ECCC8005EF9B4 /* CheckedArithmeticOperations.cpp */,
+				CE9B07F1231889E300A09BC7 /* CompactPointerTuple.cpp */,
 				0F30CB5B1FCE1792004B5323 /* ConcurrentPtrHashSet.cpp */,
 				0FEAE3671B7D19CB00CE17F2 /* Condition.cpp */,
 				278DE64B22B8D611004E0E7A /* CrossThreadCopier.cpp */,
@@ -4308,6 +4311,7 @@
 				1ADAD1501D77A9F600212586 /* BlockPtr.mm in Sources */,
 				7C83DE9C1D0A590C00FEBCF3 /* BloomFilter.cpp in Sources */,
 				7C83DEA01D0A590C00FEBCF3 /* CheckedArithmeticOperations.cpp in Sources */,
+				CE9B07F2231889E300A09BC7 /* CompactPointerTuple.cpp in Sources */,
 				0F30CB5C1FCE1796004B5323 /* ConcurrentPtrHashSet.cpp in Sources */,
 				7C83DEC31D0A590C00FEBCF3 /* Condition.cpp in Sources */,
 				7C83DEA61D0A590C00FEBCF3 /* Counters.cpp in Sources */,
diff --git a/Tools/TestWebKitAPI/Tests/WTF/CompactPointerTuple.cpp b/Tools/TestWebKitAPI/Tests/WTF/CompactPointerTuple.cpp
new file mode 100644
index 0000000..e7743fd
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/CompactPointerTuple.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2019 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 "Test.h"
+#include <wtf/CompactPointerTuple.h>
+
+namespace TestWebKitAPI {
+
+enum class ExampleFlags : uint8_t {
+    A = 1 << 0,
+    B = 1 << 1,
+    C = 1 << 2,
+};
+
+TEST(CompactPointerTuple, CompactPointerWithUInt8_Simple)
+{
+    CompactPointerTuple<int*, uint8_t> pointerWithFlags { nullptr, 7 };
+    EXPECT_EQ(nullptr, pointerWithFlags.pointer());
+    EXPECT_EQ(7, pointerWithFlags.type());
+}
+
+TEST(CompactPointerTuple, CompactPointerWithOptionSet_EmptySet)
+{
+    CompactPointerTuple<int*, OptionSet<ExampleFlags>> pointerWithFlags;
+    EXPECT_TRUE(pointerWithFlags.type().isEmpty());
+    EXPECT_FALSE(pointerWithFlags.type().contains(ExampleFlags::A));
+    EXPECT_FALSE(pointerWithFlags.type().contains(ExampleFlags::B));
+    EXPECT_FALSE(pointerWithFlags.type().contains(ExampleFlags::C));
+}
+
+TEST(CompactPointerTuple, CompactPointerWithOptionSet_Simple)
+{
+    CompactPointerTuple<int*, OptionSet<ExampleFlags>> pointerWithFlags;
+    pointerWithFlags.setType({ ExampleFlags::A, ExampleFlags::C });
+    EXPECT_FALSE(pointerWithFlags.type().isEmpty());
+    EXPECT_TRUE(pointerWithFlags.type().contains(ExampleFlags::A));
+    EXPECT_FALSE(pointerWithFlags.type().contains(ExampleFlags::B));
+    EXPECT_TRUE(pointerWithFlags.type().contains(ExampleFlags::C));
+}
+
+} // namespace TestWebKitAPI