Jelajahi Sumber

meta: checked meta_custom object

Michele Caini 1 tahun lalu
induk
melakukan
baf582fce5
5 mengubah file dengan 63 tambahan dan 29 penghapusan
  1. 0 1
      TODO
  2. 41 13
      src/entt/meta/meta.hpp
  3. 7 4
      test/entt/meta/meta_data.cpp
  4. 8 5
      test/entt/meta/meta_func.cpp
  5. 7 6
      test/entt/meta/meta_type.cpp

+ 0 - 1
TODO

@@ -41,5 +41,4 @@ TODO:
 * 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

+ 41 - 13
src/entt/meta/meta.hpp

@@ -826,6 +826,41 @@ private:
     return !(lhs == rhs);
 }
 
+/*! @brief Opaque wrapper for user defined data of any type. */
+struct meta_custom {
+    /*! @brief Default constructor. */
+    meta_custom() noexcept = default;
+
+    /**
+     * @brief Basic constructor for meta objects.
+     * @param curr The underlying node with which to construct the instance.
+     */
+    meta_custom(internal::meta_custom_node curr) noexcept
+        : node{std::move(curr)} {}
+
+    /**
+     * @brief Generic conversion operator.
+     * @tparam Type Type to which conversion is requested.
+     */
+    template<typename Type>
+    [[nodiscard]] operator const Type *() const noexcept {
+        return (type_id<Type>().hash() == node.type) ? std::static_pointer_cast<Type>(node.data).get() : nullptr;
+    }
+
+    /**
+     * @brief Generic conversion operator.
+     * @tparam Type Type to which conversion is requested.
+     */
+    template<typename Type>
+    [[nodiscard]] operator const Type &() const noexcept {
+        ENTT_ASSERT(type_id<Type>().hash() == node.type, "Invalid type");
+        return *std::static_pointer_cast<Type>(node.data);
+    }
+
+private:
+    const internal::meta_custom_node node{};
+};
+
 /*! @brief Opaque wrapper for data members. */
 struct meta_data {
     /*! @brief Unsigned integer type. */
@@ -929,13 +964,10 @@ struct meta_data {
 
     /**
      * @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.data != nullptr, "Invalid user data");
-        return *std::static_pointer_cast<Type>(node->custom.data);
+    [[nodiscard]] meta_custom custom() const noexcept {
+        return {node->custom};
     }
 
     /**
@@ -1067,10 +1099,8 @@ struct meta_func {
     }
 
     /*! @copydoc meta_data::custom */
-    template<typename Type>
-    [[nodiscard]] const Type &custom() const noexcept {
-        ENTT_ASSERT(node->custom.data != nullptr, "Invalid user data");
-        return *std::static_pointer_cast<Type>(node->custom.data);
+    [[nodiscard]] meta_custom custom() const noexcept {
+        return {node->custom};
     }
 
     /**
@@ -1544,10 +1574,8 @@ public:
     }
 
     /*! @copydoc meta_data::custom */
-    template<typename Type>
-    [[nodiscard]] const Type &custom() const noexcept {
-        ENTT_ASSERT(node.custom.data != nullptr, "Invalid user data");
-        return *std::static_pointer_cast<Type>(node.custom.data);
+    [[nodiscard]] meta_custom custom() const noexcept {
+        return {node.custom};
     }
 
     /**

+ 7 - 4
test/entt/meta/meta_data.cpp

@@ -115,7 +115,6 @@ struct MetaData: ::testing::Test {
             .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)
@@ -207,14 +206,18 @@ TEST_F(MetaData, UserTraits) {
 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);
+    ASSERT_EQ(*static_cast<const char *>(entt::resolve<clazz>().data("i"_hs).custom()), 'c');
+    ASSERT_EQ(static_cast<const char &>(entt::resolve<clazz>().data("i"_hs).custom()), 'c');
+
+    ASSERT_EQ(static_cast<const int *>(entt::resolve<clazz>().data("i"_hs).custom()), nullptr);
+    ASSERT_EQ(static_cast<const int *>(entt::resolve<clazz>().data("j"_hs).custom()), nullptr);
 }
 
 ENTT_DEBUG_TEST_F(MetaDataDeathTest, Custom) {
     using namespace entt::literals;
 
-    ASSERT_DEATH([[maybe_unused]] auto &&value = entt::resolve<clazz>().data("k"_hs).custom<int>(), "");
+    ASSERT_DEATH([[maybe_unused]] const int &value = entt::resolve<clazz>().data("i"_hs).custom(), "");
+    ASSERT_DEATH([[maybe_unused]] const char &value = entt::resolve<clazz>().data("j"_hs).custom(), "");
 }
 
 TEST_F(MetaData, Const) {

+ 8 - 5
test/entt/meta/meta_func.cpp

@@ -117,14 +117,13 @@ 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)
+            .custom<char>('c')
             .prop("true"_hs, false)
             .func<function::h>("h"_hs)
             .prop("true"_hs, false)
@@ -222,14 +221,18 @@ TEST_F(MetaFunc, UserTraits) {
 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);
+    ASSERT_EQ(*static_cast<const char *>(entt::resolve<function>().func("g"_hs).custom()), 'c');
+    ASSERT_EQ(static_cast<const char &>(entt::resolve<function>().func("g"_hs).custom()), 'c');
+
+    ASSERT_EQ(static_cast<const int *>(entt::resolve<function>().func("g"_hs).custom()), nullptr);
+    ASSERT_EQ(static_cast<const int *>(entt::resolve<function>().func("h"_hs).custom()), nullptr);
 }
 
 ENTT_DEBUG_TEST_F(MetaFuncDeathTest, Custom) {
     using namespace entt::literals;
 
-    ASSERT_DEATH([[maybe_unused]] auto &&value = entt::resolve<function>().func("f3"_hs).custom<int>(), "");
+    ASSERT_DEATH([[maybe_unused]] const int &value = entt::resolve<function>().func("g"_hs).custom(), "");
+    ASSERT_DEATH([[maybe_unused]] const char &value = entt::resolve<function>().func("h"_hs).custom(), "");
 }
 
 TEST_F(MetaFunc, Const) {

+ 7 - 6
test/entt/meta/meta_type.cpp

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