Skip to content

Commit

Permalink
Vendor jtckdint.h for Flux
Browse files Browse the repository at this point in the history
* All functions are constexpr
* #include <stdbool.h> to define the `_Bool` type to avoid an error with GCC in C++ mode
* Use GNU builtins (__builtin_add_overflow etc) even when __STRICT_ANSI__ is defined (if upstream GCC and Clang are happy to do use the builtins in strict ANSI mode then so am I)
  • Loading branch information
tcbrindle committed Nov 15, 2024
1 parent 9476074 commit 83db8c2
Showing 1 changed file with 35 additions and 14 deletions.
49 changes: 35 additions & 14 deletions include/flux/core/detail/jtckdint.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@
* PERFORMANCE OF THIS SOFTWARE.
*/

/*
* Upstream repo: https://github.com/jart/jtckdint
*
* This file contains the following changes from upstream v0.2:
* - All functions are constexpr
* - `if` changed to `if constexpr` where appropriate
* - #include <stdbool.h> before <stdckdint.h> to define the _Bool type for GCC in C++ mode
* - Use GNU builtins even if __STRICT_ANSI__ is defined
* - Use pragma to disable MSVC integer conversion warning
*/

/**
* @fileoverview C23 Checked Arithmetic
*
Expand Down Expand Up @@ -64,11 +75,17 @@
#endif

#if __ckd_has_include(<stdckdint.h>)
#include <stdbool.h>
#include <stdckdint.h>
#else

#define __STDC_VERSION_STDCKDINT_H__ 202311L

#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable: 4146 4244)
#endif

#if ((defined(__llvm__) || \
(defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ >= 406)) && \
!defined(__STRICT_ANSI__))
Expand All @@ -90,11 +107,10 @@ typedef unsigned __ckd_intmax __ckd_uintmax_t;
#define __ckd_has_builtin(x) 0
#endif

#if (!defined(__STRICT_ANSI__) && \
((defined(__GNUC__) && __GNUC__ >= 5 && !defined(__ICC)) || \
#if ((defined(__GNUC__) && __GNUC__ >= 5 && !defined(__ICC)) || \
(__ckd_has_builtin(__builtin_add_overflow) && \
__ckd_has_builtin(__builtin_sub_overflow) && \
__ckd_has_builtin(__builtin_mul_overflow))))
__ckd_has_builtin(__builtin_mul_overflow)))
#define ckd_add(res, x, y) __builtin_add_overflow((x), (y), (res))
#define ckd_sub(res, x, y) __builtin_sub_overflow((x), (y), (res))
#define ckd_mul(res, x, y) __builtin_mul_overflow((x), (y), (res))
Expand All @@ -108,7 +124,7 @@ typedef unsigned __ckd_intmax __ckd_uintmax_t;
#include <limits>

template <typename __T, typename __U, typename __V>
inline bool ckd_add(__T *__res, __U __a, __V __b) {
inline constexpr bool ckd_add(__T *__res, __U __a, __V __b) {
static_assert(std::is_integral<__T>::value &&
std::is_integral<__U>::value &&
std::is_integral<__V>::value,
Expand All @@ -125,8 +141,8 @@ inline bool ckd_add(__T *__res, __U __a, __V __b) {
__ckd_uintmax_t __y = __b;
__ckd_uintmax_t __z = __x + __y;
*__res = __z;
if (sizeof(__z) > sizeof(__U) && sizeof(__z) > sizeof(__V)) {
if (sizeof(__z) > sizeof(__T) || std::is_signed<__T>::value) {
if constexpr (sizeof(__z) > sizeof(__U) && sizeof(__z) > sizeof(__V)) {
if constexpr (sizeof(__z) > sizeof(__T) || std::is_signed<__T>::value) {
return static_cast<__ckd_intmax_t>(__z) != static_cast<__T>(__z);
} else if (!std::is_same<__T, __ckd_uintmax_t>::value) {
return (__z != static_cast<__T>(__z) ||
Expand All @@ -136,7 +152,7 @@ inline bool ckd_add(__T *__res, __U __a, __V __b) {
}
}
bool __truncated = false;
if (sizeof(__T) < sizeof(__ckd_intmax_t)) {
if constexpr (sizeof(__T) < sizeof(__ckd_intmax_t)) {
__truncated = __z != static_cast<__ckd_uintmax_t>(static_cast<__T>(__z));
}
switch (std::is_signed<__T>::value << 2 | //
Expand Down Expand Up @@ -176,7 +192,7 @@ inline bool ckd_add(__T *__res, __U __a, __V __b) {
}

template <typename __T, typename __U, typename __V>
inline bool ckd_sub(__T *__res, __U __a, __V __b) {
inline constexpr bool ckd_sub(__T *__res, __U __a, __V __b) {
static_assert(std::is_integral<__T>::value &&
std::is_integral<__U>::value &&
std::is_integral<__V>::value,
Expand All @@ -193,8 +209,8 @@ inline bool ckd_sub(__T *__res, __U __a, __V __b) {
__ckd_uintmax_t __y = __b;
__ckd_uintmax_t __z = __x - __y;
*__res = __z;
if (sizeof(__z) > sizeof(__U) && sizeof(__z) > sizeof(__V)) {
if (sizeof(__z) > sizeof(__T) || std::is_signed<__T>::value) {
if constexpr (sizeof(__z) > sizeof(__U) && sizeof(__z) > sizeof(__V)) {
if constexpr (sizeof(__z) > sizeof(__T) || std::is_signed<__T>::value) {
return static_cast<__ckd_intmax_t>(__z) != static_cast<__T>(__z);
} else if (!std::is_same<__T, __ckd_uintmax_t>::value) {
return (__z != static_cast<__T>(__z) ||
Expand All @@ -204,7 +220,7 @@ inline bool ckd_sub(__T *__res, __U __a, __V __b) {
}
}
bool __truncated = false;
if (sizeof(__T) < sizeof(__ckd_intmax_t)) {
if constexpr (sizeof(__T) < sizeof(__ckd_intmax_t)) {
__truncated = __z != static_cast<__ckd_uintmax_t>(static_cast<__T>(__z));
}
switch (std::is_signed<__T>::value << 2 | //
Expand Down Expand Up @@ -242,7 +258,7 @@ inline bool ckd_sub(__T *__res, __U __a, __V __b) {
}

template <typename __T, typename __U, typename __V>
inline bool ckd_mul(__T *__res, __U __a, __V __b) {
inline constexpr bool ckd_mul(__T *__res, __U __a, __V __b) {
static_assert(std::is_integral<__T>::value &&
std::is_integral<__U>::value &&
std::is_integral<__V>::value,
Expand All @@ -257,10 +273,10 @@ inline bool ckd_mul(__T *__res, __U __a, __V __b) {
"unqualified char type is ambiguous");
__ckd_uintmax_t __x = __a;
__ckd_uintmax_t __y = __b;
if ((sizeof(__U) * 8 - std::is_signed<__U>::value) +
if constexpr ((sizeof(__U) * 8 - std::is_signed<__U>::value) +
(sizeof(__V) * 8 - std::is_signed<__V>::value) <=
(sizeof(__T) * 8 - std::is_signed<__T>::value)) {
if (sizeof(__ckd_uintmax_t) > sizeof(__T) || std::is_signed<__T>::value) {
if constexpr (sizeof(__ckd_uintmax_t) > sizeof(__T) || std::is_signed<__T>::value) {
__ckd_intmax_t __z = __x * __y;
return __z != (*__res = __z);
} else if (!std::is_same<__T, __ckd_uintmax_t>::value) {
Expand Down Expand Up @@ -659,5 +675,10 @@ __ckd_declare_mul(__ckd_mul_uint128, unsigned __int128)
#define ckd_mul(res, x, y) (*(res) = (x) * (y), 0)

#endif /* GNU */

#if defined(_MSC_VER)
#pragma warning(pop)
#endif

#endif /* stdckdint.h */
#endif /* JTCKDINT_H_ */

0 comments on commit 83db8c2

Please sign in to comment.