Michele Caini пре 1 година
родитељ
комит
167ec4b310
3 измењених фајлова са 61 додато и 5 уклоњено
  1. 1 1
      TODO
  2. 4 4
      src/entt/meta/meta.hpp
  3. 56 0
      test/entt/meta/meta_type.cpp

+ 1 - 1
TODO

@@ -42,5 +42,5 @@ TODO:
 * sparse_set shrink_to_fit argument for sparse array shrink policy (none, empty, deep, whatever)
 * sparse_set shrink_to_fit argument for sparse array shrink policy (none, empty, deep, whatever)
 * any cdynamic to support const ownership construction
 * any cdynamic to support const ownership construction
 * track meta context on meta elements
 * track meta context on meta elements
-* safer meta_type (no blind indirections)
 * no context-less meta_any{} from meta objects if possible
 * no context-less meta_any{} from meta objects if possible
+* auto-context in meta objects to avoid checks on contexts

+ 4 - 4
src/entt/meta/meta.hpp

@@ -1152,7 +1152,7 @@ public:
      * @return The type info object of the underlying type.
      * @return The type info object of the underlying type.
      */
      */
     [[nodiscard]] const type_info &info() const noexcept {
     [[nodiscard]] const type_info &info() const noexcept {
-        return *node.info;
+        return node.info ? *node.info : type_id<void>();
     }
     }
 
 
     /**
     /**
@@ -1234,7 +1234,7 @@ public:
      * doesn't refer to a pointer type.
      * doesn't refer to a pointer type.
      */
      */
     [[nodiscard]] meta_type remove_pointer() const noexcept {
     [[nodiscard]] meta_type remove_pointer() const noexcept {
-        return {*ctx, node.remove_pointer(internal::meta_context::from(*ctx))};
+        return (ctx != nullptr) ? meta_type{*ctx, node.remove_pointer(internal::meta_context::from(*ctx))} : *this;
     }
     }
 
 
     /**
     /**
@@ -1303,7 +1303,7 @@ public:
      */
      */
     [[nodiscard]] bool can_cast(const meta_type &other) const noexcept {
     [[nodiscard]] bool can_cast(const meta_type &other) const noexcept {
         // casting this is UB in all cases but we aren't going to use the resulting pointer, so...
         // casting this is UB in all cases but we aren't going to use the resulting pointer, so...
-        return other && (internal::try_cast(internal::meta_context::from(*ctx), node, *other.node.info, this) != nullptr);
+        return (ctx != nullptr) && other && (internal::try_cast(internal::meta_context::from(*ctx), node, *other.node.info, this) != nullptr);
     }
     }
 
 
     /**
     /**
@@ -1312,7 +1312,7 @@ public:
      * @return True if the conversion is allowed, false otherwise.
      * @return True if the conversion is allowed, false otherwise.
      */
      */
     [[nodiscard]] bool can_convert(const meta_type &other) const noexcept {
     [[nodiscard]] bool can_convert(const meta_type &other) const noexcept {
-        return (internal::try_convert(internal::meta_context::from(*ctx), node, other.info(), other.is_arithmetic() || other.is_enum(), nullptr, [](const void *, auto &&...args) { return ((static_cast<void>(args), 1) + ... + 0u); }) != 0u);
+        return (ctx != nullptr) && (internal::try_convert(internal::meta_context::from(*ctx), node, other.info(), other.is_arithmetic() || other.is_enum(), nullptr, [](const void *, auto &&...args) { return ((static_cast<void>(args), 1) + ... + 0u); }) != 0u);
     }
     }
 
 
     /**
     /**

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

@@ -204,6 +204,62 @@ TEST_F(MetaType, Resolve) {
     ASSERT_TRUE(found);
     ASSERT_TRUE(found);
 }
 }
 
 
+TEST_F(MetaType, SafeWhenEmpty) {
+    using namespace entt::literals;
+
+    entt::meta_type type{};
+    entt::meta_any *args = nullptr;
+
+    ASSERT_FALSE(type);
+    ASSERT_EQ(type, entt::meta_type{});
+    ASSERT_EQ(type.info(), entt::type_id<void>());
+    ASSERT_EQ(type.id(), entt::id_type{});
+    ASSERT_EQ(type.size_of(), 0u);
+    ASSERT_FALSE(type.is_arithmetic());
+    ASSERT_FALSE(type.is_integral());
+    ASSERT_FALSE(type.is_signed());
+    ASSERT_FALSE(type.is_array());
+    ASSERT_FALSE(type.is_enum());
+    ASSERT_FALSE(type.is_class());
+    ASSERT_FALSE(type.is_pointer());
+    ASSERT_EQ(type.remove_pointer(), type);
+    ASSERT_FALSE(type.is_pointer_like());
+    ASSERT_FALSE(type.is_sequence_container());
+    ASSERT_FALSE(type.is_associative_container());
+    ASSERT_FALSE(type.is_template_specialization());
+    ASSERT_EQ(type.template_arity(), 0u);
+    ASSERT_EQ(type.template_type(), type);
+    ASSERT_EQ(type.template_arg(0u), type);
+    ASSERT_EQ(type.template_arg(1u), type);
+    ASSERT_FALSE(type.can_cast(type));
+    ASSERT_FALSE(type.can_cast(entt::resolve<void>()));
+    ASSERT_FALSE(type.can_convert(type));
+    ASSERT_FALSE(type.can_convert(entt::resolve<void>()));
+    ASSERT_EQ(type.base().begin(), type.base().end());
+    ASSERT_EQ(type.data().begin(), type.data().end());
+    ASSERT_EQ(type.data("data"_hs), entt::meta_data{});
+    ASSERT_EQ(type.func().begin(), type.func().end());
+    ASSERT_EQ(type.func("func"_hs), entt::meta_func{});
+    ASSERT_FALSE(type.construct(args, 0u));
+    ASSERT_FALSE(type.construct(args, 1u));
+    ASSERT_FALSE(type.construct());
+    ASSERT_FALSE(type.construct(0.0));
+    ASSERT_FALSE(type.from_void(static_cast<void *>(nullptr)));
+    ASSERT_FALSE(type.from_void(static_cast<void *>(nullptr), true));
+    ASSERT_FALSE(type.from_void(static_cast<void *>(&type)));
+    ASSERT_FALSE(type.from_void(static_cast<void *>(&type), true));
+    ASSERT_FALSE(type.from_void(static_cast<const void *>(nullptr)));
+    ASSERT_FALSE(type.from_void(static_cast<const void *>(&type)));
+    ASSERT_FALSE(type.invoke("func"_hs, {}, args, 0u));
+    ASSERT_FALSE(type.invoke("func"_hs, {}, args, 1u));
+    ASSERT_FALSE(type.invoke("func"_hs, {}));
+    ASSERT_FALSE(type.invoke("func"_hs, {}, 'c'));
+    ASSERT_FALSE(type.set("data"_hs, {}, 0));
+    ASSERT_FALSE(type.get("data"_hs, {}));
+    ASSERT_EQ(type.traits<test::meta_traits>(), test::meta_traits::none);
+    ASSERT_EQ(static_cast<const char *>(type.custom()), nullptr);
+}
+
 TEST_F(MetaType, UserTraits) {
 TEST_F(MetaType, UserTraits) {
     ASSERT_EQ(entt::resolve<bool>().traits<test::meta_traits>(), test::meta_traits::none);
     ASSERT_EQ(entt::resolve<bool>().traits<test::meta_traits>(), test::meta_traits::none);
     ASSERT_EQ(entt::resolve<clazz>().traits<test::meta_traits>(), test::meta_traits::none);
     ASSERT_EQ(entt::resolve<clazz>().traits<test::meta_traits>(), test::meta_traits::none);