This PR introduces full support for compile-time testing. This includes compile-time evaluation and expression decomposition. For this purpose, two new sets of macros are included:
CONSTEVAL_* performs a check purely at compile-time, reports failure to compile as constant expression at compile-time (duh), and failure of the test at run-time. No code (other than the potential failure reporting) is executed at run-time, therefore this will not generate coverage data.
CONSTEXPR_* performs a check both at compile-time and run-time. Failure to compile as constant expression is still reported at compile-time, and failure of the test is still reported at run-time. But because the code is executed both at compile-time and at run-time, this will generate coverage data.
Although we already know at compile-time if a compile-time test passes or fail, the test failure is nonetheless only reported at run-time. This is done to follow the same reporting mechanism as the one set up for regular run-time tests (custom reporter, etc.).
To achieve this, I needed to implement constexpr integer and float serialization functions, since the C++20 STL does not provide anything usable at compile time (in C++23 we would be able to use std::to_chars, but only for integers and not for floats). Although integer serialization is pretty easy, float is not. The algorithm I used is based on fixed point arithmetic with 64 bit worth of digits in base 10. It is a simpler form of common state-of-the-art algorithms (e.g. Grisu). It is probably nowhere near as efficient, but on the plus side doesn't require storing large tables or complicated arbitrary precision types. To keep it simple, I only implemented exponential format with fixed precision (6 digits after the decimal point for float, and 15 for double). This achieves a perfect match to std::printf() for floats and 6 digits precision in 99.995% of the cases (when it fails, it's just the very last digit that is off by one). I don't have the stats for doubles.
I also needed to refactor the expression decomposer a little bit, to be constexpr-friendly. This had the nice side effect of improving compilation times slightly overall.
This PR introduces full support for compile-time testing. This includes compile-time evaluation and expression decomposition. For this purpose, two new sets of macros are included:
CONSTEVAL_*
performs a check purely at compile-time, reports failure to compile as constant expression at compile-time (duh), and failure of the test at run-time. No code (other than the potential failure reporting) is executed at run-time, therefore this will not generate coverage data.CONSTEXPR_*
performs a check both at compile-time and run-time. Failure to compile as constant expression is still reported at compile-time, and failure of the test is still reported at run-time. But because the code is executed both at compile-time and at run-time, this will generate coverage data.Although we already know at compile-time if a compile-time test passes or fail, the test failure is nonetheless only reported at run-time. This is done to follow the same reporting mechanism as the one set up for regular run-time tests (custom reporter, etc.).
To achieve this, I needed to implement
constexpr
integer and float serialization functions, since the C++20 STL does not provide anything usable at compile time (in C++23 we would be able to usestd::to_chars
, but only for integers and not for floats). Although integer serialization is pretty easy, float is not. The algorithm I used is based on fixed point arithmetic with 64 bit worth of digits in base 10. It is a simpler form of common state-of-the-art algorithms (e.g. Grisu). It is probably nowhere near as efficient, but on the plus side doesn't require storing large tables or complicated arbitrary precision types. To keep it simple, I only implemented exponential format with fixed precision (6 digits after the decimal point forfloat
, and 15 fordouble
). This achieves a perfect match tostd::printf()
for floats and 6 digits precision in 99.995% of the cases (when it fails, it's just the very last digit that is off by one). I don't have the stats for doubles.I also needed to refactor the expression decomposer a little bit, to be
constexpr
-friendly. This had the nice side effect of improving compilation times slightly overall.Closes #77. Closes #60.