From 84fb3694f2907d04710430ea2b86cabe5bb1c653 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Mon, 9 Dec 2019 14:56:19 +0100 Subject: [PATCH] test: meta and plugins --- TODO | 5 +-- src/entt/meta/factory.hpp | 74 ++++++++++++++++++++++++------------- src/entt/meta/meta.hpp | 36 +++++++++++++----- test/entt/meta/meta.cpp | 6 +-- test/plugin/meta/main.cpp | 50 +++++++++++++++++++++++++ test/plugin/meta/plugin.cpp | 53 ++++++++++++++++++++++++++ test/plugin/meta/types.h | 21 +++++++++++ 7 files changed, 204 insertions(+), 41 deletions(-) diff --git a/TODO b/TODO index a9eb60450..eb71cd852 100644 --- a/TODO +++ b/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("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 diff --git a/src/entt/meta/factory.hpp b/src/entt/meta/factory.hpp index 70d136510..9be727ce5 100644 --- a/src/entt/meta/factory.hpp +++ b/src/entt/meta/factory.hpp @@ -256,8 +256,8 @@ class meta_factory; */ template class meta_factory: public meta_factory { - 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 @@ -309,7 +309,7 @@ class meta_factory: public meta_factory { } }; - ENTT_ASSERT(!duplicate(node.key(), *curr)); + ENTT_ASSERT(!exists(node.key(), *curr)); node.next = *curr; *curr = &node; } @@ -373,13 +373,13 @@ private: template class meta_factory { template - 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 - 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::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{&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 }; - 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.
* 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::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{&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::resolve(), ctx)); + + internal::meta_info::alias = internal::find_if([identifier](const auto *curr) { + return curr->identifier == identifier; + }, ctx); + + return meta_factory{&internal::meta_info::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 inline std::enable_if_t, void> resolve(Op op) { - internal::visit(std::move(op), internal::meta_info<>::node); + internal::visit(std::move(op), *internal::meta_info<>::context()); } diff --git a/src/entt/meta/meta.hpp b/src/entt/meta/meta.hpp index de057370f..0fa8d813e 100644 --- a/src/entt/meta/meta.hpp +++ b/src/entt/meta/meta.hpp @@ -192,8 +192,9 @@ bool compare(const void *lhs, const void *rhs) { template struct ENTT_API meta_node { static_assert(std::is_same_v>...>); + 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, std::extent_v, &compare, // workaround for an issue with VS2017 - []() ENTT_NOEXCEPT -> meta_type_node * { - return meta_node>...>::resolve(); - }, - []() ENTT_NOEXCEPT -> meta_type_node * { - return meta_node>...>::resolve(); - } + &meta_node>...>::resolve, + &meta_node>...>::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>...> */ +/*! @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. * diff --git a/test/entt/meta/meta.cpp b/test/entt/meta/meta.cpp index 0a7f74df6..d163775d1 100644 --- a/test/entt/meta/meta.cpp +++ b/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().reset(); entt::meta().reset(); @@ -1935,7 +1935,7 @@ TEST_F(Meta, Reset) { entt::meta().reset(); entt::meta().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.}; diff --git a/test/plugin/meta/main.cpp b/test/plugin/meta/main.cpp index e69de29bb..f731b73ff 100644 --- a/test/plugin/meta/main.cpp +++ b/test/plugin/meta/main.cpp @@ -0,0 +1,50 @@ +#define CR_HOST + +#include +#include +#include +#include +#include "types.h" + +TEST(Lib, Meta) { + entt::meta().type("double"_hs); + entt::meta().type("int"_hs); + + ASSERT_FALSE(entt::resolve("position"_hs)); + ASSERT_FALSE(entt::resolve().conv()); + + 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().conv()); + + 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()); + ASSERT_TRUE(pos.type().data("y"_hs).get(*pos).try_cast()); + ASSERT_EQ(pos.type().data("x"_hs).get(*pos).cast(), 42); + ASSERT_EQ(pos.type().data("y"_hs).get(*pos).cast(), 3); + + ASSERT_EQ(vel.type().data("dx"_hs).type(), entt::resolve()); + ASSERT_TRUE(vel.type().data("dy"_hs).get(*vel).convert()); + ASSERT_EQ(vel.type().data("dx"_hs).get(*vel).cast(), 0.); + ASSERT_EQ(vel.type().data("dy"_hs).get(*vel).cast(), 0.); + + ASSERT_EQ(ud.any.type(), entt::resolve()); + ASSERT_EQ(ud.any.cast(), 42); + + // these objects have been initialized from a different context + pos.emplace(); + vel.emplace(); + ud.any.emplace(); + + cr_plugin_close(ctx); +} diff --git a/test/plugin/meta/plugin.cpp b/test/plugin/meta/plugin.cpp index e69de29bb..910b1ad22 100644 --- a/test/plugin/meta/plugin.cpp +++ b/test/plugin/meta/plugin.cpp @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include "types.h" + +position create_position(int x, int y) { + return position{x, y}; +} + +void set_up() { + entt::meta().import("double"_hs); + entt::meta().import("int"_hs); + + entt::meta().conv(); + + entt::meta() + .type("position"_hs) + .ctor<&create_position>() + .data<&position::x>("x"_hs) + .data<&position::y>("y"_hs); + + entt::meta() + .type("velocity"_hs) + .ctor<>() + .data<&velocity::dx>("dx"_hs) + .data<&velocity::dy>("dy"_hs); +} + +void tear_down() { + entt::meta().reset(); + entt::meta().reset(); +} + +CR_EXPORT int cr_main(cr_plugin *ctx, cr_op operation) { + switch (operation) { + case CR_LOAD: + entt::meta_ctx::bind(static_cast(ctx->userdata)->ctx); + set_up(); + break; + case CR_STEP: + static_cast(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; +} diff --git a/test/plugin/meta/types.h b/test/plugin/meta/types.h index e69de29bb..f6a1e67d6 100644 --- a/test/plugin/meta/types.h +++ b/test/plugin/meta/types.h @@ -0,0 +1,21 @@ +#ifndef ENTT_PLUGIN_META_TYPES_H +#define ENTT_PLUGIN_META_TYPES_H + +#include + +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