meta: added underlying context

This commit is contained in:
Michele Caini
2019-10-07 15:35:18 +02:00
parent 75105dc1fc
commit 86e056a736
3 changed files with 150 additions and 136 deletions

View File

@@ -9,7 +9,6 @@
#include <functional>
#include <type_traits>
#include "../config/config.h"
#include "../core/utility.hpp"
#include "policy.hpp"
#include "meta.hpp"
@@ -304,10 +303,10 @@ public:
node->identifier = identifier;
node->prop = properties<Type>(std::forward<Property>(property)...);
ENTT_ASSERT(!duplicate(identifier, internal::meta_info<>::type));
ENTT_ASSERT(!duplicate(node, internal::meta_info<>::type));
node->next = internal::meta_info<>::type;
internal::meta_info<>::type = node;
ENTT_ASSERT(!duplicate(identifier, *internal::meta_info<>::ctx));
ENTT_ASSERT(!duplicate(node, *internal::meta_info<>::ctx));
node->next = *internal::meta_info<>::ctx;
*internal::meta_info<>::ctx = node;
return *this;
}
@@ -710,38 +709,7 @@ public:
* removed.
*/
void unregister() ENTT_NOEXCEPT {
auto * const node = internal::meta_info<Type>::resolve();
auto **curr = &internal::meta_info<>::type;
while(*curr && *curr != node) {
curr = &(*curr)->next;
}
if(*curr) {
*curr = (*curr)->next;
}
const auto unregister_all = y_combinator{
[](auto &&self, auto **node, auto... member) {
while(*node) {
auto *curr = *node;
(self(&(curr->*member)), ...);
*node = curr->next;
curr->next = nullptr;
}
}
};
unregister_all(&node->prop);
unregister_all(&node->base);
unregister_all(&node->conv);
unregister_all(&node->ctor, &internal::meta_ctor_node::prop);
unregister_all(&node->data, &internal::meta_data_node::prop);
unregister_all(&node->func, &internal::meta_func_node::prop);
node->dtor = nullptr;
node->identifier = {};
node->next = nullptr;
internal::meta_info<Type>::reset();
}
};
@@ -819,7 +787,7 @@ inline meta_type resolve() ENTT_NOEXCEPT {
inline meta_type resolve(const ENTT_ID_TYPE identifier) ENTT_NOEXCEPT {
return internal::find_if([identifier](auto *node) {
return node->identifier == identifier;
}, internal::meta_info<>::type);
}, *internal::meta_info<>::ctx);
}
@@ -831,7 +799,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) ENTT_NOEXCEPT {
internal::iterate<meta_type>(std::move(op), internal::meta_info<>::type);
internal::iterate<meta_type>(std::move(op), *internal::meta_info<>::ctx);
}

View File

