The most over-engineered and overpowered C++ assertion library.

Overview

Asserts

The most over-engineered assertion library.

"Did you just implement syntax highlighting for an assertion library??" - My Russian friend Oleg

Summary: Automatic expression decomposition, diagnostics on binary expressions, assert messages, extra diagnostic values, stack traces, syntax highlighting, errno help, and more!

assert(some_system_call(fd, buffer1, n) > 0, "Internal error with foobars", errno, fd, n);

The Problem:

Asserts are sanity checks for developers: Validating assumptions and helping identify problems at their sources. Assertions should prioritize providing as much information and context to the developer as possible to allow for speedy triage. Unfortunately throughout existing languages and tooling a common theme exists: Assertions are very minimal and when assert(n <= 12); fails we get no information about the value of n. There is no reason assertions should be excessively lightweight.

This library is an exploration looking at how much helpful information and functionality we can pack into assertions while still maintaining ease of use for the developer.

The Ideal:

Ideally assertions can do all of the following:

  • Provide expression strings.
  • Provide values involved in binary expressions, such as assert(count > 0);.
  • Provide failure location and a stacktrace.
  • Display values in useful formats.
  • Support an optional diagnostic message (make assertions self documenting).
  • Support extra diagnostic information being provided.

cassert/assert.h can't do most of these. No tool I know of can do all these, other than this tool 😎 It's fair to say that this is the most overpowered assertion library out there and one of the few libraries that can claim to be more bloated than Boost.

Table of Contents:

Functionality This Library Provides

  • Optional assertion messages
  • Non-fatal assertions option
  • assert_eq and variants for !=, <, >, <=, >=, &&, and ||.
  • Automatic expression decomposition: assert(foo() == bar()); is automatically understood as assert_eq(foo(), bar());. assert_eq and variants may be deprecated once support for automatic decomposition improves.
    • Displaying good diagnostic info here requires some attempt to parse C++ expression grammar, which is ambiguous without type info.
  • Comprehensive stringification (attempts to display a wide variety of types effectively and supports user-defined types).
  • Smart diagnostic info
    • 1 => 1 and other such redundant expression-value diagnostics are not displayed.
    • The library tries to provide format consistency: If a comparison involves an expression and a hex literal, the values of the left and right side are printed in both decimal and hex.
  • Support for providing extra diagnostic information.
  • Automatic strerror for errno.
  • Syntax highlighting, because why not!
  • Signed-unsigned comparison is always done safely by the assertion processor.
  • Custom assertion failure action.
  • Optional assert assumptions in release mode.
  • Stack traces are printed in columns aligned, signatures are highlighted, and paths are shortened from full paths to the shortest sub-path needed to differentiate files with the same name to make reading stack traces easy.

Demo: (note that the call to abort(); on assertion failure is commented out for this demo)

assert(false, "Error while doing XYZ"); // optional assert message
assert(false);

// Diagnostics omit redundant "2 => 2"
assert(map.count(1) == 2);
assert(map.count(1) >= 2 * garple(), "Error while doing XYZ");

// Floating point stringificaiton done carefully to provide the most helpful diagnostic info
assert(1 == 1.5); // not stringified here, it would be redundant
assert(0.1 + 0.2 == 0.3); // stringified here to expose rounding error

// Numbers are always printed in decimal but the assertion processor will also print binary, hex,
// or octal when they might be relevant. Here it will print decimal, binary, and hex because those
// are the literal formats involved.
assert_eq(1, 1 bitand 2);
assert(18446744073709551606ULL == -10); // signed-unsigned comparisons are always done safely
assert(mask bitand flag);
assert(0xf == 16);

// Same care is taken with strings: No redundant diagnostics and strings are also escaped.
assert(s == "test2");
assert(s[i] == 'c', "", s, i);
assert(BLUE "test" RESET == "test");
// The assertion processor takes care not to segfault when attempting to stringify
assert_eq(buffer, thing);

// S<T> has a custom printer (i.e. an std::ostream<< friend)
assert(S<S<int>>(2) == S<S<int>>(4));
S<void> e, f; // S<void> doesn't have a printer
assert(e == f);

