瀏覽代碼

test: meta and plugins

Michele Caini 6 年之前
父節點
當前提交
84fb3694f2
共有 7 個文件被更改,包括 204 次插入41 次删除
  1. 2 3
      TODO
  2. 48 26
      src/entt/meta/factory.hpp
  3. 27 9
      src/entt/meta/meta.hpp
  4. 3 3
      test/entt/meta/meta.cpp
  5. 50 0
      test/plugin/meta/main.cpp
  6. 53 0
      test/plugin/meta/plugin.cpp
  7. 21 0
      test/plugin/meta/types.h

+ 2 - 3
TODO

@@ -29,10 +29,9 @@
       - generators as arguments to family::type overloads
       - generators to constructors
       - bind identifiers by name (as for meta)
-    * meta
-      - shared context
-      - bind<T>("name"_hs)
   - reintroduce old-fashion family and add a new family-like thing with generators
   - families should be defined as out-of-class to guarantee the same identifiers for the same types
   - update doc: family, dispatcher, emitter, registry, meta, across boundaries
   - update tests
+  - review and suppress warnings, if any
+  - remove ENTT_API from OPAQUE_TYPE

+ 48 - 26
src/entt/meta/factory.hpp

@@ -256,8 +256,8 @@ class meta_factory;
  */
 template<typename Type, typename... Spec>
 class meta_factory<Type, Spec...>: public meta_factory<Type> {
-    bool duplicate(const meta_any &key, const internal::meta_prop_node *node) ENTT_NOEXCEPT {
-        return node && (node->key() == key || duplicate(key, node->next));
+    bool exists(const meta_any &key, const internal::meta_prop_node *node) ENTT_NOEXCEPT {
+        return node && (node->key() == key || exists(key, node->next));
     }
 
     template<std::size_t Step = 0, std::size_t... Index, typename... Property, typename... Other>
@@ -309,7 +309,7 @@ class meta_factory<Type, Spec...>: public meta_factory<Type> {
             }
         };
 
-        ENTT_ASSERT(!duplicate(node.key(), *curr));
+        ENTT_ASSERT(!exists(node.key(), *curr));
         node.next = *curr;
         *curr = &node;
     }
@@ -373,13 +373,13 @@ private:
 template<typename Type>
 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));
+    bool exists(const Node *candidate, const Node *node) ENTT_NOEXCEPT {
+        return node && (node == candidate || exists(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));
+    bool exists(const ENTT_ID_TYPE identifier, const Node *node) ENTT_NOEXCEPT {
+        return node && (node->identifier == identifier || exists(identifier, node->next));
     }
 
 public:
@@ -391,11 +391,11 @@ public:
     auto type(const ENTT_ID_TYPE identifier) ENTT_NOEXCEPT {
         auto * const node = internal::meta_info<Type>::resolve();
 
-        ENTT_ASSERT(!duplicate(identifier, internal::meta_info<>::node));
-        ENTT_ASSERT(!duplicate(node, internal::meta_info<>::node));
+        ENTT_ASSERT(!exists(identifier, *internal::meta_info<>::context()));
+        ENTT_ASSERT(!exists(node, *internal::meta_info<>::context()));
         node->identifier = identifier;
-        node->next = internal::meta_info<>::node;
-        internal::meta_info<>::node = node;
+        node->next = *internal::meta_info<>::context();
+        *internal::meta_info<>::context() = node;
 
         return meta_factory<Type, Type>{&node->prop};
     }
@@ -422,7 +422,7 @@ public:
             }
         };
 
-        ENTT_ASSERT(!duplicate(&node, type->base));
+        ENTT_ASSERT(!exists(&node, type->base));
         node.next = type->base;
         type->base = &node;
 
@@ -452,7 +452,7 @@ public:
             }
         };
 
-        ENTT_ASSERT(!duplicate(&node, type->conv));
+        ENTT_ASSERT(!exists(&node, type->conv));
         node.next = type->conv;
         type->conv = &node;
 
@@ -485,7 +485,7 @@ public:
             }
         };
 
-        ENTT_ASSERT(!duplicate(&node, type->conv));
+        ENTT_ASSERT(!exists(&node, type->conv));
         node.next = type->conv;
         type->conv = &node;
 
@@ -522,7 +522,7 @@ public:
             }
         };
 
