4#ifndef SVMP_CORE_EXCEPTION_H
5#define SVMP_CORE_EXCEPTION_H
17#if !defined(NDEBUG) || defined(DEBUG) || defined(_DEBUG)
18# define SVMP_EXCEPTION_DEBUG_MODE 1
20# define SVMP_EXCEPTION_DEBUG_MODE 0
25enum class StatusCode : std::uint8_t {
40inline const char* status_code_to_string(StatusCode status)
noexcept
43 case StatusCode::Success:
45 case StatusCode::InvalidArgument:
46 return "Invalid argument";
47 case StatusCode::InvalidState:
48 return "Invalid state";
49 case StatusCode::ParseError:
51 case StatusCode::IOError:
53 case StatusCode::ResourceExhausted:
54 return "Resource exhausted";
55 case StatusCode::DependencyError:
56 return "Dependency error";
57 case StatusCode::MPIError:
59 case StatusCode::NotImplemented:
60 return "Not implemented";
61 case StatusCode::UnsupportedOperation:
62 return "Unsupported operation";
63 case StatusCode::InternalError:
64 return "Internal error";
66 return "Unknown error";
80 StackTraceFrame(std::string symbol, std::string module, std::string file,
81 int line, std::uintptr_t address) noexcept
82 : symbol_(std::move(symbol)),
83 module_(std::move(module)),
84 file_(std::move(file)),
90 const std::string& symbol()
const noexcept {
return symbol_; }
91 const std::string& module()
const noexcept {
return module_; }
92 const std::string& file()
const noexcept {
return file_; }
93 int line()
const noexcept {
return line_; }
94 std::uintptr_t address()
const noexcept {
return address_; }
101 std::uintptr_t address_ = 0;
106 bool empty()
const noexcept {
return frames_.empty(); }
107 std::size_t size()
const noexcept {
return frames_.size(); }
108 const std::vector<StackTraceFrame>& frames()
const noexcept {
return frames_; }
109 void add_frame(
StackTraceFrame frame) { frames_.push_back(std::move(frame)); }
112 std::vector<StackTraceFrame> frames_;
116 bool has_stack_trace;
117 bool has_symbol_resolution;
124 static int query_mpi_rank()
noexcept;
126 static std::string demangle_symbol(
const char* symbol);
127 static void finalize_mpi_if_needed()
noexcept;
128 static void abort_mpi_if_needed(
int exit_code)
noexcept;
132#define SVMP_CORE_EXCEPTION_INCLUDE_PLATFORM_SUPPORT
133#include "PlatformSupport.inl"
134#undef SVMP_CORE_EXCEPTION_INCLUDE_PLATFORM_SUPPORT
140 StatusCode status_code()
const noexcept {
return status_code_; }
141 const std::string& file()
const noexcept {
return file_; }
142 int line()
const noexcept {
return line_; }
143 const std::string& function()
const noexcept {
return function_; }
144 int mpi_rank()
const noexcept {
return mpi_rank_; }
145 const StackTrace& stack_trace()
const noexcept {
return stack_trace_; }
147 void set_status_code(StatusCode status_code)
noexcept
149 status_code_ = status_code;
152 void set_source_location(
const char* file,
int line,
const char* function)
154 file_ = (file ==
nullptr) ? std::string() : std::string(file);
157 (function ==
nullptr) ? std::string() : std::string(function);
160 void set_mpi_rank(
int mpi_rank)
noexcept { mpi_rank_ = mpi_rank; }
163 stack_trace_ = std::move(stack_trace);
167 StatusCode status_code_ = StatusCode::Unknown;
170 std::string function_;
175namespace ExceptionFormatter {
178 const std::string& message,
179 std::string_view subsystem_label =
"Exception")
181 if (subsystem_label.empty()) {
182 subsystem_label =
"Exception";
185 std::ostringstream oss;
187 oss <<
"[" << subsystem_label <<
"] "
188 << status_code_to_string(context.status_code());
189 if (context.mpi_rank() >= 0) {
190 oss <<
" (Rank " << context.mpi_rank() <<
")";
194 if (!context.file().empty()) {
195 oss <<
" Location: " << context.file() <<
":" << context.line();
196 if (!context.function().empty()) {
197 oss <<
" in " << context.function() <<
"()";
202 oss <<
" Message: " << message <<
"\n";
204 if (!context.stack_trace().empty()) {
205 oss <<
" Stack trace:\n";
206 std::size_t frame_index = 0;
207 for (
const auto& frame : context.stack_trace().frames()) {
208 oss <<
" #" << frame_index++ <<
" ";
209 if (!frame.symbol().empty()) {
210 oss << frame.symbol();
212 std::ostringstream address;
213 address <<
"0x" << std::hex << frame.address();
214 oss << address.str();
217 if (!frame.module().empty()) {
218 oss <<
" [" << frame.module() <<
"]";
221 if (!frame.file().empty()) {
222 oss <<
" (" << frame.file();
223 if (frame.line() > 0) {
224 oss <<
":" << frame.line();
240namespace ExceptionRuntime {
242 inline int query_mpi_rank() noexcept
244 return PlatformSupport::query_mpi_rank();
247 inline StackTrace capture_stack_trace()
249 return PlatformSupport::capture_stack_trace();
252 inline void finalize_mpi_if_needed() noexcept
254 PlatformSupport::finalize_mpi_if_needed();
257 void install_terminate_handler();
259 inline void report_unhandled_exception(
const std::exception& exception)
261 std::cerr << exception.what() << std::endl;
264 inline void abort_mpi_if_needed(
int exit_code)
noexcept
266 PlatformSupport::abort_mpi_if_needed(exit_code);
273 const char* what()
const noexcept override {
return what_.c_str(); }
274 StatusCode status_code()
const noexcept {
return context_.status_code(); }
275 const std::string& message()
const noexcept {
return message_; }
278 void add_context(
const std::string& context)
280 message_ = context +
"\n -> " + message_;
288 std::string_view subsystem_label,
const char* file,
289 int line,
const char* function)
290 : message_(std::move(message)),
291 subsystem_label_(subsystem_label.empty() ? std::string_view(
"Exception")
294 context_.set_status_code(status);
295 context_.set_source_location(file, line, function);
296 context_.set_mpi_rank(ExceptionRuntime::query_mpi_rank());
297#if SVMP_EXCEPTION_DEBUG_MODE
298 context_.set_stack_trace(ExceptionRuntime::capture_stack_trace());
305 what_ = ExceptionFormatter::format(context_, message_, subsystem_label_);
308 std::string message_;
310 std::string_view subsystem_label_;
317 StatusCode status = StatusCode::Unknown,
318 const char* file =
"",
320 const char* function =
"")
321 :
ExceptionBase(message, status,
"Core Exception", file, line, function)
329 const char* file =
"",
331 const char* function =
"")
332 :
CoreException(message, StatusCode::ParseError, file, line, function)
340 const char* file =
"",
342 const char* function =
"")
343 :
CoreException(message, StatusCode::DependencyError, file, line,
349inline void ExceptionRuntime::install_terminate_handler()
351 std::set_terminate([]() {
353 const std::exception_ptr current = std::current_exception();
354 if (current !=
nullptr) {
355 std::rethrow_exception(current);
357 }
catch (
const std::exception& exception) {
358 ExceptionRuntime::report_unhandled_exception(exception);
360 std::cerr <<
"[Unhandled Exception] Unknown non-std exception"
364 ExceptionRuntime::abort_mpi_if_needed(EXIT_FAILURE);
369template <
class ExceptionT,
class... Args>
370[[noreturn]]
void raise(SourceLocation location, Args&&... args)
372 throw ExceptionT(std::forward<Args>(args)..., location.file, location.line,
376template <
class ExceptionT,
class... Args>
377void check(
bool condition, SourceLocation location, Args&&... args)
380 raise<ExceptionT>(location, std::forward<Args>(args)...);
384template <
class ExceptionT,
class... Args>
385void check_arg(
bool condition, SourceLocation location, Args&&... args)
388 raise<ExceptionT>(location, std::forward<Args>(args)...);
392template <
class ExceptionT,
class PointerT,
class... Args>
393void check_not_null(PointerT ptr, SourceLocation location, Args&&... args)
395 if (ptr ==
nullptr) {
396 raise<ExceptionT>(location, std::forward<Args>(args)...);
402#define SVMP_HERE ::svmp::SourceLocation{__FILE__, __LINE__, __func__}
404#if SVMP_EXCEPTION_DEBUG_MODE
405#define SVMP_DEBUG_CHECK(ExceptionT, condition, ...) \
407 if (!(condition)) { \
408 ::svmp::raise<ExceptionT>(SVMP_HERE, __VA_ARGS__); \
412#define SVMP_DEBUG_CHECK(ExceptionT, condition, ...) \
Definition Exception.h:314
Definition Exception.h:337
Definition Exception.h:271
Definition Exception.h:138
Definition Exception.h:326
Definition Exception.h:76
Definition Exception.h:104
Definition Exception.h:70