util/Exception: add FindNested()

This commit is contained in:
Max Kellermann 2021-03-01 23:01:37 +01:00 committed by Max Kellermann
parent 80172e17ac
commit 0091c4e12b
2 changed files with 90 additions and 0 deletions

View File

@ -83,6 +83,27 @@ NestException(std::exception_ptr ep, T &&t) noexcept
}
}
/**
* Find an instance of #T in the nested exception chain, and return a
* pointer. Returns nullptr if no such instance was found.
*/
template<typename T>
[[gnu::pure]]
inline const T *
FindNested(std::exception_ptr ep) noexcept
{
try {
std::rethrow_exception(ep);
} catch (const T &t) {
return &t;
} catch (const std::nested_exception &ne) {
return FindNested<T>(ne.nested_ptr());
} catch (...) {
}
return nullptr;
}
/**
* Find an instance of #T in the nested exception chain, and rethrow
* it. Does nothing if no such instance was found.

View File

@ -50,6 +50,75 @@ TEST(ExceptionTest, DerivedError)
ASSERT_EQ(GetFullMessage(std::make_exception_ptr(DerivedError("Foo"))), "Foo");
}
TEST(ExceptionTest, FindNestedDirect)
{
struct Foo {};
struct Bar {};
struct Derived : Foo {};
try {
throw Foo{};
} catch (...) {
EXPECT_NE(FindNested<Foo>(std::current_exception()),
nullptr);
}
try {
throw Bar{};
} catch (...) {
EXPECT_EQ(FindNested<Foo>(std::current_exception()),
nullptr);
}
try {
throw Derived{};
} catch (...) {
EXPECT_NE(FindNested<Foo>(std::current_exception()),
nullptr);
}
}
TEST(ExceptionTest, FindNestedIndirect)
{
struct Foo {};
struct Bar {};
struct Derived : Foo {};
struct Outer {};
try {
throw Foo{};
} catch (...) {
try {
std::throw_with_nested(Outer{});
} catch (...) {
EXPECT_NE(FindNested<Foo>(std::current_exception()),
nullptr);
}
}
try {
throw Bar{};
} catch (...) {
try {
std::throw_with_nested(Outer{});
} catch (...) {
EXPECT_EQ(FindNested<Foo>(std::current_exception()),
nullptr);
}
}
try {
throw Derived{};
} catch (...) {
try {
std::throw_with_nested(Outer{});
} catch (...) {
EXPECT_NE(FindNested<Foo>(std::current_exception()),
nullptr);
}
}
}
template<typename T>
static bool
CheckFindRetrowNested(std::exception_ptr e) noexcept