Exploring `fmath.h` - Part 1
I have been picking up part of a task that applies the macro OIIO_NODISCARD / OIIO_NODISCARD_ERROR (for the attribute [[nodiscard]] ). It is the same task as what I did for color.h, so this time, I’ll focus more on the code itself. The ambitious goal is to read through this open source code as much as possible while doing this nodiscard attribute task. I follow my curiosity wherever it leads, and this library + Stroustrup’s book will be really good learning material for me.
- OpenImageIO Repository (https://github.com/AcademySoftwareFoundation/OpenImageIO)
- Stroustrup, B. (2013). The C++ programming language. Pearson Addison-Wesley.
TIL #1 - __builtin_expect(expr, value) for gcc and clang
// gcc defines a special intrinsic to use in conditionals that can speed
// up extremely performance-critical spots if the conditional usually
// (or rarely) is true. You use it by replacing
// if (x) ...
// with
// if (OIIO_LIKELY(x)) ... // if you think x will usually be true
// or
// if (OIIO_UNLIKELY(x)) ... // if you think x will rarely be true
// Caveat: Programmers are notoriously bad at guessing this, so it
// should be used only with thorough benchmarking.
#if defined(__GNUC__) || defined(__clang__)
# define OIIO_LIKELY(x) (__builtin_expect(bool(x), true))
# define OIIO_UNLIKELY(x) (__builtin_expect(bool(x), false))
#else
# define OIIO_LIKELY(x) (x)
# define OIIO_UNLIKELY(x) (x)
#endifA compiler hint for branch prediction.
heading_4https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-_005f_005fbuiltin_005fexpect
clang
https://llvm.org/docs/BranchWeightMetadata.html#built-in-expect-instructions
TIL #2 - Comma Operator
/// OIIO_ASSERT(condition) checks if the condition is met, and if not,
/// prints an error message indicating the module and line where the error
/// occurred, and additionally aborts if in debug mode. When in release
/// mode, it prints the error message if the condition fails, but does not
/// abort.
///
/// OIIO_ASSERT_MSG(condition,msg,...) lets you add formatted output (a la
/// printf) to the failure message.
#define OIIO_ASSERT(x) \
(OIIO_LIKELY(x) \
? ((void)0) \
: (std::fprintf(stderr, "%s:%u: %s: Assertion '%s' failed.\n", \
__FILE__, __LINE__, OIIO_PRETTY_FUNCTION, #x), \
OIIO_ABORT_IF_DEBUG))
#define OIIO_ASSERT_MSG(x, msg, ...) \
(OIIO_LIKELY(x) \
? ((void)0) \
: (std::fprintf(stderr, "%s:%u: %s: Assertion '%s' failed: " msg "\n", \
__FILE__, __LINE__, OIIO_PRETTY_FUNCTION, #x, \
__VA_ARGS__), \
OIIO_ABORT_IF_DEBUG))OIIO_ASSERT and OIIO_ASSERT_MSG looks like this: cond ? A : (B, C). False-branch has 'comma operator' wrapped in parentheses!TIL #2.1 - Order of Evaluation


https://en.cppreference.com/cpp/language/operator_other#Built-in_comma_operator
TIL #2.2 - (void)0
TIL #3 - Disable Debug Macro Argument
/// OIIO_DASSERT and OIIO_DASSERT_MSG are the same as OIIO_ASSERT for debug
/// builds (test, print error, abort), but do nothing at all in release
/// builds (not even perform the test). This is similar to C/C++ assert(),
/// but gives us flexibility in improving our error messages. It is also ok
/// to use regular assert() for this purpose if you need to eliminate the
/// dependency on this header from a particular place (and don't mind that
/// assert won't format identically on all platforms).
#ifndef NDEBUG
# define OIIO_DASSERT OIIO_ASSERT
# define OIIO_DASSERT_MSG OIIO_ASSERT_MSG
#else
# define OIIO_DASSERT(x) ((void)sizeof(x)) /*NOLINT*/
# define OIIO_DASSERT_MSG(x, ...) ((void)sizeof(x)) /*NOLINT*/
#endifOIIO_DASSERT(x) is defined as ((void)sizeof(x)) . TIL #3.1 - Why sizeof specifically?
heading_4When applied to an expression,sizeofdoes not evaluate the expression (i.e. the expression is an unevaluated operand)(since C++11), and even if the expression designates a polymorphic object, the result is the size of the static type of the expression.https://en.cppreference.com/cpp/language/sizeof
https://en.cppreference.com/cpp/language/sizeof#Syntax
https://en.cppreference.com/cpp/language/expressions#Potentially-evaluated_expressions
TIL #3.2 - Silence unused result warning with (void)
Since sizeof(x) returns a value, if we don’t cast it with (void) , the compiler will warn about an unused result unless the warning is suppressed.
👉 See also:
https://gamedev.net/forums/topic/673263-old-unused-variable-trick-for-assert-sizeof/#post-5262455