meta_any: added support for const references, reviewed meta_any::cast (T vs T &)

This commit is contained in:
Michele Caini
2020-12-15 11:35:22 +01:00
parent ade3e58829
commit 5578ea2f30
6 changed files with 68 additions and 42 deletions

View File

@@ -342,7 +342,15 @@ public:
/*! @copydoc try_cast */
template<typename Type>
[[nodiscard]] Type * try_cast() {
return const_cast<Type *>(std::as_const(*this).try_cast<Type>());
if(node) {
if(const auto info = internal::meta_info<Type>::resolve()->info; node->info == info) {
return static_cast<Type *>(storage.data());
} else if(const auto *base = internal::find_if<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type()->info == info; }, node); base) {
return static_cast<Type *>(const_cast<void *>(base->cast(storage.data())));
}
}
return nullptr;
}
/**
@@ -358,16 +366,25 @@ public:
* @return A reference to the contained instance.
*/
template<typename Type>
[[nodiscard]] const Type & cast() const {
auto * const actual = try_cast<Type>();
[[nodiscard]] Type cast() const {
auto * const actual = try_cast<std::remove_cv_t<std::remove_reference_t<Type>>>();
ENTT_ASSERT(actual);
return *actual;
return static_cast<Type>(*actual);
}
/*! @copydoc cast */
template<typename Type>
[[nodiscard]] Type & cast() {
return const_cast<Type &>(std::as_const(*this).cast<Type>());
[[nodiscard]] Type cast() {
if constexpr(!std::is_reference_v<Type> || std::is_const_v<std::remove_reference_t<Type>>) {
// last attempt to make wrappers for const references return their values
auto * const actual = std::as_const(*this).try_cast<std::remove_cv_t<std::remove_reference_t<Type>>>();
ENTT_ASSERT(actual);
return static_cast<Type>(*actual);
} else {
auto * const actual = try_cast<std::remove_cv_t<std::remove_reference_t<Type>>>();
ENTT_ASSERT(actual);
return static_cast<Type>(*actual);
}
}
/**
@@ -1628,15 +1645,15 @@ class meta_sequence_container::meta_iterator {
template<typename It>
static void incr(meta_any any) {
++any.cast<It>();
++any.cast<It &>();
}
template<typename It>
[[nodiscard]] static meta_any deref(meta_any any) {
if constexpr(std::is_const_v<std::remove_reference_t<decltype(*std::declval<It>())>>) {
return *any.cast<It>();
return *any.cast<It &>();
} else {
return std::ref(*any.cast<It>());
return std::ref(*any.cast<It &>());
}
}
@@ -1751,16 +1768,16 @@ struct meta_sequence_container::meta_sequence_container_proxy {
[[nodiscard]] static std::pair<iterator, bool> insert(void *container, iterator it, meta_any value) {
if(const auto *v_ptr = value.try_cast<typename traits_type::value_type>(); v_ptr || value.convert<typename traits_type::value_type>()) {
auto ret = traits_type::insert(*static_cast<Type *>(container), it.handle.cast<typename traits_type::iterator>(), v_ptr ? *v_ptr : value.cast<typename traits_type::value_type>());
return {iterator{std::move(ret.first)}, ret.second};
auto ret = traits_type::insert(*static_cast<Type *>(container), it.handle.cast<const typename traits_type::iterator &>(), v_ptr ? *v_ptr : value.cast<const typename traits_type::value_type &>());
return { iterator{std::move(ret.first)}, ret.second };
}
return {};
}
[[nodiscard]] static std::pair<iterator, bool> erase(void *container, iterator it) {
auto ret = traits_type::erase(*static_cast<Type *>(container), it.handle.cast<typename traits_type::iterator>());
return {iterator{std::move(ret.first)}, ret.second};
auto ret = traits_type::erase(*static_cast<Type *>(container), it.handle.cast<const typename traits_type::iterator &>());
return { iterator{std::move(ret.first)}, ret.second };
}
[[nodiscard]] static meta_any get(void *container, size_type pos) {
@@ -1874,15 +1891,15 @@ inline std::pair<meta_sequence_container::iterator, bool> meta_sequence_containe
class meta_associative_container::meta_iterator {
template<typename It>
static void incr(meta_any any) {
++any.cast<It>();
++any.cast<It &>();
}
template<bool KeyOnly, typename It>
[[nodiscard]] static meta_any key(meta_any any) {
if constexpr(KeyOnly) {
return *any.cast<It>();
return *any.cast<It &>();
} else {
return any.cast<It>()->first;
return any.cast<It &>()->first;
}
}
@@ -1891,7 +1908,7 @@ class meta_associative_container::meta_iterator {
if constexpr(KeyOnly) {
return meta_any{};
} else {
return std::ref(any.cast<It>()->second);
return std::ref(any.cast<It &>()->second);
}
}
@@ -2019,10 +2036,10 @@ struct meta_associative_container::meta_associative_container_proxy {
[[nodiscard]] static bool insert(void *container, meta_any key, meta_any value) {
if(const auto *k_ptr = key.try_cast<typename traits_type::key_type>(); k_ptr || key.convert<typename traits_type::key_type>()) {
if constexpr(is_key_only_meta_associative_container_v<Type>) {
return traits_type::insert(*static_cast<Type *>(container), k_ptr ? *k_ptr : key.cast<typename traits_type::key_type>());
return traits_type::insert(*static_cast<Type *>(container), k_ptr ? *k_ptr : key.cast<const typename traits_type::key_type &>());
} else {
if(auto *m_ptr = value.try_cast<typename traits_type::mapped_type>(); m_ptr || value.convert<typename traits_type::mapped_type>()) {
return traits_type::insert(*static_cast<Type *>(container), k_ptr ? *k_ptr : key.cast<typename traits_type::key_type>(), m_ptr ? *m_ptr : value.cast<typename traits_type::mapped_type>());
if(const auto *m_ptr = value.try_cast<typename traits_type::mapped_type>(); m_ptr || value.convert<typename traits_type::mapped_type>()) {
return traits_type::insert(*static_cast<Type *>(container), k_ptr ? *k_ptr : key.cast<const typename traits_type::key_type &>(), m_ptr ? *m_ptr : value.cast<const typename traits_type::mapped_type &>());
}
}
}
@@ -2032,7 +2049,7 @@ struct meta_associative_container::meta_associative_container_proxy {
[[nodiscard]] static bool erase(void *container, meta_any key) {
if(const auto *k_ptr = key.try_cast<typename traits_type::key_type>(); k_ptr || key.convert<typename traits_type::key_type>()) {
return traits_type::erase(*static_cast<Type *>(container), k_ptr ? *k_ptr : key.cast<typename traits_type::key_type>());
return traits_type::erase(*static_cast<Type *>(container), k_ptr ? *k_ptr : key.cast<const typename traits_type::key_type &>());
}
return false;
@@ -2040,7 +2057,7 @@ struct meta_associative_container::meta_associative_container_proxy {
[[nodiscard]] static iterator find(void *container, meta_any key) {
if(const auto *k_ptr = key.try_cast<typename traits_type::key_type>(); k_ptr || key.convert<typename traits_type::key_type>()) {
return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::find(*static_cast<Type *>(container), k_ptr ? *k_ptr : key.cast<typename traits_type::key_type>())};
return iterator{is_key_only_meta_associative_container<Type>{}, traits_type::find(*static_cast<Type *>(container), k_ptr ? *k_ptr : key.cast<const typename traits_type::key_type &>())};
}
return {};

View File

@@ -579,11 +579,20 @@ TEST_F(MetaAny, Cast) {
ASSERT_TRUE(any);
ASSERT_EQ(any.type(), entt::resolve<fat_t>());
ASSERT_EQ(any.try_cast<std::size_t>(), nullptr);
ASSERT_NE(any.try_cast<empty_t>(), nullptr);
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).cast<const fat_t &>(), fat_t{});
ASSERT_EQ(any.cast<const fat_t>(), fat_t{});
ASSERT_EQ(any.cast<fat_t &>(), fat_t{});
ASSERT_EQ(any.cast<fat_t>(), fat_t{});
ASSERT_EQ(any.cast<fat_t>().gnam[0u], 0.);
any.cast<fat_t>().gnam[0u] = 3.;
ASSERT_EQ(any.cast<fat_t>().gnam[0u], 0.);
any.cast<fat_t &>().gnam[0u] = 3.;
ASSERT_EQ(any.cast<fat_t>().gnam[0u], 3.);
}
TEST_F(MetaAny, Convert) {

View File

@@ -111,9 +111,9 @@ TEST_F(MetaContainer, StdVector) {
ASSERT_EQ(view.size(), 3u);
ASSERT_NE(view.begin(), view.end());
view[0].cast<int>() = 2;
view[1].cast<int>() = 3;
view[2].cast<int>() = 4;
view[0].cast<int &>() = 2;
view[1].cast<int &>() = 3;
view[2].cast<int &>() = 4;
ASSERT_EQ(view[1u].cast<int>(), 3);
@@ -153,9 +153,9 @@ TEST_F(MetaContainer, StdArray) {
ASSERT_FALSE(view.resize(5u));
ASSERT_EQ(view.size(), 3u);
view[0].cast<int>() = 2;
view[1].cast<int>() = 3;
view[2].cast<int>() = 4;
view[0].cast<int &>() = 2;
view[1].cast<int &>() = 3;
view[2].cast<int &>() = 4;
ASSERT_EQ(view[1u].cast<int>(), 3);
@@ -216,7 +216,7 @@ TEST_F(MetaContainer, StdMap) {
ASSERT_EQ(view.size(), 4u);
ASSERT_EQ(view.find(0), view.end());
(*view.find(1)).second.cast<char>() = 'f';
(*view.find(1)).second.cast<char &>() = 'f';
ASSERT_EQ((*view.find(1)).second.cast<char>(), 'f');
@@ -259,7 +259,7 @@ TEST_F(MetaContainer, StdSet) {
ASSERT_EQ(view.size(), 4u);
ASSERT_EQ(view.find(0), view.end());
(*view.find(1)).first.cast<int>() = 42;
(*view.find(1)).first.cast<int &>() = 42;
ASSERT_EQ((*view.find(1)).first.cast<int>(), 1);

View File

@@ -224,7 +224,7 @@ TEST_F(MetaData, GetMetaAnyArg) {
using namespace entt::literals;
entt::meta_any any{clazz_t{}};
any.cast<clazz_t>().i = 99;
any.cast<clazz_t &>().i = 99;
const auto value = entt::resolve<clazz_t>().data("i"_hs).get(any);
ASSERT_TRUE(value);
@@ -433,8 +433,8 @@ TEST_F(MetaData, AsRef) {
ASSERT_EQ(h_data.type(), entt::resolve<int>());
ASSERT_EQ(i_data.type(), entt::resolve<int>());
h_data.get(instance).cast<int>() = 3;
i_data.get(instance).cast<int>() = 3;
h_data.get(instance).cast<int &>() = 3;
i_data.get(instance).cast<int &>() = 3;
ASSERT_NE(instance.h, 3);
ASSERT_EQ(instance.i, 3);

View File

@@ -322,7 +322,7 @@ TEST_F(MetaFunc, AsRef) {
func_t instance{};
auto func = entt::resolve<func_t>().func("a"_hs);
func.invoke(instance).cast<int>() = 3;
func.invoke(instance).cast<int &>() = 3;
ASSERT_EQ(func.ret(), entt::resolve<int>());
ASSERT_EQ(instance.value, 3);

View File

@@ -40,7 +40,7 @@ TEST(MetaPointerLike, DereferenceOperatorConstType) {
ASSERT_FALSE(deref.type().is_pointer_like());
ASSERT_EQ(deref.type(), entt::resolve<int>());
deref.cast<int>() = 42;
deref.cast<int &>() = 42;
ASSERT_EQ(*any.cast<const int *>(), 0);
ASSERT_EQ(value, 0);
@@ -61,7 +61,7 @@ TEST(MetaPointerLike, DereferenceOperatorRawPointer) {
ASSERT_FALSE(deref.type().is_pointer_like());
ASSERT_EQ(deref.type(), entt::resolve<int>());
deref.cast<int>() = 42;
deref.cast<int &>() = 42;
ASSERT_EQ(*any.cast<int *>(), 42);
ASSERT_EQ(value, 42);
@@ -82,7 +82,7 @@ TEST(MetaPointerLike, DereferenceOperatorSmartPointer) {
ASSERT_FALSE(deref.type().is_pointer_like());
ASSERT_EQ(deref.type(), entt::resolve<int>());
deref.cast<int>() = 42;
deref.cast<int &>() = 42;
ASSERT_EQ(*any.cast<std::shared_ptr<int>>(), 42);
ASSERT_EQ(*value, 42);