Explorar o código

meta: as_auto policy

skypjack hai 4 meses
pai
achega
d366a5ed92

+ 1 - 1
TODO

@@ -33,6 +33,6 @@ TODO:
 * resource: shared_from_this?
 * resource: shared_from_this?
 * finish the imgui viewer/editor!
 * finish the imgui viewer/editor!
 * introduce compile-time flag to skip dll-only checks in basic_any
 * introduce compile-time flag to skip dll-only checks in basic_any
-* auto policy for return types in meta (i.e. it picks as_is or as_(c)ref automatically as needed)
 * find a way to test deleter and the absence of it in basic_any
 * find a way to test deleter and the absence of it in basic_any
 * archetype-like a-là EnTT support (see my own notes)
 * archetype-like a-là EnTT support (see my own notes)
+* rename meta policy as_is in as_copy

+ 12 - 0
docs/md/meta.md

@@ -825,6 +825,18 @@ There are a few alternatives available at the moment:
   `as_ref_t` _adapts_ to the constness of the passed object and to that of the
   `as_ref_t` _adapts_ to the constness of the passed object and to that of the
   return type if any.
   return type if any.
 
 
+* The _as-auto_ policy, associated with the type `entt::as_auto_t`.<br/>
+  Useful for decoupling meta type creation code from calling code while still
+  preserving the behavior of data members and member functions as defined:
+
+  ```cpp
+  entt::meta_factory<my_type>{}.func<&my_type::any_member, entt::as_auto_t>("member"_hs);
+  ```
+
+  For data members or member functions that return a reference type, the value
+  is returned by reference with the same constness. In all other cases, the
+  value is returned by copy.
+
 Some uses are rather trivial, but it is useful to note that there are some less
 Some uses are rather trivial, but it is useful to note that there are some less
 obvious corner cases that can in turn be solved with the use of policies.
 obvious corner cases that can in turn be solved with the use of policies.
 
 

+ 29 - 13
src/entt/meta/policy.hpp

