Browse Source

meta: cleanup

Michele Caini 6 years ago
parent
commit
50f07a6a0d
4 changed files with 108 additions and 186 deletions
  1. 5 3
      TODO
  2. 57 109
      src/entt/meta/factory.hpp
  3. 32 58
      src/entt/meta/meta.hpp
  4. 14 16
      test/entt/meta/meta.cpp

+ 5 - 3
TODO

@@ -19,9 +19,6 @@
 * deprecate/replace snapshot
 * hibitset, views and non-owning groups
 * custom (decoupled) pools ==> double buffering, shared components, multi-model
-* make meta work across boundaries
-  - inline variables are fine here, only the head represents a problem
-  - we should always resolve by looking into the list of types when working across boundaries, no direct resolve
 * snapshot rework/deprecation
   - create(hint: entity) -> force-create
   - assign<T...>(first, last)
@@ -32,3 +29,8 @@
 * multi component registry::remove and some others?
   - auto foo(It first, It last = entity_type{null})
 * range based registry::remove and some others?
+
+* make meta work across boundaries
+  - inline variables are fine here, only the head represents a problem
+  - we should always resolve by looking into the list of types when working across boundaries, no direct resolve
+  - factory: allow to attach multiple times the same type, data, func, ctor

+ 57 - 109
src/entt/meta/factory.hpp

@@ -9,6 +9,7 @@
 #include <functional>
 #include <type_traits>
 #include "../config/config.h"
+#include "../core/utility.hpp"
 #include "policy.hpp"
 #include "meta.hpp"
 
@@ -247,6 +248,11 @@ meta_any invoke([[maybe_unused]] meta_handle handle, meta_any *args, std::index_
  */
 template<typename Type>
 class meta_factory {
+    template<typename Node>
+    bool duplicate(const Node *candidate, const Node *node) ENTT_NOEXCEPT {
+        return node && (node == candidate || duplicate(candidate, node->next));
+    }
+
     template<typename Node>
     bool duplicate(const ENTT_ID_TYPE identifier, const Node *node) ENTT_NOEXCEPT {
         return node && (node->identifier == identifier || duplicate(identifier, node->next));
@@ -284,43 +290,6 @@ class meta_factory {
         return &node;
     }
 
-    void unregister_prop(internal::meta_prop_node **prop) {
-        while(*prop) {
-            auto *node = *prop;
-            *prop = node->next;
-            node->next = nullptr;
-        }
-    }
-
-    void unregister_dtor() {
-        if(auto node = internal::meta_info<Type>::type->dtor; node) {
-            internal::meta_info<Type>::type->dtor = nullptr;
-            *node->underlying = nullptr;
-        }
-    }
-
-    template<auto Member>
-    auto unregister_all(int)
-    -> decltype((internal::meta_info<Type>::type->*Member)->prop, void()) {
-        while(internal::meta_info<Type>::type->*Member) {
-            auto node = internal::meta_info<Type>::type->*Member;
-            internal::meta_info<Type>::type->*Member = node->next;
-            unregister_prop(&node->prop);
-            node->next = nullptr;
-            *node->underlying = nullptr;
-        }
-    }
-
-    template<auto Member>
-    void unregister_all(char) {
-        while(internal::meta_info<Type>::type->*Member) {
-            auto node = internal::meta_info<Type>::type->*Member;
-            internal::meta_info<Type>::type->*Member = node->next;
-            node->next = nullptr;
-            *node->underlying = nullptr;
-        }
-    }
-
 public:
     /*! @brief Default constructor. */
     meta_factory() ENTT_NOEXCEPT = default;
@@ -334,13 +303,13 @@ public:
      */
     template<typename... Property>
     meta_factory type(const ENTT_ID_TYPE identifier, Property &&... property) ENTT_NOEXCEPT {
-        ENTT_ASSERT(!internal::meta_info<Type>::type);
-        auto *node = internal::meta_info<Type>::resolve();
+        auto * const node = internal::meta_info<Type>::resolve();
+
         node->identifier = identifier;
-        node->next = internal::meta_info<>::type;
         node->prop = properties<Type>(std::forward<Property>(property)...);
-        ENTT_ASSERT(!duplicate(identifier, node->next));
-        internal::meta_info<Type>::type = node;
+        ENTT_ASSERT(!duplicate(identifier, internal::meta_info<>::type));
+        ENTT_ASSERT(!duplicate(node, internal::meta_info<>::type));
+        node->next = internal::meta_info<>::type;
         internal::meta_info<>::type = node;
 
         return *this;
@@ -360,7 +329,6 @@ public:
         auto * const type = internal::meta_info<Type>::resolve();
 
         static internal::meta_base_node node{
-            &internal::meta_info<Type>::template base<Base>,
             type,
             nullptr,
             &internal::meta_info<Base>::resolve,
@@ -372,9 +340,8 @@ public:
             }
         };
 
+        ENTT_ASSERT(!duplicate(&node, type->base));
         node.next = type->base;
-        ENTT_ASSERT((!internal::meta_info<Type>::template base<Base>));
-        internal::meta_info<Type>::template base<Base> = &node;
         type->base = &node;
 
         return *this;
@@ -395,7 +362,6 @@ public:
         auto * const type = internal::meta_info<Type>::resolve();
 
         static internal::meta_conv_node node{
-            &internal::meta_info<Type>::template conv<To>,
             type,
             nullptr,
             &internal::meta_info<To>::resolve,
@@ -407,9 +373,8 @@ public:
             }
         };
 
+        ENTT_ASSERT(!duplicate(&node, type->conv));
         node.next = type->conv;
-        ENTT_ASSERT((!internal::meta_info<Type>::template conv<To>));
-        internal::meta_info<Type>::template conv<To> = &node;
         type->conv = &node;
 
         return *this;
@@ -433,7 +398,6 @@ public:
         auto * const type = internal::meta_info<Type>::resolve();
 
         static internal::meta_conv_node node{
-            &internal::meta_info<Type>::template conv<conv_type>,
             type,
             nullptr,
             &internal::meta_info<conv_type>::resolve,
@@ -445,9 +409,8 @@ public:
             }
         };
 
+        ENTT_ASSERT(!duplicate(&node, type->conv));
         node.next = type->conv;
-        ENTT_ASSERT((!internal::meta_info<Type>::template conv<conv_type>));
-        internal::meta_info<Type>::template conv<conv_type> = &node;
         type->conv = &node;
 
         return *this;
@@ -475,7 +438,6 @@ public:
         auto * const type = internal::meta_info<Type>::resolve();
 
         static internal::meta_ctor_node node{
-            &internal::meta_info<Type>::template ctor<typename helper_type::args_type>,
             type,
             nullptr,
             nullptr,
@@ -489,10 +451,9 @@ public:
             }
         };
 