-        ENTT_ASSERT(!duplicate(&node, type->ctor));
+        ENTT_ASSERT(!exists(&node, type->ctor));
         node.next = type->ctor;
         type->ctor = &node;
 
@@ -555,7 +555,7 @@ public:
             }
         };
 
-        ENTT_ASSERT(!duplicate(&node, type->ctor));
+        ENTT_ASSERT(!exists(&node, type->ctor));
         node.next = type->ctor;
         type->ctor = &node;
 
@@ -667,8 +667,8 @@ public:
             curr = &node;
         }
 
-        ENTT_ASSERT(!duplicate(identifier, type->data));
-        ENTT_ASSERT(!duplicate(curr, type->data));
+        ENTT_ASSERT(!exists(identifier, type->data));
+        ENTT_ASSERT(!exists(curr, type->data));
         curr->identifier = identifier;
         curr->next = type->data;
         type->data = curr;
@@ -714,8 +714,8 @@ public:
             &internal::getter<Type, Getter, Policy>
         };
 
-        ENTT_ASSERT(!duplicate(identifier, type->data));
-        ENTT_ASSERT(!duplicate(&node, type->data));
+        ENTT_ASSERT(!exists(identifier, type->data));
+        ENTT_ASSERT(!exists(&node, type->data));
         node.identifier = identifier;
         node.next = type->data;
         type->data = &node;
@@ -756,8 +756,8 @@ public:
             }
         };
 
-        ENTT_ASSERT(!duplicate(identifier, type->func));
-        ENTT_ASSERT(!duplicate(&node, type->func));
+        ENTT_ASSERT(!exists(identifier, type->func));
+        ENTT_ASSERT(!exists(&node, type->func));
         node.identifier = identifier;
         node.next = type->func;
         type->func = &node;
@@ -772,10 +772,12 @@ public:
      * functions and properties, as well as its constructors, destructors and
      * conversion functions if any.<br/>
      * Base classes aren't reset but the link between the two types is removed.
+     *
+     * @return An extended meta factory for the given type.
      */
-    void reset() ENTT_NOEXCEPT {
+    auto reset() ENTT_NOEXCEPT {
         auto * const node = internal::meta_info<Type>::resolve();
-        auto **it = &internal::meta_node<>::node;
+        auto **it = internal::meta_info<>::context();
 
         while(*it && *it != node) {
             it = &(*it)->next;
@@ -806,6 +808,26 @@ public:
         node->identifier = {};
         node->next = nullptr;
         node->dtor = nullptr;
+
+        return meta_factory<Type, Type>{&node->prop};
+    }
+
+    /**
+     * @brief Imports a meta type from another context.
+     * @param identifier Unique identifier.
+     * @return An extended meta factory for the given type.
+     */
+    auto import(const ENTT_ID_TYPE identifier) ENTT_NOEXCEPT {
+        auto * const ctx = *internal::meta_info<>::context();
+
+        ENTT_ASSERT(exists(identifier, ctx));
+        ENTT_ASSERT(!exists(internal::meta_info<Type>::resolve(), ctx));
+
+        internal::meta_info<Type>::alias = internal::find_if([identifier](const auto *curr) {
+            return curr->identifier == identifier;
+        }, ctx);
+
+        return meta_factory<Type, Type>{&internal::meta_info<Type>::resolve()->prop};
     }
 };
 
@@ -848,7 +870,7 @@ inline meta_type resolve() ENTT_NOEXCEPT {
 inline meta_type resolve(const ENTT_ID_TYPE identifier) ENTT_NOEXCEPT {
     return internal::find_if([identifier](const auto *curr) {
         return curr->identifier == identifier;
-    }, internal::meta_info<>::node);
+    }, *internal::meta_info<>::context());
 }
 
 
