|
| 1 | +#ifndef YSTDLIB_ERROR_HANDLING_TRACEABLEEXCEPTION_HPP |
| 2 | +#define YSTDLIB_ERROR_HANDLING_TRACEABLEEXCEPTION_HPP |
| 3 | + |
| 4 | +#include <concepts> |
| 5 | +#include <exception> |
| 6 | +#include <source_location> |
| 7 | +#include <stacktrace> |
| 8 | +#include <string> |
| 9 | +#include <system_error> |
| 10 | + |
| 11 | +#include "SourceLocation.hpp" |
| 12 | + |
| 13 | +namespace ystdlib::error_handling { |
| 14 | +/** |
| 15 | + * Concept that defines a template parameter of an integer-based error code enumeration. |
| 16 | + * @tparam Type |
| 17 | + */ |
| 18 | +template <typename Type> |
| 19 | +concept ErrorCodeType |
| 20 | + = std::same_as<Type, std::error_code> || std::convertible_to<Type, std::error_code>; |
| 21 | + |
| 22 | +/** |
| 23 | + * An exception class that is thrown with an `std::error_code`. |
| 24 | + * |
| 25 | + * This class extends `std::exception` and can be thrown with an `std::error_code` argument. It also |
| 26 | + * provides additional information to aid in debugging by storing details in `std::source_location`, |
| 27 | + * including the function name, file name, and line number of the throwing location. |
| 28 | + * |
| 29 | + * @see std::source_location::file_name() |
| 30 | + * @see std::source_location::function_name() |
| 31 | + * @see std::source_location::line() |
| 32 | + */ |
| 33 | +template <typename ErrorCodeType> |
| 34 | +class TraceableException : public std::exception, public std::source_location { |
| 35 | +public: |
| 36 | + // Constructors |
| 37 | + explicit TraceableException( |
| 38 | + ErrorCodeType error_code, |
| 39 | + std::source_location const& where = std::source_location::current() |
| 40 | + ) |
| 41 | + : TraceableException{std::move(error_code), where.function_name(), where} {} |
| 42 | + |
| 43 | + explicit TraceableException( |
| 44 | + ErrorCodeType error_code, |
| 45 | + std::string what, |
| 46 | + std::source_location const& where = std::source_location::current() |
| 47 | + ) |
| 48 | + : m_error_code{std::move(error_code)}, |
| 49 | + m_what{std::move(what)}, |
| 50 | + m_where{where} {} |
| 51 | + |
| 52 | + // Methods implementing std::exception |
| 53 | + [[nodiscard]] auto what() const noexcept -> char const* override { return m_what.c_str(); } |
| 54 | + |
| 55 | + // Methods |
| 56 | + [[nodiscard]] auto error_code() const -> ErrorCodeType { return m_error_code; } |
| 57 | + |
| 58 | + [[nodiscard]] auto what() -> std::string& { return m_what; } |
| 59 | + |
| 60 | + [[nodiscard]] auto where() const noexcept -> SourceLocation const& { return m_where; } |
| 61 | + |
| 62 | +private: |
| 63 | + // Variables |
| 64 | + ErrorCodeType const m_error_code; |
| 65 | + std::string m_what; |
| 66 | + SourceLocation const m_where; |
| 67 | +}; |
| 68 | + |
| 69 | +} // namespace ystdlib::error_handling |
| 70 | + |
| 71 | +/** |
| 72 | + * The macro to define a `TraceableException` class with the given class name T. |
| 73 | + */ |
| 74 | +// NOLINTBEGIN(bugprone-macro-parentheses, cppcoreguidelines-macro-usage) |
| 75 | +#define YSTDLIB_ERROR_HANDLING_DEFINE_TRACEABLE_EXCEPTION(T, E) \ |
| 76 | + class T : public ystdlib::error_handling::TraceableException<E> { \ |
| 77 | + using ystdlib::error_handling::TraceableException<E>::TraceableException; \ |
| 78 | + } |
| 79 | +// NOLINTEND(bugprone-macro-parentheses, cppcoreguidelines-macro-usage) |
| 80 | + |
| 81 | +#endif // YSTDLIB_ERROR_HANDLING_TRACEABLEEXCEPTION_HPP |
0 commit comments