* removed the possibility of invoking meta_factory::prop multiple times
* further reduced instantiations due to meta properties
This commit is contained in:
Michele Caini
2021-08-11 17:11:09 +02:00
parent c0eb6590da
commit d9494960a2
5 changed files with 59 additions and 79 deletions

1
TODO
View File

@@ -6,6 +6,7 @@
WIP:
* runtime components (registry), runtime events (dispatcher/emitter), ...
* single prop call with operator() for meta factories (to cut down instantiations)
* add constrained type policy to iterable view
* add constrained type policy to view iterators
* custom allocators all over

View File

@@ -897,29 +897,15 @@ Multiple formats are supported when it comes to defining a property:
An annotation is an invocable object that returns one or more properties. All
of them are treated individually.
It's possible to invoke the `prop` function several times if needed, one for
each property to associate with the last meta object created:
```cpp
entt::meta<my_type>()
.type("reflected_type"_hs)
.prop(entt::hashed_string{"Name"}, "Reflected Type")
.data<&my_type::data_member>("member"_hs)
.prop(std::make_pair("tooltip"_hs, "Member"))
.prop(my_enum::a_value, 42);
```
Alternatively, the `props` function is available to associate several properties
at a time. However, in this case properties in the key/value form aren't
allowed, since they would be interpreted as two different properties rather than
a single one.
Note that it's not possible to invoke `prop` multiple times for the same meta
object and trying to do that will result in a compilation error.<br/>
However, the `props` function is available to associate several properties at
once. In this case, properties in the key/value form aren't allowed, since they
would be interpreted as two different properties rather than a single one.
The meta objects for which properties are supported are currently the meta
types, meta constructors, meta data and meta functions. It's not possible to
attach properties to other types of meta objects and the factory returned as a
result of their construction won't allow such an operation.
These types offer a couple of member functions named `prop` to iterate all
types, meta constructors, meta data and meta functions.<br/>
These types also offer a couple of member functions named `prop` to iterate all
properties at once or to search a specific property by key:
```cpp

View File

@@ -114,14 +114,14 @@ public:
* @return A meta factory for the parent type.
*/
template<typename PropertyOrKey, typename... Value>
auto prop(PropertyOrKey &&property_or_key, Value &&... value) && {
meta_factory<Type> prop(PropertyOrKey &&property_or_key, Value &&... value) && {
if constexpr(sizeof...(Value) == 0) {
unroll(choice<3>, std::forward<PropertyOrKey>(property_or_key));
} else {
assign(std::forward<PropertyOrKey>(property_or_key), std::forward<Value>(value)...);
}
return meta_factory<Type, Spec..., PropertyOrKey, Value...>{ref};
return {};
}
/**
@@ -135,9 +135,9 @@ public:
* @return A meta factory for the parent type.
*/
template <typename... Property>
auto props(Property... property) && {
meta_factory<Type> props(Property... property) && {
unroll(choice<3>, std::forward<Property>(property)...);
return meta_factory<Type, Spec..., Property...>{ref};
return {};
}
private:
@@ -151,24 +151,27 @@ private:
*/
template<typename Type>
struct meta_factory<Type> {
/*! @brief Default constructor. */
meta_factory()
: owner{internal::meta_info<Type>::resolve()}
{}
/**
* @brief Makes a meta type _searchable_.
* @param id Optional unique identifier.
* @return An extended meta factory for the given type.
*/
auto type(const id_type id = type_hash<Type>::value()) {
auto * const node = internal::meta_info<Type>::resolve();
meta_range<internal::meta_type_node *, internal::meta_type_node> range{*internal::meta_context::global()};
ENTT_ASSERT(std::find_if(range.cbegin(), range.cend(), [id, node](const auto *curr) { return curr != node && curr->id == id; }) == range.cend(), "Duplicate identifier");
node->id = id;
ENTT_ASSERT(std::find_if(range.cbegin(), range.cend(), [id, this](const auto *curr) { return curr != owner && curr->id == id; }) == range.cend(), "Duplicate identifier");
owner->id = id;
if(std::find(range.cbegin(), range.cend(), node) == range.cend()) {
node->next = *internal::meta_context::global();
*internal::meta_context::global() = node;
if(std::find(range.cbegin(), range.cend(), owner) == range.cend()) {
owner->next = *internal::meta_context::global();
*internal::meta_context::global() = owner;
}
return meta_factory<Type, Type>{&node->prop};
return meta_factory<Type, Type>{&owner->prop};
}
/**
@@ -182,7 +185,6 @@ struct meta_factory<Type> {
template<typename Base>
auto base() ENTT_NOEXCEPT {
static_assert(std::is_base_of_v<Base, Type>, "Invalid base type");
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_base_node node{
nullptr,
@@ -192,9 +194,9 @@ struct meta_factory<Type> {
}
};
if(meta_range<internal::meta_base_node *, internal::meta_base_node> range{type->base}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
node.next = type->base;
type->base = &node;
if(meta_range<internal::meta_base_node *, internal::meta_base_node> range{owner->base}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
node.next = owner->base;
owner->base = &node;
}
return meta_factory<Type>{};
@@ -215,7 +217,6 @@ struct meta_factory<Type> {
template<auto Candidate>
std::enable_if_t<std::is_member_function_pointer_v<decltype(Candidate)>, meta_factory<Type>> 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{
nullptr,
@@ -225,9 +226,9 @@ struct meta_factory<Type> {
}
};
if(meta_range<internal::meta_conv_node *, internal::meta_conv_node> range{type->conv}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
node.next = type->conv;
type->conv = &node;
if(meta_range<internal::meta_conv_node *, internal::meta_conv_node> range{owner->conv}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
node.next = owner->conv;
owner->conv = &node;
}
return meta_factory<Type>{};
@@ -237,7 +238,6 @@ struct meta_factory<Type> {
template<auto Candidate>
std::enable_if_t<!std::is_member_function_pointer_v<decltype(Candidate)>, meta_factory<Type>> 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{
nullptr,
@@ -247,9 +247,9 @@ struct meta_factory<Type> {
}
};
if(meta_range<internal::meta_conv_node *, internal::meta_conv_node> range{type->conv}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
node.next = type->conv;
type->conv = &node;
if(meta_range<internal::meta_conv_node *, internal::meta_conv_node> range{owner->conv}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
node.next = owner->conv;
owner->conv = &node;
}
return meta_factory<Type>{};
@@ -267,7 +267,6 @@ struct meta_factory<Type> {
template<typename To>
auto conv() ENTT_NOEXCEPT {
static_assert(std::is_convertible_v<Type, To>, "Could not convert to the required type");
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_conv_node node{
nullptr,
@@ -277,9 +276,9 @@ struct meta_factory<Type> {
}
};
if(meta_range<internal::meta_conv_node *, internal::meta_conv_node> range{type->conv}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
node.next = type->conv;
type->conv = &node;
if(meta_range<internal::meta_conv_node *, internal::meta_conv_node> range{owner->conv}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
node.next = owner->conv;
owner->conv = &node;
}
return meta_factory<Type>{};
@@ -302,7 +301,6 @@ struct meta_factory<Type> {
auto ctor() ENTT_NOEXCEPT {
using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
static_assert(std::is_same_v<std::decay_t<typename descriptor::return_type>, Type>, "The function doesn't return an object of the required type");
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_ctor_node node{
nullptr,
@@ -312,9 +310,9 @@ struct meta_factory<Type> {
&meta_construct<Type, Candidate, Policy>
};
if(meta_range<internal::meta_ctor_node *, internal::meta_ctor_node> range{type->ctor}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
node.next = type->ctor;
type->ctor = &node;
if(meta_range<internal::meta_ctor_node *, internal::meta_ctor_node> range{owner->ctor}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
node.next = owner->ctor;
owner->ctor = &node;
}
return meta_factory<Type, std::integral_constant<decltype(Candidate), Candidate>>{&node.prop};
@@ -333,7 +331,6 @@ struct meta_factory<Type> {
template<typename... Args>
auto ctor() ENTT_NOEXCEPT {
using descriptor = meta_function_helper_t<Type, Type(*)(Args...)>;
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_ctor_node node{
nullptr,
@@ -343,9 +340,9 @@ struct meta_factory<Type> {
&meta_construct<Type, Args...>
};
if(meta_range<internal::meta_ctor_node *, internal::meta_ctor_node> range{type->ctor}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
node.next = type->ctor;
type->ctor = &node;
if(meta_range<internal::meta_ctor_node *, internal::meta_ctor_node> range{owner->ctor}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
node.next = owner->ctor;
owner->ctor = &node;
}
return meta_factory<Type, Type(Args...)>{&node.prop};
@@ -370,9 +367,8 @@ struct meta_factory<Type> {
template<auto Func>
auto dtor() ENTT_NOEXCEPT {
static_assert(std::is_invocable_v<decltype(Func), Type &>, "The function doesn't accept an object of the type provided");
auto * const type = internal::meta_info<Type>::resolve();
type->dtor = [](void *instance) {
owner->dtor = [](void *instance) {
Func(*static_cast<Type *>(instance));
};
@@ -398,7 +394,6 @@ struct meta_factory<Type> {
return data<Data, Data, Policy>(id);
} else {
using data_type = std::remove_pointer_t<decltype(Data)>;
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_data_node node{
{},
@@ -412,13 +407,13 @@ struct meta_factory<Type> {
&meta_getter<Type, Data, Policy>
};
meta_range<internal::meta_data_node *, internal::meta_data_node> range{type->data};
meta_range<internal::meta_data_node *, internal::meta_data_node> range{owner->data};
ENTT_ASSERT(std::find_if(range.cbegin(), range.cend(), [id](const auto *curr) { return curr != &node && curr->id == id; }) == range.cend(), "Duplicate identifier");
node.id = id;
if(std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
node.next = type->data;
type->data = &node;
node.next = owner->data;
owner->data = &node;
}
return meta_factory<Type, std::integral_constant<decltype(Data), Data>>{&node.prop};
@@ -448,7 +443,6 @@ struct meta_factory<Type> {
template<auto Setter, auto Getter, typename Policy = as_is_t>
auto data(const id_type id) ENTT_NOEXCEPT {
using underlying_type = std::remove_reference_t<std::invoke_result_t<decltype(Getter), Type &>>;
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_data_node node{
{},
@@ -462,13 +456,13 @@ struct meta_factory<Type> {
&meta_getter<Type, Getter, Policy>
};
meta_range<internal::meta_data_node *, internal::meta_data_node> range{type->data};
meta_range<internal::meta_data_node *, internal::meta_data_node> range{owner->data};
ENTT_ASSERT(std::find_if(range.cbegin(), range.cend(), [id](const auto *curr) { return curr != &node && curr->id == id; }) == range.cend(), "Duplicate identifier");
node.id = id;
if(std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
node.next = type->data;
type->data = &node;
node.next = owner->data;
owner->data = &node;
}
return meta_factory<Type, std::integral_constant<decltype(Setter), Setter>, std::integral_constant<decltype(Getter), Getter>>{&node.prop};
@@ -490,7 +484,6 @@ struct meta_factory<Type> {
template<auto Candidate, typename Policy = as_is_t>
auto func(const id_type id) ENTT_NOEXCEPT {
using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_func_node node{
{},
@@ -505,14 +498,14 @@ struct meta_factory<Type> {
&meta_invoke<Type, Candidate, Policy>
};
for(auto *it = &type->func; *it; it = &(*it)->next) {
for(auto *it = &owner->func; *it; it = &(*it)->next) {
if(*it == &node) {
*it = node.next;
break;
}
}
internal::meta_func_node **it = &type->func;
internal::meta_func_node **it = &owner->func;
for(; *it && (*it)->id != id; it = &(*it)->next);
for(; *it && (*it)->id == id && (*it)->arity < node.arity; it = &(*it)->next);
@@ -522,6 +515,9 @@ struct meta_factory<Type> {
return meta_factory<Type, std::integral_constant<decltype(Candidate), Candidate>>{&node.prop};
}
private:
internal::meta_type_node *owner;
};

View File

@@ -19,8 +19,7 @@ struct MetaProp: ::testing::Test {
entt::meta<base_2_t>()
.type("base_2"_hs)
.prop("bool"_hs, false)
.prop("char[]"_hs, "char[]");
.props(std::make_pair("bool"_hs, false), std::make_pair("char[]"_hs, "char[]"));
entt::meta<derived_t>()
.type("derived"_hs)

View File

@@ -1,5 +1,6 @@
#include <map>
#include <memory>
#include <utility>
#include <vector>
#include <gtest/gtest.h>
#include <entt/core/hashed_string.hpp>
@@ -130,15 +131,13 @@ struct MetaType: ::testing::Test {
entt::meta<property_t>()
.type("property"_hs)
.data<property_t::random>("random"_hs)
.prop(property_t::random, 0)
.prop(property_t::value, 3)
.props(std::make_pair(property_t::random, 0), std::make_pair(property_t::value, 3))
.data<property_t::value>("value"_hs)
.prop(std::make_tuple(std::make_pair(property_t::random, true), std::make_pair(property_t::value, 0), property_t::key_only))
.prop(property_t::list)
.props(std::make_pair(property_t::random, true), std::make_pair(property_t::value, 0), property_t::key_only, property_t::list)
.data<property_t::key_only>("key_only"_hs)
.prop([]() { return property_t::key_only; })
.data<property_t::list>("list"_hs)
.props(std::make_pair(property_t::random, false), std::make_pair(property_t::value, 0), property_t::key_only)
.props(std::make_pair(property_t::random, false), std::make_pair(property_t::value, 0), property_t::key_only)
.data<set<property_t>, get<property_t>>("var"_hs);
entt::meta<clazz_t>()
@@ -609,8 +608,7 @@ TEST_F(MetaType, ResetAndReRegistrationAfterReset) {
entt::meta<property_t>()
.type("property"_hs)
.data<property_t::random>("rand"_hs)
.prop(property_t::value, 42)
.prop(property_t::random, 3);
.props(std::make_pair(property_t::value, 42), std::make_pair(property_t::random, 3));
ASSERT_TRUE(entt::resolve<property_t>().data("rand"_hs).prop(property_t::value));
ASSERT_TRUE(entt::resolve<property_t>().data("rand"_hs).prop(property_t::random));