Title: [264277] trunk
Revision
264277
Author
[email protected]
Date
2020-07-12 02:47:05 -0700 (Sun, 12 Jul 2020)

Log Message

Relanding "Make hasher work with tuple-like classes"
https://bugs.webkit.org/show_bug.cgi?id=214224

Reviewed by Darin Adler.

Source/WTF:

The original patch broke the internal build. And reverting patch (r264274) broke the build too.
This patch relands r264270 with `constexpr` => `inline constexpr` template variable fix.

* wtf/Hasher.h:
(WTF::add):
(WTF::addTupleLikeHelper):
(WTF::TypeCheckHelper<decltype): Deleted.
(WTF::addTupleHelper): Deleted.
Add support for tuple-like classes. These are classes that:
- Have defined specializations of std::tuple_size<> and std::tuple_element<>.
- And have either a member function named get<> or there exists a function get<>()
  that takes the class as argument that can be looked up via ADL.

To avoid abiguity when hashing std::array, the add() overload enabled for containers
with a begin member functions also now checks that the container is not tuple-like.
The std::pair overload is no longer needed as it will use the tuple-like one now.

* wtf/OptionSet.h:
* wtf/StdLibExtras.h:
Move is_type_complete_v<> from OptionSet.h to StdLibExtras.h and rename to
adhere to WebKit style as IsTypeComplete<>.

Tools:

* TestWebKitAPI/Tests/WTF/Hasher.cpp:
(TestWebKitAPI::get):
(TestWebKitAPI::HasherAddTupleLikeClass3::get const):
(TestWebKitAPI::TEST):
Update using new Color constructor for extended colors.

Modified Paths

Diff

Modified: trunk/Source/WTF/ChangeLog (264276 => 264277)


--- trunk/Source/WTF/ChangeLog	2020-07-12 08:16:13 UTC (rev 264276)
+++ trunk/Source/WTF/ChangeLog	2020-07-12 09:47:05 UTC (rev 264277)
@@ -1,3 +1,32 @@
+2020-07-11  Sam Weinig  <[email protected]> and Yusuke Suzuki  <[email protected]>
+
+        Relanding "Make hasher work with tuple-like classes"
+        https://bugs.webkit.org/show_bug.cgi?id=214224
+
+        Reviewed by Darin Adler.
+
+        The original patch broke the internal build. And reverting patch (r264274) broke the build too.
+        This patch relands r264270 with `constexpr` => `inline constexpr` template variable fix.
+
+        * wtf/Hasher.h:
+        (WTF::add):
+        (WTF::addTupleLikeHelper):
+        (WTF::TypeCheckHelper<decltype): Deleted.
+        (WTF::addTupleHelper): Deleted.
+        Add support for tuple-like classes. These are classes that:
+        - Have defined specializations of std::tuple_size<> and std::tuple_element<>.
+        - And have either a member function named get<> or there exists a function get<>()
+          that takes the class as argument that can be looked up via ADL.
+
+        To avoid abiguity when hashing std::array, the add() overload enabled for containers
+        with a begin member functions also now checks that the container is not tuple-like.
+        The std::pair overload is no longer needed as it will use the tuple-like one now.
+
+        * wtf/OptionSet.h:
+        * wtf/StdLibExtras.h:
+        Move is_type_complete_v<> from OptionSet.h to StdLibExtras.h and rename to
+        adhere to WebKit style as IsTypeComplete<>.
+
 2020-07-11  Commit Queue  <[email protected]>
 
         Unreviewed, reverting r264270.

Modified: trunk/Source/WTF/wtf/Hasher.h (264276 => 264277)


--- trunk/Source/WTF/wtf/Hasher.h	2020-07-12 08:16:13 UTC (rev 264276)
+++ trunk/Source/WTF/wtf/Hasher.h	2020-07-12 09:47:05 UTC (rev 264277)
@@ -106,11 +106,10 @@
     add(hasher, static_cast<std::underlying_type_t<Enumeration>>(value));
 }
 
