From 2f22395eeaf80b7fe33e685d3aef622afdc0f060 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Mon, 6 Sep 2021 10:19:23 +0200 Subject: [PATCH] meta: * a more robust meta_any::allow_cast (reviewed all overloads) * removed internal meta_info dispatcher to reduce useless instantiations * reviewed meta_conversion_helper --- src/entt/meta/factory.hpp | 28 +++++++------- src/entt/meta/meta.hpp | 74 ++++++++++++++++++++---------------- src/entt/meta/node.hpp | 16 +++----- src/entt/meta/resolve.hpp | 2 +- test/entt/meta/meta_any.cpp | 59 ++++++++++++++++++++++++++++ test/entt/meta/meta_base.cpp | 2 +- test/entt/meta/meta_conv.cpp | 2 +- test/entt/meta/meta_ctor.cpp | 2 +- test/entt/meta/meta_data.cpp | 2 +- test/entt/meta/meta_dtor.cpp | 2 +- test/entt/meta/meta_prop.cpp | 2 +- 11 files changed, 127 insertions(+), 64 deletions(-) diff --git a/src/entt/meta/factory.hpp b/src/entt/meta/factory.hpp index b5daa5a49..5c6790660 100644 --- a/src/entt/meta/factory.hpp +++ b/src/entt/meta/factory.hpp @@ -142,7 +142,7 @@ template struct meta_factory { /*! @brief Default constructor. */ meta_factory() - : owner{internal::meta_info::resolve()} + : owner{internal::meta_node::resolve()} {} /** @@ -177,7 +177,7 @@ struct meta_factory { static internal::meta_base_node node{ nullptr, - internal::meta_info::resolve(), + internal::meta_node::resolve(), [](const void *instance) ENTT_NOEXCEPT -> const void * { return static_cast(static_cast(instance)); } @@ -205,11 +205,11 @@ struct meta_factory { */ template std::enable_if_t, meta_factory> conv() ENTT_NOEXCEPT { - using conv_type = std::invoke_result_t; + using conv_type = std::remove_const_t>>; static internal::meta_conv_node node{ nullptr, - internal::meta_info::resolve(), + internal::meta_node::resolve(), [](const void *instance) -> meta_any { return forward_as_meta(static_cast(instance)->*Candidate)(); } @@ -226,11 +226,11 @@ struct meta_factory { /*! @copydoc conv */ template std::enable_if_t, meta_factory> conv() ENTT_NOEXCEPT { - using conv_type = std::invoke_result_t; + using conv_type = std::remove_const_t>>; static internal::meta_conv_node node{ nullptr, - internal::meta_info::resolve(), + internal::meta_node::resolve(), [](const void *instance) -> meta_any { return forward_as_meta(Candidate(*static_cast(instance))); } @@ -259,7 +259,7 @@ struct meta_factory { static internal::meta_conv_node node{ nullptr, - internal::meta_info::resolve(), + internal::meta_node>>::resolve(), [](const void *instance) -> meta_any { return forward_as_meta(static_cast(*static_cast(instance))); } @@ -391,7 +391,7 @@ struct meta_factory { internal::meta_traits::IS_NONE | ((std::is_same_v || std::is_const_v) ? internal::meta_traits::IS_CONST : internal::meta_traits::IS_NONE) | internal::meta_traits::IS_STATIC, - internal::meta_info::resolve(), + internal::meta_node>>::resolve(), &meta_setter, &meta_getter }; @@ -431,16 +431,16 @@ struct meta_factory { */ template auto data(const id_type id) ENTT_NOEXCEPT { - using underlying_type = std::remove_reference_t>; + using data_type = std::remove_reference_t>; static internal::meta_data_node node{ {}, nullptr, nullptr, internal::meta_traits::IS_NONE - | ((std::is_same_v || (std::is_member_object_pointer_v && std::is_const_v)) ? internal::meta_traits::IS_CONST : internal::meta_traits::IS_NONE) + | ((std::is_same_v || (std::is_member_object_pointer_v && std::is_const_v)) ? internal::meta_traits::IS_CONST : internal::meta_traits::IS_NONE) /* this is never static */, - internal::meta_info::resolve(), + internal::meta_node>>::resolve(), &meta_setter, &meta_getter }; @@ -482,7 +482,7 @@ struct meta_factory { internal::meta_traits::IS_NONE | (descriptor::is_const ? internal::meta_traits::IS_CONST : internal::meta_traits::IS_NONE) | (descriptor::is_static ? internal::meta_traits::IS_STATIC : internal::meta_traits::IS_NONE), - internal::meta_info, void, typename descriptor::return_type>>::resolve(), + internal::meta_node, void, std::remove_const_t>>>::resolve(), &meta_arg, &meta_invoke }; @@ -523,7 +523,7 @@ private: */ template [[nodiscard]] auto meta() ENTT_NOEXCEPT { - auto * const node = internal::meta_info::resolve(); + auto * const node = internal::meta_node::resolve(); // extended meta factory to allow assigning properties to opaque meta types return meta_factory{&node->prop}; } @@ -577,7 +577,7 @@ inline void meta_reset(const id_type id) ENTT_NOEXCEPT { */ template void meta_reset() ENTT_NOEXCEPT { - meta_reset(internal::meta_info::resolve()->id); + meta_reset(internal::meta_node::resolve()->id); } diff --git a/src/entt/meta/meta.hpp b/src/entt/meta/meta.hpp index 0b081eca3..351938f1b 100644 --- a/src/entt/meta/meta.hpp +++ b/src/entt/meta/meta.hpp @@ -47,7 +47,7 @@ public: */ template meta_sequence_container(std::in_place_type_t, any instance) ENTT_NOEXCEPT - : value_type_node{internal::meta_info::resolve()}, + : value_type_node{internal::meta_node>>::resolve()}, size_fn{&meta_sequence_container_traits::size}, resize_fn{&meta_sequence_container_traits::resize}, clear_fn{&meta_sequence_container_traits::clear}, @@ -105,9 +105,9 @@ public: template meta_associative_container(std::in_place_type_t, any instance) ENTT_NOEXCEPT : key_only_container{meta_associative_container_traits::key_only()}, - key_type_node{internal::meta_info::resolve()}, + key_type_node{internal::meta_node>>::resolve()}, mapped_type_node{nullptr}, - value_type_node{internal::meta_info::resolve()}, + value_type_node{internal::meta_node>>::resolve()}, size_fn{&meta_associative_container_traits::size}, clear_fn{&meta_associative_container_traits::clear}, begin_fn{&meta_associative_container_traits::begin}, @@ -118,7 +118,7 @@ public: storage{std::move(instance)} { if constexpr(!meta_associative_container_traits::key_only()) { - mapped_type_node = internal::meta_info::resolve(); + mapped_type_node = internal::meta_node>>::resolve(); } } @@ -218,7 +218,7 @@ public: template explicit meta_any(std::in_place_type_t, Args &&... args) : storage{std::in_place_type, std::forward(args)...}, - node{internal::meta_info::resolve()}, + node{internal::meta_node>>::resolve()}, vtable{&basic_vtable>>} {} @@ -230,8 +230,8 @@ public: template, meta_any>>> meta_any(Type &&value) : storage{std::forward(value)}, - node{internal::meta_info>::resolve()}, - vtable{&basic_vtable>} + node{internal::meta_node>>::resolve()}, + vtable{&basic_vtable>>} {} /** @@ -361,9 +361,7 @@ public: */ template [[nodiscard]] const Type * try_cast() const { - if(!node) { return nullptr; } - - if(const auto info = type_id(); node->info == info) { + if(const auto info = type_id(); node && node->info == info) { return any_cast(&storage); } else if(const auto *base = internal::visit<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type->info == info; }, node); base) { return static_cast(base->cast(storage.data())); @@ -375,19 +373,13 @@ public: /*! @copydoc try_cast */ template [[nodiscard]] Type * try_cast() { - if constexpr(std::is_const_v) { - return std::as_const(*this).try_cast(); - } else { - if(!node) { return nullptr; } - - if(const auto info = type_id(); node->info == info) { - return any_cast(&storage); - } else if(const auto *base = internal::visit<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type->info == info; }, node); base) { - return const_cast(static_cast(base->cast(storage.data()))); - } - - return nullptr; + if(const auto info = type_id(); node && node->info == info) { + return any_cast(&storage); + } else if(const auto *base = internal::visit<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type->info == info; }, node); base) { + return static_cast(const_cast *>(base->cast(static_cast &>(storage).data()))); } + + return nullptr; } /** @@ -440,7 +432,13 @@ public: */ template [[nodiscard]] meta_any allow_cast() const { - return allow_cast(internal::meta_info::resolve()); + const auto other = allow_cast(internal::meta_node>>::resolve()); + + if constexpr(std::is_reference_v && !std::is_const_v>) { + return other.storage.owner() ? other : meta_any{}; + } else { + return other; + } } /** @@ -450,7 +448,20 @@ public: */ template bool allow_cast() { - return allow_cast(internal::meta_info::resolve()); + if constexpr(std::is_reference_v && !std::is_const_v>) { + if(auto other = std::as_const(*this).allow_cast(internal::meta_node>>::resolve()); other) { + if(other.storage.owner()) { + std::swap(*this, other); + return true; + } + + return (storage.data() != nullptr); + } + + return false; + } else { + return allow_cast(internal::meta_node>>::resolve()); + } } /** @@ -464,7 +475,7 @@ public: release(); vtable = &basic_vtable>>; storage.emplace(std::forward(args)...); - node = internal::meta_info::resolve(); + node = internal::meta_node>>::resolve(); } /*! @brief Destroys contained object */ @@ -1045,7 +1056,7 @@ class meta_type { template [[nodiscard]] static const internal::meta_ctor_node * ctor(const internal::meta_ctor_node *curr, std::index_sequence) { for(; curr; curr = curr->next) { - if(curr->arity == sizeof...(Args) && (can_cast_or_convert(internal::meta_info::resolve(), curr->arg(Index)) && ...)) { + if(curr->arity == sizeof...(Args) && (can_cast_or_convert(internal::meta_node>>::resolve(), curr->arg(Index)) && ...)) { return curr; } } @@ -1501,18 +1512,15 @@ bool meta_any::set(const id_type id, Type &&value) { [[nodiscard]] inline meta_any meta_any::allow_cast(const meta_type &type) const { - if(!node) { return {}; } - - if(const auto info = type.info(); node->info == info || internal::visit<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type->info == info; }, node)) { + if(const auto info = type.info(); (node && node->info == info) || internal::visit<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type->info == info; }, node)) { return as_ref(); } else if(const auto * const conv = internal::visit<&internal::meta_type_node::conv>([info](const auto *curr) { return curr->type->info == info; }, node); conv) { return conv->conv(storage.data()); - } else if((type.is_arithmetic() || type.is_enum()) && node->conversion_helper) { + } else if(node && node->conversion_helper && (type.is_arithmetic() || type.is_enum())) { // exploits the fact that arithmetic types and enums are also default constructible auto other = type.construct(); - const double value = node->conversion_helper(storage, nullptr); ENTT_ASSERT(other.node->conversion_helper, "Conversion helper not found"); - other.node->conversion_helper(other.storage, &value); + other.node->conversion_helper(other.storage, node->conversion_helper(storage, {})); return other; } @@ -1523,7 +1531,7 @@ bool meta_any::set(const id_type id, Type &&value) { inline bool meta_any::allow_cast(const meta_type &type) { if(auto other = std::as_const(*this).allow_cast(type); other) { if(other.storage.owner()) { - *this = std::move(other); + std::swap(*this, other); } return true; diff --git a/src/entt/meta/node.hpp b/src/entt/meta/node.hpp index b2dc4f8bc..c65bd0f4e 100644 --- a/src/entt/meta/node.hpp +++ b/src/entt/meta/node.hpp @@ -122,7 +122,7 @@ struct meta_type_node { const size_type size_of; const meta_traits traits; meta_any(* const default_constructor)(); - double(* const conversion_helper)(const any &, const double *); + double(* const conversion_helper)(const any &, const any &); const meta_template_node *const templ; meta_ctor_node *ctor{nullptr}; meta_base_node *base{nullptr}; @@ -151,12 +151,12 @@ class ENTT_API meta_node { [[nodiscard]] static decltype(meta_type_node::conversion_helper) meta_conversion_helper() ENTT_NOEXCEPT { if constexpr(std::is_arithmetic_v) { - return +[](const any &storage, const double *value) { - return value ? static_cast(any_cast(const_cast(storage)) = static_cast(*value)) : static_cast(any_cast(storage)); + return +[](const any &storage, const any &value) { + return value ? static_cast(any_cast(const_cast(storage)) = static_cast(any_cast(value))) : static_cast(any_cast(storage)); }; } else if constexpr(std::is_enum_v) { - return +[](const any &storage, const double *value) { - return value ? static_cast(any_cast(const_cast(storage)) = Type{static_cast>(*value)}) : static_cast(any_cast(storage)); + return +[](const any &storage, const any &value) { + return value ? static_cast(any_cast(const_cast(storage)) = Type{static_cast>(any_cast(value))}) : static_cast(any_cast(storage)); }; } else { return nullptr; @@ -206,13 +206,9 @@ public: }; -template -struct meta_info: meta_node>> {}; - - template [[nodiscard]] meta_type_node * meta_arg_node(type_list, const std::size_t index) ENTT_NOEXCEPT { - meta_type_node *args[sizeof...(Args) + 1u]{nullptr, internal::meta_info::resolve()...}; + meta_type_node *args[sizeof...(Args) + 1u]{nullptr, internal::meta_node>>::resolve()...}; return args[index + 1u]; } diff --git a/src/entt/meta/resolve.hpp b/src/entt/meta/resolve.hpp index ca1fbfab4..0883c9aae 100644 --- a/src/entt/meta/resolve.hpp +++ b/src/entt/meta/resolve.hpp @@ -20,7 +20,7 @@ namespace entt { */ template [[nodiscard]] meta_type resolve() ENTT_NOEXCEPT { - return internal::meta_info::resolve(); + return internal::meta_node>>::resolve(); } diff --git a/test/entt/meta/meta_any.cpp b/test/entt/meta/meta_any.cpp index 473ba0c75..52e57e95c 100644 --- a/test/entt/meta/meta_any.cpp +++ b/test/entt/meta/meta_any.cpp @@ -804,6 +804,7 @@ TEST_F(MetaAny, TryCast) { ASSERT_EQ(any.try_cast(), any.data()); ASSERT_EQ(std::as_const(any).try_cast(), any.try_cast()); ASSERT_EQ(std::as_const(any).try_cast(), any.data()); + ASSERT_EQ(std::as_const(any).try_cast(), nullptr); } TEST_F(MetaAny, Cast) { @@ -823,6 +824,64 @@ TEST_F(MetaAny, Cast) { ASSERT_EQ(any.cast().value[0u], 3.); } +TEST_F(MetaAny, AllowCast) { + entt::meta_any clazz{clazz_t{}}; + entt::meta_any fat{fat_t{}}; + entt::meta_any arithmetic{42}; + auto as_cref = entt::forward_as_meta(arithmetic.cast()); + + ASSERT_TRUE(clazz); + ASSERT_TRUE(fat); + ASSERT_TRUE(arithmetic); + ASSERT_TRUE(as_cref); + + ASSERT_TRUE(clazz.allow_cast()); + ASSERT_TRUE(clazz.allow_cast()); + ASSERT_TRUE(clazz.allow_cast()); + ASSERT_EQ(clazz.type(), entt::resolve()); + + ASSERT_TRUE(clazz.allow_cast()); + ASSERT_EQ(clazz.type(), entt::resolve()); + ASSERT_TRUE(clazz.allow_cast()); + ASSERT_TRUE(clazz.allow_cast()); + ASSERT_TRUE(clazz.allow_cast()); + + ASSERT_TRUE(fat.allow_cast()); + ASSERT_TRUE(fat.allow_cast()); + ASSERT_TRUE(fat.allow_cast()); + ASSERT_EQ(fat.type(), entt::resolve()); + ASSERT_FALSE(fat.allow_cast()); + + ASSERT_TRUE(std::as_const(fat).allow_cast()); + ASSERT_FALSE(std::as_const(fat).allow_cast()); + ASSERT_TRUE(std::as_const(fat).allow_cast()); + ASSERT_EQ(fat.type(), entt::resolve()); + ASSERT_FALSE(fat.allow_cast()); + + ASSERT_TRUE(arithmetic.allow_cast()); + ASSERT_TRUE(arithmetic.allow_cast()); + ASSERT_TRUE(arithmetic.allow_cast()); + ASSERT_EQ(arithmetic.type(), entt::resolve()); + ASSERT_FALSE(arithmetic.allow_cast()); + + ASSERT_TRUE(arithmetic.allow_cast()); + ASSERT_EQ(arithmetic.type(), entt::resolve()); + ASSERT_EQ(arithmetic.cast(), 42.); + + ASSERT_TRUE(arithmetic.allow_cast()); + ASSERT_EQ(arithmetic.type(), entt::resolve()); + ASSERT_EQ(arithmetic.cast(), 42.f); + + ASSERT_TRUE(as_cref.allow_cast()); + ASSERT_FALSE(as_cref.allow_cast()); + ASSERT_TRUE(as_cref.allow_cast()); + ASSERT_EQ(as_cref.type(), entt::resolve()); + ASSERT_FALSE(as_cref.allow_cast()); + + ASSERT_TRUE(as_cref.allow_cast()); + ASSERT_EQ(as_cref.type(), entt::resolve()); +} + TEST_F(MetaAny, Convert) { entt::meta_any any{clazz_t{}}; any.cast().value = 42; diff --git a/test/entt/meta/meta_base.cpp b/test/entt/meta/meta_base.cpp index acadd0750..2e54ad106 100644 --- a/test/entt/meta/meta_base.cpp +++ b/test/entt/meta/meta_base.cpp @@ -48,7 +48,7 @@ TEST_F(MetaBase, Functionalities) { TEST_F(MetaBase, ReRegistration) { SetUp(); - auto *node = entt::internal::meta_info::resolve(); + auto *node = entt::internal::meta_node::resolve(); ASSERT_NE(node->base, nullptr); ASSERT_EQ(node->base->next, nullptr); diff --git a/test/entt/meta/meta_conv.cpp b/test/entt/meta/meta_conv.cpp index 672aa8c73..d03365bc9 100644 --- a/test/entt/meta/meta_conv.cpp +++ b/test/entt/meta/meta_conv.cpp @@ -49,7 +49,7 @@ TEST_F(MetaConv, Functionalities) { TEST_F(MetaConv, ReRegistration) { SetUp(); - auto *node = entt::internal::meta_info::resolve(); + auto *node = entt::internal::meta_node::resolve(); ASSERT_NE(node->conv, nullptr); ASSERT_NE(node->conv->next, nullptr); diff --git a/test/entt/meta/meta_ctor.cpp b/test/entt/meta/meta_ctor.cpp index 62530f50e..651d38e88 100644 --- a/test/entt/meta/meta_ctor.cpp +++ b/test/entt/meta/meta_ctor.cpp @@ -281,7 +281,7 @@ TEST_F(MetaCtor, NonDefaultConstructibleType) { TEST_F(MetaCtor, ReRegistration) { SetUp(); - auto *node = entt::internal::meta_info::resolve(); + auto *node = entt::internal::meta_node::resolve(); ASSERT_NE(node->ctor, nullptr); // implicitly generated default constructor is not cleared diff --git a/test/entt/meta/meta_data.cpp b/test/entt/meta/meta_data.cpp index 0c0223d09..b4c0863e4 100644 --- a/test/entt/meta/meta_data.cpp +++ b/test/entt/meta/meta_data.cpp @@ -543,7 +543,7 @@ TEST_F(MetaData, ReRegistration) { SetUp(); - auto *node = entt::internal::meta_info::resolve(); + auto *node = entt::internal::meta_node::resolve(); auto type = entt::resolve(); ASSERT_NE(node->data, nullptr); diff --git a/test/entt/meta/meta_dtor.cpp b/test/entt/meta/meta_dtor.cpp index 8a8a962f1..f798fe91d 100644 --- a/test/entt/meta/meta_dtor.cpp +++ b/test/entt/meta/meta_dtor.cpp @@ -100,7 +100,7 @@ TEST_F(MetaDtor, AsRefConstruction) { TEST_F(MetaDtor, ReRegistration) { SetUp(); - auto *node = entt::internal::meta_info::resolve(); + auto *node = entt::internal::meta_node::resolve(); ASSERT_NE(node->dtor, nullptr); diff --git a/test/entt/meta/meta_prop.cpp b/test/entt/meta/meta_prop.cpp index 57a96e7e0..6e5b2af5f 100644 --- a/test/entt/meta/meta_prop.cpp +++ b/test/entt/meta/meta_prop.cpp @@ -72,7 +72,7 @@ TEST_F(MetaProp, ReRegistration) { SetUp(); - auto *node = entt::internal::meta_info::resolve(); + auto *node = entt::internal::meta_node::resolve(); auto type = entt::resolve(); ASSERT_NE(node->prop, nullptr);