meta:
* removed the possibility of invoking meta_factory::prop multiple times * further reduced instantiations due to meta properties
This commit is contained in:
1
TODO
1
TODO
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user