Browse Source

meta: review utilities + code coverage

Michele Caini 4 years ago
parent
commit
012083a4a1
3 changed files with 239 additions and 33 deletions
  1. 27 33
      src/entt/meta/utility.hpp
  2. 1 0
      test/CMakeLists.txt
  3. 211 0
      test/entt/meta/meta_utility.cpp

+ 27 - 33
src/entt/meta/utility.hpp

@@ -262,7 +262,7 @@ template<typename Type, typename Policy = as_is_t, typename Candidate, std::size
 [[nodiscard]] meta_any meta_invoke([[maybe_unused]] meta_handle instance, Candidate &&candidate, meta_any *args, std::index_sequence<Index...>) {
     using descriptor = meta_function_helper_t<Type, Candidate>;
 
-    const auto invoke = [&candidate](auto &&maybe_clazz, auto &&...other) {
+    const auto invoke_with_args = [&candidate](auto &&maybe_clazz, auto &&...other) {
         if constexpr(std::is_member_function_pointer_v<std::remove_reference_t<Candidate>>) {
             if constexpr(std::is_void_v<typename descriptor::return_type>) {
                 (std::forward<decltype(maybe_clazz)>(maybe_clazz).*std::forward<Candidate>(candidate))(std::forward<decltype(other)>(other)...);
@@ -270,28 +270,31 @@ template<typename Type, typename Policy = as_is_t, typename Candidate, std::size
             } else {
                 return meta_dispatch<Policy>((std::forward<decltype(maybe_clazz)>(maybe_clazz).*std::forward<Candidate>(candidate))(std::forward<decltype(other)>(other)...));
             }
+        } else if constexpr(std::is_void_v<typename descriptor::return_type>) {
+            std::forward<Candidate>(candidate)(std::forward<decltype(maybe_clazz)>(maybe_clazz), std::forward<decltype(other)>(other)...);
+            return meta_any{std::in_place_type<void>};
         } else {
-            if constexpr(std::is_void_v<typename descriptor::return_type>) {
-                std::forward<Candidate>(candidate)(std::forward<decltype(maybe_clazz)>(maybe_clazz), std::forward<decltype(other)>(other)...);
-                return meta_any{std::in_place_type<void>};
-            } else {
-                return meta_dispatch<Policy>(std::forward<Candidate>(candidate)(std::forward<decltype(maybe_clazz)>(maybe_clazz), std::forward<decltype(other)>(other)...));
-            }
+            return meta_dispatch<Policy>(std::forward<Candidate>(candidate)(std::forward<decltype(maybe_clazz)>(maybe_clazz), std::forward<decltype(other)>(other)...));
         }
     };
 
     if constexpr(std::is_invocable_v<std::remove_reference_t<Candidate>, const Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
         if(const auto *const clazz = instance->try_cast<const Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
-            return invoke(*clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
+            return invoke_with_args(*clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
         }
     } else if constexpr(std::is_invocable_v<std::remove_reference_t<Candidate>, Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
         if(auto *const clazz = instance->try_cast<Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
-            return invoke(*clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
+            return invoke_with_args(*clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
         }
-    } else {
+    } else if constexpr(sizeof...(Index) != 0u) {
         if(((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
-            return invoke((args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
+            return invoke_with_args((args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
         }
+    } else if constexpr(std::is_void_v<decltype(std::forward<Candidate>(candidate)())>) {
+        std::forward<Candidate>(candidate)();
+        return meta_any{std::in_place_type<void>};
+    } else {
+        return meta_dispatch<Policy>(std::forward<Candidate>(candidate)());
     }
 
     return meta_any{};
@@ -314,27 +317,18 @@ template<typename Type, typename... Args, std::size_t... Index>
  */
 
 /**
- * @brief Tries to invoke a callable object given a list of erased parameters.
- * @tparam Type Reflected type to which the callable object is associated.
+ * @brief Tries to _invoke_ an object given a list of erased parameters.
+ * @tparam Type Reflected type to which the object to _invoke_ is associated.
  * @tparam Policy Optional policy (no policy set by default).
- * @tparam Candidate The type of the actual callable object to invoke.
+ * @tparam Candidate The type of the actual object to _invoke_.
  * @param instance An opaque instance of the underlying type, if required.
- * @param candidate The actual callable object to invoke.
- * @param args Parameters to use to invoke the callable object.
+ * @param candidate The actual object to _invoke_.
+ * @param args Parameters to use to _invoke_ the object.
  * @return A meta any containing the returned value, if any.
  */
 template<typename Type, typename Policy = as_is_t, typename Candidate>
 [[nodiscard]] meta_any meta_invoke([[maybe_unused]] meta_handle instance, Candidate &&candidate, [[maybe_unused]] meta_any *const args) {
-    if constexpr(std::is_invocable_v<std::remove_reference_t<Candidate>>) {
-        if constexpr(std::is_void_v<decltype(std::forward<Candidate>(candidate)())>) {
-            std::forward<Candidate>(candidate)();
-            return meta_any{std::in_place_type<void>};
-        } else {
-            return meta_dispatch<Policy>(std::forward<Candidate>(candidate)());
-        }
-    } else {
-        return internal::meta_invoke<Type, Policy>(std::move(instance), std::forward<Candidate>(candidate), args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
-    }
+    return internal::meta_invoke<Type, Policy>(std::move(instance), std::forward<Candidate>(candidate), args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
 }
 
 /**
@@ -348,7 +342,7 @@ template<typename Type, typename Policy = as_is_t, typename Candidate>
  */
 template<typename Type, auto Candidate, typename Policy = as_is_t>
 [[nodiscard]] meta_any meta_invoke(meta_handle instance, meta_any *const args) {
-    return meta_invoke<Type, Policy>(std::move(instance), Candidate, args);
+    return internal::meta_invoke<Type, Policy>(std::move(instance), Candidate, args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<decltype(Candidate)>>::args_type::size>{});
 }
 
 /**
@@ -365,16 +359,16 @@ template<typename Type, typename... Args>
 
 /**
  * @brief Tries to construct an instance given a list of erased parameters.
- * @tparam Type Reflected type to which the callable object is associated.
+ * @tparam Type Reflected type to which the object to _invoke_ is associated.
  * @tparam Policy Optional policy (no policy set by default).
- * @tparam Candidate The actual callable object to invoke.
- * @param args Parameters to use to invoke the callable object.
- * @param candidate The actual callable object to invoke.
+ * @tparam Candidate The type of the actual object to _invoke_.
+ * @param args Parameters to use to _invoke_ the object.
+ * @param candidate The actual object to _invoke_.
  * @return A meta any containing the returned value, if any.
  */
 template<typename Type, typename Policy = as_is_t, typename Candidate>
 [[nodiscard]] meta_any meta_construct(Candidate &&candidate, meta_any *const args) {
-    return meta_invoke<Type, Policy>({}, std::forward<Candidate>(candidate), args);
+    return internal::meta_invoke<Type, Policy>({}, std::forward<Candidate>(candidate), args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
 }
 
 /**
@@ -387,7 +381,7 @@ template<typename Type, typename Policy = as_is_t, typename Candidate>
  */
 template<typename Type, auto Candidate, typename Policy = as_is_t>
 [[nodiscard]] meta_any meta_construct(meta_any *const args) {
-    return meta_invoke<Type, Policy>({}, Candidate, args);
+    return internal::meta_invoke<Type, Policy>({}, Candidate, args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<decltype(Candidate)>>::args_type::size>{});
 }
 
 } // namespace entt

+ 1 - 0
test/CMakeLists.txt

@@ -214,6 +214,7 @@ SETUP_BASIC_TEST(meta_prop entt/meta/meta_prop.cpp)
 SETUP_BASIC_TEST(meta_range entt/meta/meta_range.cpp)
 SETUP_BASIC_TEST(meta_template entt/meta/meta_template.cpp)
 SETUP_BASIC_TEST(meta_type entt/meta/meta_type.cpp)
+SETUP_BASIC_TEST(meta_utility entt/meta/meta_utility.cpp)
 
 # Test poly
 

+ 211 - 0
test/entt/meta/meta_utility.cpp

@@ -0,0 +1,211 @@
+#include <type_traits>
+#include <gtest/gtest.h>
+#include <entt/meta/resolve.hpp>
+#include <entt/meta/utility.hpp>
+
+struct clazz {
+    void setter(int v) {
+        member = v;
+    }
+
+    int getter() const {
+        return member;
+    }
+
+    static void static_setter(clazz &instance, int v) {
+        instance.member = v;
+    }
+
+    static int static_getter(const clazz &instance) {
+        return instance.member;
+    }
+
+    static void reset_value() {
+        value = 0;
+    }
+
+    static int get_value() {
+        return value;
+    }
+
+    static clazz factory(int v) {
+        clazz instance{};
+        instance.member = v;
+        return instance;
+    }
+
+    int member{};
+    const int cmember{};
+    inline static int value{};
+    inline static const int cvalue{};
+    inline static int arr[3u]{};
+};
+
+struct MetaUtility: ::testing::Test {
+    void SetUp() override {
+        clazz::value = 0;
+    }
+};
+
+TEST_F(MetaUtility, MetaDispatch) {
+    int value = 42;
+
+    auto as_void = entt::meta_dispatch<entt::as_void_t>(value);
+    auto as_ref = entt::meta_dispatch<entt::as_ref_t>(value);
+    auto as_cref = entt::meta_dispatch<entt::as_cref_t>(value);
+    auto as_is = entt::meta_dispatch(value);
+
+    ASSERT_EQ(as_void.type(), entt::resolve<void>());
+    ASSERT_EQ(as_ref.type(), entt::resolve<int>());
+    ASSERT_EQ(as_cref.type(), entt::resolve<int>());
+    ASSERT_EQ(as_is.type(), entt::resolve<int>());
+
+    ASSERT_NE(as_is.try_cast<int>(), nullptr);
+    ASSERT_NE(as_ref.try_cast<int>(), nullptr);
+    ASSERT_EQ(as_cref.try_cast<int>(), nullptr);
+    ASSERT_NE(as_cref.try_cast<const int>(), nullptr);
+
+    ASSERT_EQ(as_is.cast<int>(), 42);
+    ASSERT_EQ(as_ref.cast<int>(), 42);
+    ASSERT_EQ(as_cref.cast<int>(), 42);
+}
+
+TEST_F(MetaUtility, MetaArg) {
+    ASSERT_EQ((entt::meta_arg<entt::type_list<int, char>>(0u)), entt::resolve<int>());
+    ASSERT_EQ((entt::meta_arg<entt::type_list<int, char>>(1u)), entt::resolve<char>());
+}
+
+TEST_F(MetaUtility, MetaSetter) {
+    const int invalid{};
+    clazz instance{};
+
+    ASSERT_FALSE((entt::meta_setter<clazz, &clazz::static_setter>(instance, instance)));
+    ASSERT_FALSE((entt::meta_setter<clazz, &clazz::static_setter>(std::as_const(instance), 42)));
+    ASSERT_FALSE((entt::meta_setter<clazz, &clazz::static_setter>(invalid, 42)));
+    ASSERT_TRUE((entt::meta_setter<clazz, &clazz::static_setter>(instance, 42)));
+    ASSERT_EQ(instance.member, 42);
+
+    ASSERT_FALSE((entt::meta_setter<clazz, &clazz::setter>(instance, instance)));
+    ASSERT_FALSE((entt::meta_setter<clazz, &clazz::setter>(std::as_const(instance), 3)));
+    ASSERT_FALSE((entt::meta_setter<clazz, &clazz::setter>(invalid, 3)));
+    ASSERT_TRUE((entt::meta_setter<clazz, &clazz::setter>(instance, 3)));
+    ASSERT_EQ(instance.member, 3);
+
+    ASSERT_FALSE((entt::meta_setter<clazz, &clazz::member>(instance, instance)));
+    ASSERT_FALSE((entt::meta_setter<clazz, &clazz::member>(invalid, 99)));
+    ASSERT_TRUE((entt::meta_setter<clazz, &clazz::member>(instance, 99)));
+    ASSERT_EQ(instance.member, 99);
+
+    ASSERT_FALSE((entt::meta_setter<clazz, &clazz::cmember>(instance, 99)));
+    ASSERT_FALSE((entt::meta_setter<clazz, &clazz::cmember>(invalid, 99)));
+    ASSERT_EQ(instance.cmember, 0);
+
+    ASSERT_FALSE((entt::meta_setter<clazz, &clazz::value>(instance, instance)));
+    ASSERT_TRUE((entt::meta_setter<clazz, &clazz::value>(invalid, 1)));
+    ASSERT_TRUE((entt::meta_setter<clazz, &clazz::value>(instance, 2)));
+    ASSERT_EQ(clazz::value, 2);
+
+    ASSERT_FALSE((entt::meta_setter<clazz, &clazz::cvalue>(instance, 1)));
+    ASSERT_FALSE((entt::meta_setter<clazz, &clazz::cvalue>(invalid, 1)));
+    ASSERT_EQ(clazz::cvalue, 0);
+}
+
+TEST_F(MetaUtility, MetaGetter) {
+    const int invalid{};
+    clazz instance{};
+
+    ASSERT_FALSE((entt::meta_getter<clazz, &clazz::static_getter>(invalid)));
+    ASSERT_EQ((entt::meta_getter<clazz, &clazz::static_getter>(instance)).cast<int>(), 0);
+
+    ASSERT_FALSE((entt::meta_getter<clazz, &clazz::getter>(invalid)));
+    ASSERT_EQ((entt::meta_getter<clazz, &clazz::getter>(instance)).cast<int>(), 0);
+
+    ASSERT_FALSE((entt::meta_getter<clazz, &clazz::member>(invalid)));
+    ASSERT_EQ((entt::meta_getter<clazz, &clazz::member>(instance)).cast<int>(), 0);
+    ASSERT_EQ((entt::meta_getter<clazz, &clazz::member>(std::as_const(instance))).cast<int>(), 0);
+
+    ASSERT_FALSE((entt::meta_getter<clazz, &clazz::cmember>(invalid)));
+    ASSERT_EQ((entt::meta_getter<clazz, &clazz::cmember>(instance)).cast<int>(), 0);
+    ASSERT_EQ((entt::meta_getter<clazz, &clazz::cmember>(std::as_const(instance))).cast<int>(), 0);
+
+    ASSERT_FALSE((entt::meta_getter<clazz, &clazz::arr>(invalid)));
+    ASSERT_FALSE((entt::meta_getter<clazz, &clazz::arr>(instance)));
+
+    ASSERT_EQ((entt::meta_getter<clazz, &clazz::value>(invalid)).cast<int>(), 0);
+    ASSERT_EQ((entt::meta_getter<clazz, &clazz::value>(instance)).cast<int>(), 0);
+
+    ASSERT_EQ((entt::meta_getter<clazz, &clazz::cvalue>(invalid)).cast<int>(), 0);
+    ASSERT_EQ((entt::meta_getter<clazz, &clazz::cvalue>(instance)).cast<int>(), 0);
+
+    ASSERT_EQ((entt::meta_getter<clazz, 42>(invalid)).cast<int>(), 42);
+    ASSERT_EQ((entt::meta_getter<clazz, 42>(instance)).cast<int>(), 42);
+}
+
+TEST_F(MetaUtility, MetaInvokeWithCandidate) {
+    entt::meta_any args[2u]{clazz{}, 42};
+    args[0u].cast<clazz &>().value = 99;
+
+    ASSERT_FALSE((entt::meta_invoke<clazz>({}, &clazz::setter, nullptr)));
+    ASSERT_FALSE((entt::meta_invoke<clazz>({}, &clazz::getter, nullptr)));
+
+    ASSERT_TRUE((entt::meta_invoke<clazz>(args[0u], &clazz::setter, args + 1u)));
+    ASSERT_FALSE((entt::meta_invoke<clazz>(args[0u], &clazz::setter, args)));
+    ASSERT_EQ((entt::meta_invoke<clazz>(args[0u], &clazz::getter, nullptr)).cast<int>(), 42);
+    ASSERT_FALSE((entt::meta_invoke<clazz>(args[1u], &clazz::getter, nullptr)));
+
+    ASSERT_EQ((entt::meta_invoke<clazz>({}, &clazz::get_value, nullptr)).cast<int>(), 99);
+    ASSERT_TRUE((entt::meta_invoke<clazz>({}, &clazz::reset_value, nullptr)));
+    ASSERT_EQ(args[0u].cast<clazz &>().value, 0);
+}
+
+TEST_F(MetaUtility, MetaInvoke) {
+    entt::meta_any args[2u]{clazz{}, 42};
+    args[0u].cast<clazz &>().value = 99;
+
+    ASSERT_FALSE((entt::meta_invoke<clazz, &clazz::setter>({}, nullptr)));
+    ASSERT_FALSE((entt::meta_invoke<clazz, &clazz::getter>({}, nullptr)));
+
+    ASSERT_TRUE((entt::meta_invoke<clazz, &clazz::setter>(args[0u], args + 1u)));
+    ASSERT_FALSE((entt::meta_invoke<clazz, &clazz::setter>(args[0u], args)));
+    ASSERT_EQ((entt::meta_invoke<clazz, &clazz::getter>(args[0u], nullptr)).cast<int>(), 42);
+    ASSERT_FALSE((entt::meta_invoke<clazz, &clazz::getter>(args[1u], nullptr)));
+
+    ASSERT_EQ((entt::meta_invoke<clazz, &clazz::get_value>({}, nullptr)).cast<int>(), 99);
+    ASSERT_TRUE((entt::meta_invoke<clazz, &clazz::reset_value>({}, nullptr)));
+    ASSERT_EQ(args[0u].cast<clazz &>().value, 0);
+}
+
+TEST_F(MetaUtility, MetaConstructArgsOnly) {
+    entt::meta_any args[2u]{clazz{}, 42};
+    const auto any = entt::meta_construct<clazz, int>(args + 1u);
+
+    ASSERT_TRUE(any);
+    ASSERT_FALSE((entt::meta_construct<clazz, int>(args)));
+    ASSERT_EQ(any.cast<const clazz &>().member, 42);
+}
+
+TEST_F(MetaUtility, MetaConstructWithCandidate) {
+    entt::meta_any args[2u]{clazz{}, 42};
+    const auto any = entt::meta_construct<clazz>(&clazz::factory, args + 1u);
+
+    ASSERT_TRUE(any);
+    ASSERT_FALSE((entt::meta_construct<clazz>(&clazz::factory, args)));
+    ASSERT_EQ(any.cast<const clazz &>().member, 42);
+
+    ASSERT_EQ(args[0u].cast<const clazz &>().member, 0);
+    ASSERT_TRUE((entt::meta_construct<clazz>(&clazz::static_setter, args)));
+    ASSERT_EQ(args[0u].cast<const clazz &>().member, 42);
+}
+
+TEST_F(MetaUtility, MetaConstruct) {
+    entt::meta_any args[2u]{clazz{}, 42};
+    const auto any = entt::meta_construct<clazz, &clazz::factory>(args + 1u);
+
+    ASSERT_TRUE(any);
+    ASSERT_FALSE((entt::meta_construct<clazz, &clazz::factory>(args)));
+    ASSERT_EQ(any.cast<const clazz &>().member, 42);
+
+    ASSERT_EQ(args[0u].cast<const clazz &>().member, 0);
+    ASSERT_TRUE((entt::meta_construct<clazz, &clazz::static_setter>(args)));
+    ASSERT_EQ(args[0u].cast<const clazz &>().member, 42);
+}