/* * Brickworks * * Copyright (C) 2022-2024 Orastron Srl unipersonale * * Brickworks is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 3 of the License. * * Brickworks is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Brickworks. If not, see . * * File author: Stefano D'Angelo */ /*! * module_type {{{ foundation }}} * version {{{ 1.1.1 }}} * description {{{ * A common header to make sure that a bunch of basic definitions are * available and consistent for all Brickworks modules. * }}} * changelog {{{ * * }}} */ #ifndef BW_COMMON_H #define BW_COMMON_H /*** Public API ***/ #ifdef __cplusplus # if __cplusplus < 201103L # if _MSC_VER # pragma message("Detected MSVC compiler reporting not to support C++11. Please use /Zc:__cplusplus if possible, or otherwise ignore this message if everything works for you. See https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/ for more information.") # else # error Detected C++ compiler that does not support C++11 # endif # endif #endif /*! api {{{ * * #### Basic definitions * * Brickworks requires definitions of: * * * `NULL` (C only) and `size_t`, normally supplied by `stddef.h`; * * `(u)int{8,16,32,64}_t`, `INT{8,16,32,64}_{MIN,MAX}`, and * `UINT{8,16,32,64}_MAX`, normally supplied by `stdint.h`; * * `INFINITY`, normally supplied by `math.h`. * * You can control whether those definitions are taken from said headers * or you can supply them yourselves. In particular: * * * if `BW_NO_STDLIB` or `BW_NO_STDDEF_H` is defined, then `stddef.h` is not * `#include`d; * * if `BW_NO_STDLIB` or `BW_NO_STDINT_H` is defined, then `stdint.h` is not * `#include`d; * * if `BW_NO_STDLIB` or `BW_NO_MATH_H` is defined, then `math.h` is not * `#include`d. * * A `BW_NULL` macro is defined whose value is either `NULL` (C) or `nullptr` * (C++). * >>> */ #if !defined(BW_NO_STDLIB) && !defined(BW_NO_STDDEF_H) # include #endif #ifdef __cplusplus # define BW_NULL nullptr #else # ifndef NULL # error NULL not defined # endif # define BW_NULL NULL #endif #if !defined(BW_NO_STDLIB) && !defined(BW_NO_STDINT_H) # include #endif #if !defined(INT8_MIN) || !defined(INT8_MAX) \ || !defined(INT16_MIN) || !defined(INT16_MAX) \ || !defined(INT32_MIN) || !defined(INT32_MAX) \ || !defined(INT64_MIN) || !defined(INT64_MAX) \ || !defined(UINT8_MAX) || !defined(UINT16_MAX) \ || !defined(UINT32_MAX) || !defined(UINT64_MAX) # error At least one definition in INT{8,16,32,64}_{MIN,MAX} or UINT{8,16,32,64}_MAX is missing #endif #if !defined(BW_NO_STDLIB) && !defined(BW_NO_MATH_H) # include #endif #ifndef INFINITY # error INFINITY not defined #endif /*! ... * * #### BW_CXX_NO_ARRAY * * C++ APIs of Brickworks modules typically include overloaded methods that * use `std::array` arguments, and thus require the `` header file. * * If this is not wanted, defining `BW_CXX_NO_ARRAY` suppresses such methods * and the inclusion of said header file. * * #### BW_RESTRICT * * `BW_RESTRICT` is a preprocessor definition that wraps the `restrict` * keyword. * * If it is not defined already, then it gets defined as `restrict` if C99 is * supported, otherwise it has no effect (typically when compiling C++ code). * * >>> */ #ifndef BW_RESTRICT # if defined(__STDC__) && (__STDC_VERSION__ >= 199901L) # define BW_RESTRICT restrict # else # define BW_RESTRICT # endif #endif /*! ... * * #### BW_ASSERT and BW_ASSERT_DEEP * * Both macros are `assert()`-like. `BW_ASSERT` is meant to perform * rapid/basic validity checks (e.g., input pointer is not `NULL`, input * `float` number is finite), while `BW_ASSERT_DEEP` should be used for * deeper checks (e.g., validate data structures and internal states). * * If `BW_NO_DEBUG` is defined then "calls" to both `BW_ASSERT` and * `BW_ASSERT_DEEP` will be stripped away by the preprocessor. * * Whether `BW_NO_DEBUG` is defined or not, "calls" to `BW_ASSERT_DEEP` will * still be stripped anyway if `BW_DEBUG_DEEP` is not defined. * * Otherwise, `BW_ASSERT` and `BW_ASSERT_DEEP` can either be provided by you, * otherwise `BW_ASSERT` is defined as `assert` (`assert.h` is `#include`d * and `BW_NO_STDLIB` must not be defined — please mind that `assert.h` * is still influenced by `NDEBUG`), and `BW_ASSERT_DEEP` is defined as * `BW_ASSERT`. * * >>> */ #ifdef BW_NO_DEBUG # undef BW_ASSERT # undef BW_ASSERT_DEEP # define BW_ASSERT(ignore) ((void)0) # define BW_ASSERT_DEEP(ignore) ((void)0) #else # ifndef BW_ASSERT # ifdef BW_NO_STDLIB # error BW_NO_STDLIB defined but BW_ASSERT not defined # endif # include # endif # ifndef BW_ASSERT # define BW_ASSERT assert # endif # ifdef BW_DEBUG_DEEP # ifndef BW_ASSERT_DEEP # define BW_ASSERT_DEEP BW_ASSERT # endif # else # undef BW_ASSERT_DEEP # define BW_ASSERT_DEEP(ignore) ((void)0) # endif #endif #ifdef __cplusplus extern "C" { #endif /*! ... * * #### bw_is_inf() * ```>>> */ static inline char bw_is_inf( float x); /*! <<<``` * Returns non-`0` if `x` is positive or negative infinity, `0` otherwise. * * #### bw_is_nan() * ```>>> */ static inline char bw_is_nan( float x); /*! <<<``` * Returns non-`0` if `x` is NaN, `0` otherwise. * * #### bw_is_finite() * ```>>> */ static inline char bw_is_finite( float x); /*! <<<``` * Returns non-`0` if `x` is finite (neither NaN nor positive or negative * infinity), `0` otherwise. * * #### bw_has_inf() * ```>>> */ static inline char bw_has_inf( const float * BW_RESTRICT x, size_t n_elems); /*! <<<``` * Scans the fist `n_elems` in buffer `x` and returns non-`0` if it contains * at least one positive or negative inifinity value, `0` otherwise. * * #### bw_has_nan() * ```>>> */ static inline char bw_has_nan( const float * BW_RESTRICT x, size_t n_elems); /*! <<<``` * Scans the fist `n_elems` in buffer `x` and returns non-`0` if it contains * at least one NaN value, `0` otherwise. * * #### bw_has_only_finite() * ```>>> */ static inline char bw_has_only_finite( const float * BW_RESTRICT x, size_t n_elems); /*! <<<``` * Scans the fist `n_elems` in buffer `x` and returns non-`0` if it only * finds finite values (neither NaN nor positive or negative infinity), `0` * otherwise. * * #### bw_hash_sdbm() * ```>>> */ static inline uint32_t bw_hash_sdbm( const char * BW_RESTRICT string); /*! <<<``` * Returns the sdbm hash of the given `string`. * }}} */ #ifdef __cplusplus } #endif /*** Implementation ***/ /* WARNING: This part of the file is not part of the public API. Its content may * change at any time in future versions. Please, do not use it directly. */ #ifdef __cplusplus extern "C" { #endif static inline char bw_is_inf( float x) { union { uint32_t u; float f; } v; v.f = x; return (v.u & 0x7fffffff) == 0x7f800000; } static inline char bw_is_nan( float x) { union { uint32_t u; float f; } v; v.f = x; return ((v.u & 0x7f800000) == 0x7f800000) && (v.u & 0x7fffff); } static inline char bw_is_finite( float x) { union { uint32_t u; float f; } v; v.f = x; return (v.u & 0x7f800000) != 0x7f800000; } static inline char bw_has_inf( const float * BW_RESTRICT x, size_t n_elems) { char ret = 0; for (size_t i = 0; i < n_elems && !ret; i++) ret = bw_is_inf(x[i]); return ret; } static inline char bw_has_nan( const float * BW_RESTRICT x, size_t n_elems) { char ret = 0; for (size_t i = 0; i < n_elems && !ret; i++) ret = bw_is_nan(x[i]); return ret; } static inline char bw_has_only_finite( const float * BW_RESTRICT x, size_t n_elems) { char ret = 1; for (size_t i = 0; i < n_elems && ret; i++) ret = bw_is_finite(x[i]); return ret; } static inline uint32_t bw_hash_sdbm( const char * BW_RESTRICT string) { uint32_t hash = 0; for (; *string != '\0'; string++) hash = (uint32_t)*string + (hash << 6) + (hash << 16) - hash; return hash; } #ifdef __cplusplus } #endif #endif