From 0091c4e12b3e25ecdf9c0da091e32739d7907d10 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 1 Mar 2021 23:01:37 +0100 Subject: [PATCH] util/Exception: add FindNested() --- src/util/Exception.hxx | 21 +++++++++++ test/util/TestException.cxx | 69 +++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/src/util/Exception.hxx b/src/util/Exception.hxx index 390f5763f..3f131a260 100644 --- a/src/util/Exception.hxx +++ b/src/util/Exception.hxx @@ -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 +[[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(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. diff --git a/test/util/TestException.cxx b/test/util/TestException.cxx index be4e557e5..947b86f91 100644 --- a/test/util/TestException.cxx +++ b/test/util/TestException.cxx @@ -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(std::current_exception()), + nullptr); + } + + try { + throw Bar{}; + } catch (...) { + EXPECT_EQ(FindNested(std::current_exception()), + nullptr); + } + + try { + throw Derived{}; + } catch (...) { + EXPECT_NE(FindNested(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(std::current_exception()), + nullptr); + } + } + + try { + throw Bar{}; + } catch (...) { + try { + std::throw_with_nested(Outer{}); + } catch (...) { + EXPECT_EQ(FindNested(std::current_exception()), + nullptr); + } + } + + try { + throw Derived{}; + } catch (...) { + try { + std::throw_with_nested(Outer{}); + } catch (...) { + EXPECT_NE(FindNested(std::current_exception()), + nullptr); + } + } +} + template static bool CheckFindRetrowNested(std::exception_ptr e) noexcept