-template<typename> struct TypeCheckHelper { };
-template<typename, typename = void> struct HasBeginFunctionMember : std::false_type { };
-template<typename Container> struct HasBeginFunctionMember<Container, std::conditional_t<false, TypeCheckHelper<decltype(std::declval<Container>().begin())>, void>> : std::true_type { };
+template<typename, typename = void> inline constexpr bool HasBeginFunctionMember = false;
+template<typename T> inline constexpr bool HasBeginFunctionMember<T, std::void_t<decltype(std::declval<T>().begin())>> = true;
 
-template<typename Container> std::enable_if_t<HasBeginFunctionMember<Container>::value, void> add(Hasher& hasher, const Container& container)
+template<typename Container> std::enable_if_t<HasBeginFunctionMember<Container> && !IsTypeComplete<std::tuple_size<Container>>, void> add(Hasher& hasher, const Container& container)
 {
     for (const auto& value : container)
         add(hasher, value);
@@ -126,20 +125,22 @@
     addArgs(hasher, args...);
 }
 
-template<typename Tuple, std::size_t ...i> void addTupleHelper(Hasher& hasher, const Tuple& values, std::index_sequence<i...>)
-{
-    addArgs(hasher, std::get<i>(values)...);
-}
+template<typename, typename = void> inline constexpr bool HasGetFunctionMember = false;
+template<typename T> inline constexpr bool HasGetFunctionMember<T, std::void_t<decltype(std::declval<T>().template get<0>())>> = true;
 
-template<typename... Types> void add(Hasher& hasher, const std::tuple<Types...>& tuple)
+template<typename TupleLike, std::size_t ...I> void addTupleLikeHelper(Hasher& hasher, const TupleLike& tupleLike, std::index_sequence<I...>)
 {
-    addTupleHelper(hasher, tuple, std::make_index_sequence<std::tuple_size<std::tuple<Types...>>::value> { });
+    if constexpr (HasGetFunctionMember<TupleLike>)
+        addArgs(hasher, tupleLike.template get<I>()...);
+    else {
+        using std::get;
+        addArgs(hasher, get<I>(tupleLike)...);
+    }
 }
 
-template<typename T1, typename T2> void add(Hasher& hasher, const std::pair<T1, T2>& pair)
+template<typename TupleLike> std::enable_if_t<IsTypeComplete<std::tuple_size<TupleLike>>, void> add(Hasher& hasher, const TupleLike& tuple)
 {
-    add(hasher, pair.first);
-    add(hasher, pair.second);
+    addTupleLikeHelper(hasher, tuple, std::make_index_sequence<std::tuple_size<TupleLike>::value> { });
 }
 
 template<typename T> void add(Hasher& hasher, const Optional<T>& optional)

Modified: trunk/Source/WTF/wtf/OptionSet.h (264276 => 264277)


--- trunk/Source/WTF/wtf/OptionSet.h	2020-07-12 08:16:13 UTC (rev 264276)
+++ trunk/Source/WTF/wtf/OptionSet.h	2020-07-12 09:47:05 UTC (rev 264277)
@@ -32,18 +32,10 @@
 #include <wtf/EnumTraits.h>
 #include <wtf/MathExtras.h>
 #include <wtf/Optional.h>
+#include <wtf/StdLibExtras.h>
 
 namespace WTF {
 
-// Detecting in C++ whether a type is defined, part 3: SFINAE and incomplete types
-// <https://devblogs.microsoft.com/oldnewthing/20190710-00/?p=102678>
-template<typename, typename = void>
-constexpr bool is_type_complete_v = false;
-
-template<typename T>
-constexpr bool is_type_complete_v<T, std::void_t<decltype(sizeof(T))>> = true;
-
-
 template<typename E> class OptionSet;
 
 
@@ -76,13 +68,13 @@
 };
 
 
