added support for free/member functions to meta_conv

This commit is contained in:
Michele Caini
2019-07-10 14:29:17 +02:00
parent 25afea4f9c
commit 0d921dc1fc
4 changed files with 84 additions and 13 deletions

6
TODO
View File

@@ -17,14 +17,10 @@
* add take functionality, eg registry.take(entity, other); where it takes the entity and all its components from registry and move them to other
* add opaque input iterators to views and groups that return tuples <entity, T &...> (proxy), multi-pass guaranteed
* add fast lane for raw iterations, extend mt doc to describe allowed add/remove with pre-allocations on fast lanes
* review 64 bit id: user defined area + dedicated member on the registry to set it
* early out in views using bitmasks with bloom filter like access based on modulus
- standard each, use bitmask to speed up the whole thing and avoid accessing the pools to test for the page
- iterator based each with a couple of iterators passed from outside (use bitmask + has)
* stable component handle that isn't affected by reallocations
* multi component registry::remove and some others?
* can I use opaque connection also for the emitter?
* built-in support for dual (or N-) buffering
* meta: opaque references and pointers
TODO
* registry::sort also for types that are part of a group (untracked items only)

View File

@@ -244,8 +244,8 @@ public:
type,
nullptr,
&internal::meta_info<To>::resolve,
[](void *instance) -> meta_any {
return static_cast<To>(*static_cast<Type *>(instance));
[](const void *instance) -> meta_any {
return static_cast<To>(*static_cast<const Type *>(instance));
},
[]() ENTT_NOEXCEPT -> meta_conv {
return &node;
@@ -260,12 +260,50 @@ public:
return *this;
}
/**
* @brief Assigns a meta conversion function to a meta type.
*
* Conversion functions can be either free functions or member
* functions.<br/>
* In case of free functions, they must accept a reference to an instance of
* the parent type as an argument. Otherwise, they must accept no arguments
* at all.
*
* @tparam Candidate The actual function to use for the conversion.
* @return A meta factory for the parent type.
*/
template<auto Candidate>
meta_factory conv() ENTT_NOEXCEPT {
using conv_type = std::invoke_result_t<decltype(Candidate), Type &>;
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,
[](const void *instance) -> meta_any {
return std::invoke(Candidate, *static_cast<const Type *>(instance));
},
[]() ENTT_NOEXCEPT -> meta_conv {
return &node;
}
};
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;
}
/**
* @brief Assigns a meta constructor to a meta type.
*
* Free functions can be assigned to meta types in the role of
* constructors. All that is required is that they return an instance of the
* underlying type.<br/>
* Free functions can be assigned to meta types in the role of constructors.
* All that is required is that they return an instance of the underlying
* type.<br/>
* From a client's point of view, nothing changes if a constructor of a meta
* type is a built-in one or a free function.
*

View File

@@ -63,7 +63,7 @@ struct meta_conv_node {
meta_type_node * const parent;
meta_conv_node * next;
meta_type_node *(* const type)() ENTT_NOEXCEPT;
meta_any(* const conv)(void *);
meta_any(* const conv)(const void *);
meta_conv(* const meta)() ENTT_NOEXCEPT;
};
@@ -982,7 +982,7 @@ public:
* @param instance The instance to convert.
* @return An opaque pointer to the instance to convert.
*/
meta_any convert(void *instance) const ENTT_NOEXCEPT {
meta_any convert(const void *instance) const ENTT_NOEXCEPT {
return node->conv(instance);
}

View File

@@ -56,6 +56,9 @@ struct derived_type: base_type {
: i{value}, c{character}
{}
int f() const { return i; }
static char g(const derived_type &type) { return type.c; }
const int i{};
const char c{};
};
@@ -144,7 +147,9 @@ struct Meta: public ::testing::Test {
entt::reflect<derived_type>("derived"_hs, std::make_pair(properties::prop_int, 99))
.base<base_type>()
.ctor<const base_type &, int, char>(std::make_pair(properties::prop_bool, false))
.ctor<&derived_factory>(std::make_pair(properties::prop_int, 42));
.ctor<&derived_factory>(std::make_pair(properties::prop_int, 42))
.conv<&derived_type::f>()
.conv<&derived_type::g>();
entt::reflect<empty_type>("empty"_hs)
.dtor<&empty_type::destroy>();
@@ -849,6 +854,38 @@ TEST_F(Meta, MetaConv) {
ASSERT_EQ(any.cast<int>(), 3);
}
TEST_F(Meta, MetaConvAsFreeFunctions) {
auto conv = entt::resolve<derived_type>().conv<int>();
derived_type derived{derived_type{}, 42, 'c'};
ASSERT_TRUE(conv);
ASSERT_NE(conv, entt::meta_conv{});
ASSERT_EQ(conv.parent(), entt::resolve<derived_type>());
ASSERT_EQ(conv.type(), entt::resolve<int>());
auto any = conv.convert(&derived);
ASSERT_TRUE(any);
ASSERT_EQ(any.type(), entt::resolve<int>());
ASSERT_EQ(any.cast<int>(), 42);
}
TEST_F(Meta, MetaConvAsMemberFunctions) {
auto conv = entt::resolve<derived_type>().conv<char>();
derived_type derived{derived_type{}, 42, 'c'};
ASSERT_TRUE(conv);
ASSERT_NE(conv, entt::meta_conv{});
ASSERT_EQ(conv.parent(), entt::resolve<derived_type>());
ASSERT_EQ(conv.type(), entt::resolve<char>());
auto any = conv.convert(&derived);
ASSERT_TRUE(any);
ASSERT_EQ(any.type(), entt::resolve<char>());
ASSERT_EQ(any.cast<char>(), 'c');
}
TEST_F(Meta, MetaCtor) {
auto ctor = entt::resolve<derived_type>().ctor<const base_type &, int, char>();