Просмотр исходного кода

type_traits: sequence/associative container traits

Michele Caini 5 лет назад
Родитель
Сommit
2e4becad60
2 измененных файлов с 158 добавлено и 8 удалено
  1. 120 0
      src/entt/core/type_traits.hpp
  2. 38 8
      test/entt/core/type_traits.cpp

+ 120 - 0
src/entt/core/type_traits.hpp

@@ -204,6 +204,126 @@ template<class Type>
 inline constexpr auto is_equality_comparable_v = is_equality_comparable<Type>::value;
 
 
+/**
+ * @brief Provides the member constant `value` to true if a given type is a
+ * container, false otherwise.
+ * @tparam Type Potentially container type.
+ */
+template<typename Type, typename = void>
+struct is_container: std::false_type {};
+
+
+/*! @copydoc is_container */
+template<typename Type>
+struct is_container<Type, std::void_t<decltype(begin(std::declval<Type>()), end(std::declval<Type>()))>>
+        : std::true_type
+{};
+
+
+/**
+ * @brief Helper variable template.
+ * @tparam Type Potentially container type.
+ */
+template<typename Type>
+inline constexpr auto is_container_v = is_container<Type>::value;
+
+
+/**
+ * @brief Provides the member constant `value` to true if a given type is an
+ * associative container, false otherwise.
+ * @tparam Type Potentially associative container type.
+ */
+template<typename, typename = void>
+struct is_associative_container: std::false_type {};
+
+
+/*! @copydoc is_associative_container */
+template<typename Type>
+struct is_associative_container<Type, std::void_t<typename Type::key_type>>
+        : is_container<Type>
+{};
+
+
+/**
+ * @brief Helper variable template.
+ * @tparam Type Potentially associative container type.
+ */
+template<typename Type>
+inline constexpr auto is_associative_container_v = is_associative_container<Type>::value;
+
+
+/**
+ * @brief Provides the member constant `value` to true if a given type is a
+ * key-only associative container, false otherwise.
+ * @tparam Type Potentially key-only associative container type.
+ */
+template<typename, typename = void>
+struct is_key_only_associative_container: std::false_type {};
+
+
+/*! @copydoc is_associative_container */
+template<typename Type>
+struct is_key_only_associative_container<Type, std::enable_if_t<std::is_same_v<typename Type::key_type, typename Type::value_type>>>
+        : is_associative_container<Type>
+{};
+
+
+/**
+ * @brief Helper variable template.
+ * @tparam Type Potentially key-only associative container type.
+ */
+template<typename Type>
+inline constexpr auto is_key_only_associative_container_v = is_key_only_associative_container<Type>::value;
+
+
+/**
+ * @brief Provides the member constant `value` to true if a given type is a
+ * sequence container, false otherwise.
+ * @tparam Type Potentially sequence container type.
+ */
+template<typename, typename = void>
+struct is_sequence_container: std::false_type {};
+
+
+/*! @copydoc is_sequence_container */
+template<typename Type>
+struct is_sequence_container<Type, std::enable_if_t<!is_associative_container_v<Type>>>
+        : is_container<Type>
+{};
+
+
+/**
+ * @brief Helper variable template.
+ * @tparam Type Potentially sequence container type.
+ */
+template<typename Type>
+inline constexpr auto is_sequence_container_v = is_sequence_container<Type>::value;
+
+
+/**
+ * @brief Provides the member constant `value` to true if a given type is a
+ * dynamic sequence container, false otherwise.
+ * @tparam Type Potentially dynamic sequence container type.
+ */
+template<typename, typename = void>
+struct is_dynamic_sequence_container: std::false_type {};
+
+
+/*! @copydoc is_dynamic_sequence_container */
+template<typename Type>
+struct is_dynamic_sequence_container<Type, std::void_t<decltype(std::declval<Type>().insert({}, std::declval<typename Type::value_type>()))>>
+        : is_sequence_container<Type>
+{};
+
+
+/**
+ * @brief Helper variable template.
+ * @tparam Type Potentially dynamic sequence container type.
+ */
+template<typename Type>
+inline constexpr auto is_dynamic_sequence_container_v = is_dynamic_sequence_container<Type>::value;
+
+
 /**
  * @brief Extracts the class of a non-static member object or function.
  * @tparam Member A pointer to a non-static member object or function.

+ 38 - 8
test/entt/core/type_traits.cpp

@@ -1,10 +1,14 @@
+#include <array>
+#include <map>
+#include <set>
 #include <type_traits>
+#include <vector>
 #include <gtest/gtest.h>
 #include <entt/config/config.h>
 #include <entt/core/hashed_string.hpp>
 #include <entt/core/type_traits.hpp>
 
-TEST(Unpack, AsType) {
+TEST(TypeTraits, UnpackAsType) {
     ASSERT_EQ([](auto &&... args) {
         return [](entt::unpack_as_t<int, decltype(args)>... value) {
             return (value + ... + 0);
@@ -12,25 +16,25 @@ TEST(Unpack, AsType) {
     }('c', 42., true)(1, 2, 3), 6);
 }
 
-TEST(Unpack, AsValue) {
+TEST(TypeTraits, UnpackAsValue) {
     ASSERT_EQ([](auto &&... args) {
         return (entt::unpack_as_v<2, decltype(args)> + ... + 0);
     }('c', 42., true), 6);
 }
 
-TEST(IntegralConstant, Functionalities) {
+TEST(TypeTraits, IntegralConstant) {
     entt::integral_constant<3> constant;
 
     ASSERT_TRUE((std::is_same_v<typename entt::integral_constant<3>::value_type, int>));
     ASSERT_EQ(constant.value, 3);
 }
 
-TEST(Choice, Functionalities) {
+TEST(TypeTraits, Choice) {
     ASSERT_TRUE((std::is_base_of_v<entt::choice_t<0>, entt::choice_t<1>>));
     ASSERT_FALSE((std::is_base_of_v<entt::choice_t<1>, entt::choice_t<0>>));
 }
 
-TEST(TypeList, Functionalities) {
+TEST(TypeTraits, TypeList) {
     using type = entt::type_list<int, char>;
     using other = entt::type_list<double>;
 
@@ -42,12 +46,38 @@ TEST(TypeList, Functionalities) {
     ASSERT_TRUE((std::is_same_v<entt::type_list_unique_t<entt::type_list_cat_t<type, type>>, entt::type_list<int, char>>));
 }
 
-TEST(IsEqualityComparable, Functionalities) {
+TEST(TypeTraits, IsEqualityComparable) {
     ASSERT_TRUE(entt::is_equality_comparable_v<int>);
     ASSERT_FALSE(entt::is_equality_comparable_v<void>);
 }
 
-TEST(MemberClass, Functionalities) {
+TEST(TypeTraits, IsContainerType) {
+    ASSERT_TRUE(entt::is_container_v<std::vector<int>>);
+    ASSERT_FALSE(entt::is_associative_container_v<std::vector<int>>);
+    ASSERT_FALSE(entt::is_key_only_associative_container_v<std::vector<int>>);
+    ASSERT_TRUE(entt::is_sequence_container_v<std::vector<int>>);
+    ASSERT_TRUE(entt::is_dynamic_sequence_container_v<std::vector<int>>);
+
+    ASSERT_TRUE((entt::is_container_v<std::array<int, 3>>));
+    ASSERT_FALSE((entt::is_associative_container_v<std::array<int, 3>>));
+    ASSERT_FALSE((entt::is_key_only_associative_container_v<std::array<int, 3>>));
+    ASSERT_TRUE((entt::is_sequence_container_v<std::array<int, 3>>));
+    ASSERT_FALSE((entt::is_dynamic_sequence_container_v<std::array<int, 3>>));
+
+    ASSERT_TRUE((entt::is_container_v<std::map<int, char>>));
+    ASSERT_TRUE((entt::is_associative_container_v<std::map<int, char>>));
+    ASSERT_FALSE((entt::is_key_only_associative_container_v<std::map<int, char>>));
+    ASSERT_FALSE((entt::is_sequence_container_v<std::map<int, char>>));
+    ASSERT_FALSE((entt::is_dynamic_sequence_container_v<std::map<int, char>>));
+
+    ASSERT_TRUE(entt::is_container_v<std::set<int>>);
+    ASSERT_TRUE(entt::is_associative_container_v<std::set<int>>);
+    ASSERT_TRUE(entt::is_key_only_associative_container_v<std::set<int>>);
+    ASSERT_FALSE(entt::is_sequence_container_v<std::set<int>>);
+    ASSERT_FALSE(entt::is_dynamic_sequence_container_v<std::set<int>>);
+}
+
+TEST(TypeTraits, MemberClass) {
     struct clazz {
         char foo(int) { return {}; }
         int bar(double, float) const { return {}; }
@@ -59,7 +89,7 @@ TEST(MemberClass, Functionalities) {
     ASSERT_TRUE((std::is_same_v<clazz, entt::member_class_t<decltype(&clazz::quux)>>));
 }
 
-TEST(Tag, Functionalities) {
+TEST(TypeTraits, Tag) {
     ASSERT_EQ(entt::tag<"foobar"_hs>::value, entt::hashed_string::value("foobar"));
     ASSERT_TRUE((std::is_same_v<typename entt::tag<"foobar"_hs>::value_type, ENTT_ID_TYPE>));
 }