From ea7d65a74c45abea617a8e81dea1688f5157b9c4 Mon Sep 17 00:00:00 2001 From: Dan Smith Date: Wed, 28 Dec 2022 11:56:24 -0500 Subject: [PATCH] ThrowableEx inherits from Throwable --- modules/c++/except/include/except/Throwable.h | 123 ++---------------- modules/c++/except/source/Throwable.cpp | 92 ------------- modules/c++/include/TestCase.h | 11 +- 3 files changed, 15 insertions(+), 211 deletions(-) diff --git a/modules/c++/except/include/except/Throwable.h b/modules/c++/except/include/except/Throwable.h index 075bceb7f..c6fea1786 100644 --- a/modules/c++/except/include/except/Throwable.h +++ b/modules/c++/except/include/except/Throwable.h @@ -82,6 +82,7 @@ class CODA_OSS_API Throwable void doGetBacktrace(); template Throwable(const Context*, const TThrowable* pT, const std::string* pMessage, bool callGetBacktrace, std::nullptr_t); +protected: Throwable(const Context*, const Throwable* pT = nullptr, const std::string* pMessage = nullptr, bool callGetBacktrace = false); Throwable(const Context*, const ThrowableEx* pT, const std::string* pMessage = nullptr, bool callGetBacktrace = false); @@ -226,24 +227,12 @@ class CODA_OSS_API Throwable * break existing code as "catch (const std::exception&)" will catch * except::Throwable when it didn't before. */ -class ThrowableEx : public std::exception // "ThrowableEx" = "Throwable exception" +// Use multiple-inheritance :-( to reduce duplicated boilerplate code. +class ThrowableEx : public Throwable // "ThrowableEx" = "Throwable exception" +#if !CODA_OSS_except_Throwable_ISA_std_exception + , public std::exception +#endif { - void doGetBacktrace(); - template - ThrowableEx(const Context*, - const TThrowable* pT, - const std::string* pMessage, - bool callGetBacktrace, - std::nullptr_t); - ThrowableEx(const Context*, - const ThrowableEx* pT = nullptr, - const std::string* pMessage = nullptr, - bool callGetBacktrace = false); - ThrowableEx(const Context*, - const Throwable* pT, - const std::string* pMessage = nullptr, - bool callGetBacktrace = false); - public: ThrowableEx() = default; virtual ~ThrowableEx() = default; @@ -252,119 +241,33 @@ class ThrowableEx : public std::exception // "ThrowableEx" = "Throwable exceptio ThrowableEx(ThrowableEx&&) = default; ThrowableEx& operator=(ThrowableEx&&) = default; - ThrowableEx(const Throwable&); + ThrowableEx(const Throwable& t) : Throwable(t){} /*! * Constructor. Takes a message * \param message The message */ - ThrowableEx(const std::string& message); + ThrowableEx(const std::string& message) : Throwable(message) {} /*! * Constructor. Takes a Context. * \param c The Context */ - ThrowableEx(const Context&); + ThrowableEx(const Context& ctx) : Throwable(ctx) {} /*! * Constructor. Takes a Throwable and a Context * \param t The throwable * \param c The Context */ - ThrowableEx(const ThrowableEx&, const Context&); - ThrowableEx(const Throwable&, const Context&); - - /*! - * Get the message - * \return The message - */ - std::string getMessage() const - { - return mMessage; - } - - /*! - * Get the trace - * \return The trace (const) - */ - const Trace& getTrace() const noexcept - { - return mTrace; - } - - /*! - * Get the trace - * \return The trace (non-const) - */ - Trace& getTrace() noexcept - { - return mTrace; - } - - /*! - * Get the type id - * \return The type - */ - virtual std::string getType() const noexcept - { - return "ThrowableEx"; - } - - virtual std::string toString() const - { - std::ostringstream s; - s << getType() << ": " << getMessage(); - - const Trace& t = getTrace(); - if (t.getSize() > 0) - s << ": " << t; - return s.str(); - } - - const std::vector& getBacktrace() const noexcept - { - return mBacktrace; - } - - // It seems that overloading constructors creates ambiguities ... so allow - // for a "fluent" way of doing this.: throw Exception(...).backtrace() - ThrowableEx& backtrace() - { - doGetBacktrace(); - return *this; - } - - virtual std::string toString(bool includeBacktrace) const - { - // Adding the backtrace to existing toString() output could substantally - // alter existing strings. - std::string backtrace; - if (includeBacktrace) - { - backtrace = "***** getBacktrace() *****\n"; - backtrace += std::accumulate(mBacktrace.begin(), - mBacktrace.end(), - std::string()); - } - return toString() + backtrace; - } + ThrowableEx(const ThrowableEx& t, const Context& ctx) : Throwable(t, ctx) {} + ThrowableEx(const Throwable& t, const Context& ctx) : Throwable(t, ctx) {} const char* what() const noexcept final // derived classes override toString() { - // adding this to toString() output could (significantly) alter existing display - mWhat = toString(true /*includeBacktrace*/); // call any derived toString() - return mWhat.c_str(); + const Throwable* pThrowable = this; + return pThrowable->what(); } - -protected: - //! The name of exception trace - Trace mTrace; - //! The name of the message the exception was thrown - std::string mMessage; - -private: - mutable std::string mWhat; - std::vector mBacktrace; }; using Throwable11 = ThrowableEx; // keep old name around for other projects } diff --git a/modules/c++/except/source/Throwable.cpp b/modules/c++/except/source/Throwable.cpp index 317e73ade..a30d484df 100644 --- a/modules/c++/except/source/Throwable.cpp +++ b/modules/c++/except/source/Throwable.cpp @@ -98,95 +98,3 @@ except::Throwable::Throwable(const except::ThrowableEx& t, except::Context c) : except::Throwable::Throwable(const except::ThrowableEx& t) : Throwable(nullptr, &t) { } - -//****************************************************************************** - -void except::ThrowableEx::doGetBacktrace() -{ - // This could be time-consuming or generate a lot of (noisy) output; only do - // it if requested - bool supported; - (void)except::getBacktrace(supported, mBacktrace); -} - -template -except::ThrowableEx::ThrowableEx(const Context* pContext, - const TThrowable* pThrowable, - const std::string* pMessage, - bool callGetBacktrace, - std::nullptr_t) -{ - if (pThrowable != nullptr) - { - // Copy t's exception stack and push c onto local one - mTrace = pThrowable->getTrace(); - } - - if (pContext != nullptr) - { - assert(pMessage == nullptr); - - // Push context onto exception stack - mTrace.pushContext(*pContext); - - // Assign c's message as our internal one - mMessage = pContext->getMessage(); - } - - if (pMessage != nullptr) - { - assert(pContext == nullptr); - mMessage = *pMessage; - } - - // This will record a back-trace from where the Throwable object was - // instantiated. That's not necessarily where the "throw" will occur, but - // it's often the case; Throwable instances ususally aren't passed around. - // That is, hardly anybody does: - // Exception e; // Throwable instance - // might_throw(e); - // rather, the idiom is usually - // throw Exception(...); // instantiate and throw - if (callGetBacktrace) - { - doGetBacktrace(); - } -} -except::ThrowableEx::ThrowableEx(const Context* pContext, - const ThrowableEx* pThrowable, - const std::string* pMessage, - bool callGetBacktrace) : - ThrowableEx(pContext, pThrowable, pMessage, callGetBacktrace, nullptr) -{ -} -except::ThrowableEx::ThrowableEx(const Context* pContext, - const Throwable* pThrowable, - const std::string* pMessage, - bool callGetBacktrace) : - ThrowableEx(pContext, pThrowable, pMessage, callGetBacktrace, nullptr) -{ -} - -except::ThrowableEx::ThrowableEx(const std::string& message) : - ThrowableEx(nullptr, static_cast(nullptr), &message) -{ -} - -except::ThrowableEx::ThrowableEx(const except::Context& c) : ThrowableEx(&c) -{ -} - -except::ThrowableEx::ThrowableEx(const except::ThrowableEx& t, - const except::Context& c) : - ThrowableEx(&c, &t) -{ -} -except::ThrowableEx::ThrowableEx(const except::Throwable& t, - const except::Context& c) : - ThrowableEx(&c, &t) -{ -} -except::ThrowableEx::ThrowableEx(const except::Throwable& t) : - ThrowableEx(nullptr, &t) -{ -} diff --git a/modules/c++/include/TestCase.h b/modules/c++/include/TestCase.h index ad2da45dc..9b8a873f2 100644 --- a/modules/c++/include/TestCase.h +++ b/modules/c++/include/TestCase.h @@ -139,10 +139,6 @@ inline void specific_exception(TFunc f, { diePrintf(format, testName, file, func, line); } - catch (const except::ThrowableEx&) - { - diePrintf(format, testName, file, func, line); - } } template @@ -173,9 +169,7 @@ inline int main(TFunc f) #define CODA_OSS_TEST_CHECK_catch_diePrintf_(X, name_) \ catch(const name_& ex) { test::diePrintf("%s: FAILED: Exception thrown: %s\n", #X, ex.what()); } -#define CODA_OSS_TEST_CHECK_catch_(X) \ - CODA_OSS_TEST_CHECK_catch_diePrintf_(X, except::Throwable) \ - CODA_OSS_TEST_CHECK_catch_diePrintf_(X, except::ThrowableEx) +#define CODA_OSS_TEST_CHECK_catch_(X) CODA_OSS_TEST_CHECK_catch_diePrintf_(X, except::Throwable) #define TEST_CHECK(X) try{ X(std::string(#X)); std::cerr << #X << ": PASSED\n"; } CODA_OSS_TEST_CHECK_catch_(X) #define TEST_ASSERT_NULL(X) if ((X) != nullptr) { test_diePrintf0("%s (%s,%s,%d): FAILED: Value should be NULL\n"); } @@ -191,8 +185,7 @@ inline int main(TFunc f) #define TEST_ASSERT_ALMOST_EQ_EPS(X1, X2, EPS) test::assert_almost_eq_eps(X1, X2, EPS, testName, __FILE__, SYS_FUNC, __LINE__) #define TEST_ASSERT_ALMOST_EQ(X1, X2) TEST_ASSERT_ALMOST_EQ_EPS(X1, X2, std::numeric_limits::epsilon()) -#define CODA_OSS_TEST_EXCEPTION_catch_ \ - catch (const except::Throwable&){} catch (const except::ThrowableEx&){} +#define CODA_OSS_TEST_EXCEPTION_catch_ catch (const except::Throwable&){} #define TEST_EXCEPTION(X) try{ (X); test_diePrintf0("%s (%s,%s,%d): FAILED: Should have thrown exception\n"); } \ CODA_OSS_TEST_EXCEPTION_catch_ #define TEST_THROWS(X) try{ (X); test_diePrintf0("%s (%s,%s,%d): FAILED: Should have thrown exception\n"); } catch (...){}