@@ -10,6 +10,7 @@
#include <type_traits>
#include "../config/config.h"
#include "../core/type_traits.hpp"
#include "../core/utility.hpp"
namespace entt {
@@ -17,7 +18,7 @@ namespace entt {
class meta_any;
class meta_handle;
struct meta_type;
class meta_type;
/**
@@ -128,60 +129,6 @@ struct meta_type_node {
};
template<typename...>
struct meta_node;
template<>
struct meta_node<> {
inline static meta_type_node *type = nullptr;
};
template<typename Type>
static bool compare(const void *lhs, const void *rhs) {
if constexpr(!std::is_function_v<Type> && is_equality_comparable_v<Type>) {
return *static_cast<const Type *>(lhs) == *static_cast<const Type *>(rhs);
} else {
return lhs == rhs;
}
}
template<typename Type>
struct meta_node<Type> {
static meta_type_node * resolve() ENTT_NOEXCEPT {
static meta_type_node node{
{},
nullptr,
nullptr,
std::is_void_v<Type>,
std::is_integral_v<Type>,
std::is_floating_point_v<Type>,
std::is_array_v<Type>,
std::is_enum_v<Type>,
std::is_union_v<Type>,
std::is_class_v<Type>,
std::is_pointer_v<Type>,
std::is_pointer_v<Type> && std::is_function_v<std::remove_pointer_t<Type>>,
std::is_member_object_pointer_v<Type>,
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();
}
};
return &node;
}
};
template<typename... Type>
struct meta_info: meta_node<std::remove_cv_t<std::remove_reference_t<Type>>...> {};
template<typename Type, typename Op, typename Node>
void iterate(Op op, const Node *curr) ENTT_NOEXCEPT {
while(curr) {
@@ -235,42 +182,110 @@ auto find_if(Op op, const meta_type_node *node) ENTT_NOEXCEPT
template<typename Type>
const Type * try_cast(const meta_type_node *node, void *instance) ENTT_NOEXCEPT {
const auto * const type = meta_info<Type>::resolve();
void *ret = nullptr;
if(node == type) {
ret = instance;
static bool compare(const void *lhs, const void *rhs) {
if constexpr(!std::is_function_v<Type> && is_equality_comparable_v<Type>) {
return *static_cast<const Type *>(lhs) == *static_cast<const Type *>(rhs);
} else {
const auto *base = find_if<&meta_type_node::base>([type](auto *candidate) {
return candidate->type() == type;
}, node);
return lhs == rhs;
}
}
ret = base ? base->cast(instance) : nullptr;
template<typename...>
struct meta_node;
template<>
struct meta_node<> {
inline static meta_type_node *local = nullptr;
inline static meta_type_node **ctx = &local;
};
template<typename Type>
struct meta_node<Type> {
static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>);
inline static meta_type_node *type = nullptr;
static void reset() ENTT_NOEXCEPT {
auto * const node = type ? type : resolve();
auto **curr = meta_node<>::ctx;
while(*curr && *curr != node) {
curr = &(*curr)->next;
}
if(*curr) {
*curr = (*curr)->next;
}
const auto unregister_all = y_combinator{
[](auto &&self, auto **node, auto... member) {
while(*node) {
auto *curr = *node;
(self(&(curr->*member)), ...);
*node = curr->next;
curr->next = nullptr;
}
}
};
unregister_all(&node->prop);
unregister_all(&node->base);
unregister_all(&node->conv);
unregister_all(&node->ctor, &internal::meta_ctor_node::prop);
unregister_all(&node->data, &internal::meta_data_node::prop);
unregister_all(&node->func, &internal::meta_func_node::prop);
node->identifier = {};
node->dtor = nullptr;
node->next = nullptr;
type = nullptr;
}
return static_cast<const Type *>(ret);
}
static meta_type_node * resolve() ENTT_NOEXCEPT {
static meta_type_node node{
{},
nullptr,
nullptr,
std::is_void_v<Type>,
std::is_integral_v<Type>,
std::is_floating_point_v<Type>,
std::is_array_v<Type>,
std::is_enum_v<Type>,
std::is_union_v<Type>,
std::is_class_v<Type>,
std::is_pointer_v<Type>,
std::is_pointer_v<Type> && std::is_function_v<std::remove_pointer_t<Type>>,
std::is_member_object_pointer_v<Type>,
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();
}
};
if(!type) {
if constexpr(is_named_type_v<Type>) {
iterate<meta_type_node>([](const auto *node) {
if(node->identifer == named_type_traits<Type>::value) {
type = node;
}
}, *meta_node<>::ctx);
} else {
type = &node;
}
}
return type;
}
};
template<auto Member>
inline bool can_cast_or_convert(const meta_type_node *from, const meta_type_node *to) ENTT_NOEXCEPT {
return (from == to) || find_if<Member>([to](auto *node) {
return node->type() == to;
}, from);
}
template<typename... Args, std::size_t... Indexes>
inline auto ctor(std::index_sequence<Indexes...>, const meta_type_node *node) ENTT_NOEXCEPT {
return internal::find_if([](auto *candidate) {
return candidate->size == sizeof...(Args) &&
(([](auto *from, auto *to) {
return internal::can_cast_or_convert<&internal::meta_type_node::base>(from, to)
|| internal::can_cast_or_convert<&internal::meta_type_node::conv>(from, to);
}(internal::meta_info<Args>::resolve(), candidate->arg(Indexes))) && ...);
}, node->ctor);
}
template<typename... Type>
struct meta_info: meta_node<std::remove_cv_t<std::remove_reference_t<Type>>...> {};
}
@@ -511,7 +526,20 @@ public:
*/
template<typename Type>
const Type * try_cast() const ENTT_NOEXCEPT {
return internal::try_cast<Type>(node, instance);
const auto * const type = internal::meta_info<Type>::resolve();
void *ret = nullptr;
if(node == type) {
ret = instance;
} else {
const auto *base = internal::find_if<&internal::meta_type_node::base>([type](auto *candidate) {
return candidate->type() == type;
}, node);
ret = base ? base->cast(instance) : nullptr;
}
return static_cast<const Type *>(ret);
}
/*! @copydoc try_cast */
@@ -599,7 +627,7 @@ public:
* @param args Parameters to use to construct the instance.
*/
template<typename Type, typename... Args>
void emplace(Args&& ... args) {
void emplace(Args &&... args) {
*this = meta_any{std::in_place_type_t<Type>{}, std::forward<Args>(args)...};
}
@@ -1330,7 +1358,18 @@ inline bool operator!=(const meta_func &lhs, const meta_func &rhs) ENTT_NOEXCEPT
/*! @brief Opaque container for meta types. */
struct meta_type {
class meta_type {
template<typename... Args, std::size_t... Indexes>
auto ctor(std::index_sequence<Indexes...>, const internal::meta_type_node *node) const ENTT_NOEXCEPT {
return internal::find_if([](auto *candidate) {
return candidate->size == sizeof...(Args) && ([](auto *from, auto *to) {
return (from == to) || internal::find_if<&internal::meta_type_node::base>([to](auto *node) { return node->type() == to; }, from)
|| internal::find_if<&internal::meta_type_node::conv>([to](auto *node) { return node->type() == to; }, from);
}(internal::meta_info<Args>::resolve(), candidate->arg(Indexes)) && ...);
}, node->ctor);
}
public:
/*! @brief Unsigned integer type. */
using size_type = typename internal::meta_type_node::size_type;
@@ -1540,7 +1579,7 @@ struct meta_type {
*/
template<typename... Args>
meta_ctor ctor() const ENTT_NOEXCEPT {
return internal::ctor<Args...>(std::make_index_sequence<sizeof...(Args)>{}, node);
return ctor<Args...>(std::make_index_sequence<sizeof...(Args)>{}, node);
}
/**

View File

@@ -1969,20 +1969,27 @@ TEST_F(Meta, Variables) {
}
TEST_F(Meta, Unregister) {
entt::unregister<double>();
ASSERT_NE(*entt::internal::meta_info<>::ctx, nullptr);
ASSERT_NE(entt::internal::meta_info<>::local, nullptr);
entt::unregister<char>();
entt::unregister<properties>();
entt::unregister<unsigned int>();
entt::unregister<base_type>();
entt::unregister<derived_type>();
entt::unregister<empty_type>();
entt::unregister<concrete_type>();
entt::unregister<setter_getter_type>();
entt::unregister<fat_type>();
entt::unregister<data_type>();
entt::unregister<func_type>();
entt::unregister<setter_getter_type>();
entt::unregister<array_type>();
entt::unregister<double>();
entt::unregister<properties>();
entt::unregister<base_type>();
entt::unregister<derived_type>();
entt::unregister<empty_type>();
entt::unregister<an_abstract_type>();
entt::unregister<another_abstract_type>();
entt::unregister<concrete_type>();
entt::unregister<unsigned int>();
ASSERT_EQ(*entt::internal::meta_info<>::ctx, nullptr);
ASSERT_EQ(entt::internal::meta_info<>::local, nullptr);
ASSERT_FALSE(entt::resolve("char"_hs));
ASSERT_FALSE(entt::resolve("base"_hs));