Skip to content

Commit

Permalink
Make the default failure handler public and update docs for custom fa…
Browse files Browse the repository at this point in the history
…ilure handlers
  • Loading branch information
jeremy-rifkin committed Dec 22, 2024
1 parent 470ff6b commit 3bf1bc6
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 26 deletions.
19 changes: 16 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ screenshots above. This is to help enhance readability.
Libassert supports custom assertion failure handlers:

```cpp
void handler(assert_type type, const assertion_info& assertion) {
void handler(const assertion_info& info) {
throw std::runtime_error("Assertion failed:\n" + assertion.to_string());
}

Expand All @@ -224,6 +224,8 @@ int main() {
}
```
More details [below](#custom-failure-handlers-1).
## Debug Stringification <!-- omit in toc -->
A lot of care is given to producing debug stringifications of values as effectively as possible: Strings, characters,
Expand Down Expand Up @@ -689,15 +691,26 @@ Lastly, any types with an ostream `operator<<` overload can be stringified.
```cpp
namespace libassert {
void set_failure_handler(void (*handler)(const assertion_info&));
[[noreturn]] void default_failure_handler(const assertion_info& info);
}
```
- `set_failure_handler`: Sets the assertion handler for the program.
- `default_failure_handler`: The default failure handler, provided for convenience.
Example: If you wanted to log to a file in addition to the default behavior you could do something along the lines of:
```cpp
void handler(const assertion_info& info) {
logger::error(info.to_string());
libassert::default_failure_handler(info);
}
```

An example assertion handler similar to the default handler:
For more complex custom handling you can modify the default handler's logic:

```cpp
void libassert_default_failure_handler(const assertion_info& info) {
void default_failure_handler(const assertion_info& info) {
libassert::enable_virtual_terminal_processing_if_needed(); // for terminal colors on windows
std::string message = info.to_string(
libassert::terminal_width(libassert::stderr_fileno),
Expand Down
2 changes: 2 additions & 0 deletions include/libassert/assert.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ namespace libassert {

struct assertion_info;

LIBASSERT_EXPORT [[noreturn]] void default_failure_handler(const assertion_info& info);

LIBASSERT_EXPORT void set_failure_handler(void (*handler)(const assertion_info&));

struct LIBASSERT_EXPORT binary_diagnostics_descriptor {
Expand Down
47 changes: 24 additions & 23 deletions src/assert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -422,32 +422,33 @@ namespace libassert {
}
}

LIBASSERT_ATTR_COLD
void libassert_default_failure_handler(const assertion_info& info) {
enable_virtual_terminal_processing_if_needed(); // for terminal colors on windows
std::string message = info.to_string(
terminal_width(STDERR_FILENO),
isatty(STDERR_FILENO) ? get_color_scheme() : color_scheme::blank
);
std::cerr << message << std::endl;
switch(info.type) {
case assert_type::assertion:
case assert_type::debug_assertion:
case assert_type::assumption:
case assert_type::panic:
case assert_type::unreachable:
(void)fflush(stderr);
std::abort();
// Breaking here as debug CRT allows aborts to be ignored, if someone wants to make a debug build of
// this library
break;
default:
LIBASSERT_PRIMITIVE_DEBUG_ASSERT(false);
}
}

LIBASSERT_ATTR_COLD LIBASSERT_EXPORT [[noreturn]]
void default_failure_handler(const assertion_info& info) {
enable_virtual_terminal_processing_if_needed(); // for terminal colors on windows
std::string message = info.to_string(
terminal_width(STDERR_FILENO),
isatty(STDERR_FILENO) ? get_color_scheme() : color_scheme::blank
);
std::cerr << message << std::endl;
switch(info.type) {
case assert_type::assertion:
case assert_type::debug_assertion:
case assert_type::assumption:
case assert_type::panic:
case assert_type::unreachable:
(void)fflush(stderr);
std::abort();
// Breaking here as debug CRT allows aborts to be ignored, if someone wants to make a debug build of
// this library
break;
default:
LIBASSERT_PRIMITIVE_PANIC("Unknown assertion type in assertion failure handler");
}
}

static std::atomic failure_handler = detail::libassert_default_failure_handler;
static std::atomic failure_handler = default_failure_handler;

LIBASSERT_ATTR_COLD LIBASSERT_EXPORT
void set_failure_handler(void (*handler)(const assertion_info&)) {
Expand Down

0 comments on commit 3bf1bc6

Please sign in to comment.