Przeglądaj źródła

type_traits: is_equality_comparable, support for standard containers

Michele Caini 5 lat temu
rodzic
commit
f4bd868d6a
3 zmienionych plików z 105 dodań i 41 usunięć
  1. 77 34
      src/entt/core/type_traits.hpp
  2. 15 7
      test/entt/core/any.cpp
  3. 13 0
      test/entt/core/type_traits.cpp

+ 77 - 34
src/entt/core/type_traits.hpp

@@ -12,6 +12,32 @@
 namespace entt {
 
 
+/**
+ * @brief Utility class to disambiguate overloaded functions.
+ * @tparam N Number of choices available.
+ */
+template<std::size_t N>
+struct choice_t
+        // Unfortunately, doxygen cannot parse such a construct.
+        /*! @cond TURN_OFF_DOXYGEN */
+        : choice_t<N-1>
+        /*! @endcond */
+{};
+
+
+/*! @copybrief choice_t */
+template<>
+struct choice_t<0> {};
+
+
+/**
+ * @brief Variable template for the choice trick.
+ * @tparam N Number of choices available.
+ */
+template<std::size_t N>
+inline constexpr choice_t<N> choice{};
+
+
 /**
  * @brief Identity type trait.
  *
@@ -93,32 +119,6 @@ template<id_type Value>
 using tag = integral_constant<Value>;
 
 
-/**
- * @brief Utility class to disambiguate overloaded functions.
- * @tparam N Number of choices available.
- */
-template<std::size_t N>
-struct choice_t
-        // Unfortunately, doxygen cannot parse such a construct.
-        /*! @cond TURN_OFF_DOXYGEN */
-        : choice_t<N-1>
-        /*! @endcond */
-{};
-
-
-/*! @copybrief choice_t */
-template<>
-struct choice_t<0> {};
-
-
-/**
- * @brief Variable template for the choice trick.
- * @tparam N Number of choices available.
- */
-template<std::size_t N>
-inline constexpr choice_t<N> choice{};
-
-
 /**
  * @brief A class to use to push around lists of types, nothing more.
  * @tparam Type Types provided by the type list.
@@ -396,20 +396,63 @@ template<typename... List>
 using value_list_cat_t = typename value_list_cat<List...>::type;
 
 
+/**
+ * @cond TURN_OFF_DOXYGEN
+ * Internal details not to be documented.
+ */
+
+
+namespace internal {
+
+
+template<typename Type>
+constexpr auto is_equality_comparable()
+-> decltype(is_equality_comparable<Type>(choice<2>));
+
+
+template<typename Type>
+constexpr auto is_equality_comparable(choice_t<2>)
+-> decltype(
+    std::declval<typename Type::mapped_type>(),
+    std::declval<Type>() == std::declval<Type>(),
+    std::conjunction<decltype(is_equality_comparable<typename Type::key_type>()), decltype(is_equality_comparable<typename Type::mapped_type>())>{}
+);
+
+
+template<typename Type>
+constexpr auto is_equality_comparable(choice_t<1>)
+-> decltype(
+    std::declval<typename Type::value_type>(),
+    std::declval<Type>() == std::declval<Type>(),
+    is_equality_comparable<typename Type::value_type>()
+);
+
+
+template<typename Type>
+constexpr auto is_equality_comparable(choice_t<0>)
+-> decltype(std::declval<Type>() == std::declval<Type>(), std::true_type{});
+
+
+template<typename>
+constexpr std::false_type is_equality_comparable(...);
+
+
+}
+
+
+/**
+ * Internal details not to be documented.
+ * @endcond
+ */
+
+
 /**
  * @brief Provides the member constant `value` to true if a given type is
  * equality comparable, false otherwise.
  * @tparam Type Potentially equality comparable type.
  */
 template<typename Type, typename = void>
-struct is_equality_comparable: std::false_type {};
-
-
-/*! @copydoc is_equality_comparable */
-template<typename Type>
-struct is_equality_comparable<Type, std::void_t<decltype(std::declval<Type>() == std::declval<Type>())>>
-        : std::true_type
-{};
+struct is_equality_comparable: decltype(internal::is_equality_comparable<Type>()) {};
 
 
 /**

+ 15 - 7
test/entt/core/any.cpp

@@ -1,5 +1,7 @@
 #include <algorithm>
 #include <memory>
+#include <unordered_map>
+#include <vector>
 #include <gtest/gtest.h>
 #include <entt/core/any.hpp>
 
@@ -736,15 +738,21 @@ TEST(Any, Comparable) {
 }
 
 TEST(Any, NotComparable) {
-    entt::any any{not_comparable{}};
+    auto test = [](const auto &instance) {
+        entt::any any{std::cref(instance)};
 
-    ASSERT_EQ(any, any);
-    ASSERT_NE(any, entt::any{not_comparable{}});
-    ASSERT_NE(entt::any{}, any);
+        ASSERT_EQ(any, any);
+        ASSERT_NE(any, entt::any{instance});
+        ASSERT_NE(entt::any{}, any);
 
-    ASSERT_TRUE(any == any);
-    ASSERT_FALSE(any == entt::any{not_comparable{}});
-    ASSERT_TRUE(entt::any{} != any);
+        ASSERT_TRUE(any == any);
+        ASSERT_FALSE(any == entt::any{instance});
+        ASSERT_TRUE(entt::any{} != any);
+    };
+
+    test(not_comparable{});
+    test(std::unordered_map<int, not_comparable>{});
+    test(std::vector<not_comparable>{});
 }
 
 TEST(Any, CompareVoid) {

+ 13 - 0
test/entt/core/type_traits.cpp

@@ -1,10 +1,16 @@
 #include <tuple>
 #include <type_traits>
+#include <unordered_map>
+#include <vector>
 #include <gtest/gtest.h>
 #include <entt/config/config.h>
 #include <entt/core/hashed_string.hpp>
 #include <entt/core/type_traits.hpp>
 
+struct not_comparable {
+    bool operator==(const not_comparable &) const = delete;
+};
+
 TEST(TypeTraits, SizeOf) {
     static_assert(entt::size_of_v<void> == 0u);
     static_assert(entt::size_of_v<char> == sizeof(char));
@@ -79,6 +85,13 @@ TEST(TypeTraits, ValueList) {
 
 TEST(TypeTraits, IsEqualityComparable) {
     static_assert(entt::is_equality_comparable_v<int>);
+    static_assert(entt::is_equality_comparable_v<std::vector<int>>);
+    static_assert(entt::is_equality_comparable_v<std::unordered_map<int, int>>);
+
+    static_assert(!entt::is_equality_comparable_v<not_comparable>);
+    static_assert(!entt::is_equality_comparable_v<std::vector<not_comparable>>);
+    static_assert(!entt::is_equality_comparable_v<std::unordered_map<int, not_comparable>>);
+
     static_assert(!entt::is_equality_comparable_v<void>);
 }