Skip to content
/ chk Public

Compile time asserts and other utilities for code validation

License

Notifications You must be signed in to change notification settings

fekir/chk

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

chk

Library for compile time checks, header-only, requires at least C++14.

Components

cassert

This C++ library was conceived by the need of having a compile-time assert function (not static_assert).

If you need something like

constexpr int foo(int i) {
	chk::cassert(i > 2);
	return i - 2;
}

then this library is for you.

Notice that in the given example it is not possible to use assert or static_assert, as the former is not constexpr, and the latter requires a constexpr-expression.

chk::cassert work like a constexpr function and can take an optional string in two forms:

  • takes a string-like (\0 terminated const char*, std::string) object as optional parameter: chk::cassert(i > 2, "fail");

  • the string can be computed lazily only in case of failure: chk::cassert(i > 2, [](){/* compute string at runtime*/});

The second form is useful in order not to waste time creating an error message if the test does not fail.

Also the expression to verify can be computed lazily through a function: chk::cassert([&i](){return i > 2});

This is useful is the verification is expensive, and because chk::cassert is not a macro.

If NDEBUG is not defined, then chk::cassert compiles to a no-op, but the expression is still computed at the caller site. If it is expensive, this is undesirable, and maybe it won’t get optimized away, especially if it has side effects like memory allocations.

By using a lambda or normal function, the compiler is able to remove the entire verification as the lambda/function is never called.

Since chk::cassert is a normal (templated) function, it can be also used in those places where assert, since it is a macro, is unsuitable, for example as parameter for an algorithm:

std::for_each(begin, end, chk::cassert)

If the expression evaluates to false at compile-time, compilation stops, while at runtime it calls abort just like assert.

assert is a debugging tool controlled by NDEBUG, which can be used to control chk::cassert too. But if the check takes place at compile-time, it will still get executed (the motivation behind this decision is that compile-time checks take 0 time at runtime) Nevertheless there might be situations where it makes sense (reduce compilation times) also the checks at compile-time. This is controlled by the macro CNDEBUG.

unreachable

GCC (and clang) have a very useful function when

  • one wants to take advantage of diagnostics for unreachable code

  • trying to remove useless boilerplate

  • document better some invariant through code

The function is __builtin_unreachable.

But like assert, it’s not constexpr.

There are other utilities, like chk::unreachable

chk::unreachable

  • adds the constexpr modifier, in order to use it inside constexpr functions.

  • has an optional message parameter, to help the developer in case NDEBUG is not defined (similarly to assert) if the code is reached.

constexpr void foo(int i) {
	if(i > 5){
		//
	} else if(i < 3){
		//
	} else {
		chk::unreachable("foo should never reach this point"); //message is optional
	}
}

cterminate and cabort

Those two functions behaves just like the standard terminate and abort functions, but can be used in constexpr functions too. If one of those functions is "executed" at compile-time it terminates/abort the compilation. At runtime they just call terminate and abort.

How to use the library

Since it is header-only, there are multiple ways of consuming this library.

Option 1)

Just copy the include folder in you project somewhere, possibly no adjustment to the build system required

Option 2)

This is a CMake-Project, thus "build" and install the library:

cmake -S <dir of this project> -B <build directory> -DCMAKE_INSTALL_PREFIX:PATH=<optional, where to install the headers and cmake target>
cmake --build <build directory> --target install

And in your CMakeLists.txt add find_package(chk REQUIRED) for importing chk as target, and adapt CMAKE_PREFIX_PATH, for example:

cmake -S <dir of your project> -B <build directory of your project> -DCMAKE_PREFIX_PATH=<installation directory of chk>

Option 3)

Use conan, the project provides a conanfile

conan create <dir of this project> <name of package>

And add to the conanfile of you project

[requires]
	chk/1.0@<choosen name>

For example usages, just look in the test directory.

Execute test suite

Recommended, as some features used are not fully supported by all compilers. This library has been mainly tested with GCC, Clang and MSVC.

cmake -S <dir of this project> -B <build directory>
cmake --build <build directory> --target test -- ARGS="--progress"

About

Compile time asserts and other utilities for code validation

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published