@@ -5,8 +5,32 @@
 
 
 namespace entt {
 namespace entt {
 
 
+/*! @cond TURN_OFF_DOXYGEN */
+namespace internal {
+
+struct meta_policy {};
+
+} // namespace internal
+/*! @endcond */
+
+/*! @brief Empty class type used to request the _as-is_ policy. */
+struct as_is_t final: private internal::meta_policy {
+    /*! @cond TURN_OFF_DOXYGEN */
+    template<typename>
+    static constexpr bool value = true;
+    /*! @endcond */
+};
+
+/*! @brief Empty class type used to request the _as void_ policy. */
+struct as_void_t final: private internal::meta_policy {
+    /*! @cond TURN_OFF_DOXYGEN */
+    template<typename>
+    static constexpr bool value = true;
+    /*! @endcond */
+};
+
 /*! @brief Empty class type used to request the _as ref_ policy. */
 /*! @brief Empty class type used to request the _as ref_ policy. */
-struct as_ref_t final {
+struct as_ref_t final: private internal::meta_policy {
     /*! @cond TURN_OFF_DOXYGEN */
     /*! @cond TURN_OFF_DOXYGEN */
     template<typename Type>
     template<typename Type>
     static constexpr bool value = std::is_reference_v<Type> && !std::is_const_v<std::remove_reference_t<Type>>;
     static constexpr bool value = std::is_reference_v<Type> && !std::is_const_v<std::remove_reference_t<Type>>;
@@ -14,23 +38,15 @@ struct as_ref_t final {
 };
 };
 
 
 /*! @brief Empty class type used to request the _as cref_ policy. */
 /*! @brief Empty class type used to request the _as cref_ policy. */
-struct as_cref_t final {
+struct as_cref_t final: private internal::meta_policy {
     /*! @cond TURN_OFF_DOXYGEN */
     /*! @cond TURN_OFF_DOXYGEN */
     template<typename Type>
     template<typename Type>
     static constexpr bool value = std::is_reference_v<Type>;
     static constexpr bool value = std::is_reference_v<Type>;
     /*! @endcond */
     /*! @endcond */
 };
 };
 
 
-/*! @brief Empty class type used to request the _as-is_ policy. */
-struct as_is_t final {
-    /*! @cond TURN_OFF_DOXYGEN */
-    template<typename>
-    static constexpr bool value = true;
-    /*! @endcond */
-};
-
-/*! @brief Empty class type used to request the _as void_ policy. */
-struct as_void_t final {
+/*! @brief Empty class type used to request the _as auto_ policy. */
+struct as_auto_t final: private internal::meta_policy {
     /*! @cond TURN_OFF_DOXYGEN */
     /*! @cond TURN_OFF_DOXYGEN */
     template<typename>
     template<typename>
     static constexpr bool value = true;
     static constexpr bool value = true;
@@ -44,7 +60,7 @@ struct as_void_t final {
  */
  */
 template<typename Type>
 template<typename Type>
 struct is_meta_policy
 struct is_meta_policy
-    : std::bool_constant<std::is_same_v<Type, as_ref_t> || std::is_same_v<Type, as_cref_t> || std::is_same_v<Type, as_is_t> || std::is_same_v<Type, as_void_t>> {};
+    : std::bool_constant<std::is_base_of_v<internal::meta_policy, Type>> {};
 
 
 /**
 /**
  * @brief Helper variable template.
  * @brief Helper variable template.

+ 5 - 5
src/entt/meta/utility.hpp

@@ -166,13 +166,13 @@ using meta_function_helper_t = typename meta_function_helper<Type, Candidate>::t
  */
  */
 template<typename Policy = as_is_t, typename Type>
 template<typename Policy = as_is_t, typename Type>
 [[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_dispatch(const meta_ctx &ctx, [[maybe_unused]] Type &&value) {
 [[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_dispatch(const meta_ctx &ctx, [[maybe_unused]] Type &&value) {
-    if constexpr(std::is_same_v<Policy, as_void_t>) {
-        return meta_any{ctx, std::in_place_type<void>};
-    } else if constexpr(std::is_same_v<Policy, as_ref_t>) {
-        return meta_any{ctx, std::in_place_type<Type>, value};
-    } else if constexpr(std::is_same_v<Policy, as_cref_t>) {
+    if constexpr(std::is_same_v<Policy, as_cref_t>) {
         static_assert(std::is_lvalue_reference_v<Type>, "Invalid type");
         static_assert(std::is_lvalue_reference_v<Type>, "Invalid type");
         return meta_any{ctx, std::in_place_type<const std::remove_reference_t<Type> &>, std::as_const(value)};
         return meta_any{ctx, std::in_place_type<const std::remove_reference_t<Type> &>, std::as_const(value)};
+    } else if constexpr(std::is_same_v<Policy, as_ref_t> || (std::is_same_v<Policy, as_auto_t> && std::is_lvalue_reference_v<Type>)) {
+        return meta_any{ctx, std::in_place_type<Type>, value};
+    } else if constexpr(std::is_same_v<Policy, as_void_t>) {
+        return meta_any{ctx, std::in_place_type<void>};
     } else {
     } else {
         return meta_any{ctx, std::forward<Type>(value)};
         return meta_any{ctx, std::forward<Type>(value)};
     }
     }

+ 45 - 0
test/entt/meta/meta_data.cpp

@@ -97,6 +97,13 @@ struct MetaData: ::testing::Test {
             .data<&clazz::i, entt::as_void_t>("void"_hs)
             .data<&clazz::i, entt::as_void_t>("void"_hs)
             .conv<int>();
             .conv<int>();
 
 
+        entt::meta_factory<clazz>{}
+            .data<&clazz::i, entt::as_auto_t>("ai"_hs)
+            .data<&clazz::j, entt::as_auto_t>("aj"_hs)
+            .data<&clazz::h, entt::as_auto_t>("ah"_hs)
+            .data<&clazz::k, entt::as_auto_t>("ak"_hs)
+            .data<nullptr, &clazz::operator int, entt::as_auto_t>("ao"_hs);
+
         entt::meta_factory<setter_getter>{}
         entt::meta_factory<setter_getter>{}
             .type("setter_getter"_hs)
             .type("setter_getter"_hs)
             .data<&setter_getter::static_setter, &setter_getter::static_getter>("x"_hs)
             .data<&setter_getter::static_setter, &setter_getter::static_getter>("x"_hs)
@@ -541,6 +548,44 @@ TEST_F(MetaData, AsVoid) {
     ASSERT_EQ(data.get(instance), entt::meta_any{std::in_place_type<void>});
     ASSERT_EQ(data.get(instance), entt::meta_any{std::in_place_type<void>});
 }
 }
 
 
+TEST_F(MetaData, AsAuto) {
+    using namespace entt::literals;
+
+    auto type = entt::resolve<clazz>();
+    entt::meta_data data{};
+    clazz instance{};
+
+    data = type.data("ai"_hs);
+
+    ASSERT_TRUE(data);
+    ASSERT_EQ(data.type(), entt::resolve<int>());
+    ASSERT_EQ(data.get(instance).base().policy(), entt::any_policy::ref);
+
+    data = type.data("aj"_hs);
+
+    ASSERT_TRUE(data);
+    ASSERT_EQ(data.type(), entt::resolve<int>());
+    ASSERT_EQ(data.get(instance).base().policy(), entt::any_policy::cref);
+
+    data = type.data("ah"_hs);
+
+    ASSERT_TRUE(data);
+    ASSERT_EQ(data.type(), entt::resolve<int>());
+    ASSERT_EQ(data.get(instance).base().policy(), entt::any_policy::ref);
+
+    data = type.data("ak"_hs);
+
+    ASSERT_TRUE(data);
+    ASSERT_EQ(data.type(), entt::resolve<int>());
+    ASSERT_EQ(data.get(instance).base().policy(), entt::any_policy::cref);
+
+    data = type.data("ao"_hs);
+
+    ASSERT_TRUE(data);
+    ASSERT_EQ(data.type(), entt::resolve<int>());
+    ASSERT_EQ(data.get(instance).base().policy(), entt::any_policy::embedded);
+}
+
 TEST_F(MetaData, AsRef) {
 TEST_F(MetaData, AsRef) {
     using namespace entt::literals;
     using namespace entt::literals;
 
 

+ 39 - 1
test/entt/meta/meta_func.cpp

@@ -74,7 +74,7 @@ struct function {
         instance.value = iv;
         instance.value = iv;
     }
     }
 
 
-    [[nodiscard]] int v(int &iv) const {
+    [[nodiscard]] const int &v(int &iv) const {
         return (iv = value);
         return (iv = value);
     }
     }
 
 
@@ -137,6 +137,12 @@ struct MetaFunc: ::testing::Test {
             .func<&function::a, entt::as_ref_t>("a"_hs)
             .func<&function::a, entt::as_ref_t>("a"_hs)
             .func<&function::a, entt::as_cref_t>("ca"_hs)
             .func<&function::a, entt::as_cref_t>("ca"_hs)
             .conv<int>();
             .conv<int>();
+
+        entt::meta_factory<function>{}
+            .func<&function::a, entt::as_auto_t>("aa"_hs)
+            .func<&function::v, entt::as_auto_t>("av"_hs)
+            .func<&function::operator int, entt::as_auto_t>("ao"_hs)
+            .func<&function::g, entt::as_auto_t>("ag"_hs);
     }
     }
 
 
     void TearDown() override {
     void TearDown() override {
@@ -503,6 +509,38 @@ TEST_F(MetaFunc, AsVoid) {
     ASSERT_EQ(value, instance.value);
     ASSERT_EQ(value, instance.value);
 }
 }
 
 
+TEST_F(MetaFunc, AsAuto) {
+    using namespace entt::literals;
+
+    auto type = entt::resolve<function>();
+    entt::meta_func func{};
+    function instance{3};
+
+    func = type.func("aa"_hs);
+
+    ASSERT_TRUE(func);
+    ASSERT_EQ(func.ret(), entt::resolve<int>());
+    ASSERT_EQ(func.invoke(instance).base().policy(), entt::any_policy::ref);
+
+    func = type.func("av"_hs);
+
+    ASSERT_TRUE(func);
+    ASSERT_EQ(func.ret(), entt::resolve<int>());
+    ASSERT_EQ(func.invoke(instance, 3).base().policy(), entt::any_policy::cref);
+
+    func = type.func("ao"_hs);
+
+    ASSERT_TRUE(func);
+    ASSERT_EQ(func.ret(), entt::resolve<int>());
+    ASSERT_EQ(func.invoke(instance).base().policy(), entt::any_policy::embedded);
+
+    func = type.func("ag"_hs);
+
+    ASSERT_TRUE(func);
+    ASSERT_EQ(func.ret(), entt::resolve<void>());
+    ASSERT_EQ(func.invoke(instance).base().policy(), entt::any_policy::empty);
+}
+
 TEST_F(MetaFunc, AsRef) {
 TEST_F(MetaFunc, AsRef) {
     using namespace entt::literals;
     using namespace entt::literals;
 
 

+ 28 - 8
test/entt/meta/meta_utility.cpp

@@ -59,24 +59,44 @@ using MetaUtilityDeathTest = MetaUtility;
 TEST_F(MetaUtility, MetaDispatch) {
 TEST_F(MetaUtility, MetaDispatch) {
     int value = 2;
     int value = 2;
 
 
-    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_cref = entt::meta_dispatch<entt::as_cref_t>(value);
+    auto as_ref = entt::meta_dispatch<entt::as_ref_t>(value);
+    auto as_void = entt::meta_dispatch<entt::as_void_t>(value);
+    auto as_auto_copy = entt::meta_dispatch<entt::as_auto_t>(static_cast<int &&>(value));
+    auto as_auto_cref = entt::meta_dispatch<entt::as_auto_t>(std::as_const(value));
+    auto as_auto_ref = entt::meta_dispatch<entt::as_auto_t>(value);
     auto as_is = entt::meta_dispatch(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_cref.type(), entt::resolve<int>());
+    ASSERT_EQ(as_ref.type(), entt::resolve<int>());
+    ASSERT_EQ(as_void.type(), entt::resolve<void>());
+    ASSERT_EQ(as_auto_copy.type(), entt::resolve<int>());
+    ASSERT_EQ(as_auto_cref.type(), entt::resolve<int>());
+    ASSERT_EQ(as_auto_ref.type(), entt::resolve<int>());
     ASSERT_EQ(as_is.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.base().policy(), entt::any_policy::cref);
+    ASSERT_EQ(as_ref.base().policy(), entt::any_policy::ref);
+    ASSERT_EQ(as_void.base().policy(), entt::any_policy::empty);
+    ASSERT_EQ(as_auto_copy.base().policy(), entt::any_policy::embedded);
+    ASSERT_EQ(as_auto_cref.base().policy(), entt::any_policy::cref);
+    ASSERT_EQ(as_auto_ref.base().policy(), entt::any_policy::ref);
+    ASSERT_EQ(as_is.base().policy(), entt::any_policy::embedded);
+
     ASSERT_EQ(as_cref.try_cast<int>(), nullptr);
     ASSERT_EQ(as_cref.try_cast<int>(), nullptr);
     ASSERT_NE(as_cref.try_cast<const int>(), nullptr);
     ASSERT_NE(as_cref.try_cast<const int>(), nullptr);
+    ASSERT_NE(as_ref.try_cast<int>(), nullptr);
+    ASSERT_NE(as_auto_copy.try_cast<int>(), nullptr);
+    ASSERT_EQ(as_auto_cref.try_cast<int>(), nullptr);
+    ASSERT_NE(as_auto_ref.try_cast<int>(), nullptr);
+    ASSERT_NE(as_is.try_cast<int>(), nullptr);
 
 
-    ASSERT_EQ(as_is.cast<int>(), 2);
-    ASSERT_EQ(as_ref.cast<int>(), 2);
     ASSERT_EQ(as_cref.cast<int>(), 2);
     ASSERT_EQ(as_cref.cast<int>(), 2);
+    ASSERT_EQ(as_ref.cast<int>(), 2);
+    ASSERT_EQ(as_auto_copy.cast<int>(), 2);
+    ASSERT_EQ(as_auto_cref.cast<int>(), 2);
+    ASSERT_EQ(as_auto_ref.cast<int>(), 2);
+    ASSERT_EQ(as_is.cast<int>(), 2);
 }
 }
 
 
 TEST_F(MetaUtility, MetaDispatchMetaAny) {
 TEST_F(MetaUtility, MetaDispatchMetaAny) {