Castable: Have Switch() support nullptr objects.
Change-Id: I7635b01707e80c2d2e0b79148e07874f2fa2b5ff Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/79764 Auto-Submit: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Antonio Maiorano <amaiorano@google.com> Commit-Queue: Antonio Maiorano <amaiorano@google.com>
This commit is contained in:
parent
6839cba568
commit
88d1a433aa
|
@ -565,7 +565,6 @@ inline bool NonDefaultCases(T* object,
|
|||
/// @see NonDefaultCases
|
||||
template <typename T, typename RETURN_TYPE, typename... CASES>
|
||||
inline void SwitchCases(T* object,
|
||||
const TypeInfo* type,
|
||||
RETURN_TYPE* result,
|
||||
std::tuple<CASES...>&& cases) {
|
||||
using Cases = std::tuple<CASES...>;
|
||||
|
@ -575,19 +574,32 @@ inline void SwitchCases(T* object,
|
|||
static constexpr bool kHasDefaultCase = kDefaultIndex >= 0;
|
||||
static constexpr bool kHasReturnType = !std::is_same_v<RETURN_TYPE, void>;
|
||||
|
||||
if constexpr (kHasDefaultCase) {
|
||||
// Evaluate non-default cases.
|
||||
if (!detail::NonDefaultCases<T>(object, type, result,
|
||||
traits::Slice<0, kDefaultIndex>(cases))) {
|
||||
// Nothing matched. Evaluate default case.
|
||||
if (object) {
|
||||
auto* type = &object->TypeInfo();
|
||||
if constexpr (kHasDefaultCase) {
|
||||
// Evaluate non-default cases.
|
||||
if (!detail::NonDefaultCases<T>(object, type, result,
|
||||
traits::Slice<0, kDefaultIndex>(cases))) {
|
||||
// Nothing matched. Evaluate default case.
|
||||
if constexpr (kHasReturnType) {
|
||||
*result = std::get<kDefaultIndex>(cases)({});
|
||||
} else {
|
||||
std::get<kDefaultIndex>(cases)({});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
detail::NonDefaultCases<T>(object, type, result, std::move(cases));
|
||||
}
|
||||
} else {
|
||||
// Object is nullptr, so no cases can match
|
||||
if constexpr (kHasDefaultCase) {
|
||||
// Evaluate default case.
|
||||
if constexpr (kHasReturnType) {
|
||||
*result = std::get<kDefaultIndex>(cases)({});
|
||||
} else {
|
||||
std::get<kDefaultIndex>(cases)({});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
detail::NonDefaultCases<T>(object, type, result, std::move(cases));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -608,6 +620,10 @@ inline void SwitchCases(T* object,
|
|||
/// used as the last case. This default case will be called if all previous
|
||||
/// cases failed to match.
|
||||
///
|
||||
/// If `object` is nullptr and a default case is provided, then the default case
|
||||
/// will be called. If `object` is nullptr and no default case is provided, then
|
||||
/// no cases will be called.
|
||||
///
|
||||
/// Example:
|
||||
/// ```
|
||||
/// Switch(object,
|
||||
|
@ -630,17 +646,14 @@ inline auto Switch(T* object, CASES&&... cases) {
|
|||
using ReturnType = traits::ReturnType<std::tuple_element_t<0, Cases>>;
|
||||
static constexpr bool kHasReturnType = !std::is_same_v<ReturnType, void>;
|
||||
|
||||
auto& type = object->TypeInfo();
|
||||
|
||||
if constexpr (kHasReturnType) {
|
||||
ReturnType res = {};
|
||||
detail::SwitchCases(object, &type, &res,
|
||||
detail::SwitchCases(object, &res,
|
||||
std::forward_as_tuple(std::forward<CASES>(cases)...));
|
||||
return res;
|
||||
} else {
|
||||
detail::SwitchCases<T, void>(
|
||||
object, &type, nullptr,
|
||||
std::forward_as_tuple(std::forward<CASES>(cases)...));
|
||||
object, nullptr, std::forward_as_tuple(std::forward<CASES>(cases)...));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -371,6 +371,7 @@ TEST(Castable, SwitchDefault) {
|
|||
EXPECT_TRUE(gecko_matched_default);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Castable, SwitchMatchFirst) {
|
||||
std::unique_ptr<Animal> frog = std::make_unique<Frog>();
|
||||
{
|
||||
|
@ -397,6 +398,25 @@ TEST(Castable, SwitchMatchFirst) {
|
|||
}
|
||||
}
|
||||
|
||||
TEST(Castable, SwitchNull) {
|
||||
Animal* null = nullptr;
|
||||
Switch(
|
||||
null, //
|
||||
[&](Amphibian*) { FAIL() << "should not be called"; },
|
||||
[&](Animal*) { FAIL() << "should not be called"; });
|
||||
}
|
||||
|
||||
TEST(Castable, SwitchNullNoDefault) {
|
||||
Animal* null = nullptr;
|
||||
bool default_called = false;
|
||||
Switch(
|
||||
null, //
|
||||
[&](Amphibian*) { FAIL() << "should not be called"; },
|
||||
[&](Animal*) { FAIL() << "should not be called"; },
|
||||
[&](Default) { default_called = true; });
|
||||
EXPECT_TRUE(default_called);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TINT_INSTANTIATE_TYPEINFO(Animal);
|
||||
|
|
Loading…
Reference in New Issue