And lastly, stack traces don't print the full paths but when multiple files have the same name enough of the path is displayed to differentiate:

A note on performance: I've kept the impact of asserts at callsites minimal. A lot of logic is required to process assertion failures once they happen but failures are the coldest path in a binary, I'm not concerned with performance in the assertion processor as long as it's not noticeably slow. Automatic expression decomposition requires a lot of template shenanigans which is not free.

A note on automatic expression decomposition: In automatic decomposition the assertion processor is only able to obtain a the string for the full expression instead of the left and right parts independently. Because of this the library needs to do some basic expression parsing, just figuring out the very top-level of the expression tree. Unfortunately C++ grammar is ambiguous without type information. The assertion processor is able to disambiguate many expressions but will return {"left", "right"} if it's unable to. Disambiguating expressions is currently done by essentially traversing all possible parse trees. There is probably a more optimal way to do this.

Quick Library Documentation

The library provides a set of macros, invoked as so:

void assert(<expression>, [optional assertion message], [optional extra diagnostics, ...]);

void ASSERT(<expression>, [optional assertion message], [optional extra diagnostics, ...]);
void ASSERT_OP(left, right, [optional assertion message], [optional extra diagnostics, ...]);

T VERIFY(<expression>, [optional assertion message], [optional extra diagnostics, ...]);
T VERIFY_OP(left, right, [optional assertion message], [optional extra diagnostics, ...]);

// Where `op` ∈ {`eq`, `neq`, `lt`, `gt`, `lteq`, `gteq`, `and`, `or`}.

The <expression> is automatically decomposed so diagnostic information can be printed for the left and right sides. The resultant type must be convertible to boolean.

An optional assertion message may be provided. If the first argument following <expression> or left, right is any string type it will be used as the message (if you want the first parameter, which happens to be a string, to be an extra diagnostic simply pass an empty string first).

An aribtray number of extra diagnostic values may be provided. There is special handling when errno is provided, strerror is called automatically. ASSERT::FATAL and ASSERT::NONFATAL may be passed in any position (controlling whether the fail function is called).

VERIFY assertions are fatal but are not disabled with NDEBUG. They return the result of the <expression> or the invocation of the comparison between left and right. One place this is useful is verifying an std::optional has a value, similar to Rust's .unwrap():

if(auto bar = *VERIFY(foo())) {
    ...
}

assert is provided as an alias for ASSERT to be compatible with C's assert.h.

Note: There is no short-circuiting for ASSERT_AND and ASSERT_OR or && and || in expression decomposition.

Note: Top-level integral comparisons are automatically done with sign safety.

Note: left and right hand types in automatically decomposed expressions require move semantics.

Build options:

  • -DNCOLOR Turns off colors
  • -DNDEBUG Disables assertions
  • -DASSUME_ASSERTS Makes assertions serve as optimizer hints in NDEBUG mode. Note: This is not always a win. Sometimes assertion expressions have side effects that are undesirable at runtime in an NDEBUG build like exceptions which cannot be optimized away (e.g. std::unordered_map::at where the lookup cannot be optimized away and ends up not being a helpful compiler hint).
  • -DASSERT_FAIL_ACTION=... Can be used to specify what is done on assertion failure, after diagnostic printing, e.g. throwing an exception instead of calling abort() which is the default. The function should have signature void().

How To Use This Library

This library targets >=C++17 and supports gcc and clang on windows and linux. Note: The library does rely on some compiler extensions / compiler specific features. It supports at least GCC >= 8 and Clang >= 9. The library is no longer single header due to compile times.

  1. Run make to compile static and shared libraries
  2. Copy the static or shared library where you want it.
  3. Copy include/assert.hpp where you want it.
  4. Add a -I path if needed, add a -L path if needed, link with the library (-lassert)
    • For the shared library you may need to add a path to your LD_LIBRARY_PATH environment variable.
    • If static linking, additionally link with dbghelp (-ldbghelp) on windows or lib dl (-ldl) on linux.

Comparison With Other Languages

Even when standard libraries provide constructs like assert_eq they don't always do a good job of providing helpful diagnostics. E.g. Rust where the left and right values are displayed but not the expressions themselves:

