* a more robust meta_any::allow_cast (reviewed all overloads)
* removed internal meta_info dispatcher to reduce useless instantiations
* reviewed meta_conversion_helper
This commit is contained in:
Michele Caini
2021-09-06 10:19:23 +02:00
parent 21bc8d4dfb
commit 2f22395eea
11 changed files with 127 additions and 64 deletions

View File

@@ -142,7 +142,7 @@ template<typename Type>
struct meta_factory<Type> {
/*! @brief Default constructor. */
meta_factory()
: owner{internal::meta_info<Type>::resolve()}
: owner{internal::meta_node<Type>::resolve()}
{}
/**
@@ -177,7 +177,7 @@ struct meta_factory<Type> {
static internal::meta_base_node node{
nullptr,
internal::meta_info<Base>::resolve(),
internal::meta_node<Base>::resolve(),
[](const void *instance) ENTT_NOEXCEPT -> const void * {
return static_cast<const Base *>(static_cast<const Type *>(instance));
}
@@ -205,11 +205,11 @@ 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 &>;
using conv_type = std::remove_const_t<std::remove_reference_t<std::invoke_result_t<decltype(Candidate), Type &>>>;
static internal::meta_conv_node node{
nullptr,
internal::meta_info<conv_type>::resolve(),
internal::meta_node<conv_type>::resolve(),
[](const void *instance) -> meta_any {
return forward_as_meta(static_cast<const Type *>(instance)->*Candidate)();
}
@@ -226,11 +226,11 @@ struct meta_factory<Type> {
/*! @copydoc conv */
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 &>;
using conv_type = std::remove_const_t<std::remove_reference_t<std::invoke_result_t<decltype(Candidate), Type &>>>;
static internal::meta_conv_node node{
nullptr,
internal::meta_info<conv_type>::resolve(),
internal::meta_node<conv_type>::resolve(),
[](const void *instance) -> meta_any {
return forward_as_meta(Candidate(*static_cast<const Type *>(instance)));
}
@@ -259,7 +259,7 @@ struct meta_factory<Type> {
static internal::meta_conv_node node{
nullptr,
internal::meta_info<To>::resolve(),
internal::meta_node<std::remove_const_t<std::remove_reference_t<To>>>::resolve(),
[](const void *instance) -> meta_any {
return forward_as_meta(static_cast<To>(*static_cast<const Type *>(instance)));
}
@@ -391,7 +391,7 @@ struct meta_factory<Type> {
internal::meta_traits::IS_NONE
| ((std::is_same_v<Type, data_type> || std::is_const_v<data_type>) ? internal::meta_traits::IS_CONST : internal::meta_traits::IS_NONE)
| internal::meta_traits::IS_STATIC,
internal::meta_info<data_type>::resolve(),
internal::meta_node<std::remove_const_t<std::remove_reference_t<data_type>>>::resolve(),
&meta_setter<Type, Data>,
&meta_getter<Type, Data, Policy>
};
@@ -431,16 +431,16 @@ 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 &>>;
using data_type = std::remove_reference_t<std::invoke_result_t<decltype(Getter), Type &>>;
static internal::meta_data_node node{
{},
nullptr,
nullptr,
internal::meta_traits::IS_NONE
| ((std::is_same_v<decltype(Setter), std::nullptr_t> || (std::is_member_object_pointer_v<decltype(Setter)> && std::is_const_v<underlying_type>)) ? internal::meta_traits::IS_CONST : internal::meta_traits::IS_NONE)
| ((std::is_same_v<decltype(Setter), std::nullptr_t> || (std::is_member_object_pointer_v<decltype(Setter)> && std::is_const_v<data_type>)) ? internal::meta_traits::IS_CONST : internal::meta_traits::IS_NONE)
/* this is never static */,
internal::meta_info<underlying_type>::resolve(),
internal::meta_node<std::remove_const_t<std::remove_reference_t<data_type>>>::resolve(),
&meta_setter<Type, Setter>,
&meta_getter<Type, Getter, Policy>
};
@@ -482,7 +482,7 @@ struct meta_factory<Type> {
internal::meta_traits::IS_NONE
| (descriptor::is_const ? internal::meta_traits::IS_CONST : internal::meta_traits::IS_NONE)
| (descriptor::is_static ? internal::meta_traits::IS_STATIC : internal::meta_traits::IS_NONE),
internal::meta_info<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, typename descriptor::return_type>>::resolve(),
internal::meta_node<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, std::remove_const_t<std::remove_reference_t<typename descriptor::return_type>>>>::resolve(),
&meta_arg<typename descriptor::args_type>,
&meta_invoke<Type, Candidate, Policy>
};
@@ -523,7 +523,7 @@ private:
*/
template<typename Type>
[[nodiscard]] auto meta() ENTT_NOEXCEPT {
auto * const node = internal::meta_info<Type>::resolve();
auto * const node = internal::meta_node<Type>::resolve();
// extended meta factory to allow assigning properties to opaque meta types
return meta_factory<Type, Type>{&node->prop};
}
@@ -577,7 +577,7 @@ inline void meta_reset(const id_type id) ENTT_NOEXCEPT {
*/
template<typename Type>
void meta_reset() ENTT_NOEXCEPT {
meta_reset(internal::meta_info<Type>::resolve()->id);
meta_reset(internal::meta_node<Type>::resolve()->id);
}

View File

@@ -47,7 +47,7 @@ public:
*/
template<typename Type>
meta_sequence_container(std::in_place_type_t<Type>, any instance) ENTT_NOEXCEPT
: value_type_node{internal::meta_info<typename Type::value_type>::resolve()},
: value_type_node{internal::meta_node<std::remove_const_t<std::remove_reference_t<typename Type::value_type>>>::resolve()},
size_fn{&meta_sequence_container_traits<Type>::size},
resize_fn{&meta_sequence_container_traits<Type>::resize},
clear_fn{&meta_sequence_container_traits<Type>::clear},
@@ -105,9 +105,9 @@ public:
template<typename Type>
meta_associative_container(std::in_place_type_t<Type>, any instance) ENTT_NOEXCEPT
: key_only_container{meta_associative_container_traits<Type>::key_only()},
key_type_node{internal::meta_info<typename Type::key_type>::resolve()},
key_type_node{internal::meta_node<std::remove_const_t<std::remove_reference_t<typename Type::key_type>>>::resolve()},
mapped_type_node{nullptr},
value_type_node{internal::meta_info<typename Type::value_type>::resolve()},
value_type_node{internal::meta_node<std::remove_const_t<std::remove_reference_t<typename Type::value_type>>>::resolve()},
size_fn{&meta_associative_container_traits<Type>::size},
clear_fn{&meta_associative_container_traits<Type>::clear},
begin_fn{&meta_associative_container_traits<Type>::begin},
@@ -118,7 +118,7 @@ public:
storage{std::move(instance)}
{
if constexpr(!meta_associative_container_traits<Type>::key_only()) {
mapped_type_node = internal::meta_info<typename Type::mapped_type>::resolve();
mapped_type_node = internal::meta_node<std::remove_const_t<std::remove_reference_t<typename Type::mapped_type>>>::resolve();
}
}
@@ -218,7 +218,7 @@ public:
template<typename Type, typename... Args>
explicit meta_any(std::in_place_type_t<Type>, Args &&... args)
: storage{std::in_place_type<Type>, std::forward<Args>(args)...},
node{internal::meta_info<Type>::resolve()},
node{internal::meta_node<std::remove_const_t<std::remove_reference_t<Type>>>::resolve()},
vtable{&basic_vtable<std::remove_const_t<std::remove_reference_t<Type>>>}
{}
@@ -230,8 +230,8 @@ public:
template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_any>>>
meta_any(Type &&value)
: storage{std::forward<Type>(value)},
node{internal::meta_info<std::decay_t<Type>>::resolve()},
vtable{&basic_vtable<std::decay_t<Type>>}
node{internal::meta_node<std::remove_const_t<std::remove_reference_t<Type>>>::resolve()},
vtable{&basic_vtable<std::remove_const_t<std::remove_reference_t<Type>>>}
{}
/**
@@ -361,9 +361,7 @@ public:
*/
template<typename Type>
[[nodiscard]] const Type * try_cast() const {
if(!node) { return nullptr; }
if(const auto info = type_id<Type>(); node->info == info) {
if(const auto info = type_id<Type>(); node && node->info == info) {
return any_cast<Type>(&storage);
} else if(const auto *base = internal::visit<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type->info == info; }, node); base) {
return static_cast<const Type *>(base->cast(storage.data()));
@@ -375,19 +373,13 @@ public:
/*! @copydoc try_cast */
template<typename Type>
[[nodiscard]] Type * try_cast() {
if constexpr(std::is_const_v<Type>) {
return std::as_const(*this).try_cast<Type>();
} else {
if(!node) { return nullptr; }
if(const auto info = type_id<Type>(); node->info == info) {
return any_cast<Type>(&storage);
} else if(const auto *base = internal::visit<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type->info == info; }, node); base) {
return const_cast<Type *>(static_cast<const Type *>(base->cast(storage.data())));
}
return nullptr;
if(const auto info = type_id<Type>(); node && node->info == info) {
return any_cast<Type>(&storage);
} else if(const auto *base = internal::visit<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type->info == info; }, node); base) {
return static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(base->cast(static_cast<constness_as_t<any, Type> &>(storage).data())));
}
return nullptr;
}
/**
@@ -440,7 +432,13 @@ public:
*/
template<typename Type>
[[nodiscard]] meta_any allow_cast() const {
return allow_cast(internal::meta_info<Type>::resolve());
const auto other = allow_cast(internal::meta_node<std::remove_const_t<std::remove_reference_t<Type>>>::resolve());
if constexpr(std::is_reference_v<Type> && !std::is_const_v<std::remove_reference_t<Type>>) {
return other.storage.owner() ? other : meta_any{};
} else {
return other;
}
}
/**
@@ -450,7 +448,20 @@ public:
*/
template<typename Type>
bool allow_cast() {
return allow_cast(internal::meta_info<Type>::resolve());
if constexpr(std::is_reference_v<Type> && !std::is_const_v<std::remove_reference_t<Type>>) {
if(auto other = std::as_const(*this).allow_cast(internal::meta_node<std::remove_const_t<std::remove_reference_t<Type>>>::resolve()); other) {
if(other.storage.owner()) {
std::swap(*this, other);
return true;
}
return (storage.data() != nullptr);
}
return false;
} else {
return allow_cast(internal::meta_node<std::remove_const_t<std::remove_reference_t<Type>>>::resolve());
}
}
/**
@@ -464,7 +475,7 @@ public:
release();
vtable = &basic_vtable<std::remove_const_t<std::remove_reference_t<Type>>>;
storage.emplace<Type>(std::forward<Args>(args)...);
node = internal::meta_info<Type>::resolve();
node = internal::meta_node<std::remove_const_t<std::remove_reference_t<Type>>>::resolve();
}
/*! @brief Destroys contained object */
@@ -1045,7 +1056,7 @@ class meta_type {
template<typename... Args, auto... Index>
[[nodiscard]] static const internal::meta_ctor_node * ctor(const internal::meta_ctor_node *curr, std::index_sequence<Index...>) {
for(; curr; curr = curr->next) {
if(curr->arity == sizeof...(Args) && (can_cast_or_convert(internal::meta_info<Args>::resolve(), curr->arg(Index)) && ...)) {
if(curr->arity == sizeof...(Args) && (can_cast_or_convert(internal::meta_node<std::remove_const_t<std::remove_reference_t<Args>>>::resolve(), curr->arg(Index)) && ...)) {
return curr;
}
}
@@ -1501,18 +1512,15 @@ bool meta_any::set(const id_type id, Type &&value) {
[[nodiscard]] inline meta_any meta_any::allow_cast(const meta_type &type) const {
if(!node) { return {}; }
if(const auto info = type.info(); node->info == info || internal::visit<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type->info == info; }, node)) {
if(const auto info = type.info(); (node && node->info == info) || internal::visit<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type->info == info; }, node)) {
return as_ref();
} else if(const auto * const conv = internal::visit<&internal::meta_type_node::conv>([info](const auto *curr) { return curr->type->info == info; }, node); conv) {
return conv->conv(storage.data());
} else if((type.is_arithmetic() || type.is_enum()) && node->conversion_helper) {
} else if(node && node->conversion_helper && (type.is_arithmetic() || type.is_enum())) {
// exploits the fact that arithmetic types and enums are also default constructible
auto other = type.construct();
const double value = node->conversion_helper(storage, nullptr);
ENTT_ASSERT(other.node->conversion_helper, "Conversion helper not found");
other.node->conversion_helper(other.storage, &value);
other.node->conversion_helper(other.storage, node->conversion_helper(storage, {}));
return other;
}
@@ -1523,7 +1531,7 @@ bool meta_any::set(const id_type id, Type &&value) {
inline bool meta_any::allow_cast(const meta_type &type) {
if(auto other = std::as_const(*this).allow_cast(type); other) {
if(other.storage.owner()) {
*this = std::move(other);
std::swap(*this, other);
}
return true;

View File

@@ -122,7 +122,7 @@ struct meta_type_node {
const size_type size_of;
const meta_traits traits;
meta_any(* const default_constructor)();
double(* const conversion_helper)(const any &, const double *);
double(* const conversion_helper)(const any &, const any &);
const meta_template_node *const templ;
meta_ctor_node *ctor{nullptr};
meta_base_node *base{nullptr};
@@ -151,12 +151,12 @@ class ENTT_API meta_node {
[[nodiscard]] static decltype(meta_type_node::conversion_helper) meta_conversion_helper() ENTT_NOEXCEPT {
if constexpr(std::is_arithmetic_v<Type>) {
return +[](const any &storage, const double *value) {
return value ? static_cast<double>(any_cast<Type &>(const_cast<any &>(storage)) = static_cast<Type>(*value)) : static_cast<double>(any_cast<const Type &>(storage));
return +[](const any &storage, const any &value) {
return value ? static_cast<double>(any_cast<Type &>(const_cast<any &>(storage)) = static_cast<Type>(any_cast<double>(value))) : static_cast<double>(any_cast<const Type &>(storage));
};
} else if constexpr(std::is_enum_v<Type>) {
return +[](const any &storage, const double *value) {
return value ? static_cast<double>(any_cast<Type &>(const_cast<any &>(storage)) = Type{static_cast<std::underlying_type_t<Type>>(*value)}) : static_cast<double>(any_cast<const Type &>(storage));
return +[](const any &storage, const any &value) {
return value ? static_cast<double>(any_cast<Type &>(const_cast<any &>(storage)) = Type{static_cast<std::underlying_type_t<Type>>(any_cast<double>(value))}) : static_cast<double>(any_cast<const Type &>(storage));
};
} else {
return nullptr;
@@ -206,13 +206,9 @@ public:
};
template<typename Type>
struct meta_info: meta_node<std::remove_cv_t<std::remove_reference_t<Type>>> {};
template<typename... Args>
[[nodiscard]] meta_type_node * meta_arg_node(type_list<Args...>, const std::size_t index) ENTT_NOEXCEPT {
meta_type_node *args[sizeof...(Args) + 1u]{nullptr, internal::meta_info<Args>::resolve()...};
meta_type_node *args[sizeof...(Args) + 1u]{nullptr, internal::meta_node<std::remove_const_t<std::remove_reference_t<Args>>>::resolve()...};
return args[index + 1u];
}

View File

@@ -20,7 +20,7 @@ namespace entt {
*/
template<typename Type>
[[nodiscard]] meta_type resolve() ENTT_NOEXCEPT {
return internal::meta_info<Type>::resolve();
return internal::meta_node<std::remove_const_t<std::remove_reference_t<Type>>>::resolve();
}

View File

@@ -804,6 +804,7 @@ TEST_F(MetaAny, TryCast) {
ASSERT_EQ(any.try_cast<fat_t>(), any.data());
ASSERT_EQ(std::as_const(any).try_cast<empty_t>(), any.try_cast<empty_t>());
ASSERT_EQ(std::as_const(any).try_cast<fat_t>(), any.data());
ASSERT_EQ(std::as_const(any).try_cast<int>(), nullptr);
}
TEST_F(MetaAny, Cast) {
@@ -823,6 +824,64 @@ TEST_F(MetaAny, Cast) {
ASSERT_EQ(any.cast<fat_t>().value[0u], 3.);
}
TEST_F(MetaAny, AllowCast) {
entt::meta_any clazz{clazz_t{}};
entt::meta_any fat{fat_t{}};
entt::meta_any arithmetic{42};
auto as_cref = entt::forward_as_meta(arithmetic.cast<const int &>());
ASSERT_TRUE(clazz);
ASSERT_TRUE(fat);
ASSERT_TRUE(arithmetic);
ASSERT_TRUE(as_cref);
ASSERT_TRUE(clazz.allow_cast<clazz_t>());
ASSERT_TRUE(clazz.allow_cast<clazz_t &>());
ASSERT_TRUE(clazz.allow_cast<const clazz_t &>());
ASSERT_EQ(clazz.type(), entt::resolve<clazz_t>());
ASSERT_TRUE(clazz.allow_cast<const int &>());
ASSERT_EQ(clazz.type(), entt::resolve<int>());
ASSERT_TRUE(clazz.allow_cast<int>());
ASSERT_TRUE(clazz.allow_cast<int &>());
ASSERT_TRUE(clazz.allow_cast<const int &>());
ASSERT_TRUE(fat.allow_cast<fat_t>());
ASSERT_TRUE(fat.allow_cast<fat_t &>());
ASSERT_TRUE(fat.allow_cast<const empty_t &>());
ASSERT_EQ(fat.type(), entt::resolve<fat_t>());
ASSERT_FALSE(fat.allow_cast<int>());
ASSERT_TRUE(std::as_const(fat).allow_cast<fat_t>());
ASSERT_FALSE(std::as_const(fat).allow_cast<fat_t &>());
ASSERT_TRUE(std::as_const(fat).allow_cast<const empty_t &>());
ASSERT_EQ(fat.type(), entt::resolve<fat_t>());
ASSERT_FALSE(fat.allow_cast<int>());
ASSERT_TRUE(arithmetic.allow_cast<int>());
ASSERT_TRUE(arithmetic.allow_cast<int &>());
ASSERT_TRUE(arithmetic.allow_cast<const int &>());
ASSERT_EQ(arithmetic.type(), entt::resolve<int>());
ASSERT_FALSE(arithmetic.allow_cast<fat_t>());
ASSERT_TRUE(arithmetic.allow_cast<double &>());
ASSERT_EQ(arithmetic.type(), entt::resolve<double>());
ASSERT_EQ(arithmetic.cast<double &>(), 42.);
ASSERT_TRUE(arithmetic.allow_cast<const float &>());
ASSERT_EQ(arithmetic.type(), entt::resolve<float>());
ASSERT_EQ(arithmetic.cast<float &>(), 42.f);
ASSERT_TRUE(as_cref.allow_cast<int>());
ASSERT_FALSE(as_cref.allow_cast<int &>());
ASSERT_TRUE(as_cref.allow_cast<const int &>());
ASSERT_EQ(as_cref.type(), entt::resolve<int>());
ASSERT_FALSE(as_cref.allow_cast<fat_t>());
ASSERT_TRUE(as_cref.allow_cast<double &>());
ASSERT_EQ(as_cref.type(), entt::resolve<double>());
}
TEST_F(MetaAny, Convert) {
entt::meta_any any{clazz_t{}};
any.cast<clazz_t &>().value = 42;

View File

@@ -48,7 +48,7 @@ TEST_F(MetaBase, Functionalities) {
TEST_F(MetaBase, ReRegistration) {
SetUp();
auto *node = entt::internal::meta_info<derived_t>::resolve();
auto *node = entt::internal::meta_node<derived_t>::resolve();
ASSERT_NE(node->base, nullptr);
ASSERT_EQ(node->base->next, nullptr);

View File

@@ -49,7 +49,7 @@ TEST_F(MetaConv, Functionalities) {
TEST_F(MetaConv, ReRegistration) {
SetUp();
auto *node = entt::internal::meta_info<clazz_t>::resolve();
auto *node = entt::internal::meta_node<clazz_t>::resolve();
ASSERT_NE(node->conv, nullptr);
ASSERT_NE(node->conv->next, nullptr);

View File

@@ -281,7 +281,7 @@ TEST_F(MetaCtor, NonDefaultConstructibleType) {
TEST_F(MetaCtor, ReRegistration) {
SetUp();
auto *node = entt::internal::meta_info<double>::resolve();
auto *node = entt::internal::meta_node<double>::resolve();
ASSERT_NE(node->ctor, nullptr);
// implicitly generated default constructor is not cleared

View File

@@ -543,7 +543,7 @@ TEST_F(MetaData, ReRegistration) {
SetUp();
auto *node = entt::internal::meta_info<base_t>::resolve();
auto *node = entt::internal::meta_node<base_t>::resolve();
auto type = entt::resolve<base_t>();
ASSERT_NE(node->data, nullptr);

View File

@@ -100,7 +100,7 @@ TEST_F(MetaDtor, AsRefConstruction) {
TEST_F(MetaDtor, ReRegistration) {
SetUp();
auto *node = entt::internal::meta_info<clazz_t>::resolve();
auto *node = entt::internal::meta_node<clazz_t>::resolve();
ASSERT_NE(node->dtor, nullptr);

View File

@@ -72,7 +72,7 @@ TEST_F(MetaProp, ReRegistration) {
SetUp();
auto *node = entt::internal::meta_info<base_1_t>::resolve();
auto *node = entt::internal::meta_node<base_1_t>::resolve();
auto type = entt::resolve<base_1_t>();
ASSERT_NE(node->prop, nullptr);