Skip to content

Commit

Permalink
Update API and add documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremy-rifkin committed Jun 1, 2024
1 parent 1ec4999 commit fdd2dda
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 9 deletions.
44 changes: 43 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
- [Anatomy of Assertion Information](#anatomy-of-assertion-information)
- [Stringification of Custom Objects](#stringification-of-custom-objects)
- [Custom Failure Handlers](#custom-failure-handlers-1)
- [Breakpoints](#breakpoints)
- [Other Donfigurations](#other-donfigurations)
- [Integration with Test Libraries](#integration-with-test-libraries)
- [Catch2](#catch2)
Expand Down Expand Up @@ -99,12 +100,13 @@ You can enable the lowercase `debug_assert` and `assert` aliases with `-DLIBASSE
- Syntax highlighting
- Stack traces
- `DEBUG_ASSERT_VAL` and `ASSERT_VAL` variants that return a value so they can be integrated seamlessly into code, e.g.
`FILE* f = ASSERT_VAL(fopen(path, "r") != nullptr)`.
`FILE* f = ASSERT_VAL(fopen(path, "r") != nullptr)`
- Smart literal formatting
- Stringification of user-defined types
- Custom failure handlers
- Catch2/Gtest integrations
- {fmt} support
- Programatic breakpoints on assertion failures for more debugger-friendly assertions, more info below
## CMake FetchContent Usage
Expand Down Expand Up @@ -727,6 +729,46 @@ all assertion types instead of aborting.
> [!IMPORTANT]
> Failure handlers must not return for `assert_type::panic` and `assert_type::unreachable`.

## Breakpoints

Libassert supports programatic breakpoints on assertion failure to make assertions more debugger-friendly by breaking on
the assertion line as opposed to several layers deep in a callstack:

![breakpoints](./screenshots/breakpoint.png)

This functionality is currently opt-in and it can be enabled by defining `LIBASSERT_BREAK_ON_FAIL`. This is best done as
a compiler flag: `-DLIBASSERT_BREAK_ON_FAIL` or `/DLIBASSERT_BREAK_ON_FAIL`.

Internally the library checks for the presense of a debugger before executing an instruction to breakpoint the debugger.
By default the check is only performed once on the first assertion failure. In some scenarios it may be desirable to
configure this check to always be performed, e.g. if you're using a custom assertion handler that throws an exception
instead of aborting and you may be able to recover from an assertion failure allowing additional failures later and you
only attach a debugger part-way through the run of your program. You can use `libassert::set_debugger_check_mode` to
control how this check is performed:
```cpp
namespace libassert {
enum class debugger_check_mode {
check_once,
check_every_time,
};
void set_debugger_check_mode(debugger_check_mode mode) noexcept;
}
```
The library also exposes its internal utilities for setting breakpoints and checking if the program is being debugged:
```cpp
namespace libassert {
bool is_debugger_present() noexcept;
}
#define LIBASSERT_BREAKPOINT() <...internals...>
#define LIBASSERT_BREAKPOINT_IF_DEBUGGING() <...internals...>
```
This API mimics the API of [P2514](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2546r3.html), which has
been accepted to C++26.
## Other Donfigurations
**Defines:**
Expand Down
18 changes: 10 additions & 8 deletions include/libassert/assert.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -696,15 +696,17 @@ namespace libassert {
#define LIBASSERT_IGNORE_UNUSED_VALUE
#endif

#define LIBASSERT_BREAKPOINT_IF_DEBUGGING() \
do \
if(libassert::is_debugger_present()) { \
LIBASSERT_BREAKPOINT(); \
} \
while(0)

#ifdef LIBASSERT_BREAK_ON_FAIL
#define LIBASSERT_BREAKPOINT_IF_DEBUGGING() \
do \
if(libassert::is_debugger_present()) { \
LIBASSERT_BREAKPOINT(); \
} \
while(0)
#define LIBASSERT_BREAKPOINT_IF_DEBUGGING_ON_FAIL() LIBASSERT_BREAKPOINT_IF_DEBUGGING()
#else
#define LIBASSERT_BREAKPOINT_IF_DEBUGGING()
#define LIBASSERT_BREAKPOINT_IF_DEBUGGING_ON_FAIL()
#endif

#define LIBASSERT_INVOKE(expr, name, type, failaction, ...) \
Expand All @@ -722,7 +724,7 @@ namespace libassert {
LIBASSERT_WARNING_PRAGMA_POP_GCC \
if(LIBASSERT_STRONG_EXPECT(!static_cast<bool>(libassert_decomposer.get_value()), 0)) { \
libassert::ERROR_ASSERTION_FAILURE_IN_CONSTEXPR_CONTEXT(); \
LIBASSERT_BREAKPOINT_IF_DEBUGGING(); \
LIBASSERT_BREAKPOINT_IF_DEBUGGING_ON_FAIL(); \
failaction \
LIBASSERT_STATIC_DATA(name, libassert::assert_type::type, #expr, __VA_ARGS__) \
if constexpr(sizeof libassert_decomposer > 32) { \
Expand Down

0 comments on commit fdd2dda

Please sign in to comment.