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

meta: support to user defined arbitrary data

Michele Caini 1 год назад
Родитель
Сommit
24808b11bb

+ 3 - 1
TODO

@@ -36,9 +36,11 @@ TODO:
 * improve front (no multiple checks) and back (ie no contains) for multi-type view
 * cleanup common view from tricks to handle single swap-only and in-place, if constexpr branches
 * exploit ref/cref in any to avoid invoking the vtable if possible
-* review meta properties and details: maybe a dense map is too much, investigate using any rather than shared<void> for meta properties
 * entity based component_traits
 * copy-and-swap for any and meta_any
 * improve seek function for overloaded meta functions
 * fix cmake warning about FetchContent_Populate
+* deprecate meta properties in favor of custom data
+* refine custom with debug-only type check if possible
+* make meta objects safe to use with null nodes
 

+ 23 - 0
src/entt/meta/factory.hpp

@@ -114,6 +114,16 @@ protected:
         }
     }
 
+    void custom(std::shared_ptr<void> udata) {
+        if(bucket == parent) {
+            internal::meta_context::from(*ctx).value[parent].custom = std::move(udata);
+        } else if(is_data) {
+            details->data[bucket].custom = std::move(udata);
+        } else {
+            details->func[bucket].custom = std::move(udata);
+        }
+    }
+
 public:
     basic_meta_factory(const type_info &info, meta_ctx &area)
         : ctx{&area},
@@ -524,6 +534,19 @@ public:
         base_type::traits(internal::user_to_meta_traits(value));
         return *this;
     }