-        node.next = type->ctor;
         node.prop = properties<typename helper_type::args_type>(std::forward<Property>(property)...);
-        ENTT_ASSERT((!internal::meta_info<Type>::template ctor<typename helper_type::args_type>));
-        internal::meta_info<Type>::template ctor<typename helper_type::args_type> = &node;
+        ENTT_ASSERT(!duplicate(&node, type->ctor));
+        node.next = type->ctor;
         type->ctor = &node;
 
         return *this;
@@ -516,7 +477,6 @@ public:
         auto * const type = internal::meta_info<Type>::resolve();
 
         static internal::meta_ctor_node node{
-            &internal::meta_info<Type>::template ctor<typename helper_type::args_type>,
             type,
             nullptr,
             nullptr,
@@ -530,10 +490,9 @@ public:
             }
         };
 
-        node.next = type->ctor;
         node.prop = properties<typename helper_type::args_type>(std::forward<Property>(property)...);
-        ENTT_ASSERT((!internal::meta_info<Type>::template ctor<typename helper_type::args_type>));
-        internal::meta_info<Type>::template ctor<typename helper_type::args_type> = &node;
+        ENTT_ASSERT(!duplicate(&node, type->ctor));
+        node.next = type->ctor;
         type->ctor = &node;
 
         return *this;
@@ -561,7 +520,6 @@ public:
         auto * const type = internal::meta_info<Type>::resolve();
 
         static internal::meta_dtor_node node{
-            &internal::meta_info<Type>::template dtor<Func>,
             type,
             [](meta_handle handle) {
                 const auto valid = (handle.type() == internal::meta_info<Type>::resolve()->meta());
@@ -577,10 +535,8 @@ public:
             }
         };
 
-        ENTT_ASSERT(!internal::meta_info<Type>::type->dtor);
-        ENTT_ASSERT((!internal::meta_info<Type>::template dtor<Func>));
-        internal::meta_info<Type>::template dtor<Func> = &node;
-        internal::meta_info<Type>::type->dtor = &node;
+        ENTT_ASSERT(!type->dtor);
+        type->dtor = &node;
 
         return *this;
     }
