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.
This commit is contained in:
Ali Mohammad Pur 2022-11-10 12:42:19 +03:30 committed by Ali Mohammad Pur
parent 4a9218451d
commit 40b07901ac
2 changed files with 43 additions and 16 deletions

View file

@ -406,30 +406,50 @@ public:
}
template<typename... NewTs>
Variant<NewTs...> downcast() &&
decltype(auto) downcast() &&
{
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;
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>
Variant<NewTs...> downcast() const&
decltype(auto) downcast() 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;
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...>>) &&
{
return move(*this).template downcast<NewTs...>();
}
template<typename... NewTs>
Variant<NewTs...> downcast_variant(TypeWrapper<Variant<NewTs...>>) const&
{
return (*this).template downcast<NewTs...>();
}
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...>;

View file

@ -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)