meta: internal review to fully support re-registration

This commit is contained in:
Michele Caini
2021-03-09 09:50:48 +01:00
parent d0b93f565a
commit 03c7dac92f
4 changed files with 92 additions and 64 deletions

View File

@@ -19,6 +19,40 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
namespace internal {
template<typename Node>
[[nodiscard]] bool find_if(const Node *candidate, const Node *node) ENTT_NOEXCEPT {
return node && (node == candidate || find_if(candidate, node->next));
}
template<typename Id, typename Node>
[[nodiscard]] bool find_if_not(const Id id, Node *node, const Node *owner) ENTT_NOEXCEPT {
if constexpr(std::is_pointer_v<Id>) {
return node && ((*node->id == *id && node != owner) || find_if_not(id, node->next, owner));
} else {
return node && ((node->id == id && node != owner) || find_if_not(id, node->next, owner));
}
}
}
/**
* Internal details not to be documented.
* @endcond
*/
/**
* @brief Meta factory to be used for reflection purposes.
*
@@ -28,7 +62,7 @@ namespace entt {
* there are no subtle errors at runtime.
*/
template<typename...>
class meta_factory;
struct meta_factory;
/**
@@ -37,11 +71,8 @@ class meta_factory;
* @tparam Spec Property specialization pack used to disambiguate overloads.
*/
template<typename Type, typename... Spec>
class meta_factory<Type, Spec...>: public meta_factory<Type> {
[[nodiscard]] bool exists(const meta_any &key, const internal::meta_prop_node *node) ENTT_NOEXCEPT {
return node && (node->key() == key || exists(key, node->next));
}
struct meta_factory<Type, Spec...>: public meta_factory<Type> {
private:
template<std::size_t Step = 0, std::size_t... Index, typename... Property, typename... Other>
void unpack(std::index_sequence<Index...>, std::tuple<Property...> property, Other &&... other) {
unroll<Step>(choice<3>, std::move(std::get<Index>(property))..., std::forward<Other>(other)...);
@@ -75,23 +106,23 @@ class meta_factory<Type, Spec...>: public meta_factory<Type> {
template<std::size_t = 0, typename Key, typename... Value>
void assign(Key &&key, Value &&... value) {
static const auto property{std::make_tuple(std::forward<Key>(key), std::forward<Value>(value)...)};
static meta_any property[1u + sizeof...(Value)]{};
static internal::meta_prop_node node{
nullptr,
[]() -> meta_any {
return meta_any{std::in_place_type<const Key &>, std::get<0>(property)};
},
[]() -> meta_any {
if constexpr(sizeof...(Value) == 0) {
return {};
} else {
return std::get<1>(property);
}
}
property,
sizeof...(Value) ? property + 1u : nullptr
};
if(!exists(node.key(), *curr)) {
entt::meta_any instance{std::forward<Key>(key)};
ENTT_ASSERT(!internal::find_if_not(&instance, *curr, &node));
property[0u] = std::move(instance);
if constexpr(sizeof...(Value) > 0) {
property[1u] = (std::forward<Value>(value), ...);
}
if(!internal::find_if(&node, *curr)) {
node.next = *curr;
*curr = &node;
}
@@ -154,18 +185,7 @@ private:
* @tparam Type Reflected type for which the factory was created.
*/
template<typename Type>
class meta_factory<Type> {
template<typename Node>
bool exists(const Node *candidate, const Node *node) ENTT_NOEXCEPT {
return node && (node == candidate || exists(candidate, node->next));
}
template<typename Node>
Node * find(const id_type id, Node *node, const Node *owner) ENTT_NOEXCEPT {
return (!node || (node->id == id && node != owner)) ? node : find(id, node->next, owner);
}
public:
struct meta_factory<Type> {
/**
* @brief Makes a meta type _searchable_.
* @param id Optional unique identifier.
@@ -174,9 +194,10 @@ public:
auto type(const id_type id = type_hash<Type>::value()) {
auto * const node = internal::meta_info<Type>::resolve();
if(!exists(node, *internal::meta_context::global())) {
ENTT_ASSERT(!find(id, *internal::meta_context::global(), node));
node->id = id;
ENTT_ASSERT(!internal::find_if_not(id, *internal::meta_context::global(), node));
node->id = id;
if(!internal::find_if(node, *internal::meta_context::global())) {
node->next = *internal::meta_context::global();
*internal::meta_context::global() = node;
}
@@ -206,7 +227,7 @@ public:
}
};
if(!exists(&node, type->base)) {
if(!internal::find_if(&node, type->base)) {
node.next = type->base;
type->base = &node;
}
@@ -237,7 +258,7 @@ public:
}
};
if(!exists(&node, type->conv)) {
if(!internal::find_if(&node, type->conv)) {
node.next = type->conv;
type->conv = &node;
}
@@ -271,7 +292,7 @@ public:
}
};
if(!exists(&node, type->conv)) {
if(!internal::find_if(&node, type->conv)) {
node.next = type->conv;
type->conv = &node;
}
@@ -311,7 +332,7 @@ public:
}
};
if(!exists(&node, type->ctor)) {
if(!internal::find_if(&node, type->ctor)) {
node.next = type->ctor;
type->ctor = &node;
}
@@ -347,7 +368,7 @@ public:
}
};
if(!exists(&node, type->ctor)) {
if(!internal::find_if(&node, type->ctor)) {
node.next = type->ctor;
type->ctor = &node;
}
@@ -418,9 +439,10 @@ public:
&meta_getter<Type, Data, Policy>
};
if(!exists(&node, type->data)) {
ENTT_ASSERT(!find(id, type->data, &node));
node.id = id;
ENTT_ASSERT(!internal::find_if_not(id, type->data, &node));
node.id = id;
if(!internal::find_if(&node, type->data)) {
node.next = type->data;
type->data = &node;
}
@@ -466,9 +488,10 @@ public:
&meta_getter<Type, Getter, Policy>
};
if(!exists(&node, type->data)) {
ENTT_ASSERT(!find(id, type->data, &node));
node.id = id;
ENTT_ASSERT(!internal::find_if_not(id, type->data, &node));
node.id = id;
if(!internal::find_if(&node, type->data)) {
node.next = type->data;
type->data = &node;
}
@@ -511,16 +534,21 @@ public:
}
};
if(!exists(&node, type->func)) {
internal::meta_func_node **it = &type->func;
for(; *it && (*it)->id != id; it = &(*it)->next);
for(; *it && (*it)->id == id && (*it)->arity < node.arity; it = &(*it)->next);
node.id = id;
node.next = *it;
*it = &node;
for(auto *it = &type->func; *it; it = &(*it)->next) {
if(*it == &node) {
*it = node.next;
break;
}
}
internal::meta_func_node **it = &type->func;
for(; *it && (*it)->id != id; it = &(*it)->next);
for(; *it && (*it)->id == id && (*it)->arity < node.arity; it = &(*it)->next);
node.id = id;
node.next = *it;
*it = &node;
return meta_factory<Type, std::integral_constant<decltype(Candidate), Candidate>>{&node.prop};
}
};

View File

@@ -647,19 +647,19 @@ struct meta_prop {
{}
/**
* @brief Returns the stored key.
* @brief Returns the stored key as a const reference.
* @return A meta any containing the key stored with the property.
*/
[[nodiscard]] meta_any key() const {
return node->key();
return node->id->as_ref();
}
/**
* @brief Returns the stored value.
* @brief Returns the stored value by copy.
* @return A meta any containing the value stored with the property.
*/
[[nodiscard]] meta_any value() const {
return node->value();
return node->value ? *node->value : meta_any{};
}
/**
@@ -751,7 +751,7 @@ struct meta_ctor {
* @return The property associated with the given key, if any.
*/
[[nodiscard]] meta_prop prop(meta_any key) const {
return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->key() == key; }, node);
return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return *curr->id == key; }, node);
}
/**
@@ -847,7 +847,7 @@ struct meta_data {
* @return The property associated with the given key, if any.
*/
[[nodiscard]] meta_prop prop(meta_any key) const {
return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->key() == key; }, node);
return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return *curr->id == key; }, node);
}
/**
@@ -966,7 +966,7 @@ struct meta_func {
* @return The property associated with the given key, if any.
*/
[[nodiscard]] meta_prop prop(meta_any key) const {
return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->key() == key; }, node);
return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return *curr->id == key; }, node);
}
/**
@@ -1474,7 +1474,7 @@ public:
* @return The property associated with the given key, if any.
*/
[[nodiscard]] meta_prop prop(meta_any key) const {
return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->key() == key; }, node);
return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return *curr->id == key; }, node);
}
/**

View File

@@ -41,8 +41,8 @@ struct meta_type_node;
struct meta_prop_node {
meta_prop_node * next;
meta_any(* const key)();
meta_any(* const value)();
const meta_any * const id;
meta_any * const value;
};

View File

@@ -651,8 +651,8 @@ 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);
.prop(property_t::value, 42)
.prop(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));