@@ -609,7 +565,6 @@ public:
             static_assert(std::is_same_v<Policy, as_is_t>);
 
             static internal::meta_data_node node{
-                &internal::meta_info<Type>::template data<Data>,
                 {},
                 type,
                 nullptr,
@@ -630,7 +585,6 @@ public:
             using data_type = std::remove_reference_t<decltype(std::declval<Type>().*Data)>;
 
             static internal::meta_data_node node{
-                &internal::meta_info<Type>::template data<Data>,
                 {},
                 type,
                 nullptr,
@@ -652,7 +606,6 @@ public:
             using data_type = std::remove_pointer_t<std::decay_t<decltype(Data)>>;
 
             static internal::meta_data_node node{
-                &internal::meta_info<Type>::template data<Data>,
                 {},
                 type,
                 nullptr,
@@ -672,10 +625,9 @@ public:
         }
 
         curr->identifier = identifier;
+        ENTT_ASSERT(!duplicate(identifier, type->data));
+        ENTT_ASSERT(!duplicate(curr, type->data));
         curr->next = type->data;
-        ENTT_ASSERT(!duplicate(identifier, curr->next));
-        ENTT_ASSERT((!internal::meta_info<Type>::template data<Data>));
-        internal::meta_info<Type>::template data<Data> = curr;
         type->data = curr;
 
         return *this;
@@ -711,7 +663,6 @@ public:
         auto * const type = internal::meta_info<Type>::resolve();
 
         static internal::meta_data_node node{
-            &internal::meta_info<Type>::template data<Setter, Getter>,
             {},
             type,
             nullptr,
@@ -727,11 +678,10 @@ public:
         };
 
         node.identifier = identifier;
-        node.next = type->data;
         node.prop = properties<owner_type>(std::forward<Property>(property)...);
-        ENTT_ASSERT(!duplicate(identifier, node.next));
-        ENTT_ASSERT((!internal::meta_info<Type>::template data<Setter, Getter>));
-        internal::meta_info<Type>::template data<Setter, Getter> = &node;
+        ENTT_ASSERT(!duplicate(identifier, type->data));
+        ENTT_ASSERT(!duplicate(&node, type->data));
+        node.next = type->data;
         type->data = &node;
 
         return *this;
@@ -759,7 +709,6 @@ public:
         auto * const type = internal::meta_info<Type>::resolve();
 
         static internal::meta_func_node node{
-            &internal::meta_info<Type>::template func<Candidate>,
             {},
             type,
             nullptr,
@@ -778,11 +727,10 @@ public:
         };
 
         node.identifier = identifier;
-        node.next = type->func;
         node.prop = properties<owner_type>(std::forward<Property>(property)...);
-        ENTT_ASSERT(!duplicate(identifier, node.next));
-        ENTT_ASSERT((!internal::meta_info<Type>::template func<Candidate>));
-        internal::meta_info<Type>::template func<Candidate> = &node;
+        ENTT_ASSERT(!duplicate(identifier, type->func));
+        ENTT_ASSERT(!duplicate(&node, type->func));
+        node.next = type->func;
         type->func = &node;
 
         return *this;
@@ -796,39 +744,40 @@ public:
      * conversion functions if any.<br/>
      * Base classes aren't unregistered but the link between the two types is
      * removed.
-     *
-     * @return True if the meta type exists, false otherwise.
      */
-    bool unregister() ENTT_NOEXCEPT {
-        const auto registered = internal::meta_info<Type>::type;
+    void unregister() ENTT_NOEXCEPT {
+        auto * const node = internal::meta_info<Type>::resolve();
+        auto **curr = &internal::meta_info<>::type;
 
-        if(registered) {
-            if(auto *curr = internal::meta_info<>::type; curr == internal::meta_info<Type>::type) {
-                internal::meta_info<>::type = internal::meta_info<Type>::type->next;
-            } else {
-                while(curr && curr->next != internal::meta_info<Type>::type) {
-                    curr = curr->next;
-                }
+        while(*curr && *curr != node) {
+            curr = &(*curr)->next;
+        }
 
-                if(curr) {
-                    curr->next = internal::meta_info<Type>::type->next;
+        if(*curr) {
+            *curr = (*curr)->next;
+        }
+
+        const auto unregister_all = y_combinator{
+            [](auto &&self, auto **node, auto... member) {
+                while(*node) {
+                    auto *curr = *node;
+                    (self(&(curr->*member)), ...);
+                    *node = curr->next;
+                    curr->next = nullptr;
                 }
             }
+        };
 
-            unregister_prop(&internal::meta_info<Type>::type->prop);
-            unregister_all<&internal::meta_type_node::base>(0);
-            unregister_all<&internal::meta_type_node::conv>(0);
-            unregister_all<&internal::meta_type_node::ctor>(0);
-            unregister_all<&internal::meta_type_node::data>(0);
-            unregister_all<&internal::meta_type_node::func>(0);
-            unregister_dtor();
-
-            internal::meta_info<Type>::type->identifier = {};
-            internal::meta_info<Type>::type->next = nullptr;
-            internal::meta_info<Type>::type = nullptr;
-        }
+        unregister_all(&node->prop);
+        unregister_all(&node->base);
+        unregister_all(&node->conv);
+        unregister_all(&node->ctor, &internal::meta_ctor_node::prop);
+        unregister_all(&node->data, &internal::meta_data_node::prop);
+        unregister_all(&node->func, &internal::meta_func_node::prop);
 
-        return registered;
+        node->dtor = nullptr;
+        node->identifier = {};
+        node->next = nullptr;
     }
 };
 
@@ -880,11 +829,10 @@ inline meta_factory<Type> reflect() ENTT_NOEXCEPT {
  * removed.
  *
  * @tparam Type Type to unregister.
- * @return True if the type to unregister exists, false otherwise.
  */
 template<typename Type>
-inline bool unregister() ENTT_NOEXCEPT {
-    return meta_factory<Type>{}.unregister();
+inline void unregister() ENTT_NOEXCEPT {
+    meta_factory<Type>{}.unregister();
 }
 
 

+ 32 - 58
src/entt/meta/meta.hpp

@@ -47,7 +47,6 @@ struct meta_prop_node {
 
 
 struct meta_base_node {
-    meta_base_node ** const underlying;
     meta_type_node * const parent;
     meta_base_node * next;
     meta_type_node *(* const type)() ENTT_NOEXCEPT;
@@ -57,7 +56,6 @@ struct meta_base_node {
 
 
 struct meta_conv_node {
-    meta_conv_node ** const underlying;
     meta_type_node * const parent;
     meta_conv_node * next;
     meta_type_node *(* const type)() ENTT_NOEXCEPT;
@@ -68,7 +66,6 @@ struct meta_conv_node {
 
 struct meta_ctor_node {
     using size_type = std::size_t;
-    meta_ctor_node ** const underlying;
     meta_type_node * const parent;
     meta_ctor_node * next;
     meta_prop_node * prop;
@@ -80,7 +77,6 @@ struct meta_ctor_node {
 
 
 struct meta_dtor_node {
-    meta_dtor_node ** const underlying;
     meta_type_node * const parent;
     bool(* const invoke)(meta_handle);
     meta_dtor(* const meta)() ENTT_NOEXCEPT;
@@ -88,7 +84,6 @@ struct meta_dtor_node {
 
 
 struct meta_data_node {
-    meta_data_node ** const underlying;
     ENTT_ID_TYPE identifier;
     meta_type_node * const parent;
     meta_data_node * next;
@@ -104,7 +99,6 @@ struct meta_data_node {
 
 struct meta_func_node {
     using size_type = std::size_t;
-    meta_func_node ** const underlying;
     ENTT_ID_TYPE identifier;
     meta_type_node * const parent;
     meta_func_node * next;
@@ -149,33 +143,17 @@ struct meta_type_node {
 
 
 template<typename...>
-struct meta_node {
+struct meta_node;
+
+
+template<>
+struct meta_node<> {
     inline static meta_type_node *type = nullptr;
 };
 
 
 template<typename Type>
 struct meta_node<Type> {
-    inline static meta_type_node *type = nullptr;
-
-    template<typename>
-    inline static meta_base_node *base = nullptr;
-
-    template<typename>
-    inline static meta_conv_node *conv = nullptr;
-
-    template<typename>
-    inline static meta_ctor_node *ctor = nullptr;
-
-    template<auto>
-    inline static meta_dtor_node *dtor = nullptr;
-
-    template<auto...>
-    inline static meta_data_node *data = nullptr;
-
-    template<auto>
-    inline static meta_func_node *func = nullptr;
-
     inline static meta_type_node * resolve() ENTT_NOEXCEPT;
 };
 
@@ -2064,38 +2042,34 @@ static bool compare(char, const void *lhs, const void *rhs) {
 
 template<typename Type>
 inline meta_type_node * meta_node<Type>::resolve() ENTT_NOEXCEPT {
-    if(!type) {
-        static meta_type_node node{
-            {},
-            nullptr,
-            nullptr,
-            std::is_void_v<Type>,
-            std::is_integral_v<Type>,
-            std::is_floating_point_v<Type>,
-            std::is_array_v<Type>,
-            std::is_enum_v<Type>,
-            std::is_union_v<Type>,
-            std::is_class_v<Type>,
-            std::is_pointer_v<Type>,
-            std::is_pointer_v<Type> && std::is_function_v<std::remove_pointer_t<Type>>,
-            std::is_member_object_pointer_v<Type>,
-            std::is_member_function_pointer_v<Type>,
-            std::extent_v<Type>,
-            [](const void *lhs, const void *rhs) {
-                return compare<Type>(0, lhs, rhs);
-            },
-            []() ENTT_NOEXCEPT -> meta_type {
-                return internal::meta_info<std::remove_pointer_t<Type>>::resolve();
-            },
-            []() ENTT_NOEXCEPT -> meta_type {
-                return &node;
-            }
-        };
-
-        type = &node;
-    }
+    static meta_type_node node{
+        {},
+        nullptr,
+        nullptr,
+        std::is_void_v<Type>,
+        std::is_integral_v<Type>,
+        std::is_floating_point_v<Type>,
+        std::is_array_v<Type>,
+        std::is_enum_v<Type>,
+        std::is_union_v<Type>,
+        std::is_class_v<Type>,
+        std::is_pointer_v<Type>,
+        std::is_pointer_v<Type> && std::is_function_v<std::remove_pointer_t<Type>>,
+        std::is_member_object_pointer_v<Type>,
+        std::is_member_function_pointer_v<Type>,
+        std::extent_v<Type>,
+        [](const void *lhs, const void *rhs) {
+            return compare<Type>(0, lhs, rhs);
+        },
+        []() ENTT_NOEXCEPT -> meta_type {
+            return internal::meta_info<std::remove_pointer_t<Type>>::resolve();
+        },
+        []() ENTT_NOEXCEPT -> meta_type {
+            return &node;
+        }
+    };
 
-    return type;
+    return &node;
 }
 
 

+ 14 - 16
test/entt/meta/meta.cpp

@@ -1969,22 +1969,20 @@ TEST_F(Meta, Variables) {
 }
 
 TEST_F(Meta, Unregister) {
-    ASSERT_FALSE(entt::unregister<float>());
-    ASSERT_TRUE(entt::unregister<double>());
-    ASSERT_TRUE(entt::unregister<char>());
-    ASSERT_TRUE(entt::unregister<properties>());
-    ASSERT_TRUE(entt::unregister<unsigned int>());
-    ASSERT_TRUE(entt::unregister<base_type>());
-    ASSERT_TRUE(entt::unregister<derived_type>());
-    ASSERT_TRUE(entt::unregister<empty_type>());
-    ASSERT_TRUE(entt::unregister<fat_type>());
-    ASSERT_TRUE(entt::unregister<data_type>());
-    ASSERT_TRUE(entt::unregister<func_type>());
-    ASSERT_TRUE(entt::unregister<setter_getter_type>());
-    ASSERT_TRUE(entt::unregister<an_abstract_type>());
-    ASSERT_TRUE(entt::unregister<another_abstract_type>());
-    ASSERT_TRUE(entt::unregister<concrete_type>());
-    ASSERT_FALSE(entt::unregister<double>());
+    entt::unregister<double>();
+    entt::unregister<char>();
+    entt::unregister<properties>();
+    entt::unregister<unsigned int>();
+    entt::unregister<base_type>();
+    entt::unregister<derived_type>();
+    entt::unregister<empty_type>();
+    entt::unregister<fat_type>();
+    entt::unregister<data_type>();
+    entt::unregister<func_type>();
+    entt::unregister<setter_getter_type>();
+    entt::unregister<an_abstract_type>();
+    entt::unregister<another_abstract_type>();
+    entt::unregister<concrete_type>();
 
     ASSERT_FALSE(entt::resolve("char"_hs));
     ASSERT_FALSE(entt::resolve("base"_hs));