From d9494960a218ffb4126db766ef021790a60d8b92 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Wed, 11 Aug 2021 17:11:09 +0200 Subject: [PATCH] meta: * removed the possibility of invoking meta_factory::prop multiple times * further reduced instantiations due to meta properties --- TODO | 1 + docs/md/meta.md | 28 +++-------- src/entt/meta/factory.hpp | 94 +++++++++++++++++------------------- test/entt/meta/meta_prop.cpp | 3 +- test/entt/meta/meta_type.cpp | 12 ++--- 5 files changed, 59 insertions(+), 79 deletions(-) diff --git a/TODO b/TODO index c344288b5..2eb49a4b9 100644 --- a/TODO +++ b/TODO @@ -6,6 +6,7 @@ WIP: * runtime components (registry), runtime events (dispatcher/emitter), ... +* single prop call with operator() for meta factories (to cut down instantiations) * add constrained type policy to iterable view * add constrained type policy to view iterators * custom allocators all over diff --git a/docs/md/meta.md b/docs/md/meta.md index 2af121242..c54121f7f 100644 --- a/docs/md/meta.md +++ b/docs/md/meta.md @@ -897,29 +897,15 @@ Multiple formats are supported when it comes to defining a property: An annotation is an invocable object that returns one or more properties. All of them are treated individually. -It's possible to invoke the `prop` function several times if needed, one for -each property to associate with the last meta object created: - -```cpp -entt::meta() - .type("reflected_type"_hs) - .prop(entt::hashed_string{"Name"}, "Reflected Type") - .data<&my_type::data_member>("member"_hs) - .prop(std::make_pair("tooltip"_hs, "Member")) - .prop(my_enum::a_value, 42); -``` - -Alternatively, the `props` function is available to associate several properties -at a time. However, in this case properties in the key/value form aren't -allowed, since they would be interpreted as two different properties rather than -a single one. +Note that it's not possible to invoke `prop` multiple times for the same meta +object and trying to do that will result in a compilation error.
+However, the `props` function is available to associate several properties at +once. In this case, properties in the key/value form aren't allowed, since they +would be interpreted as two different properties rather than a single one. The meta objects for which properties are supported are currently the meta -types, meta constructors, meta data and meta functions. It's not possible to -attach properties to other types of meta objects and the factory returned as a -result of their construction won't allow such an operation. - -These types offer a couple of member functions named `prop` to iterate all +types, meta constructors, meta data and meta functions.
+These types also offer a couple of member functions named `prop` to iterate all properties at once or to search a specific property by key: ```cpp diff --git a/src/entt/meta/factory.hpp b/src/entt/meta/factory.hpp index c16ccae06..e6a4e9a35 100644 --- a/src/entt/meta/factory.hpp +++ b/src/entt/meta/factory.hpp @@ -114,14 +114,14 @@ public: * @return A meta factory for the parent type. */ template - auto prop(PropertyOrKey &&property_or_key, Value &&... value) && { + meta_factory prop(PropertyOrKey &&property_or_key, Value &&... value) && { if constexpr(sizeof...(Value) == 0) { unroll(choice<3>, std::forward(property_or_key)); } else { assign(std::forward(property_or_key), std::forward(value)...); } - return meta_factory{ref}; + return {}; } /** @@ -135,9 +135,9 @@ public: * @return A meta factory for the parent type. */ template - auto props(Property... property) && { + meta_factory props(Property... property) && { unroll(choice<3>, std::forward(property)...); - return meta_factory{ref}; + return {}; } private: @@ -151,24 +151,27 @@ private: */ template struct meta_factory { + /*! @brief Default constructor. */ + meta_factory() + : owner{internal::meta_info::resolve()} + {} + /** * @brief Makes a meta type _searchable_. * @param id Optional unique identifier. * @return An extended meta factory for the given type. */ auto type(const id_type id = type_hash::value()) { - auto * const node = internal::meta_info::resolve(); - meta_range range{*internal::meta_context::global()}; - ENTT_ASSERT(std::find_if(range.cbegin(), range.cend(), [id, node](const auto *curr) { return curr != node && curr->id == id; }) == range.cend(), "Duplicate identifier"); - node->id = id; + ENTT_ASSERT(std::find_if(range.cbegin(), range.cend(), [id, this](const auto *curr) { return curr != owner && curr->id == id; }) == range.cend(), "Duplicate identifier"); + owner->id = id; - if(std::find(range.cbegin(), range.cend(), node) == range.cend()) { - node->next = *internal::meta_context::global(); - *internal::meta_context::global() = node; + if(std::find(range.cbegin(), range.cend(), owner) == range.cend()) { + owner->next = *internal::meta_context::global(); + *internal::meta_context::global() = owner; } - return meta_factory{&node->prop}; + return meta_factory{&owner->prop}; } /** @@ -182,7 +185,6 @@ struct meta_factory { template auto base() ENTT_NOEXCEPT { static_assert(std::is_base_of_v, "Invalid base type"); - auto * const type = internal::meta_info::resolve(); static internal::meta_base_node node{ nullptr, @@ -192,9 +194,9 @@ struct meta_factory { } }; - if(meta_range range{type->base}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) { - node.next = type->base; - type->base = &node; + if(meta_range range{owner->base}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) { + node.next = owner->base; + owner->base = &node; } return meta_factory{}; @@ -215,7 +217,6 @@ struct meta_factory { template std::enable_if_t, meta_factory> conv() ENTT_NOEXCEPT { using conv_type = std::invoke_result_t; - auto * const type = internal::meta_info::resolve(); static internal::meta_conv_node node{ nullptr, @@ -225,9 +226,9 @@ struct meta_factory { } }; - if(meta_range range{type->conv}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) { - node.next = type->conv; - type->conv = &node; + if(meta_range range{owner->conv}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) { + node.next = owner->conv; + owner->conv = &node; } return meta_factory{}; @@ -237,7 +238,6 @@ struct meta_factory { template std::enable_if_t, meta_factory> conv() ENTT_NOEXCEPT { using conv_type = std::invoke_result_t; - auto * const type = internal::meta_info::resolve(); static internal::meta_conv_node node{ nullptr, @@ -247,9 +247,9 @@ struct meta_factory { } }; - if(meta_range range{type->conv}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) { - node.next = type->conv; - type->conv = &node; + if(meta_range range{owner->conv}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) { + node.next = owner->conv; + owner->conv = &node; } return meta_factory{}; @@ -267,7 +267,6 @@ struct meta_factory { template auto conv() ENTT_NOEXCEPT { static_assert(std::is_convertible_v, "Could not convert to the required type"); - auto * const type = internal::meta_info::resolve(); static internal::meta_conv_node node{ nullptr, @@ -277,9 +276,9 @@ struct meta_factory { } }; - if(meta_range range{type->conv}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) { - node.next = type->conv; - type->conv = &node; + if(meta_range range{owner->conv}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) { + node.next = owner->conv; + owner->conv = &node; } return meta_factory{}; @@ -302,7 +301,6 @@ struct meta_factory { auto ctor() ENTT_NOEXCEPT { using descriptor = meta_function_helper_t; static_assert(std::is_same_v, Type>, "The function doesn't return an object of the required type"); - auto * const type = internal::meta_info::resolve(); static internal::meta_ctor_node node{ nullptr, @@ -312,9 +310,9 @@ struct meta_factory { &meta_construct }; - if(meta_range range{type->ctor}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) { - node.next = type->ctor; - type->ctor = &node; + if(meta_range range{owner->ctor}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) { + node.next = owner->ctor; + owner->ctor = &node; } return meta_factory>{&node.prop}; @@ -333,7 +331,6 @@ struct meta_factory { template auto ctor() ENTT_NOEXCEPT { using descriptor = meta_function_helper_t; - auto * const type = internal::meta_info::resolve(); static internal::meta_ctor_node node{ nullptr, @@ -343,9 +340,9 @@ struct meta_factory { &meta_construct }; - if(meta_range range{type->ctor}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) { - node.next = type->ctor; - type->ctor = &node; + if(meta_range range{owner->ctor}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) { + node.next = owner->ctor; + owner->ctor = &node; } return meta_factory{&node.prop}; @@ -370,9 +367,8 @@ struct meta_factory { template auto dtor() ENTT_NOEXCEPT { static_assert(std::is_invocable_v, "The function doesn't accept an object of the type provided"); - auto * const type = internal::meta_info::resolve(); - type->dtor = [](void *instance) { + owner->dtor = [](void *instance) { Func(*static_cast(instance)); }; @@ -398,7 +394,6 @@ struct meta_factory { return data(id); } else { using data_type = std::remove_pointer_t; - auto * const type = internal::meta_info::resolve(); static internal::meta_data_node node{ {}, @@ -412,13 +407,13 @@ struct meta_factory { &meta_getter }; - meta_range range{type->data}; + meta_range range{owner->data}; ENTT_ASSERT(std::find_if(range.cbegin(), range.cend(), [id](const auto *curr) { return curr != &node && curr->id == id; }) == range.cend(), "Duplicate identifier"); node.id = id; if(std::find(range.cbegin(), range.cend(), &node) == range.cend()) { - node.next = type->data; - type->data = &node; + node.next = owner->data; + owner->data = &node; } return meta_factory>{&node.prop}; @@ -448,7 +443,6 @@ struct meta_factory { template auto data(const id_type id) ENTT_NOEXCEPT { using underlying_type = std::remove_reference_t>; - auto * const type = internal::meta_info::resolve(); static internal::meta_data_node node{ {}, @@ -462,13 +456,13 @@ struct meta_factory { &meta_getter }; - meta_range range{type->data}; + meta_range range{owner->data}; ENTT_ASSERT(std::find_if(range.cbegin(), range.cend(), [id](const auto *curr) { return curr != &node && curr->id == id; }) == range.cend(), "Duplicate identifier"); node.id = id; if(std::find(range.cbegin(), range.cend(), &node) == range.cend()) { - node.next = type->data; - type->data = &node; + node.next = owner->data; + owner->data = &node; } return meta_factory, std::integral_constant>{&node.prop}; @@ -490,7 +484,6 @@ struct meta_factory { template auto func(const id_type id) ENTT_NOEXCEPT { using descriptor = meta_function_helper_t; - auto * const type = internal::meta_info::resolve(); static internal::meta_func_node node{ {}, @@ -505,14 +498,14 @@ struct meta_factory { &meta_invoke }; - for(auto *it = &type->func; *it; it = &(*it)->next) { + for(auto *it = &owner->func; *it; it = &(*it)->next) { if(*it == &node) { *it = node.next; break; } } - internal::meta_func_node **it = &type->func; + internal::meta_func_node **it = &owner->func; for(; *it && (*it)->id != id; it = &(*it)->next); for(; *it && (*it)->id == id && (*it)->arity < node.arity; it = &(*it)->next); @@ -522,6 +515,9 @@ struct meta_factory { return meta_factory>{&node.prop}; } + +private: + internal::meta_type_node *owner; }; diff --git a/test/entt/meta/meta_prop.cpp b/test/entt/meta/meta_prop.cpp index 9404c1285..57a96e7e0 100644 --- a/test/entt/meta/meta_prop.cpp +++ b/test/entt/meta/meta_prop.cpp @@ -19,8 +19,7 @@ struct MetaProp: ::testing::Test { entt::meta() .type("base_2"_hs) - .prop("bool"_hs, false) - .prop("char[]"_hs, "char[]"); + .props(std::make_pair("bool"_hs, false), std::make_pair("char[]"_hs, "char[]")); entt::meta() .type("derived"_hs) diff --git a/test/entt/meta/meta_type.cpp b/test/entt/meta/meta_type.cpp index 4e7ac0fd7..4632b4e47 100644 --- a/test/entt/meta/meta_type.cpp +++ b/test/entt/meta/meta_type.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -130,15 +131,13 @@ struct MetaType: ::testing::Test { entt::meta() .type("property"_hs) .data("random"_hs) - .prop(property_t::random, 0) - .prop(property_t::value, 3) + .props(std::make_pair(property_t::random, 0), std::make_pair(property_t::value, 3)) .data("value"_hs) - .prop(std::make_tuple(std::make_pair(property_t::random, true), std::make_pair(property_t::value, 0), property_t::key_only)) - .prop(property_t::list) + .props(std::make_pair(property_t::random, true), std::make_pair(property_t::value, 0), property_t::key_only, property_t::list) .data("key_only"_hs) .prop([]() { return property_t::key_only; }) .data("list"_hs) - .props(std::make_pair(property_t::random, false), std::make_pair(property_t::value, 0), property_t::key_only) + .props(std::make_pair(property_t::random, false), std::make_pair(property_t::value, 0), property_t::key_only) .data, get>("var"_hs); entt::meta() @@ -609,8 +608,7 @@ TEST_F(MetaType, ResetAndReRegistrationAfterReset) { entt::meta() .type("property"_hs) .data("rand"_hs) - .prop(property_t::value, 42) - .prop(property_t::random, 3); + .props(std::make_pair(property_t::value, 42), std::make_pair(property_t::random, 3)); ASSERT_TRUE(entt::resolve().data("rand"_hs).prop(property_t::value)); ASSERT_TRUE(entt::resolve().data("rand"_hs).prop(property_t::random));