summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAli Mohammad Pur <ali.mpfard@gmail.com>2022-11-10 12:42:19 +0330
committerAli Mohammad Pur <Ali.mpfard@gmail.com>2022-11-10 16:02:42 +0330
commit40b07901ac3cdc4e8942bff62f4784370543003b (patch)
tree1fbc8773c48520df6451c829723dba7118b9f3ea
parent4a9218451dbf6bd5b58addd37f7e334669882ece (diff)
downloadserenity-40b07901ac3cdc4e8942bff62f4784370543003b.zip
AK: Allow Variant::downcast<OtherVariantType>()
We usually give type aliases to variants, so their variant types are not always available, so make it possible to downcast to another variant type.
-rw-r--r--AK/Variant.h54
-rw-r--r--Tests/AK/TestVariant.cpp7
2 files changed, 44 insertions, 17 deletions
diff --git a/AK/Variant.h b/AK/Variant.h
index 8962b7ee0a..eb6500bc44 100644
--- a/AK/Variant.h
+++ b/AK/Variant.h
@@ -406,30 +406,50 @@ public:
}
template<typename... NewTs>
- Variant<NewTs...> downcast() &&
+ decltype(auto) downcast() &&
+ {
+ if constexpr (sizeof...(NewTs) == 1 && (IsSpecializationOf<NewTs, Variant> && ...)) {
+ return move(*this).template downcast_variant<NewTs...>();
+ } else {
+ Variant<NewTs...> instance { Variant<NewTs...>::invalid_index, Detail::VariantConstructTag {} };
+ visit([&](auto& value) {
+ if constexpr (Variant<NewTs...>::template can_contain<RemoveCVReference<decltype(value)>>())
+ instance.set(move(value), Detail::VariantNoClearTag {});
+ });
+ VERIFY(instance.m_index != instance.invalid_index);
+ return instance;
+ }
+ }
+
+ template<typename... NewTs>
+ decltype(auto) downcast() const&
+ {
+ if constexpr (sizeof...(NewTs) == 1 && (IsSpecializationOf<NewTs, Variant> && ...)) {
+ return (*this).template downcast_variant(TypeWrapper<NewTs...> {});
+ } else {
+ Variant<NewTs...> instance { Variant<NewTs...>::invalid_index, Detail::VariantConstructTag {} };
+ visit([&](auto const& value) {
+ if constexpr (Variant<NewTs...>::template can_contain<RemoveCVReference<decltype(value)>>())
+ instance.set(value, Detail::VariantNoClearTag {});
+ });
+ VERIFY(instance.m_index != instance.invalid_index);
+ return instance;
+ }
+ }
+
+private:
+ template<typename... NewTs>
+ Variant<NewTs...> downcast_variant(TypeWrapper<Variant<NewTs...>>) &&
{
- Variant<NewTs...> instance { Variant<NewTs...>::invalid_index, Detail::VariantConstructTag {} };
- visit([&](auto& value) {
- if constexpr (Variant<NewTs...>::template can_contain<RemoveCVReference<decltype(value)>>())
- instance.set(move(value), Detail::VariantNoClearTag {});
- });
- VERIFY(instance.m_index != instance.invalid_index);
- return instance;
+ return move(*this).template downcast<NewTs...>();
}
template<typename... NewTs>
- Variant<NewTs...> downcast() const&
+ Variant<NewTs...> downcast_variant(TypeWrapper<Variant<NewTs...>>) const&
{
- Variant<NewTs...> instance { Variant<NewTs...>::invalid_index, Detail::VariantConstructTag {} };
- visit([&](auto const& value) {
- if constexpr (Variant<NewTs...>::template can_contain<RemoveCVReference<decltype(value)>>())
- instance.set(value, Detail::VariantNoClearTag {});
- });
- VERIFY(instance.m_index != instance.invalid_index);
- return instance;
+ return (*this).template downcast<NewTs...>();
}
-private:
static constexpr auto data_size = Detail::integer_sequence_generate_array<size_t>(0, IntegerSequence<size_t, sizeof(Ts)...>()).max();
static constexpr auto data_alignment = Detail::integer_sequence_generate_array<size_t>(0, IntegerSequence<size_t, alignof(Ts)...>()).max();
using Helper = Detail::Variant<IndexType, 0, Ts...>;
diff --git a/Tests/AK/TestVariant.cpp b/Tests/AK/TestVariant.cpp
index f55d176537..ea7998a099 100644
--- a/Tests/AK/TestVariant.cpp
+++ b/Tests/AK/TestVariant.cpp
@@ -125,6 +125,13 @@ TEST_CASE(verify_cast)
EXPECT(one_integer_to_rule_them_all.has<i8>());
EXPECT_EQ(fake_integer.get<i8>(), 60);
EXPECT_EQ(one_integer_to_rule_them_all.get<i8>(), 60);
+
+ using SomeFancyType = Variant<i8, i16>;
+ one_integer_to_rule_them_all = fake_integer.downcast<SomeFancyType>();
+ EXPECT(fake_integer.has<i8>());
+ EXPECT(one_integer_to_rule_them_all.has<i8>());
+ EXPECT_EQ(fake_integer.get<i8>(), 60);
+ EXPECT_EQ(one_integer_to_rule_them_all.get<i8>(), 60);
}
TEST_CASE(moved_from_state)