Browse Source

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

Michele Caini 4 years ago
parent
commit
d9494960a2
5 changed files with 59 additions and 79 deletions
  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:
 WIP:
 * runtime components (registry), runtime events (dispatcher/emitter), ...
 * 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 iterable view
 * add constrained type policy to view iterators
 * add constrained type policy to view iterators
 * custom allocators all over
 * 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
   An annotation is an invocable object that returns one or more properties. All
   of them are treated individually.
   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
 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:
 properties at once or to search a specific property by key:
 
 
 ```cpp
 ```cpp

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

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

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

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