Skip to content

Commit 40b0790

Browse files
committed
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.
1 parent 4a92184 commit 40b0790

File tree

2 files changed

+44
-17
lines changed

2 files changed

+44
-17
lines changed

AK/Variant.h

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -406,30 +406,50 @@ struct Variant
406406
}
407407

408408
template<typename... NewTs>
409-
Variant<NewTs...> downcast() &&
409+
decltype(auto) downcast() &&
410+
{
411+
if constexpr (sizeof...(NewTs) == 1 && (IsSpecializationOf<NewTs, Variant> && ...)) {
412+
return move(*this).template downcast_variant<NewTs...>();
413+
} else {
414+
Variant<NewTs...> instance { Variant<NewTs...>::invalid_index, Detail::VariantConstructTag {} };
415+
visit([&](auto& value) {
416+
if constexpr (Variant<NewTs...>::template can_contain<RemoveCVReference<decltype(value)>>())
417+
instance.set(move(value), Detail::VariantNoClearTag {});
418+
});
419+
VERIFY(instance.m_index != instance.invalid_index);
420+
return instance;
421+
}
422+
}
423+
424+
template<typename... NewTs>
425+
decltype(auto) downcast() const&
426+
{
427+
if constexpr (sizeof...(NewTs) == 1 && (IsSpecializationOf<NewTs, Variant> && ...)) {
428+
return (*this).template downcast_variant(TypeWrapper<NewTs...> {});
429+
} else {
430+
Variant<NewTs...> instance { Variant<NewTs...>::invalid_index, Detail::VariantConstructTag {} };
431+
visit([&](auto const& value) {
432+
if constexpr (Variant<NewTs...>::template can_contain<RemoveCVReference<decltype(value)>>())
433+
instance.set(value, Detail::VariantNoClearTag {});
434+
});
435+
VERIFY(instance.m_index != instance.invalid_index);
436+
return instance;
437+
}
438+
}
439+
440+
private:
441+
template<typename... NewTs>
442+
Variant<NewTs...> downcast_variant(TypeWrapper<Variant<NewTs...>>) &&
410443
{
411-
Variant<NewTs...> instance { Variant<NewTs...>::invalid_index, Detail::VariantConstructTag {} };
412-
visit([&](auto& value) {
413-
if constexpr (Variant<NewTs...>::template can_contain<RemoveCVReference<decltype(value)>>())
414-
instance.set(move(value), Detail::VariantNoClearTag {});
415-
});
416-
VERIFY(instance.m_index != instance.invalid_index);
417-
return instance;
444+
return move(*this).template downcast<NewTs...>();
418445
}
419446

420447
template<typename... NewTs>
421-
Variant<NewTs...> downcast() const&
448+
Variant<NewTs...> downcast_variant(TypeWrapper<Variant<NewTs...>>) const&
422449
{
423-
Variant<NewTs...> instance { Variant<NewTs...>::invalid_index, Detail::VariantConstructTag {} };
424-
visit([&](auto const& value) {
425-
if constexpr (Variant<NewTs...>::template can_contain<RemoveCVReference<decltype(value)>>())
426-
instance.set(value, Detail::VariantNoClearTag {});
427-
});
428-
VERIFY(instance.m_index != instance.invalid_index);
429-
return instance;
450+
return (*this).template downcast<NewTs...>();
430451
}
431452

432-
private:
433453
static constexpr auto data_size = Detail::integer_sequence_generate_array<size_t>(0, IntegerSequence<size_t, sizeof(Ts)...>()).max();
434454
static constexpr auto data_alignment = Detail::integer_sequence_generate_array<size_t>(0, IntegerSequence<size_t, alignof(Ts)...>()).max();
435455
using Helper = Detail::Variant<IndexType, 0, Ts...>;

Tests/AK/TestVariant.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,13 @@ TEST_CASE(verify_cast)
125125
EXPECT(one_integer_to_rule_them_all.has<i8>());
126126
EXPECT_EQ(fake_integer.get<i8>(), 60);
127127
EXPECT_EQ(one_integer_to_rule_them_all.get<i8>(), 60);
128+
129+
using SomeFancyType = Variant<i8, i16>;
130+
one_integer_to_rule_them_all = fake_integer.downcast<SomeFancyType>();
131+
EXPECT(fake_integer.has<i8>());
132+
EXPECT(one_integer_to_rule_them_all.has<i8>());
133+
EXPECT_EQ(fake_integer.get<i8>(), 60);
134+
EXPECT_EQ(one_integer_to_rule_them_all.get<i8>(), 60);
128135
}
129136

130137
TEST_CASE(moved_from_state)

0 commit comments

Comments
 (0)