diff --git a/TODO b/TODO index b539c4519..ac0dd84e6 100644 --- a/TODO +++ b/TODO @@ -32,5 +32,4 @@ TODO: * avoid copying meta_type nodes, and use unique_ptr for meta_custom * paged vector as a standalone class * resource: shared_from_this? -* meta perf: the node in the meta_any is pretty much irrelevant, but it affects perf a lot (also fix natvis after this) * change meta_any::base name, it's confusing due to meta_base_node and base types in meta diff --git a/src/entt/meta/meta.hpp b/src/entt/meta/meta.hpp index db5516aa6..d47b9184b 100644 --- a/src/entt/meta/meta.hpp +++ b/src/entt/meta/meta.hpp @@ -199,11 +199,19 @@ class meta_any { ctx{other.ctx} { if(storage || !other.storage) { resolve = other.resolve; - node = other.node; + lazy_node = other.lazy_node; vtable = other.vtable; } } + const auto &fetch_node() const { + if((lazy_node.info == nullptr) && (resolve != nullptr)) { + lazy_node = resolve(internal::meta_context::from(*ctx)); + } + + return lazy_node; + } + public: /*! Default constructor. */ meta_any() = default; @@ -237,7 +245,6 @@ public: : storage{std::in_place_type, std::forward(args)...}, ctx{&area}, resolve{&internal::resolve>>}, - node{resolve(internal::meta_context::from(*ctx))}, vtable{&basic_vtable>>} {} /** @@ -261,7 +268,6 @@ public: ctx{&area} { if(storage) { resolve = &internal::resolve; - node = resolve(internal::meta_context::from(*ctx)); vtable = &basic_vtable; } } @@ -294,7 +300,7 @@ public: : storage{other.storage}, ctx{&area}, resolve{other.resolve}, - node{((ctx != other.ctx) && (resolve != nullptr)) ? resolve(internal::meta_context::from(*ctx)) : other.node}, + lazy_node{(ctx == other.ctx) ? other.lazy_node : internal::meta_type_node{}}, vtable{other.vtable} {} /** @@ -306,7 +312,7 @@ public: : storage{std::move(other.storage)}, ctx{&area}, resolve{std::exchange(other.resolve, nullptr)}, - node{((ctx != other.ctx) && (resolve != nullptr)) ? resolve(internal::meta_context::from(*ctx)) : std::exchange(other.node, internal::meta_type_node{})}, + lazy_node{(ctx == other.ctx) ? std::exchange(other.lazy_node, internal::meta_type_node{}) : internal::meta_type_node{}}, vtable{std::exchange(other.vtable, nullptr)} {} /** @@ -335,7 +341,7 @@ public: storage = other.storage; ctx = other.ctx; resolve = other.resolve; - node = other.node; + lazy_node = other.lazy_node; vtable = other.vtable; } @@ -356,7 +362,7 @@ public: storage = std::move(other.storage); ctx = other.ctx; resolve = std::exchange(other.resolve, nullptr); - node = std::exchange(other.node, internal::meta_type_node{}); + lazy_node = std::exchange(other.lazy_node, internal::meta_type_node{}); vtable = std::exchange(other.vtable, nullptr); return *this; } @@ -418,7 +424,7 @@ public: template [[nodiscard]] const Type *try_cast() const { const auto *elem = any_cast(&storage); - return (elem != nullptr) ? elem : static_cast(internal::try_cast(internal::meta_context::from(*ctx), node, type_id>().hash(), storage.data())); + return (elem != nullptr) ? elem : static_cast(internal::try_cast(internal::meta_context::from(*ctx), fetch_node(), type_id>().hash(), storage.data())); } /*! @copydoc try_cast */ @@ -429,7 +435,7 @@ public: } else { auto *elem = any_cast(&storage); // NOLINTNEXTLINE(bugprone-casting-through-void) - return (elem != nullptr) ? elem : static_cast(const_cast(internal::try_cast(internal::meta_context::from(*ctx), node, type_id().hash(), storage.data()))); + return (elem != nullptr) ? elem : static_cast(const_cast(internal::try_cast(internal::meta_context::from(*ctx), fetch_node(), type_id().hash(), storage.data()))); } } @@ -513,7 +519,7 @@ public: void emplace(Args &&...args) { storage.emplace(std::forward(args)...); resolve = internal::resolve>>; - node = resolve(internal::meta_context::from(*ctx)); + lazy_node = internal::meta_type_node{}; vtable = &basic_vtable>>; } @@ -527,7 +533,7 @@ public: void reset() { storage.reset(); resolve = nullptr; - node = {}; + lazy_node = {}; vtable = nullptr; } @@ -624,7 +630,7 @@ private: any storage; const meta_ctx *ctx{&locator::value_or()}; internal::meta_type_node (*resolve)(const internal::meta_context &) noexcept {}; - internal::meta_type_node node{}; + mutable internal::meta_type_node lazy_node{}; vtable_type *vtable{}; }; @@ -1539,7 +1545,7 @@ private: } [[nodiscard]] inline meta_type meta_any::type() const noexcept { - return meta_type{*ctx, node}; + return meta_type{*ctx, fetch_node()}; } template @@ -1567,7 +1573,7 @@ bool meta_any::set(const id_type id, Type &&value) { } [[nodiscard]] inline meta_any meta_any::allow_cast(const meta_type &type) const { - return (storage.info() == type.info()) ? as_ref() : internal::try_convert(internal::meta_context::from(*ctx), node, type.info().hash(), type.is_arithmetic() || type.is_enum(), storage.data(), [this, &type]([[maybe_unused]] const void *instance, [[maybe_unused]] auto &&...args) { + return (storage.info() == type.info()) ? as_ref() : internal::try_convert(internal::meta_context::from(*ctx), fetch_node(), type.info().hash(), type.is_arithmetic() || type.is_enum(), storage.data(), [this, &type]([[maybe_unused]] const void *instance, [[maybe_unused]] auto &&...args) { if constexpr((std::is_same_v>, internal::meta_type_node> || ...)) { return (args.from_void(*ctx, nullptr, instance), ...); } else if constexpr((std::is_same_v>, internal::meta_conv_node> || ...)) { @@ -1576,7 +1582,7 @@ bool meta_any::set(const id_type id, Type &&value) { // exploits the fact that arithmetic types and enums are also default constructible auto other = type.construct(); const auto value = (args(nullptr, instance), ...); - other.node.conversion_helper(other.storage.data(), &value); + other.fetch_node().conversion_helper(other.storage.data(), &value); return other; } else { // forwards to force a compile-time error in case of available arguments