4#ifndef SVMP_CORE_EXCEPTION_H
5#define SVMP_CORE_EXCEPTION_H
18#if !defined(NDEBUG) || defined(DEBUG) || defined(_DEBUG)
19#define SVMP_EXCEPTION_DEBUG_MODE 1
21#define SVMP_EXCEPTION_DEBUG_MODE 0
26enum class StatusCode : std::uint8_t {
41inline 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)), module_(std::move(module)),
83 file_(std::move(file)), line_(line), address_(address) {}
85 const std::string &symbol()
const noexcept {
return symbol_; }
86 const std::string &module()
const noexcept {
return module_; }
87 const std::string &file()
const noexcept {
return file_; }
88 int line()
const noexcept {
return line_; }
89 std::uintptr_t address()
const noexcept {
return address_; }
96 std::uintptr_t address_ = 0;
101 bool empty()
const noexcept {
return frames_.empty(); }
102 std::size_t size()
const noexcept {
return frames_.size(); }
103 const std::vector<StackTraceFrame> &frames()
const noexcept {
106 void add_frame(
StackTraceFrame frame) { frames_.push_back(std::move(frame)); }
109 std::vector<StackTraceFrame> frames_;
113 bool has_stack_trace;
114 bool has_symbol_resolution;
121 static int query_mpi_rank()
noexcept;
123 static std::string demangle_symbol(
const char *symbol);
124 static void finalize_mpi_if_needed()
noexcept;
125 static void abort_mpi_if_needed(
int exit_code)
noexcept;
129#define SVMP_CORE_EXCEPTION_INCLUDE_PLATFORM_SUPPORT
130#include "PlatformSupport.inl"
131#undef SVMP_CORE_EXCEPTION_INCLUDE_PLATFORM_SUPPORT
137 StatusCode status_code()
const noexcept {
return status_code_; }
138 const std::string &file()
const noexcept {
return file_; }
139 int line()
const noexcept {
return line_; }
140 const std::string &function()
const noexcept {
return function_; }
141 int mpi_rank()
const noexcept {
return mpi_rank_; }
142 const StackTrace &stack_trace()
const noexcept {
return stack_trace_; }
144 void set_status_code(StatusCode status_code)
noexcept {
145 status_code_ = status_code;
148 void set_source_location(
const char *file,
int line,
const char *function) {
149 file_ = (file ==
nullptr) ? std::string() : std::string(file);
151 function_ = (function ==
nullptr) ? std::string() : std::string(function);
154 void set_mpi_rank(
int mpi_rank)
noexcept { mpi_rank_ = mpi_rank; }
155 void set_stack_trace(
StackTrace stack_trace) {
156 stack_trace_ = std::move(stack_trace);
160 StatusCode status_code_ = StatusCode::Unknown;
163 std::string function_;
168namespace ExceptionFormatter {
171 const std::string &message,
172 std::string_view subsystem_label =
"Exception") {
173 if (subsystem_label.empty()) {
174 subsystem_label =
"Exception";
177 std::ostringstream oss;
179 oss <<
"[" << subsystem_label <<
"] "
180 << status_code_to_string(context.status_code());
181 if (context.mpi_rank() >= 0) {
182 oss <<
" (Rank " << context.mpi_rank() <<
")";
186 if (!context.file().empty()) {
187 oss <<
" Location: " << context.file() <<
":" << context.line();
188 if (!context.function().empty()) {
189 oss <<
" in " << context.function() <<
"()";
194 oss <<
" Message: " << message <<
"\n";
196 if (!context.stack_trace().empty()) {
197 oss <<
" Stack trace:\n";
198 std::size_t frame_index = 0;
199 for (
const auto &frame : context.stack_trace().frames()) {
200 oss <<
" #" << frame_index++ <<
" ";
201 if (!frame.symbol().empty()) {
202 oss << frame.symbol();
204 std::ostringstream address;
205 address <<
"0x" << std::hex << frame.address();
206 oss << address.str();
209 if (!frame.module().empty()) {
210 oss <<
" [" << frame.module() <<
"]";
213 if (!frame.file().empty()) {
214 oss <<
" (" << frame.file();
215 if (frame.line() > 0) {
216 oss <<
":" << frame.line();
232namespace ExceptionRuntime {
234inline int query_mpi_rank() noexcept {
235 return PlatformSupport::query_mpi_rank();
238inline StackTrace capture_stack_trace() {
239 return PlatformSupport::capture_stack_trace();
242inline void finalize_mpi_if_needed() noexcept {
243 PlatformSupport::finalize_mpi_if_needed();
246void install_terminate_handler();
248inline void report_unhandled_exception(
const std::exception &exception) {
249 std::cerr << exception.what() << std::endl;
252inline void abort_mpi_if_needed(
int exit_code)
noexcept {
253 PlatformSupport::abort_mpi_if_needed(exit_code);
260 const char *what()
const noexcept override {
return what_.c_str(); }
261 StatusCode status_code()
const noexcept {
return context_.status_code(); }
262 const std::string &message()
const noexcept {
return message_; }
265 void add_context(
const std::string &context) {
266 message_ = context +
"\n -> " + message_;
275 context_.set_source_location(location.file, location.line,
284 std::string_view subsystem_label, const
char *file = "",
285 int line = 0, const
char *function = "")
286 : message_(std::move(message)),
287 subsystem_label_(subsystem_label.empty() ? std::string_view("Exception")
289 context_.set_status_code(status);
290 context_.set_source_location(file, line, function);
291 context_.set_mpi_rank(ExceptionRuntime::query_mpi_rank());
292#if SVMP_EXCEPTION_DEBUG_MODE
293 context_.set_stack_trace(ExceptionRuntime::capture_stack_trace());
298 void rebuild_what() {
299 what_ = ExceptionFormatter::format(context_, message_, subsystem_label_);
302 std::string message_;
303 ExceptionContext context_;
304 std::string_view subsystem_label_;
311 StatusCode status = StatusCode::Unknown,
const char *file =
"",
312 int line = 0,
const char *function =
"")
313 :
ExceptionBase(message, status,
"Core Exception", file, line, function) {
335#define SVMP_DEFINE_EXCEPTION(Name, Base, Status) \
336 class Name : public Base { \
338 explicit Name(const std::string &message) : Base(message, (Status)) {} \
346 StatusCode::DependencyError);
352 StatusCode::NotImplemented);
359 StatusCode::InvalidArgument);
366 StatusCode::InternalError);
375 int line = 0,
const char *function =
"")
376 :
CoreException(
"Could not open file " + file_name, StatusCode::IOError,
377 file, line, function) {}
389 const char *file =
"",
int line = 0,
390 const char *function =
"")
391 :
CoreException(
"Error parsing file " + file_name +
". " + message,
392 StatusCode::IOError, file, line, function) {}
395inline void ExceptionRuntime::install_terminate_handler() {
396 std::set_terminate([]() {
398 const std::exception_ptr current = std::current_exception();
399 if (current !=
nullptr) {
400 std::rethrow_exception(current);
402 }
catch (
const std::exception &exception) {
403 ExceptionRuntime::report_unhandled_exception(exception);
405 std::cerr <<
"[Unhandled Exception] Unknown non-std exception"
409 ExceptionRuntime::abort_mpi_if_needed(EXIT_FAILURE);
441 int line = __builtin_LINE(),
442 const char *function = __builtin_FUNCTION())
443 : message_(
message), location_{file, line, function} {}
453 int line = __builtin_LINE(),
454 const char *function = __builtin_FUNCTION())
455 : message_(std::move(
message)), location_{file, line, function} {}
461 const std::string &
message() const noexcept {
return message_; }
469 std::string message_;
484template <
class ExceptionT,
class... Args>
485[[noreturn]]
void raise(Diagnostic diagnostic, Args &&...args) {
487 std::is_base_of_v<ExceptionBase, ExceptionT>,
488 "raise<>() requires an svmp::ExceptionBase-derived exception type");
489 ExceptionT exception(diagnostic.message(), std::forward<Args>(args)...);
490 exception.set_source_location(diagnostic.location());
501template <
class ExceptionT,
class... Args>
502void check(
bool condition, Diagnostic diagnostic, Args &&...args) {
504 raise<ExceptionT>(std::move(diagnostic), std::forward<Args>(args)...);
511template <
class ExceptionT,
class PointerT,
class... Args>
512void check_not_null(PointerT ptr, Diagnostic diagnostic, Args &&...args) {
513 if (ptr ==
nullptr) {
514 raise<ExceptionT>(std::move(diagnostic), std::forward<Args>(args)...);
525template <
class ExceptionT,
class... Args>
526void throw_if(
bool condition, Diagnostic diagnostic, Args &&...args) {
528 raise<ExceptionT>(std::move(diagnostic), std::forward<Args>(args)...);
539template <
class ExceptionT = IndexOutOfRangeException,
class IndexT,
541void check_index(IndexT index, SizeT size,
const char *file = __builtin_FILE(),
542 int line = __builtin_LINE(),
543 const char *function = __builtin_FUNCTION()) {
544 const long long index_value =
static_cast<long long>(index);
545 const long long size_value =
static_cast<long long>(size);
546 check<ExceptionT>(index_value >= 0 && index_value < size_value,
547 Diagnostic(
"Index " + std::to_string(index_value) +
548 " out of bounds [0, " +
549 std::to_string(size_value) +
")",
550 file, line, function));
563template <
class ExceptionT = NotImplementedException>
564[[noreturn]]
void not_implemented(std::string message,
565 const char *file = __builtin_FILE(),
566 int line = __builtin_LINE(),
567 const char *function = __builtin_FUNCTION()) {
568 raise<ExceptionT>(Diagnostic(std::move(message), file, line, function));
573#if SVMP_EXCEPTION_DEBUG_MODE
574#define SVMP_DEBUG_CHECK(ExceptionT, condition, ...) \
576 if (!(condition)) { \
577 ::svmp::raise<ExceptionT>(__VA_ARGS__); \
581#define SVMP_DEBUG_CHECK(ExceptionT, condition, ...) \
Definition Exception.h:308
A required dependency is missing or failed to load.
Definition Exception.h:346
A diagnostic message bundled with the source location where it was written.
Definition Exception.h:430
const SourceLocation & location() const noexcept
The source location captured when the Diagnostic was constructed.
Definition Exception.h:466
Diagnostic(const char *message, const char *file=__builtin_FILE(), int line=__builtin_LINE(), const char *function=__builtin_FUNCTION())
Wrap a message, capturing the caller's source location by default.
Definition Exception.h:440
const std::string & message() const noexcept
The diagnostic message.
Definition Exception.h:461
Diagnostic(std::string message, const char *file=__builtin_FILE(), int line=__builtin_LINE(), const char *function=__builtin_FUNCTION())
Wrap a message, capturing the caller's source location by default.
Definition Exception.h:452
Definition Exception.h:258
void set_source_location(const SourceLocation &location)
Record the originating source location and refresh what().
Definition Exception.h:274
Definition Exception.h:135
An exception raised when a file cannot be opened.
Definition Exception.h:372
An index is outside its valid range.
Definition Exception.h:359
Internal error exception.
Definition Exception.h:366
A requested operation or feature is not implemented.
Definition Exception.h:352
A parsing or input-format error.
Definition Exception.h:342
Definition Exception.h:76
Definition Exception.h:99
Definition Exception.h:70