-template<typename E, std::enable_if_t<std::is_enum<E>::value && is_type_complete_v<EnumTraits<E>>>* = nullptr>
+template<typename E, std::enable_if_t<std::is_enum<E>::value && IsTypeComplete<EnumTraits<E>>>* = nullptr>
 constexpr bool isValidOptionSetEnum(E e)
 {
     return OptionSetValueChecker<std::underlying_type_t<E>, typename EnumTraits<E>::values>::isValidOptionSetEnum(static_cast<std::underlying_type_t<E>>(e));
 }
 
-template<typename E, std::enable_if_t<std::is_enum<E>::value && !is_type_complete_v<EnumTraits<E>>>* = nullptr>
+template<typename E, std::enable_if_t<std::is_enum<E>::value && !IsTypeComplete<EnumTraits<E>>>* = nullptr>
 constexpr bool isValidOptionSetEnum(E e)
 {
     // FIXME: Remove once all OptionSet<> enums have EnumTraits<> defined.
@@ -90,7 +82,7 @@
 }
 
 
-template<typename E, std::enable_if_t<std::is_enum<E>::value && is_type_complete_v<EnumTraits<E>>>* = nullptr>
+template<typename E, std::enable_if_t<std::is_enum<E>::value && IsTypeComplete<EnumTraits<E>>>* = nullptr>
 constexpr typename OptionSet<E>::StorageType maskRawValue(typename OptionSet<E>::StorageType rawValue)
 {
     auto allValidBitsValue = OptionSetValueChecker<std::underlying_type_t<E>, typename EnumTraits<E>::values>::allValidBits();
@@ -97,7 +89,7 @@
     return rawValue & allValidBitsValue;
 }
 