@@ -860,7 +882,7 @@ inline meta_type resolve(const ENTT_ID_TYPE identifier) ENTT_NOEXCEPT {
 template<typename Op>
 inline std::enable_if_t<std::is_invocable_v<Op, meta_type>, void>
 resolve(Op op) {
-    internal::visit<meta_type>(std::move(op), internal::meta_info<>::node);
+    internal::visit<meta_type>(std::move(op), *internal::meta_info<>::context());
 }
 
 

+ 27 - 9
src/entt/meta/meta.hpp

@@ -192,8 +192,9 @@ bool compare(const void *lhs, const void *rhs) {
 template<typename... Type>
 struct ENTT_API meta_node {
     static_assert(std::is_same_v<Type..., std::remove_cv_t<std::remove_reference_t<Type>>...>);
+    inline static meta_type_node *alias = nullptr;
 
-    static meta_type_node * resolve() ENTT_NOEXCEPT {
+    inline static meta_type_node * resolve() ENTT_NOEXCEPT {
         static meta_type_node node{
             {},
             nullptr,
@@ -211,22 +212,23 @@ struct ENTT_API meta_node {
             std::is_member_function_pointer_v<Type...>,
             std::extent_v<Type...>,
             &compare<Type...>, // workaround for an issue with VS2017
-            []() ENTT_NOEXCEPT -> meta_type_node * {
-                return meta_node<std::remove_const_t<std::remove_pointer_t<Type>>...>::resolve();
-            },
-            []() ENTT_NOEXCEPT -> meta_type_node * {
-                return meta_node<std::remove_const_t<std::remove_extent_t<Type>>...>::resolve();
-            }
+            &meta_node<std::remove_const_t<std::remove_pointer_t<Type>>...>::resolve,
+            &meta_node<std::remove_const_t<std::remove_extent_t<Type>>...>::resolve
         };
 
-        return &node;
+        return alias ? alias : &node;
     }
 };
 
 
 template<>
 struct ENTT_API meta_node<> {
-    inline static meta_type_node *node = nullptr;
+    inline static meta_type_node **shared = nullptr;
+
+    inline static meta_type_node ** context() ENTT_NOEXCEPT {
+        static meta_type_node *local = nullptr;
+        return shared ? shared : &local;
+    }
 };
 
 
@@ -243,6 +245,22 @@ struct meta_info: meta_node<std::remove_cv_t<std::remove_reference_t<Type>>...>
  */
 
 
+/*! @brief Opaque container for a meta context. */
+struct meta_ctx {
+    /**
+     * @brief Binds the meta system to the given context.
+     * @param other A valid context to which to bind.
+     */
+    static void bind(meta_ctx other) ENTT_NOEXCEPT {
+        ENTT_ASSERT(!internal::meta_info<>::shared);
+        internal::meta_info<>::shared = other.ctx;
+    }
+
+private:
+    internal::meta_type_node **ctx{internal::meta_info<>::context()};
+};
+
+
 /**
  * @brief Opaque container for values of any type.
  *

+ 3 - 3
test/entt/meta/meta.cpp

@@ -1917,7 +1917,7 @@ TEST_F(Meta, PropertiesAndCornerCases) {
 }
 
 TEST_F(Meta, Reset) {
-    ASSERT_NE(entt::internal::meta_info<>::node, nullptr);
+    ASSERT_NE(*entt::internal::meta_info<>::context(), nullptr);
 
     entt::meta<char>().reset();
     entt::meta<concrete_type>().reset();
@@ -1935,7 +1935,7 @@ TEST_F(Meta, Reset) {
     entt::meta<another_abstract_type>().reset();
     entt::meta<unsigned int>().reset();
 
-    ASSERT_EQ(entt::internal::meta_info<>::node, nullptr);
+    ASSERT_EQ(*entt::internal::meta_info<>::context(), nullptr);
 
     ASSERT_FALSE(entt::resolve("char"_hs));
     ASSERT_FALSE(entt::resolve("base"_hs));
@@ -1949,7 +1949,7 @@ TEST_F(Meta, Reset) {
     ASSERT_FALSE(entt::resolve("another_abstract_type"_hs));
     ASSERT_FALSE(entt::resolve("concrete"_hs));
 
-    ASSERT_EQ(entt::internal::meta_info<>::node, nullptr);
+    ASSERT_EQ(*entt::internal::meta_info<>::context(), nullptr);
 
     Meta::SetUpAfterUnregistration();
     entt::meta_any any{42.};

+ 50 - 0
test/plugin/meta/main.cpp

@@ -0,0 +1,50 @@
+#define CR_HOST
+
+#include <cr.h>
+#include <gtest/gtest.h>
+#include <entt/meta/factory.hpp>
+#include <entt/meta/meta.hpp>
+#include "types.h"
+
+TEST(Lib, Meta) {
+    entt::meta<double>().type("double"_hs);
+    entt::meta<int>().type("int"_hs);
+
+    ASSERT_FALSE(entt::resolve("position"_hs));
+    ASSERT_FALSE(entt::resolve<double>().conv<int>());
+
+    userdata ud{};
+
+    cr_plugin ctx;
+    ctx.userdata = &ud;
+    cr_plugin_load(ctx, PLUGIN);
+    cr_plugin_update(ctx);
+
+    ASSERT_TRUE(entt::resolve("position"_hs));
+    ASSERT_TRUE(entt::resolve<double>().conv<int>());
+
+    auto pos = entt::resolve("position"_hs).construct(42., 3.);
+    auto vel = entt::resolve("velocity"_hs).ctor().invoke();
+
+    ASSERT_TRUE(pos && vel);
+
+    ASSERT_EQ(pos.type().data("x"_hs).type(), entt::resolve<int>());
+    ASSERT_TRUE(pos.type().data("y"_hs).get(*pos).try_cast<int>());
+    ASSERT_EQ(pos.type().data("x"_hs).get(*pos).cast<int>(), 42);
+    ASSERT_EQ(pos.type().data("y"_hs).get(*pos).cast<int>(), 3);
+
+    ASSERT_EQ(vel.type().data("dx"_hs).type(), entt::resolve<double>());
+    ASSERT_TRUE(vel.type().data("dy"_hs).get(*vel).convert<int>());
+    ASSERT_EQ(vel.type().data("dx"_hs).get(*vel).cast<double>(), 0.);
+    ASSERT_EQ(vel.type().data("dy"_hs).get(*vel).cast<double>(), 0.);
+
+    ASSERT_EQ(ud.any.type(), entt::resolve<int>());
+    ASSERT_EQ(ud.any.cast<int>(), 42);
+
+    // these objects have been initialized from a different context
+    pos.emplace<void>();
+    vel.emplace<void>();
+    ud.any.emplace<void>();
+
+    cr_plugin_close(ctx);
+}

+ 53 - 0
test/plugin/meta/plugin.cpp

@@ -0,0 +1,53 @@
+#include <cr.h>
+#include <entt/core/hashed_string.hpp>
+#include <entt/meta/factory.hpp>
+#include <entt/meta/meta.hpp>
+#include "types.h"
+
+position create_position(int x, int y) {
+    return position{x, y};
+}
+
+void set_up() {
+    entt::meta<double>().import("double"_hs);
+    entt::meta<int>().import("int"_hs);
+
+    entt::meta<double>().conv<int>();
+
+    entt::meta<position>()
+            .type("position"_hs)
+            .ctor<&create_position>()
+            .data<&position::x>("x"_hs)
+            .data<&position::y>("y"_hs);
+
+    entt::meta<velocity>()
+            .type("velocity"_hs)
+            .ctor<>()
+            .data<&velocity::dx>("dx"_hs)
+            .data<&velocity::dy>("dy"_hs);
+}
+
+void tear_down() {
+    entt::meta<position>().reset();
+    entt::meta<velocity>().reset();
+}
+
+CR_EXPORT int cr_main(cr_plugin *ctx, cr_op operation) {
+    switch (operation) {
+    case CR_LOAD:
+        entt::meta_ctx::bind(static_cast<userdata *>(ctx->userdata)->ctx);
+        set_up();
+        break;
+    case CR_STEP:
+        static_cast<userdata *>(ctx->userdata)->any = 42;
+        break;
+    case CR_UNLOAD:
+        tear_down();
+        break;
+    case CR_CLOSE:
+        // nothing to do here, this is only a test.
+        break;
+    }
+
+    return 0;
+}

+ 21 - 0
test/plugin/meta/types.h

@@ -0,0 +1,21 @@
+#ifndef ENTT_PLUGIN_META_TYPES_H
+#define ENTT_PLUGIN_META_TYPES_H
+
+#include <entt/meta/meta.hpp>
+
+struct position {
+    int x{};
+    int y{};
+};
+
+struct velocity {
+    double dx{};
+    double dy{};
+};
+
+struct userdata {
+    entt::meta_ctx ctx;
+    entt::meta_any any;
+};
+
+#endif // ENTT_PLUGIN_META_TYPES_H