From ab2d440a00ea9d7b02464a6947445f6bc34afbe0 Mon Sep 17 00:00:00 2001 From: Jeremy <51220084+jeremy-rifkin@users.noreply.github.com> Date: Sun, 4 Feb 2024 13:40:12 -0600 Subject: [PATCH] Update cpptrace exceptions to defer trace generation to the callsite with a default argument --- README.md | 29 +++++----- include/cpptrace/cpptrace.hpp | 102 ++++++++++++++++++++-------------- src/cpptrace.cpp | 10 ++-- 3 files changed, 82 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index e79a366..ad32522 100644 --- a/README.md +++ b/README.md @@ -320,13 +320,13 @@ interface or type system but this seems to be the best way to do this. ```cpp namespace cpptrace { class lazy_exception : public exception { - mutable detail::lazy_trace_holder trace_holder; // basically std::variant, more docs later + // lazy_trace_holder is basically a std::variant, more docs later + mutable detail::lazy_trace_holder trace_holder; mutable std::string what_string; - protected: - explicit lazy_exception(std::size_t skip, std::size_t max_depth) noexcept; - explicit lazy_exception(std::size_t skip) noexcept; public: - explicit lazy_exception() noexcept : lazy_exception(1) {} + explicit lazy_exception( + raw_trace&& trace = detail::get_raw_trace_and_absorb() + ) noexcept : trace_holder(std::move(trace)) {} const char* what() const noexcept override; const char* message() const noexcept override; const stacktrace& trace() const noexcept override; @@ -341,19 +341,22 @@ well as a number of traced exception classes resembling ``: ```cpp namespace cpptrace { - class CPPTRACE_EXPORT exception_with_message : public lazy_exception { + class exception_with_message : public lazy_exception { mutable std::string user_message; - protected: - explicit exception_with_message(std::string&& message_arg, std::size_t skip) noexcept; - explicit exception_with_message(std::string&& message_arg, std::size_t skip, std::size_t max_depth) noexcept; public: - explicit exception_with_message(std::string&& message_arg) noexcept - : exception_with_message(std::move(message_arg), 1) {} - + explicit exception_with_message( + std::string&& message_arg, + raw_trace&& trace = detail::get_raw_trace_and_absorb() + ) noexcept : lazy_exception(std::move(trace)), user_message(std::move(message_arg)) {} const char* message() const noexcept override; }; - // All stdexcept errors have analogs here. Same constructor as exception_with_message. + // All stdexcept errors have analogs here. All have the constructor: + // explicit the_error( + // std::string&& message_arg, + // raw_trace&& trace = detail::get_raw_trace_and_absorb() + // ) noexcept + // : exception_with_message(std::move(message_arg), std::move(trace)) {} class logic_error : public exception_with_message { ... }; class domain_error : public exception_with_message { ... }; class invalid_argument : public exception_with_message { ... }; diff --git a/include/cpptrace/cpptrace.hpp b/include/cpptrace/cpptrace.hpp index 8cf1b5c..38aa7c6 100644 --- a/include/cpptrace/cpptrace.hpp +++ b/include/cpptrace/cpptrace.hpp @@ -289,6 +289,9 @@ namespace cpptrace { private: void clear(); }; + + CPPTRACE_EXPORT raw_trace get_raw_trace_and_absorb(std::size_t skip, std::size_t max_depth) noexcept; + CPPTRACE_EXPORT raw_trace get_raw_trace_and_absorb(std::size_t skip = 0) noexcept; } // Interface for a traced exception object @@ -301,17 +304,14 @@ namespace cpptrace { // Cpptrace traced exception object // I hate to have to expose anything about implementation detail but the idea here is that - // TODO: CPPTRACE_FORCE_NO_INLINE annotations class CPPTRACE_EXPORT lazy_exception : public exception { mutable detail::lazy_trace_holder trace_holder; mutable std::string what_string; - protected: - explicit lazy_exception(std::size_t skip, std::size_t max_depth) noexcept; - explicit lazy_exception(std::size_t skip) noexcept : lazy_exception(skip + 1, SIZE_MAX) {} - public: - explicit lazy_exception() noexcept : lazy_exception(1) {} + explicit lazy_exception( + raw_trace&& trace = detail::get_raw_trace_and_absorb() + ) noexcept : trace_holder(std::move(trace)) {} // std::exception const char* what() const noexcept override; // cpptrace::exception @@ -322,87 +322,105 @@ namespace cpptrace { class CPPTRACE_EXPORT exception_with_message : public lazy_exception { mutable std::string user_message; - protected: - explicit exception_with_message( - std::string&& message_arg, - std::size_t skip - ) noexcept : lazy_exception(skip + 1), user_message(std::move(message_arg)) {} - - explicit exception_with_message( - std::string&& message_arg, - std::size_t skip, - std::size_t max_depth - ) noexcept : lazy_exception(skip + 1, max_depth), user_message(std::move(message_arg)) {} - public: - explicit exception_with_message(std::string&& message_arg) noexcept - : exception_with_message(std::move(message_arg), 1) {} + explicit exception_with_message( + std::string&& message_arg, + raw_trace&& trace = detail::get_raw_trace_and_absorb() + ) noexcept : lazy_exception(std::move(trace)), user_message(std::move(message_arg)) {} const char* message() const noexcept override; }; class CPPTRACE_EXPORT logic_error : public exception_with_message { public: - explicit logic_error(std::string&& message_arg) noexcept - : exception_with_message(std::move(message_arg), 1) {} + explicit logic_error( + std::string&& message_arg, + raw_trace&& trace = detail::get_raw_trace_and_absorb() + ) noexcept + : exception_with_message(std::move(message_arg), std::move(trace)) {} }; class CPPTRACE_EXPORT domain_error : public exception_with_message { public: - explicit domain_error(std::string&& message_arg) noexcept - : exception_with_message(std::move(message_arg), 1) {} + explicit domain_error( + std::string&& message_arg, + raw_trace&& trace = detail::get_raw_trace_and_absorb() + ) noexcept + : exception_with_message(std::move(message_arg), std::move(trace)) {} }; class CPPTRACE_EXPORT invalid_argument : public exception_with_message { public: - explicit invalid_argument(std::string&& message_arg) noexcept - : exception_with_message(std::move(message_arg), 1) {} + explicit invalid_argument( + std::string&& message_arg, + raw_trace&& trace = detail::get_raw_trace_and_absorb() + ) noexcept + : exception_with_message(std::move(message_arg), std::move(trace)) {} }; class CPPTRACE_EXPORT length_error : public exception_with_message { public: - explicit length_error(std::string&& message_arg) noexcept - : exception_with_message(std::move(message_arg), 1) {} + explicit length_error( + std::string&& message_arg, + raw_trace&& trace = detail::get_raw_trace_and_absorb() + ) noexcept + : exception_with_message(std::move(message_arg), std::move(trace)) {} }; class CPPTRACE_EXPORT out_of_range : public exception_with_message { public: - explicit out_of_range(std::string&& message_arg) noexcept - : exception_with_message(std::move(message_arg), 1) {} + explicit out_of_range( + std::string&& message_arg, + raw_trace&& trace = detail::get_raw_trace_and_absorb() + ) noexcept + : exception_with_message(std::move(message_arg), std::move(trace)) {} }; class CPPTRACE_EXPORT runtime_error : public exception_with_message { public: - explicit runtime_error(std::string&& message_arg) noexcept - : exception_with_message(std::move(message_arg), 1) {} + explicit runtime_error( + std::string&& message_arg, + raw_trace&& trace = detail::get_raw_trace_and_absorb() + ) noexcept + : exception_with_message(std::move(message_arg), std::move(trace)) {} }; class CPPTRACE_EXPORT range_error : public exception_with_message { public: - explicit range_error(std::string&& message_arg) noexcept - : exception_with_message(std::move(message_arg), 1) {} + explicit range_error( + std::string&& message_arg, + raw_trace&& trace = detail::get_raw_trace_and_absorb() + ) noexcept + : exception_with_message(std::move(message_arg), std::move(trace)) {} }; class CPPTRACE_EXPORT overflow_error : public exception_with_message { public: - explicit overflow_error(std::string&& message_arg) noexcept - : exception_with_message(std::move(message_arg), 1) {} + explicit overflow_error( + std::string&& message_arg, + raw_trace&& trace = detail::get_raw_trace_and_absorb() + ) noexcept + : exception_with_message(std::move(message_arg), std::move(trace)) {} }; class CPPTRACE_EXPORT underflow_error : public exception_with_message { public: - explicit underflow_error(std::string&& message_arg) noexcept - : exception_with_message(std::move(message_arg), 1) {} + explicit underflow_error( + std::string&& message_arg, + raw_trace&& trace = detail::get_raw_trace_and_absorb() + ) noexcept + : exception_with_message(std::move(message_arg), std::move(trace)) {} }; class CPPTRACE_EXPORT nested_exception : public lazy_exception { std::exception_ptr ptr; mutable std::string message_value; public: - explicit nested_exception(std::exception_ptr exception_ptr) noexcept - : lazy_exception(1), ptr(exception_ptr) {} - explicit nested_exception(std::exception_ptr exception_ptr, std::size_t skip) noexcept - : lazy_exception(skip + 1), ptr(exception_ptr) {} + explicit nested_exception( + std::exception_ptr exception_ptr, + raw_trace&& trace = detail::get_raw_trace_and_absorb() + ) noexcept + : lazy_exception(std::move(trace)), ptr(exception_ptr) {} const char* message() const noexcept override; std::exception_ptr nested_ptr() const noexcept; diff --git a/src/cpptrace.cpp b/src/cpptrace.cpp index c632df3..acd7fc3 100644 --- a/src/cpptrace.cpp +++ b/src/cpptrace.cpp @@ -459,6 +459,11 @@ namespace cpptrace { } } + CPPTRACE_FORCE_NO_INLINE + raw_trace get_raw_trace_and_absorb(std::size_t skip) noexcept { + return get_raw_trace_and_absorb(skip + 1, SIZE_MAX); + } + lazy_trace_holder::lazy_trace_holder(const lazy_trace_holder& other) : resolved(other.resolved) { if(other.resolved) { new (&resolved_trace) stacktrace(other.resolved_trace); @@ -539,9 +544,6 @@ namespace cpptrace { } } - lazy_exception::lazy_exception(std::size_t skip, std::size_t max_depth) noexcept - : trace_holder(detail::get_raw_trace_and_absorb(skip + 1, max_depth)) {} - const char* lazy_exception::what() const noexcept { if(what_string.empty()) { what_string = message() + std::string(":\n") + trace_holder.get_resolved_trace().to_string(); @@ -585,7 +587,7 @@ namespace cpptrace { } catch(cpptrace::exception&) { throw; // already a cpptrace::exception } catch(...) { - throw nested_exception(std::current_exception(), skip + 1); + throw nested_exception(std::current_exception(), detail::get_raw_trace_and_absorb(skip + 1)); } } }