// Copyright (C) 2026 Kiyotsugu Arai // SPDX-License-Identifier: LGPL-3.0-or-later // error.hpp // // Error handling for the state-management system // // This file provides additional interfaces for error handling related to the numeric-state-management system. // It implements more specialized error handling using the exception classes and state-error functionality defined in common.hpp. // // Main features: // - Specialized error-detection utilities // - Additional error-handling policies #ifndef SANGI_ERROR_HPP #define SANGI_ERROR_HPP #include #include #include #include #include namespace sangi { // Error-handling utilities // Division-by-zero check template inline void check_division_by_zero(T divisor, const std::string& message = "Division by zero") { if (divisor == T(0)) { const auto& options = global_state_error_options(); switch (options.divide_by_zero_error_mode) { case StateErrorMode::Exception: throw DivideByZeroError(message); case StateErrorMode::ReturnSpecial: case StateErrorMode::Silent: // Special values are handled by the caller break; } } } // NaN check template inline void check_nan(const T& value, const std::string& message = "Operation resulted in NaN") { if (std::isnan(value)) { const auto& options = global_state_error_options(); switch (options.nan_error_mode) { case StateErrorMode::Exception: throw NaNError(message); case StateErrorMode::ReturnSpecial: case StateErrorMode::Silent: // Special values are handled by the caller break; } } } // Infinity check template inline void check_infinity(const T& value, const std::string& message = "Operation resulted in infinity") { if (std::isinf(value)) { const auto& options = global_state_error_options(); switch (options.infinity_error_mode) { case StateErrorMode::Exception: throw InfinityError(message, value > 0); case StateErrorMode::ReturnSpecial: case StateErrorMode::Silent: // Special values are handled by the caller break; } } } // Overflow check inline void check_overflow(bool overflow_condition, const std::string& message = "Numeric overflow") { if (overflow_condition) { const auto& options = global_state_error_options(); switch (options.overflow_error_mode) { case StateErrorMode::Exception: throw OverflowError(message); case StateErrorMode::ReturnSpecial: case StateErrorMode::Silent: // Special values are handled by the caller break; } } } // Underflow check inline void check_underflow(bool underflow_condition, const std::string& message = "Numeric underflow") { if (underflow_condition) { const auto& options = global_state_error_options(); switch (options.underflow_error_mode) { case StateErrorMode::Exception: throw UnderflowError(message); case StateErrorMode::ReturnSpecial: case StateErrorMode::Silent: // Special values are handled by the caller break; } } } // Divergence check inline void check_divergence(bool divergence_condition, DivergenceDetail detail = DivergenceDetail::Diverging, const std::string& message = "Algorithm diverged") { if (divergence_condition) { const auto& options = global_state_error_options(); switch (options.divergence_error_mode) { case StateErrorMode::Exception: throw DivergenceStateError(message, detail); case StateErrorMode::ReturnSpecial: case StateErrorMode::Silent: // Special values are handled by the caller break; } } } // Combined error-cause + state check inline void check_error_and_state(NumericError error, NumericState state, const std::string& message = "Numeric error occurred") { const auto& options = global_state_error_options(); // Checks based on error cause if (error != NumericError::None) { switch (error) { case NumericError::DivideByZero: if (options.divide_by_zero_error_mode == StateErrorMode::Exception) { throw DivideByZeroError(message); } break; case NumericError::NaNPropagation: case NumericError::ExplicitNaN: if (options.nan_error_mode == StateErrorMode::Exception) { throw NaNError(message); } break; case NumericError::ConversionError: case NumericError::OutOfRangeInput: if (options.overflow_error_mode == StateErrorMode::Exception) { throw OverflowError(message); } break; case NumericError::DivergenceError: if (options.divergence_error_mode == StateErrorMode::Exception) { throw DivergenceStateError(message); } break; default: // Other errors are not specifically handled break; } } // Checks based on state if (NumericStateTraits::isNaN(state) && options.nan_error_mode == StateErrorMode::Exception) { throw NaNError(message); } if (NumericStateTraits::isInfinite(state)) { if (options.infinity_error_mode == StateErrorMode::Exception) { bool is_positive = (state == NumericState::PositiveInfinity); throw InfinityError(message, is_positive); } } if (state == NumericState::Overflow && options.overflow_error_mode == StateErrorMode::Exception) { throw OverflowError(message); } if (state == NumericState::Underflow && options.underflow_error_mode == StateErrorMode::Exception) { throw UnderflowError(message); } if (NumericStateTraits::isDivergent(state) && options.divergence_error_mode == StateErrorMode::Exception) { throw DivergenceStateError(message); } } // Additional: utility to verify consistency between state and error inline void validate_state_and_error(NumericState& state, NumericError& error) { // If an error exists while the state is normal, set the state matching the error if (error != NumericError::None && state == NumericState::Normal) { state = NumericStateTraits::errorToState(error); } // If the state is special but no error is set, set the default error matching the state if (NumericStateTraits::requiresErrorCode(state) && error == NumericError::None) { error = NumericStateTraits::stateToDefaultError(state); } } // Additional: helper to set state and error consistently inline void set_state_and_error(NumericState& state_dest, NumericError& error_dest, NumericState state_src, NumericError error_src) { state_dest = state_src; error_dest = error_src; validate_state_and_error(state_dest, error_dest); } } // namespace sangi #endif // SANGI_ERROR_HPP