fn main() {
    let count = 4;
    assert_eq!(count, 2);
}
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `4`,
 right: `2`', /app/example.rs:3:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

This is not as helpful as it could be.

C/C++ Rust C# Java Python JavaScript This Library
Expression string βœ”οΈ ❌ ❌ ❌ ❌ ❌ βœ”οΈ
Location βœ”οΈ βœ”οΈ βœ”οΈ βœ”οΈ βœ”οΈ βœ”οΈ βœ”οΈ
Backtrace ❌ βœ”οΈ βœ”οΈ βœ”οΈ βœ”οΈ βœ”οΈ βœ”οΈ
Assertion message ❌ βœ”οΈ βœ”οΈ βœ”οΈ βœ”οΈ βœ”οΈ βœ”οΈ
Extra diagnostics ❌ ❌ * ❌ * ❌ ❌ * ❌ * βœ”οΈ
Binary specializations ❌ βœ”οΈ ❌ ❌ ❌ βœ”οΈ βœ”οΈ
Automatic expression decomposition ❌ ❌ ❌ ❌ ❌ ❌ βœ”οΈ

*: Possible through string formatting but that is sub-ideal.

Extras:

C/C++ Rust C# Java Python JavaScript This Library
Automatically Attach GDB At Failure Point ❌ ❌ ❌ ❌ ❌ ❌ Will investigate further
Syntax Highlighting ❌ ❌ ❌ ❌ ❌ ❌ βœ”οΈ
Non-Fatal Assertions ❌ ❌ ❌ ❌ ❌ ❌ βœ”οΈ
Format Consistency ❌ ❌ ❌ ❌ ❌ ❌ βœ”οΈ
Safe signed-unsigned comparison ❌ ❌ ❌ ❌ ❌ ❌ βœ”οΈ
Comments
  • Errors with GCC 12.1

    Errors with GCC 12.1

    I started getting the following error after upgrading my gcc:

    error: invalid use of β€˜auto’
    

    By expending the macro I managed to get more context:

    error: invalid use of β€˜auto’
    
    libassert_decomposer.compl expression_decomposer();
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~
    

    Replacing

    auto libassert_decomposer = libassert::detail::expression_decomposer(libassert ::detail ::expression_decomposer{} << [...] );
    

    with

    decltype(libassert::detail::expression_decomposer(libassert ::detail ::expression_decomposer{} << [...] )) libassert_decomposer = libassert::detail::expression_decomposer(libassert ::detail ::expression_decomposer{} << [...] );
    

    fixes the issue. [...] being the expression I'm testing, pretty sure it's irrelevant. Maybe a GCC bug?

    compatibility 
    opened by qdewaghe 8
  • Define to disallow return values

    Define to disallow return values

    I love this library as it mirrors some assert libraries I've seen in games; but one area of contention I foresee is return values. In many languages it's intentional to disallow this due to the desire to prevent asserts from becoming a part of control flow due to them being completely compiled out in release builds.

    Personally I like this feature, but it leads me to wonder if you do anything to ensure a call ends up being no-opped if the return value is unused? In some cases this may be impossible due to side effects, so I wonder if it would be a good idea to allow completely disabling this for those who want to ensure debug logic doesn't accidentally end up included in release builds.

    Feel free to correct me if I'm wrong about how this works though! πŸ™‚

    enhancement 
    opened by SK83RJOSH 6
  • Possible improvement to assert dialogues on Windows

    Possible improvement to assert dialogues on Windows

    Hey there! One thing that occured to me after testing this last night, is that similar libraries I've used in the past skip abort and use _CrtDbgReport to display a more user friendly dialogue to users when an assert is encountered. This is primarily useful for debug builds where you have non-technical users who will likely screenshot the dialogue box and forget to include logs; but it's also very useful as a programmer to see the assert details at a glance in the dialogue instead of needing to alt-tab to the logs (eg/ this is the assert I'm debugging right now).

    Is this something that you might consider adding? My only concern would be define/macro leakage from the required header, but perhaps the call to abort could be moved to the implementation to get around this?

    enhancement 
    opened by SK83RJOSH 4
  • Stringify error_code and error_condition

    Stringify error_code and error_condition

    testing code:

    #undef ASSERT_USE_MAGIC_ENUM
    #include <assert.hpp>
    
    int main()
    {
        // Win32 Error Code: The system cannot open the file.
        std::error_code ec(ERROR_TOO_MANY_OPEN_FILES, std::system_category());
    
        ASSERT(ec == std::error_code{}, "",
            std::io_errc::stream,
            std::errc::too_many_files_open,
            ec.default_error_condition());
    }
    

    before: image

    after: image

    opened by huangqinjin 3
  • Miscellaneous CMake fixes

    Miscellaneous CMake fixes

    This commit fixes MSVC compilation using CMake by ensuring the correct options are passed to the compiler. It also exposes all library options correctly.

    I also noticed there's another fork that includes packaging and some other things; but didn't fix these errors and omissions. Personally I would prefer a simple CMakeLists.txt that doesn't bring in such things, but feel free to merge these PRs if you'd like. πŸ‘

    opened by SK83RJOSH 3
  • CMake support

    CMake support

    Hi, what do you think about adding a CMake support to your library? I could try to prepare it. This would help people who use for example Ninja as their build system. CMake could also help prepare a package from your library, so that other users could easily link to it. If you would like to further discuss this issue. You can write me an email: [email protected]

    opened by boryssmejda 3
  • Could `libassert.hpp` theoretically be user-modified to work with C23?

    Could `libassert.hpp` theoretically be user-modified to work with C23?

    Just curious if this is possible, and how much effort it would take if so. I might give it a shot if it's in the 2-8 hour range, would be really nice πŸ˜ƒ

    (With the intent of offering a PR if I got it to work)

    opened by GavinRay97 2
  • Error with Clang 15 in `LIBASSERT_STMTEXPR` from `__extension__`:   error: expected ')'

    Error with Clang 15 in `LIBASSERT_STMTEXPR` from `__extension__`: error: expected ')'

    #include "libassert.hpp"
    
    DEBUG_ASSERT(1 == 2, "1 is not equal to 2");
    
    int main() { return 0; }
    
    [build] /usr/bin/clang++-15 -DASSERT_USE_MAGIC_ENUM -DFMT_SHARED
    -I/home/user/projects/bustub-c/include -I/home/user/projects/bustub-c/src
    -I/home/user/projects/bustub-c/build/sanitize/_deps/libassert-src/include
    -D_GLIBCXX_ASSERTIONS -D_GLIBCXX_USE_CHAR8_T -D__USE_GNU -Wall -Wextra -Werror
    -Wno-unused-variable -pipe -DDEBUG -D_GLIBCXX_DEBUG -ggdb3 -Og
    -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer
    -fsanitize=address,leak,undefined -fno-sanitize-recover=all
    -fsanitize-address-use-after-scope -fsanitize=cfi,function -fvisibility=hidden
    -flto=thin -g -fcolor-diagnostics -std=gnu++2b -MD -MT
    CMakeFiles/learning_db.dir/src/main.cpp.o -MF
    CMakeFiles/learning_db.dir/src/main.cpp.o.d -o
    CMakeFiles/learning_db.dir/src/main.cpp.o -c
    /home/user/projects/bustub-c/src/main.cpp
    
    [build] /home/user/projects/bustub-c/src/main.cpp:3:1: error: expected unqualified-id
    [build] DEBUG_ASSERT(1 == 2, "1 is not equal to 2");
    [build] ^
    [build] /home/user/projects/bustub-c/include/libassert.hpp:1226:34: note: expanded from macro 'DEBUG_ASSERT'
    [build]  #define DEBUG_ASSERT(expr, ...) ASSERT_INVOKE(expr, false, true, "DEBUG_ASSERT", debug_assertion, , __VA_ARGS__)
    [build]                                  ^
    [build] /home/user/projects/bustub-c/include/libassert.hpp:1184:9: note: expanded from macro 'ASSERT_INVOKE'
    [build]         LIBASSERT_STMTEXPR( \
    [build]         ^
    [build] /home/user/projects/bustub-c/include/libassert.hpp:1105:36: note: expanded from macro 'LIBASSERT_STMTEXPR'
    [build]  #define LIBASSERT_STMTEXPR(B, R) (__extension__ ({ B R }))
    [build]                                    ^
    [build] /home/user/projects/bustub-c/src/main.cpp:3:1: error: expected ')'
    [build] /home/user/projects/bustub-c/include/libassert.hpp:1226:34: note: expanded from macro 'DEBUG_ASSERT'
    [build]  #define DEBUG_ASSERT(expr, ...) ASSERT_INVOKE(expr, false, true, "DEBUG_ASSERT", debug_assertion, , __VA_ARGS__)
    [build]                                  ^
    [build] /home/user/projects/bustub-c/include/libassert.hpp:1184:9: note: expanded from macro 'ASSERT_INVOKE'
    [build]         LIBASSERT_STMTEXPR( \
    [build]         ^
    [build] /home/user/projects/bustub-c/include/libassert.hpp:1105:36: note: expanded from macro 'LIBASSERT_STMTEXPR'
    [build]  #define LIBASSERT_STMTEXPR(B, R) (__extension__ ({ B R }))
    [build]                                    ^
    [build] /home/user/projects/bustub-c/src/main.cpp:3:1: note: to match this '('
    [build] /home/user/projects/bustub-c/include/libassert.hpp:1226:34: note: expanded from macro 'DEBUG_ASSERT'
    [build]  #define DEBUG_ASSERT(expr, ...) ASSERT_INVOKE(expr, false, true, "DEBUG_ASSERT", debug_assertion, , __VA_ARGS__)
    [build]                                  ^
    [build] /home/user/projects/bustub-c/include/libassert.hpp:1184:9: note: expanded from macro 'ASSERT_INVOKE'
    [build]         LIBASSERT_STMTEXPR( \
    [build]         ^
    [build] /home/user/projects/bustub-c/include/libassert.hpp:1105:35: note: expanded from macro 'LIBASSERT_STMTEXPR'
    [build]  #define LIBASSERT_STMTEXPR(B, R) (__extension__ ({ B R }))
    [build]                                   ^
    [build] 2 errors generated.
    
    opened by GavinRay97 2
  • Add: Error if compiling with < C++17

    Add: Error if compiling with < C++17

    I noticed you had reverted 40490335fa102bc7f18adc8deca52efef1721f0a because the MSVC tests were failing. MSVC has not defined __cplusplus for ages and you need to resort to the _MSVC_LANG macro to check for C++ versions with it.

    Also, for the check right below including the <compare> header, it could be possible to check for __cpp_lib_three_way_comparison from C++20's <version> header.

    opened by spnda 2
  • MSVC support and fallback to std assert

    MSVC support and fallback to std assert

    Hi thanks for the great and interesting work. Is there any plan to support msvc? I like the idea of this library to make dev experience better, but I don't want to introduce non cross platform code in my code. If there is no plan to support msvc, is this library doing any kind of fallback (I didn't see) to the standard assert if the platform is not supported by your library? Have a nice day!

    opened by OlivierLDff 2
  • Use of non standard __VA_OPT__

    Use of non standard __VA_OPT__

    The library targets C++17 but relies on the __VA_OPT__ macro which only became standard in C++20.

    This implies that compiler extensions must be enabled in order to use the library in C++17 mode. Best case the compiler accepts it but spills a bunch of warnings, which is unpleasant.

    I would suggest to either find an alternative or at least do document this

    opened by BenjaminNavarro 2
  • Do you think it'd be possible to integrate the ASSERT() expressions with C++ contracts?

    Do you think it'd be possible to integrate the ASSERT() expressions with C++ contracts?

    A few weeks ago, C++ Contracts support was merged into GCC:

    • https://www.reddit.com/r/cpp/comments/yz3l4v/gcc_13_gets_contracts_in_master/

    One thing I keep thinking is how great it would be to be able to use libassert for the contract violation messages.

    You are allowed to write your own assertion handler for failure, see below for an example with GCC Trunk and libassert v1.1:

    • https://godbolt.org/z/G8EEq81Ta
    Program returned: 139
    contract violation: /app/example.cpp:30: num > 0 is false [with contract level=default]
    violation occurs here:
    ./output.s[0x40356d]
    ./output.s[0x403728]
    /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0x7f14fa9a4083]
    ./output.s[0x4032be]
    [0x0]
    end of violation
    terminate called without an active exception
    

    Could it be possible to somehow integrate libassert here, so that you get the much nicer debug message? If you try to use DEBUG_ASSERT or ASSERT in the [[pre: ]] or post expression themselves, it fails:

    <source>:30:12: error: statement-expressions are not allowed outside functions nor in template-argument lists
       30 |     [[pre: ASSERT(num > 0)]]
    

    You have access to the original assertion expression text, ie num > 0, but I don't know that you have access to the value of IE num in the violation handler.

    void handle_contract_violation(const std::experimental::contract_violation &violation) {
      size_t _backtraceSize{0};
      void *_backtrace[MAX_BACKTRACE_DEPTH]{};
    
      _backtraceSize = backtrace(_backtrace, MAX_BACKTRACE_DEPTH);
      if(_backtraceSize == MAX_BACKTRACE_DEPTH)
        std::cerr << "warning: backtrace may have been truncated" << std::endl;
    
      std::cerr << "contract violation: " << violation.file_name()
        << ":" << violation.line_number()
        << ": " << violation.comment() << " is false"
        << " [with contract level=" << violation.assertion_level() << "]" << std::endl
        << "violation occurs here:" << std::endl;
      // skip the stack frame of handle_contract_violation and
      // on_contract_violation to get to wherever the assert was
      backtrace_symbols_fd(_backtrace + 2, _backtraceSize - 1, STDERR_FILENO);
      std::cerr << "end of violation" << std::endl;
    }
    
    int square(int num)
        [[pre: num > 0]]
        [[post res: res < 100]]
    {
        DEBUG_ASSERT(num * num < 50);
        return num * num;
    }
    
    
    int main()
    {
        // Trigger PRE
        square(-1);
        // Trigger DEBUG_ASSERT
        // square(8);
        // Trigger POST
        // square(10);
        return 0;
    }
    opened by GavinRay97 1
  • Add: Support for MacOS

    Add: Support for MacOS

    This is experimental support for MacOS, which mainly bases on properly loading Mach-O binaries and using NS functions for getting some data. Note however, that this currently does not work as addr2line does not exist on Mac systems by default. Gonna work more on this in the next few days, just leaving this here if anyone else needs the changes :)

    opened by spnda 4
  • Runtime error with regular expressions in libc++

    Runtime error with regular expressions in libc++

    terminating with uncaught exception of type std::__1::regex_error: The expression contained an invalid back reference.
    zsh: abort      ./a.out
    

    Thrown on line 1080 https://github.com/jeremy-rifkin/libassert/blob/39a1babf70585e4b2e2361adc257da3ed6ae792e/src/assert.cpp#L1074-L1081

    bug compatibility 
    opened by jeremy-rifkin 2
  • Support for expressions with template arguments.

    Support for expressions with template arguments.

    Currently, the following code fails to compile:

    template<int X, int Y> bool foo() { return X == Y; }
    
    int main()
    {
        foo<3,4>();
        ASSERT(foo<3,4>());
    }
    

    This code can be seen in action on compiler explorer.

    This is due to foo<3,4>() being seen as two arguments when passed to a macro, specifically foo<3 and 4>(). This can be worked around with an extra set of parenthesis. Working around this in the library would be difficult, but should be possible. Decomposition would need to overload operator, to handle the error message string, and additional diagnostic variables. The top level macros would then consume a single variadic argument pack.

    enhancement backlog 
    opened by CalebAdrianXYZ 3
Releases(v1.1)
  • v1.1(May 17, 2022)

    Changelog:

    • Added -DNO_ASSERT_RELEASE_EVAL to make ASSERT behave more like traditional C assert
    • Renamed library's namespace to libassert::
    • Added customization point for libassert::detail::stringify
    • Added support for assertions in constexpr functions
    • Some internal refactoring, bug fixes, and typo corrections
    • Better cmake, big thanks to @qdewaghe!
    Source code(tar.gz)
    Source code(zip)
  • v1.0(May 8, 2022)

    libassert 1.0 πŸŽ‰

    Changelog:

    • Renamed: CHECK to DEBUG_ASSERT and ASSERT no longer provides an optimizer hint in release. For the hint use ASSUME - I gave the naming a lot of thought and decided on making naming state intent clearly
    • Overhauled assertion handling to produce better codegen and only compute extra diagnostic expressions in the failure path
    • Library options:
      • No longer automatically decompose && and || expressions because of short-circuiting (decided this behavior was too surprising), this can be re-enabled if desired with -DASSERT_DECOMPOSE_BINARY_LOGICAL
      • It's no longer the default to #define the lowercase assert alias, this alias can be enabled with -DASSERT_LOWERCASE
      • Removed -DNCOLOR in favor of asserts::config::set_color_output and asserts::utils::strip_colors. This allows easiest customization of the color printing behavior and making string replacements in this code path is not a performance concern
    • Assertions are printed only in color by the default handler when the output destination is a tty
    • Custom assert failure handlers
      • Overhauled assertion printing to allow custom assertion failure handlers to print for desired widths
      • Added interface for custom assertion handlers to get a filename, line number, function signature, and assertion message from the assertion printer
    • Improved handling for extra diagnostics and optional assertion messages
    • Ensuring clean compilation under strictest possible warning flags (everything short of -pedantic and /W4, including -Wshadow)
    • Support for MSVC compilers
    • Fixed windows dbghelp stack trace bugs πŸŽ‰
    • Improved windows stack trace symbol resolution (skip the this parameter)
    • The library now makes a few internal utilities public as they are immensely useful
      • The library now exposes the internal stack trace generator, pretty type name generator, and stringification utilities as bonuses (also exposes internal utilities to get the terminal width and strip colors for use in a custom failure handler)
    • Refactoring and cleanup
      • Continued moving as much logic as possible out of the .hpp and into the .cpp. Notably, nothing related to syntax highlighting is in the .hpp anymore, a lot of stringification logic has been moved out, much of the printing logic has also been moved out)
      • "Macro Hygiene"
      • Namespace reorganization
    • Improved handling of forwarding in the expression decomposer
    • CMake configuration
    • Improved documentation
    • Improvements to trace printing
    • Improved type name generation
    • Added cleaning for type names from the compiler
      • Example from MSVC:
        Before type cleaning: class std::map<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char>>,int,struct std::less<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char>>>,class std::allocator<struct std::pair<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char>> const ,int>>>
        After type cleaning: std::map<std::string, int, std::less<std::string>>
    • Improved value printing and stringification:
      • Pointers are printed with their data type, function pointers are now supported
      • Better display of char values in conjunction with ints
      • Added printing for container types
      • Added printing for tuple-like types
      • Added optional support for magic enum for better stringification of enum class values (enabled with -DASSERT_USE_MAGIC_ENUM)
    • Added spaceship operator support
    • Added Velociraptors

    Internal Development:

    • Improved build setup
    • Lots of work to setup automated unit and integration testing for the library
    • Automated static analysis
    Source code(tar.gz)
    Source code(zip)
