Преглед на файлове

meta:
* removed the possibility of invoking meta_factory::prop multiple times
* further reduced instantiations due to meta properties

Michele Caini преди 4 години
родител
ревизия
d9494960a2
променени са 5 файла, в които са добавени 59 реда и са изтрити 79 реда
  1. 1 0
      TODO
  2. 7 21
      docs/md/meta.md
  3. 45 49
      src/entt/meta/factory.hpp
  4. 1 2
      test/entt/meta/meta_prop.cpp
  5. 5 7
      test/entt/meta/meta_type.cpp

+ 1 - 0
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

+ 7 - 21
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<my_type>()
-    .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.<br/>
+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.<br/>
+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

+ 45 - 49
src/entt/meta/factory.hpp

@@ -114,14 +114,14 @@ public:
      * @return A meta factory for the parent type.
      */
     template<typename PropertyOrKey, typename... Value>
-    auto prop(PropertyOrKey &&property_or_key, Value &&... value) && {
+    meta_factory<Type> prop(PropertyOrKey &&property_or_key, Value &&... value) && {
         if constexpr(sizeof...(Value) == 0) {
             unroll(choice<3>, std::forward<PropertyOrKey>(property_or_key));
         } else {
             assign(std::forward<PropertyOrKey>(property_or_key), std::forward<Value>(value)...);
         }
 
-        return meta_factory<Type, Spec..., PropertyOrKey, Value...>{ref};
+        return {};
     }
 
     /**
@@ -135,9 +135,9 @@ public:
      * @return A meta factory for the parent type.
      */
     template <typename... Property>
-    auto props(Property... property) && {
+    meta_factory<Type> props(Property... property) && {
         unroll(choice<3>, std::forward<Property>(property)...);
-        return meta_factory<Type, Spec..., Property...>{ref};
+        return {};
     }
 
 private:
@@ -151,24 +151,27 @@ private:
  */
 template<typename Type>
 struct meta_factory<Type> {
+    /*! @brief Default constructor. */
+    meta_factory()
+        : owner{internal::meta_info<Type>::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<Type>::value()) {
-        auto * const node = internal::meta_info<Type>::resolve();
-
         meta_range<internal::meta_type_node *, internal::meta_type_node> 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<Type, Type>{&node->prop};
+        return meta_factory<Type, Type>{&owner->prop};
     }
 
     /**
@@ -182,7 +185,6 @@ struct meta_factory<Type> {
     template<typename Base>
     auto base() ENTT_NOEXCEPT {
         static_assert(std::is_base_of_v<Base, Type>, "Invalid base type");
-        auto * const type = internal::meta_info<Type>::resolve();
 
         static internal::meta_base_node node{
             nullptr,
@@ -192,9 +194,9 @@ struct meta_factory<Type> {
             }
         };
 
-        if(meta_range<internal::meta_base_node *, internal::meta_base_node> range{type->base}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
-            node.next = type->base;
-            type->base = &node;
+        if(meta_range<internal::meta_base_node *, internal::meta_base_node> range{owner->base}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
+            node.next = owner->base;
+            owner->base = &node;
         }
 
         return meta_factory<Type>{};
@@ -215,7 +217,6 @@ struct meta_factory<Type> {
     template<auto Candidate>
     std::enable_if_t<std::is_member_function_pointer_v<decltype(Candidate)>, meta_factory<Type>> conv() ENTT_NOEXCEPT {
         using conv_type = std::invoke_result_t<decltype(Candidate), Type &>;
-        auto * const type = internal::meta_info<Type>::resolve();
 
         static internal::meta_conv_node node{
             nullptr,
@@ -225,9 +226,9 @@ struct meta_factory<Type> {
             }
         };
 
-        if(meta_range<internal::meta_conv_node *, internal::meta_conv_node> range{type->conv}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
-            node.next = type->conv;
-            type->conv = &node;
+        if(meta_range<internal::meta_conv_node *, internal::meta_conv_node> range{owner->conv}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
+            node.next = owner->conv;
+            owner->conv = &node;
         }
 
         return meta_factory<Type>{};
@@ -237,7 +238,6 @@ struct meta_factory<Type> {
     template<auto Candidate>
     std::enable_if_t<!std::is_member_function_pointer_v<decltype(Candidate)>, meta_factory<Type>> conv() ENTT_NOEXCEPT {
         using conv_type = std::invoke_result_t<decltype(Candidate), Type &>;
-        auto * const type = internal::meta_info<Type>::resolve();
 
         static internal::meta_conv_node node{
             nullptr,
@@ -247,9 +247,9 @@ struct meta_factory<Type> {
             }
         };
 
-        if(meta_range<internal::meta_conv_node *, internal::meta_conv_node> range{type->conv}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
-            node.next = type->conv;
-            type->conv = &node;
+        if(meta_range<internal::meta_conv_node *, internal::meta_conv_node> range{owner->conv}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
+            node.next = owner->conv;
+            owner->conv = &node;
         }
 
         return meta_factory<Type>{};
@@ -267,7 +267,6 @@ struct meta_factory<Type> {
     template<typename To>
     auto conv() ENTT_NOEXCEPT {
         static_assert(std::is_convertible_v<Type, To>, "Could not convert to the required type");
-        auto * const type = internal::meta_info<Type>::resolve();
 
         static internal::meta_conv_node node{
             nullptr,
@@ -277,9 +276,9 @@ struct meta_factory<Type> {
             }
         };
 
-        if(meta_range<internal::meta_conv_node *, internal::meta_conv_node> range{type->conv}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
-            node.next = type->conv;
-            type->conv = &node;
+        if(meta_range<internal::meta_conv_node *, internal::meta_conv_node> range{owner->conv}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
+            node.next = owner->conv;
+            owner->conv = &node;
         }
 
         return meta_factory<Type>{};
@@ -302,7 +301,6 @@ struct meta_factory<Type> {
     auto ctor() ENTT_NOEXCEPT {
         using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
         static_assert(std::is_same_v<std::decay_t<typename descriptor::return_type>, Type>, "The function doesn't return an object of the required type");
-        auto * const type = internal::meta_info<Type>::resolve();
 
         static internal::meta_ctor_node node{
             nullptr,
@@ -312,9 +310,9 @@ struct meta_factory<Type> {
             &meta_construct<Type, Candidate, Policy>
         };
 
-        if(meta_range<internal::meta_ctor_node *, internal::meta_ctor_node> range{type->ctor}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
-            node.next = type->ctor;
-            type->ctor = &node;
+        if(meta_range<internal::meta_ctor_node *, internal::meta_ctor_node> range{owner->ctor}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
+            node.next = owner->ctor;
+            owner->ctor = &node;
         }
 
         return meta_factory<Type, std::integral_constant<decltype(Candidate), Candidate>>{&node.prop};
@@ -333,7 +331,6 @@ struct meta_factory<Type> {
     template<typename... Args>
     auto ctor() ENTT_NOEXCEPT {
         using descriptor = meta_function_helper_t<Type, Type(*)(Args...)>;
-        auto * const type = internal::meta_info<Type>::resolve();
 
         static internal::meta_ctor_node node{
             nullptr,
@@ -343,9 +340,9 @@ struct meta_factory<Type> {
             &meta_construct<Type, Args...>
         };
 
-        if(meta_range<internal::meta_ctor_node *, internal::meta_ctor_node> range{type->ctor}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
-            node.next = type->ctor;
-            type->ctor = &node;
+        if(meta_range<internal::meta_ctor_node *, internal::meta_ctor_node> range{owner->ctor}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
+            node.next = owner->ctor;
+            owner->ctor = &node;
         }
 
         return meta_factory<Type, Type(Args...)>{&node.prop};
@@ -370,9 +367,8 @@ struct meta_factory<Type> {
     template<auto Func>
     auto dtor() ENTT_NOEXCEPT {
         static_assert(std::is_invocable_v<decltype(Func), Type &>, "The function doesn't accept an object of the type provided");
-        auto * const type = internal::meta_info<Type>::resolve();
 
-        type->dtor = [](void *instance) {
+        owner->dtor = [](void *instance) {
             Func(*static_cast<Type *>(instance));
         };
 
@@ -398,7 +394,6 @@ struct meta_factory<Type> {
             return data<Data, Data, Policy>(id);
         } else {
             using data_type = std::remove_pointer_t<decltype(Data)>;
-            auto * const type = internal::meta_info<Type>::resolve();
 
             static internal::meta_data_node node{
                 {},
@@ -412,13 +407,13 @@ struct meta_factory<Type> {
                 &meta_getter<Type, Data, Policy>
             };
 
-            meta_range<internal::meta_data_node *, internal::meta_data_node> range{type->data};
+            meta_range<internal::meta_data_node *, internal::meta_data_node> 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<Type, std::integral_constant<decltype(Data), Data>>{&node.prop};
@@ -448,7 +443,6 @@ struct meta_factory<Type> {
     template<auto Setter, auto Getter, typename Policy = as_is_t>
     auto data(const id_type id) ENTT_NOEXCEPT {
         using underlying_type = std::remove_reference_t<std::invoke_result_t<decltype(Getter), Type &>>;
-        auto * const type = internal::meta_info<Type>::resolve();
 
         static internal::meta_data_node node{
             {},
@@ -462,13 +456,13 @@ struct meta_factory<Type> {
             &meta_getter<Type, Getter, Policy>
         };
 
-        meta_range<internal::meta_data_node *, internal::meta_data_node> range{type->data};
+        meta_range<internal::meta_data_node *, internal::meta_data_node> 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<Type, std::integral_constant<decltype(Setter), Setter>, std::integral_constant<decltype(Getter), Getter>>{&node.prop};
@@ -490,7 +484,6 @@ struct meta_factory<Type> {
     template<auto Candidate, typename Policy = as_is_t>
     auto func(const id_type id) ENTT_NOEXCEPT {
         using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
-        auto * const type = internal::meta_info<Type>::resolve();
 
         static internal::meta_func_node node{
             {},
@@ -505,14 +498,14 @@ struct meta_factory<Type> {
             &meta_invoke<Type, Candidate, Policy>
         };
 
-        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<Type> {
 
         return meta_factory<Type, std::integral_constant<decltype(Candidate), Candidate>>{&node.prop};
     }
+
+private:
+    internal::meta_type_node *owner;
 };
 
 

+ 1 - 2
test/entt/meta/meta_prop.cpp

@@ -19,8 +19,7 @@ struct MetaProp: ::testing::Test {
 
         entt::meta<base_2_t>()
             .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<derived_t>()
             .type("derived"_hs)

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

@@ -1,5 +1,6 @@
 #include <map>
 #include <memory>
+#include <utility>
 #include <vector>
 #include <gtest/gtest.h>
 #include <entt/core/hashed_string.hpp>
@@ -130,15 +131,13 @@ struct MetaType: ::testing::Test {
         entt::meta<property_t>()
             .type("property"_hs)
             .data<property_t::random>("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<property_t::value>("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<property_t::key_only>("key_only"_hs)
                 .prop([]() { return property_t::key_only; })
             .data<property_t::list>("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<set<property_t>, get<property_t>>("var"_hs);
 
         entt::meta<clazz_t>()
@@ -609,8 +608,7 @@ TEST_F(MetaType, ResetAndReRegistrationAfterReset) {
     entt::meta<property_t>()
         .type("property"_hs)
         .data<property_t::random>("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<property_t>().data("rand"_hs).prop(property_t::value));
     ASSERT_TRUE(entt::resolve<property_t>().data("rand"_hs).prop(property_t::random));