test: meta and plugins
This commit is contained in:
5
TODO
5
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
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user