Owner
Jeremy Rifkin
Hi, I'm a developer and designer.
Jeremy Rifkin
A library of type safe sets over fixed size collections of types or values, including methods for accessing, modifying, visiting and iterating over those.

cpp_enum_set A library of type safe sets over fixed size collections of types or values, including methods for accessing, modifying, visiting and iter

Carl Dehlin 22 Jun 16, 2022
Implementation of two of the most famous subdivision algorithm: Loops Subdivision and CatMull-Clark Subdivision.

3D-Subdivision-Surface Implementation of two of the most famous subdivision algorithms: Loops Subdivision for Triangles and CatMull-Clark Subdivision

Phan Sang 13 Dec 18, 2022
HashTableBenchmark - A simple cross-platform speed & memory-efficiency benchmark for the most common hash-table implementations in the C++ world

Hash-Tables Benchmarks This repository contains a bunch of extendable benchmarks mostly for following containers: std:unordered_map from STL. google::

Unum 9 Nov 20, 2022
Directed Acyclic Graph Execution Engine (DAGEE) is a C++ library that enables programmers to express computation and data movement, as task graphs that are scheduled concurrently and asynchronously on both CPUs and GPUs.

Directed Acyclic Graph Execution Engine (DAGEE) is a C++ library that enables programmers to express computation and data movement, as tasks in a graph structure, where edges represent task dependencies