+
+    /**
+     * @brief Sets user defined data that will never be used by the library.
+     * @tparam Value Type of user defined data to store.
+     * @tparam Args Types of arguments to use to construct the user data.
+     * @param args Parameters to use to initialize the user data.
+     * @return A meta factory for the parent type.
+     */
+    template<typename Value, typename... Args>
+    meta_factory custom(Args &&...args) {
+        base_type::custom(std::make_shared<Value>(std::forward<Args>(args)...));
+        return *this;
+    }
 };
 
 /**

+ 25 - 0
src/entt/meta/meta.hpp

@@ -927,6 +927,17 @@ struct meta_data {
         return internal::meta_to_user_traits<Type>(node->traits);
     }
 
+    /**
+     * @brief Returns user defined data for a given meta object.
+     * @tparam Type The type to convert the user defined data to.
+     * @return User defined arbitrary data.
+     */
+    template<typename Type>
+    [[nodiscard]] const Type &custom() const noexcept {
+        ENTT_ASSERT(node->custom != nullptr, "Invalid user data");
+        return *std::static_pointer_cast<Type>(node->custom);
+    }
+
     /**
      * @brief Returns true if an object is valid, false otherwise.
      * @return True if the object is valid, false otherwise.
@@ -1055,6 +1066,13 @@ struct meta_func {
         return internal::meta_to_user_traits<Type>(node->traits);
     }
 
+    /*! @copydoc meta_data::custom */
+    template<typename Type>
+    [[nodiscard]] const Type &custom() const noexcept {
+        ENTT_ASSERT(node->custom != nullptr, "Invalid user data");
+        return *std::static_pointer_cast<Type>(node->custom);
+    }
+
     /**
      * @brief Returns the next overload of a given function, if any.
      * @return The next overload of the given function, if any.
@@ -1525,6 +1543,13 @@ public:
         return internal::meta_to_user_traits<Type>(node.traits);
     }
 
+    /*! @copydoc meta_data::custom */
+    template<typename Type>
+    [[nodiscard]] const Type &custom() const noexcept {
+        ENTT_ASSERT(node.custom != nullptr, "Invalid user data");
+        return *std::static_pointer_cast<Type>(node.custom);
+    }
+
     /**
      * @brief Returns true if an object is valid, false otherwise.
      * @return True if the object is valid, false otherwise.

+ 3 - 0
src/entt/meta/node.hpp

@@ -96,6 +96,7 @@ struct meta_data_node {
     bool (*set)(meta_handle, meta_any){};
     meta_any (*get)(const meta_ctx &, meta_handle){};
     dense_map<id_type, meta_prop_node, identity> prop{};
+    std::shared_ptr<void> custom{};
 };
 
 struct meta_func_node {
@@ -108,6 +109,7 @@ struct meta_func_node {
     meta_any (*invoke)(const meta_ctx &, meta_handle, meta_any *const){};
     std::shared_ptr<meta_func_node> next{};
     dense_map<id_type, meta_prop_node, identity> prop{};
+    std::shared_ptr<void> custom{};
 };
 
 struct meta_template_node {
@@ -142,6 +144,7 @@ struct meta_type_node {
     meta_template_node templ{};
     meta_dtor_node dtor{};
     std::shared_ptr<meta_type_descriptor> details{};
+    std::shared_ptr<void> custom{};
 };
 
 template<auto Member>

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

@@ -110,10 +110,12 @@ struct MetaData: ::testing::Test {
         entt::meta<clazz>()
             .type("clazz"_hs)
             .data<&clazz::i, entt::as_ref_t>("i"_hs)
+            .custom<char>('c')
             .traits(test::meta_traits::one | test::meta_traits::two | test::meta_traits::three)
             .prop(3u, 0)
             .data<&clazz::i, entt::as_cref_t>("ci"_hs)
             .data<&clazz::j>("j"_hs)
+            .custom<int>(3)
             .traits(test::meta_traits::one)
             .prop("true"_hs, 1)
             .data<&clazz::h>("h"_hs)
@@ -202,6 +204,19 @@ TEST_F(MetaData, UserTraits) {
     ASSERT_EQ(entt::resolve<clazz>().data("k"_hs).traits<test::meta_traits>(), test::meta_traits::three);
 }
 
+TEST_F(MetaData, Custom) {
+    using namespace entt::literals;
+
+    ASSERT_EQ(entt::resolve<clazz>().data("i"_hs).custom<char>(), 'c');
+    ASSERT_EQ(entt::resolve("clazz"_hs).data("j"_hs).custom<int>(), 3);
+}
+
+ENTT_DEBUG_TEST_F(MetaDataDeathTest, Custom) {
+    using namespace entt::literals;
+
+    ASSERT_DEATH([[maybe_unused]] auto &&value = entt::resolve<clazz>().data("k"_hs).custom<int>(), "");
+}
+
 TEST_F(MetaData, Const) {
     using namespace entt::literals;
 

+ 15 - 0
test/entt/meta/meta_func.cpp

@@ -117,9 +117,11 @@ struct MetaFunc: ::testing::Test {
             .func<entt::overload<int(const base &, int, int)>(&function::f)>("f3"_hs)
             .traits(test::meta_traits::three)
             .func<entt::overload<int(int, int)>(&function::f)>("f2"_hs)
+            .custom<int>(3)
             .traits(test::meta_traits::two)
             .prop("true"_hs, false)
             .func<entt::overload<int(int) const>(&function::f)>("f1"_hs)
+            .custom<char>('c')
             .traits(test::meta_traits::one)
             .prop("true"_hs, false)
             .func<&function::g>("g"_hs)
@@ -217,6 +219,19 @@ TEST_F(MetaFunc, UserTraits) {
     ASSERT_EQ(entt::resolve<function>().func("f3"_hs).traits<test::meta_traits>(), test::meta_traits::three);
 }
 
+TEST_F(MetaFunc, Custom) {
+    using namespace entt::literals;
+
+    ASSERT_EQ(entt::resolve<function>().func("f1"_hs).custom<char>(), 'c');
+    ASSERT_EQ(entt::resolve("func"_hs).func("f2"_hs).custom<int>(), 3);
+}
+
+ENTT_DEBUG_TEST_F(MetaFuncDeathTest, Custom) {
+    using namespace entt::literals;
+
+    ASSERT_DEATH([[maybe_unused]] auto &&value = entt::resolve<function>().func("f3"_hs).custom<int>(), "");
+}
+
 TEST_F(MetaFunc, Const) {
     using namespace entt::literals;
 

+ 13 - 0
test/entt/meta/meta_type.cpp

@@ -128,6 +128,7 @@ struct MetaType: ::testing::Test {
 
         entt::meta<base>()
             .type("base"_hs)
+            .custom<char>('c')
             .data<&base::value>("value"_hs);
 
         entt::meta<derived>()
@@ -176,6 +177,7 @@ struct MetaType: ::testing::Test {
 
         entt::meta<clazz>()
             .type("class"_hs)
+            .custom<int>(3)
             .prop(static_cast<entt::id_type>(property_type::value), 3)
             .ctor<const base &, int>()
             .data<&clazz::value>("value"_hs)
@@ -298,6 +300,17 @@ TEST_F(MetaType, UserTraits) {
     ASSERT_EQ(entt::resolve<property_type>().traits<test::meta_traits>(), test::meta_traits::two | test::meta_traits::three);
 }
 
+TEST_F(MetaType, Custom) {
+    using namespace entt::literals;
+
+    ASSERT_EQ(entt::resolve<base>().custom<char>(), 'c');
+    ASSERT_EQ(entt::resolve("class"_hs).custom<int>(), 3);
+}
+
+ENTT_DEBUG_TEST_F(MetaTypeDeathTest, Custom) {
+    ASSERT_DEATH([[maybe_unused]] auto &&value = entt::resolve<derived>().custom<int>(), "");
+}
+
 TEST_F(MetaType, RemovePointer) {
     ASSERT_EQ(entt::resolve<void *>().remove_pointer(), entt::resolve<void>());
     ASSERT_EQ(entt::resolve<char **>().remove_pointer(), entt::resolve<char *>());