Просмотр исходного кода

meta: reset-all functionality (see #358)

Michele Caini 6 лет назад
Родитель
Сommit
c645cb83a2
7 измененных файлов с 94 добавлено и 60 удалено
  1. 11 0
      docs/md/meta.md
  2. 47 16
      src/entt/meta/factory.hpp
  3. 23 16
      src/entt/meta/meta.hpp
  4. 10 25
      test/entt/meta/meta.cpp
  5. 1 1
      test/lib/a_module.cpp
  6. 1 1
      test/lib/another_module.cpp
  7. 1 1
      test/lib/lib.cpp

+ 11 - 0
docs/md/meta.md

@@ -583,3 +583,14 @@ entt::meta<my_type>().reset();
 ```
 
 The type can be re-registered later with a completely different name and form.
+
+To unregister all the types at once instead, a generic meta factory is the way
+to go:
+
+```cpp
+entt::meta().reset();
+```
+
+This function may touch more meta types than those explicitly created by the
+user. In fact, all locally created meta types are visited and reset, including
+those implicitly generated by the meta system under the hood.

+ 47 - 16
src/entt/meta/factory.hpp

@@ -241,17 +241,45 @@ class extended_meta_factory;
 
 
 /**
- * @brief A meta factory to be used for reflection purposes.
- *
- * A meta factory is an utility class used to reflect types, data and functions
- * of all sorts. This class ensures that the underlying web of types is built
- * correctly and performs some checks in debug mode to ensure that there are no
- * subtle errors at runtime.
+ * @brief Meta factory to be used for reflection purposes.
  *
+ * The meta factory is an utility class used to reflect types, data members and
+ * functions of all sorts. This class ensures that the underlying web of types
+ * is built correctly and performs some checks in debug mode to ensure that
+ * there are no subtle errors at runtime.
+ */
+template<typename...>
+class meta_factory;
+
+
+/*! @brief Generic meta factory to be used for reflection purposes. */
+template<>
+class meta_factory<> {
+public:
+    /**
+     * @brief Resets all meta types and all their parts.
+     *
+     * This function resets all meta type and their data members, member
+     * functions and properties, as well as their constructors, destructors,
+     * base classes and conversion functions if any.
+     */
+    void reset() ENTT_NOEXCEPT {
+        auto *it = internal::meta_info<>::context;
+
+        while(it) {
+            internal::meta_info<>::reset(it);
+            it = it->context;
+        }
+    }
+};
+
+
+/**
+ * @brief Basic meta factory to be used for reflection purposes.
  * @tparam Type Reflected type for which the factory was created.
  */
 template<typename Type>
-class meta_factory {
+class meta_factory<Type> {
     template<typename Node>
     bool duplicate(const Node *candidate, const Node *node) ENTT_NOEXCEPT {
         return node && (node == candidate || duplicate(candidate, node->next));
@@ -269,6 +297,8 @@ class meta_factory {
         ENTT_ASSERT(!duplicate(node, *internal::meta_info<>::global));
         node->identifier = identifier;
         node->next = *internal::meta_info<>::global;
+        if(node->next) { node->next->hook = &node->next; }
+        node->hook = internal::meta_info<>::global;
         *internal::meta_info<>::global = node;
 
         return extended_meta_factory<Type>{&node->prop};
@@ -281,7 +311,7 @@ public:
      * This function is intended only for unnamed types.
      *
      * @param identifier Unique identifier.
-     * @return An extended meta factory for the parent type.
+     * @return An extended meta factory for the given type.
      */
     auto type(const ENTT_ID_TYPE identifier) ENTT_NOEXCEPT {
         static_assert(!is_named_type_v<Type>);
@@ -293,7 +323,7 @@ public:
      *
      * This function is intended only for named types
      *
-     * @return An extended meta factory for the parent type.
+     * @return An extended meta factory for the given type.
      */
     auto type() ENTT_NOEXCEPT {
         static_assert(is_named_type_v<Type>);
@@ -678,7 +708,7 @@ public:
      * Base classes aren't reset but the link between the two types is removed.
      */
     void reset() ENTT_NOEXCEPT {
-        internal::meta_info<Type>::reset();
+        internal::meta_info<>::reset(internal::meta_info<Type>::resolve());
     }
 };
 
@@ -806,14 +836,15 @@ private:
  * This is the point from which everything starts.<br/>
  * By invoking this function with a type that is not yet reflected, a meta type
  * is created to which it will be possible to attach meta objects through a
- * dedicated factory.
+ * dedicated factory. If no type is provided, a generic meta factory is returned
+ * instead.
  *
- * @tparam Type Type to reflect.
- * @return A meta factory for the given type.
+ * @tparam Type Type to reflect, if any.
+ * @return An eventually generic meta factory.
  */
-template<typename Type>
-inline meta_factory<Type> meta() ENTT_NOEXCEPT {
-    return meta_factory<Type>{};
+template<typename... Type>
+inline meta_factory<Type...> meta() ENTT_NOEXCEPT {
+    return meta_factory<Type...>{};
 }
 
 

+ 23 - 16
src/entt/meta/meta.hpp

@@ -102,7 +102,9 @@ struct meta_func_node {
 
 struct meta_type_node {
     using size_type = std::size_t;
+    meta_type_node * const context;
     ENTT_ID_TYPE identifier;
+    meta_type_node ** hook;
     meta_type_node * next;
     meta_prop_node * prop;
     const bool is_void;
@@ -199,23 +201,15 @@ template<>
 struct meta_node<> {
     inline static meta_type_node *local = nullptr;
     inline static meta_type_node **global = &local;
-};
-
+    inline static meta_type_node *context = nullptr;
 
-template<typename Type>
-struct meta_node<Type> {
-    static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>);
+    static void reset(meta_type_node *node) ENTT_NOEXCEPT {
+        if(node->hook) {
+            *node->hook = node->next;
 
-    static void reset() ENTT_NOEXCEPT {
-        auto * const node = resolve();
-        auto **it = meta_node<>::global;
-
-        while(*it && *it != node) {
-            it = &(*it)->next;
-        }
-
-        if(*it) {
-            *it = (*it)->next;
+            if(node->next) {
+                node->next->hook = node->hook;
+            }
         }
 
         const auto unregister_all = y_combinator{
@@ -237,15 +231,28 @@ struct meta_node<Type> {
         unregister_all(&node->func, &internal::meta_func_node::prop);
 
         node->identifier = {};
-        node->dtor = nullptr;
+        node->hook = nullptr;
         node->next = nullptr;
+        node->dtor = nullptr;
     }
+};
+
+
+template<typename Type>
+struct meta_node<Type> {
+    static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>);
 
     static meta_type_node * resolve() ENTT_NOEXCEPT {
         static meta_type_node node{
+            []() {
+                auto *curr = meta_node<>::context;
+                meta_node<>::context = &node;
+                return curr;
+            }(),
             {},
             nullptr,
             nullptr,
+            nullptr,
             std::is_void_v<Type>,
             std::is_integral_v<Type>,
             std::is_floating_point_v<Type>,

+ 10 - 25
test/entt/meta/meta.cpp

@@ -2043,36 +2043,21 @@ TEST_F(Meta, Reset) {
     ASSERT_NE(*entt::internal::meta_info<>::global, nullptr);
     ASSERT_NE(entt::internal::meta_info<>::local, nullptr);
 
+    ASSERT_TRUE(entt::resolve("char"_hs));
+    ASSERT_TRUE(entt::resolve("base"_hs));
+
     entt::meta<char>().reset();
-    entt::meta<concrete_type>().reset();
-    entt::meta<setter_getter_type>().reset();
-    entt::meta<fat_type>().reset();
-    entt::meta<data_type>().reset();
-    entt::meta<func_type>().reset();
-    entt::meta<array_type>().reset();
-    entt::meta<double>().reset();
-    entt::meta<props>().reset();
-    entt::meta<base_type>().reset();
-    entt::meta<derived_type>().reset();
-    entt::meta<empty_type>().reset();
-    entt::meta<an_abstract_type>().reset();
-    entt::meta<another_abstract_type>().reset();
-    entt::meta<unsigned int>().reset();
 
-    ASSERT_EQ(*entt::internal::meta_info<>::global, nullptr);
-    ASSERT_EQ(entt::internal::meta_info<>::local, nullptr);
+    ASSERT_FALSE(entt::resolve("char"_hs));
+    ASSERT_TRUE(entt::resolve("base"_hs));
+
+    entt::meta().reset();
 
     ASSERT_FALSE(entt::resolve("char"_hs));
     ASSERT_FALSE(entt::resolve("base"_hs));
-    ASSERT_FALSE(entt::resolve("derived"_hs));
-    ASSERT_FALSE(entt::resolve("empty"_hs));
-    ASSERT_FALSE(entt::resolve("fat"_hs));
-    ASSERT_FALSE(entt::resolve("data"_hs));
-    ASSERT_FALSE(entt::resolve("func"_hs));
-    ASSERT_FALSE(entt::resolve("setter_getter"_hs));
-    ASSERT_FALSE(entt::resolve("an_abstract_type"_hs));
-    ASSERT_FALSE(entt::resolve("another_abstract_type"_hs));
-    ASSERT_FALSE(entt::resolve("concrete"_hs));
+
+    ASSERT_EQ(*entt::internal::meta_info<>::global, nullptr);
+    ASSERT_EQ(entt::internal::meta_info<>::local, nullptr);
 
     Meta::SetUpAfterUnregistration();
     entt::meta_any any{42.};

+ 1 - 1
test/lib/a_module.cpp

@@ -56,5 +56,5 @@ LIB_EXPORT void a_module_meta_init() {
 }
 
 LIB_EXPORT void a_module_meta_deinit() {
-    entt::meta<char>().reset();
+    entt::meta().reset();
 }

+ 1 - 1
test/lib/another_module.cpp

@@ -61,5 +61,5 @@ LIB_EXPORT void another_module_meta_init() {
 }
 
 LIB_EXPORT void another_module_meta_deinit() {
-    entt::meta<int>().reset();
+    entt::meta().reset();
 }

+ 1 - 1
test/lib/lib.cpp

@@ -129,8 +129,8 @@ TEST(Lib, Meta) {
     ASSERT_TRUE(entt::resolve<char>().data("c"_hs));
 
     a_module_meta_deinit();
+    entt::meta().reset();
     another_module_meta_deinit();
-    entt::meta<double>().reset();
 
     ASSERT_FALSE(entt::resolve("double"_hs));
     ASSERT_FALSE(entt::resolve("char"_hs));