diff --git a/src/include/serif/utils/error/codes.hpp b/src/include/serif/utils/error/codes.hpp index 68cf519a..98bf6d71 100644 --- a/src/include/serif/utils/error/codes.hpp +++ b/src/include/serif/utils/error/codes.hpp @@ -76,10 +76,40 @@ namespace serif::utils::errors { INVALID_ELEMENT_ID_ERROR, ELEMENT_NULLPTR_ERROR, + // Discretization Errors + DISCRETIZATION_ERROR = 500, + + //Schema Error + SCHEMA_ERROR = 510, + INVALID_SCHEMA_ARGUMENTS = 512, + //As yet uncategorized errors - MATRIX_SHAPE_ERROR = 500, + MATRIX_SHAPE_ERROR = 600, OUT_OF_RANGE_ERROR, + // Solver Errors + SOLVER_ERROR = 700, + //NormalizationErrors + NORMALIZATION_ERROR = 730, + NORMALIZATION_VECTOR_SIZE_MISMATCH, + NORMALIZATION_BUFFER_OVERLAP, + + // Preconditioner Errors + PRECONDITIONER_ERROR = 750, + PRECONDITIONER_INVALID_OPTIONS, + PRECONDITIONER_INVALID_OPERATOR, + PRECONDITIONER_SIZE_MISMATCH, + PRECONDITIONER_NONFINITE_VALUE, + PRECONDITIONER_SINGULAR_OPERATOR, + PRECONDITIONER_ILL_CONDITIONED_OPERATOR, + PRECONDITIONER_STALE_LINEARIZATION, + PRECONDITIONER_INCOMPATIBLE_STRATEGY, + PRECONDITIONER_UNPREPARED, + PRECONDITIONER_INVALID_CALIBRATION, + + // Equation Errors + EQUATION_ERROR = 800, + // COMPILE TIME FAILURES (>1000) // Type Invariant Failures FAILED_TYPE_INVARIANT = 1000 diff --git a/src/include/serif/utils/error/errors.hpp b/src/include/serif/utils/error/errors.hpp index f771a616..7b2d75d3 100644 --- a/src/include/serif/utils/error/errors.hpp +++ b/src/include/serif/utils/error/errors.hpp @@ -4,7 +4,9 @@ #include #include #include +#include #include +#include #include "serif/utils/misc/terminal/colors.hpp" #include "serif/utils/misc/concepts/exceptions.hpp" @@ -18,13 +20,15 @@ // If you want to throw a warning then look at the parallel warnings module and call serif_warning // Note errors cannot be disabled at compile time, warnings can be disabled to a noop at compile time. + namespace serif::utils::errors { - template - void serif_error(const std::string_view message, auto... args) { + template + std::string format_error_message(const std::string_view message, auto... args) { std::string error_msg; std::string code_name{SERiFErrorCodeTypeToNameMap.at(code)}; std::ranges::transform(code_name, code_name.begin(), [](const unsigned char c){ return std::toupper(c); }); + if (misc::terminal::supports_ansi(stderr)) { error_msg = std::format("{}{}{}: {}", misc::terminal::a_red, "Error", misc::terminal::a_reset, std::vformat(message, std::make_format_args(args...))); // format error code with color if terminal supports ANSI @@ -34,48 +38,41 @@ namespace serif::utils::errors { // Add error code without color if terminal does not support ANSI error_msg = std::format("{} (code No.: {} [{}])", error_msg, static_cast>(code), code_name); } - - throw ExceptionT(error_msg); + return error_msg; } - template - void serif_assert(const bool condition, const std::string_view message, auto... args) { - // collapse to a noop if NDEBUG is defined -#ifndef NDEBUG - constexpr bool is_debug_build = true; -#else - constexpr bool is_debug_build = false; -#endif - if constexpr(is_debug_build) { - if (!condition) { - serif_error(message, args...); - } - } + template + void serif_error(const std::string_view message, auto... args) { + std::string error_msg = format_error_message(message, args...); + throw ExceptionT(error_msg); } template struct serif_error_printer; - template + template constexpr void serif_assert() { #ifndef NDEBUG - constexpr bool is_debug_build = true; + if constexpr (!condition) { +#if defined(__cpp_static_assert) && __cpp_static_assert >= 202306L /// This is the feature flag for C++26 user defined static_assert messages. + static_assert(condition, message); #else - constexpr bool is_debug_build = false; + [[maybe_unused]] constexpr std::size_t errorKick = sizeof(serif_error_printer); #endif - - if constexpr (is_debug_build) { - if constexpr (!condition) { - // Trigger an intentional error to display the message and code at compile time - - // Note if we move to C++26 we can replace this with a more standard and less convoluted - // formated static_assert. - [[maybe_unused]] std::size_t error_kick = sizeof(serif_error_printer); - } } +#endif } + template + void serif_assert(const bool condition, const std::string_view message, auto&&... args) { + #ifndef NDEBUG + if (!condition) { + serif_error(message, std::forward(args)...); + } + #endif + } + // The difference between serif_assert and serif_ensure is that serif_assert is a noop in release builds, while serif_ensure is always active. // Use an ensure when you want to always check things. Use an assert when you want to check things that are true bugs // and should not manifest in release builds. @@ -86,14 +83,14 @@ namespace serif::utils::errors { } } - template + template constexpr void serif_ensure() { if constexpr (!condition) { - // Trigger an intentional error to display the message and code at compile time - - // Note if we move to C++26 we can replace this with a more standard and less convoluted - // formated static_assert. - [[maybe_unused]] std::size_t error_kick = sizeof(serif_error_printer); +#if defined(__cpp_static_assert) && __cpp_static_assert >= 202306L /// This is the feature flag for C++26 user defined static_assert messages. + static_assert(condition, message); +#else + [[maybe_unused]] constexpr std::size_t errorKick = sizeof(serif_error_printer); +#endif } } } \ No newline at end of file diff --git a/src/include/serif/utils/error/nonfinite.hpp b/src/include/serif/utils/error/nonfinite.hpp new file mode 100644 index 00000000..1dd0e5f0 --- /dev/null +++ b/src/include/serif/utils/error/nonfinite.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include + +namespace serif::utils::errors { + /** + * @brief A numerical action produced a nonfinite coefficient, distinguishable from a broken API contract. + * Most numerical interfaces report rejection as a value. MFEM operator applications return void, + * so their checked caller intercepts this specific bridge while other exceptions propagate. + */ + class NonFiniteValue final : public std::domain_error { + public: + using std::domain_error::domain_error; + }; +}