meta: make meta_any::allow_cast work with mutating this pointers

This commit is contained in:
Michele Caini
2021-09-29 09:49:22 +02:00
parent 6030f56c76
commit e835ce0697
2 changed files with 69 additions and 11 deletions
+24 -10
View File
@@ -1393,17 +1393,31 @@ bool meta_any::set(const id_type id, Type &&value) {
}
[[nodiscard]] inline meta_any meta_any::allow_cast(const meta_type &type) const {
if(const auto &info = type.info(); (node && *node->info == info) || internal::find_by<&internal::meta_type_node::base>(info, node)) {
if(const auto &info = type.info(); node && *node->info == info) {
return as_ref();
} else if(const auto *const conv = internal::find_by<&internal::meta_type_node::conv>(info, node); conv) {
return conv->conv(*this);
} 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();
ENTT_ASSERT(other.node->conversion_helper, "Conversion helper not found");
const auto value = node->conversion_helper(nullptr, storage.data());
other.node->conversion_helper(other.storage.data(), &value);
return other;
} else if(node) {
for(auto *it = node->conv; it; it = it->next) {
if(*it->type->info == info) {
return it->conv(*this);
}
}
if(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();
ENTT_ASSERT(other.node->conversion_helper, "Conversion helper not found");
const auto value = node->conversion_helper(nullptr, storage.data());
other.node->conversion_helper(other.storage.data(), &value);
return other;
}
for(auto *it = node->base; it; it = it->next) {
const auto as_const = it->cast(as_ref());
if(auto other = as_const.allow_cast(type); other) {
return other;
}
}
}
return {};
+45 -1
View File
@@ -11,6 +11,11 @@ struct base_1_t {
struct base_2_t {
base_2_t() = default;
operator int() const {
return value_2;
}
int value_2{};
};
@@ -32,6 +37,7 @@ struct MetaBase: ::testing::Test {
.data<&base_1_t::value_1>("value_1"_hs);
entt::meta<base_2_t>()
.conv<int>()
.data<&base_2_t::value_2>("value_2"_hs);
entt::meta<base_3_t>()
@@ -68,7 +74,7 @@ TEST_F(MetaBase, Functionalities) {
ASSERT_EQ(any.cast<const base_1_t &>().value_1, as_derived.cast<const derived_t &>().value_1);
}
TEST_F(MetaBase, ThisIsNotThis) {
TEST_F(MetaBase, SetGetWithMutatingThis) {
using namespace entt::literals;
derived_t instance;
@@ -106,6 +112,44 @@ TEST_F(MetaBase, ThisIsNotThis) {
ASSERT_EQ(instance.value_3, 3);
}
TEST_F(MetaBase, ConvWithMutatingThis) {
entt::meta_any any{derived_t{}};
auto as_cref = std::as_const(any).as_ref();
any.cast<derived_t &>().value_2 = 42;
auto conv = std::as_const(any).allow_cast<int>();
auto from_cref = std::as_const(as_cref).allow_cast<int>();
ASSERT_TRUE(conv);
ASSERT_TRUE(from_cref);
ASSERT_EQ(conv.cast<int>(), 42);
ASSERT_EQ(from_cref.cast<int>(), 42);
ASSERT_TRUE(any.allow_cast<int>());
ASSERT_TRUE(as_cref.allow_cast<int>());
ASSERT_EQ(any.cast<int>(), 42);
ASSERT_EQ(as_cref.cast<int>(), 42);
}
TEST_F(MetaBase, OpaqueConvWithMutatingThis) {
entt::meta_any any{derived_t{}};
auto as_cref = std::as_const(any).as_ref();
any.cast<derived_t &>().value_2 = 42;
auto conv = std::as_const(any).allow_cast(entt::resolve<int>());
auto from_cref = std::as_const(as_cref).allow_cast(entt::resolve<int>());
ASSERT_TRUE(conv);
ASSERT_TRUE(from_cref);
ASSERT_EQ(conv.cast<int>(), 42);
ASSERT_EQ(from_cref.cast<int>(), 42);
ASSERT_TRUE(any.allow_cast(entt::resolve<int>()));
ASSERT_TRUE(as_cref.allow_cast(entt::resolve<int>()));
ASSERT_EQ(any.cast<int>(), 42);
ASSERT_EQ(as_cref.cast<int>(), 42);
}
TEST_F(MetaBase, ReRegistration) {
SetUp();