null 28 Dec 18, 2022
A lightweight library of Behavior Trees Library in C++.

A lightweight behavior tree library in C++. NEWS! ?? Thanks to Davide Faconti there is now a more sophisticated version of the library. The new versio

Michele Colledanchise 168 Dec 21, 2022
Cross-platform STL-styled and STL-compatible library with implementing containers, ranges, iterators, type traits and other tools; actors system; type-safe config interface.

Yato A small repository where I'm gatherting useful snippets and abstractions for C++ development. Yato includes 3 main modules: multidimensional cont

Alexey 10 Dec 18, 2022
R :package: and header-only C++ library for geospatial space-division based compression and encoding

spress spress provides utilities for encoding and compressing geospatial objects, such as sf objects. Installation This package requires C++11 for com

UF-OKN 5 Dec 9, 2021
R :package: and header-only C++ library for geospatial space-division based compression and encoding

spress spress provides utilities for encoding and compressing geospatial objects, such as sf objects. Installation This package requires C++11 for com

UF-OKN 5 Dec 9, 2021
C++ library and cmdline tools for parsing and manipulating VCF files

vcflib A C++ library for parsing and manipulating VCF files. overview The Variant Call Format (VCF) is a flat-file, tab-delimited textual format that

null 525 Dec 23, 2022
Library of generic and type safe containers in pure C language (C99 or C11) for a wide collection of container (comparable to the C++ STL).