-template<typename E, std::enable_if_t<std::is_enum<E>::value && !is_type_complete_v<EnumTraits<E>>>* = nullptr>
+template<typename E, std::enable_if_t<std::is_enum<E>::value && !IsTypeComplete<EnumTraits<E>>>* = nullptr>
 constexpr typename OptionSet<E>::StorageType maskRawValue(typename OptionSet<E>::StorageType rawValue)
 {
     // FIXME: Remove once all OptionSet<> enums have EnumTraits<> defined.

Modified: trunk/Source/WTF/wtf/StdLibExtras.h (264276 => 264277)


--- trunk/Source/WTF/wtf/StdLibExtras.h	2020-07-12 08:16:13 UTC (rev 264276)
+++ trunk/Source/WTF/wtf/StdLibExtras.h	2020-07-12 09:47:05 UTC (rev 264277)
@@ -418,6 +418,11 @@
 template <template <typename...> class Base, typename Derived>
 struct IsBaseOfTemplate : public std::integral_constant<bool, Detail::IsBaseOfTemplateImpl<Base, Derived>::value> {};
 
+// Based on 'Detecting in C++ whether a type is defined, part 3: SFINAE and incomplete types'
+// <https://devblogs.microsoft.com/oldnewthing/20190710-00/?p=102678>
+template<typename, typename = void> inline constexpr bool IsTypeComplete = false;
+template<typename T> inline constexpr bool IsTypeComplete<T, std::void_t<decltype(sizeof(T))>> = true;
+
 template <class T>
 struct RemoveCVAndReference  {
     typedef typename std::remove_cv<typename std::remove_reference<T>::type>::type type;

Modified: trunk/Tools/ChangeLog (264276 => 264277)


--- trunk/Tools/ChangeLog	2020-07-12 08:16:13 UTC (rev 264276)
+++ trunk/Tools/ChangeLog	2020-07-12 09:47:05 UTC (rev 264277)
@@ -1,3 +1,16 @@
+2020-07-11  Sam Weinig  <[email protected]> and Yusuke Suzuki  <[email protected]>
+
+        Relanding "Make hasher work with tuple-like classes"
+        https://bugs.webkit.org/show_bug.cgi?id=214224
+
+        Reviewed by Darin Adler.
+
+        * TestWebKitAPI/Tests/WTF/Hasher.cpp:
+        (TestWebKitAPI::get):
+        (TestWebKitAPI::HasherAddTupleLikeClass3::get const):
+        (TestWebKitAPI::TEST):
+        Update using new Color constructor for extended colors.
+
 2020-07-12  Yusuke Suzuki  <[email protected]>
 
         Unreviewed, follow-up after r264210

Modified: trunk/Tools/TestWebKitAPI/Tests/WTF/Hasher.cpp (264276 => 264277)


--- trunk/Tools/TestWebKitAPI/Tests/WTF/Hasher.cpp	2020-07-12 08:16:13 UTC (rev 264276)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/Hasher.cpp	2020-07-12 09:47:05 UTC (rev 264277)
@@ -208,8 +208,6 @@
     EXPECT_EQ(1652352321U, computeHash(HasherAddCustom2 { }));
 }
 
-#if 0 // FIXME: Add support for tuple-like classes.
-
 struct HasherAddTupleLikeClass1 {
     std::array<int, 4> array { { 1, 2, 3, 4 } };
     template<size_t i> int get() const { return std::get<i>(array); }
@@ -219,34 +217,46 @@
     std::array<int, 4> array { { 1, 2, 3, 4 } };
 };
 
+template<size_t i> int get(const HasherAddTupleLikeClass2& object)
+{
+    return object.array[i];
 }
 
+struct HasherAddTupleLikeClass3 {
+    int a = 1;
+    double b = 2;
+    
+    template<size_t i> decltype(auto) get() const
+    {
+        if constexpr (!i)
+            return a;
+        if constexpr (i == 1)
+            return b;
+    }
+};
+
+}
+
 namespace std {
 
-// FIXME: Documentation at cppreference.cpp says std::tuple_size is a struct, but it's a class in current macOS tools.
-// FIXME: It's inelegant to inject this into the std namespace. Is that really how a tuple-like class needs to be defined?
-// FIXME: This is so inconvenient that I am not sure it's something we want to do for lots of classes in WebKit.
-template<> class std::tuple_size<TestWebKitAPI::HasherAddTupleLikeClass1> : public std::integral_constant<size_t, std::tuple_size<decltype(TestWebKitAPI::HasherAddTupleLikeClass1::array)>::value> { };
+template<> class tuple_size<TestWebKitAPI::HasherAddTupleLikeClass1> : public integral_constant<size_t, 4> { };
+template<size_t I> class tuple_element<I, TestWebKitAPI::HasherAddTupleLikeClass1> { public: using type = int; };
 
-template<> class std::tuple_size<TestWebKitAPI::HasherAddTupleLikeClass2> : public std::integral_constant<size_t, std::tuple_size<decltype(TestWebKitAPI::HasherAddTupleLikeClass2::array)>::value> { };
+template<> class tuple_size<TestWebKitAPI::HasherAddTupleLikeClass2> : public integral_constant<size_t, 4> { };
+template<size_t I> class tuple_element<I, TestWebKitAPI::HasherAddTupleLikeClass2> { public: using type = int; };
 
+template<> class tuple_size<TestWebKitAPI::HasherAddTupleLikeClass3> : public integral_constant<size_t, 2> { };
+template<size_t I> class tuple_element<I, TestWebKitAPI::HasherAddTupleLikeClass3> { public: using type = decltype(declval<TestWebKitAPI::HasherAddTupleLikeClass3>().template get<I>()); };
+
 }
 
 namespace TestWebKitAPI {
 
-// FIXME: Is it OK for the get to be in the class's namespace and rely on argument-dependent lookup?
-// Or does this function template need to be moved into the std namespace like the tuple_size specialization?
-template<size_t i> int get(const HasherAddTupleLikeClass2& object)
-{
-    return get<i>(object.array);
-}
-
 TEST(WTF, Hasher_tupleLike)
 {
     EXPECT_EQ(1652352321U, computeHash(HasherAddTupleLikeClass1 { }));
     EXPECT_EQ(1652352321U, computeHash(HasherAddTupleLikeClass2 { }));
+    EXPECT_EQ(3489601216U, computeHash(HasherAddTupleLikeClass3 { }));
 }
 
-#endif
-
 } // namespace TestWebKitAPI
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to