M*LIB: Generic type-safe Container Library for C language Overview M*LIB (M star lib) is a C library enabling to use generic and type safe container i

PpHd 571 Jan 5, 2023
C header library for typed lists (using macros and "template" C).

vector.h C header library for typed lists (using macros and "template" C). Essentially, this is a resizable array of elements of your choosing that is

Christopher Swenson 33 Dec 19, 2022
libsais is a library for linear time suffix array and burrows wheeler transform construction based on induced sorting algorithm.

libsais libsais is a library for fast (see Benchmarks below) linear time suffix array and Burrows-Wheeler transform construction based on induced sort

Ilya Grebnov 112 Dec 22, 2022
Wonderful library with lots of useful functions, algorithms and data structures in C, link it with -l9wada

Lib9wada Wonderful library with lots of useful functions, algorithms and data structures in C, link it with -l9wada Usage Compile the library with mak

Lprogrammers Lm9awdine 53 Nov 21, 2022
Wonderful library with lots of useful functions, algorithms and data structures in C, link it with -l9wada

LibC+ Wonderful library with lots of useful functions, algorithms and data structures in C, link it with -lC+ Better than C, not as much as c++ Usage

BnademOverflow 53 Nov 21, 2022
A simple and easy-to-use library to build pipelines in C

A simple and easy-to-use library to build pipelines in C

Ray 15 Dec 25, 2022
ring-span lite - A C++yy-like ring_span type for C++98, C++11 and later in a single-file header-only library

ring-span lite: A circular buffer view for C++98 and later Contents Example usage In a nutshell Dependencies Installation Synopsis Reported to work wi

Martin Moene 127 Dec 28, 2022
A library to convert Uber's H3 geo-index to LatLng vertices for Kotlin Multiplatform Mobile iOS and Android

A library to convert Uber's H3 geo-index to LatLng vertices for Kotlin Multiplatform Mobile iOS and android Features Uber H3 in one interface Common i

LINE 9 Jul 12, 2022
Simple and fast configuration file library (written in C99)

Features Configuration file reading Supported operating systems Ubuntu MacOS Windows Build requirements C99 compiler CMake 3.10+ Cloning git clone htt

Nikita Fediuchin 3 May 26, 2022