2023-08-08 03:22:49 +00:00
|
|
|
#ifndef COSMOPOLITAN_LIBC_STDCKDINT_H_
|
|
|
|
#define COSMOPOLITAN_LIBC_STDCKDINT_H_
|
|
|
|
/* clang-format off */
|
2023-07-30 18:05:05 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @fileoverview C23 Checked Arithmetic
|
|
|
|
*
|
|
|
|
* This header defines three type generic functions:
|
|
|
|
*
|
|
|
|
* - `bool ckd_add(res, a, b)`
|
|
|
|
* - `bool ckd_sub(res, a, b)`
|
|
|
|
* - `bool ckd_mul(res, a, b)`
|
|
|
|
*
|
|
|
|
* Which allow integer arithmetic errors to be detected. There are many
|
|
|
|
* kinds of integer errors, e.g. overflow, truncation, etc. These funcs
|
|
|
|
* catch them all. Here's an example of how it works:
|
|
|
|
*
|
|
|
|
* uint32_t c;
|
|
|
|
* int32_t a = 0x7fffffff;
|
|
|
|
* int32_t b = 2;
|
|
|
|
* assert(!ckd_add(&c, a, b));
|
|
|
|
* assert(c == 0x80000001u);
|
|
|
|
*
|
|
|
|
* Experienced C / C++ users should find this example counter-intuitive
|
|
|
|
* because the expression `0x7fffffff + 2` not only overflows it's also
|
|
|
|
* undefined behavior. However here we see it's specified, and does not
|
|
|
|
* result in an error. That's because C23 checked arithmetic is not the
|
|
|
|
* arithmetic you're used to. The new standard changes the mathematics.
|
|
|
|
*
|
|
|
|
* C23 checked arithmetic is defined as performing the arithmetic using
|
|
|
|
* infinite precision and then checking if the resulting value will fit
|
|
|
|
* in the output type. Our example above did not result in an error due
|
|
|
|
* to `0x80000001` being a legal value for `uint32_t`.
|
|
|
|
*
|
|
|
|
* This implementation will use the GNU compiler builtins, when they're
|
|
|
|
* available, only if you don't use build flags like `-std=c11` because
|
|
|
|
* they define `__STRICT_ANSI__` and GCC extensions aren't really ANSI.
|
|
|
|
* Instead, you'll get a pretty good pure C11 and C++11 implementation.
|
|
|
|
*
|
|
|
|
* @see https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf
|
2024-11-20 23:56:56 +00:00
|
|
|
* @see https://github.com/jart/jtckdint
|
2024-12-07 11:19:11 +00:00
|
|
|
* @version 1.0 (2024-12-07)
|
2023-07-30 18:05:05 +00:00
|
|
|
*/
|
|
|
|
|
2023-06-18 07:55:09 +00:00
|
|
|
#define __STDC_VERSION_STDCKDINT_H__ 202311L
|
|
|
|
|
2024-11-20 23:56:56 +00:00
|
|
|
#if (!defined(__STRICT_ANSI__) && defined(__SIZEOF_INT128__))
|
2023-07-30 18:05:05 +00:00
|
|
|
#define __ckd_have_int128
|
|
|
|
#define __ckd_intmax __int128
|
|
|
|
#elif ((defined(__cplusplus) && __cplusplus >= 201103L) || \
|
|
|
|
(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L))
|
|
|
|
#define __ckd_intmax long long
|
|
|
|
#else
|
|
|
|
#define __ckd_intmax long
|
|
|
|
#endif
|
|
|
|
|
|
|
|
typedef signed __ckd_intmax __ckd_intmax_t;
|
|
|
|
typedef unsigned __ckd_intmax __ckd_uintmax_t;
|
|
|
|
|
2024-11-20 23:56:56 +00:00
|
|
|
#if (!defined(__STRICT_ANSI__) && \
|
|
|
|
((defined(__GNUC__) && __GNUC__ >= 5 && !defined(__ICC)) || \
|
|
|
|
(__has_builtin(__builtin_add_overflow) && \
|
|
|
|
__has_builtin(__builtin_sub_overflow) && \
|
2023-08-08 03:22:49 +00:00
|
|
|
__has_builtin(__builtin_mul_overflow))))
|
2023-06-16 22:32:18 +00:00
|
|
|
#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))
|
2023-06-10 16:15:19 +00:00
|
|
|
|
2024-11-20 23:56:56 +00:00
|
|
|
#elif (defined(__cplusplus) && \
|
|
|
|
(__cplusplus >= 201103L || \
|
|
|
|
(defined(_MSC_VER) && __cplusplus >= 199711L && \
|
|
|
|
__ckd_has_include(<type_traits>) && \
|
|
|
|
__ckd_has_include(<limits>))))
|
|
|
|
#include <type_traits>
|
|
|
|
#include <limits>
|
2023-07-30 18:05:05 +00:00
|
|
|
|
|
|
|
template <typename __T, typename __U, typename __V>
|
|
|
|
inline 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,
|
|
|
|
"non-integral types not allowed");
|
|
|
|
static_assert(!std::is_same<__T, bool>::value &&
|
|
|
|
!std::is_same<__U, bool>::value &&
|
|
|
|
!std::is_same<__V, bool>::value,
|
|
|
|
"checked booleans not supported");
|
|
|
|
static_assert(!std::is_same<__T, char>::value &&
|
|
|
|
!std::is_same<__U, char>::value &&
|
|
|
|
!std::is_same<__V, char>::value,
|
|
|
|
"unqualified char type is ambiguous");
|
|
|
|
__ckd_uintmax_t __x = __a;
|
|
|
|
__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) {
|
|
|
|
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) ||
|
|
|
|
((std::is_signed<__U>::value ||
|
|
|
|
std::is_signed<__V>::value) &&
|
|
|
|
static_cast<__ckd_intmax_t>(__z) < 0));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bool __truncated = false;
|
|
|
|
if (sizeof(__T) < sizeof(__ckd_intmax_t)) {
|
|
|
|
__truncated = __z != static_cast<__ckd_uintmax_t>(static_cast<__T>(__z));
|
|
|
|
}
|
|
|
|
switch (std::is_signed<__T>::value << 2 | //
|
|
|
|
std::is_signed<__U>::value << 1 | //
|
|
|
|
std::is_signed<__V>::value) {
|
|
|
|
case 0: // u = u + u
|
|
|
|
return __truncated | (__z < __x);
|
|
|
|
case 1: // u = u + s
|
|
|
|
__y ^= std::numeric_limits<__ckd_intmax_t>::min();
|
|
|
|
return __truncated |
|
|
|
|
(static_cast<__ckd_intmax_t>((__z ^ __x) &
|
|
|
|
(__z ^ __y)) < 0);
|
|
|
|
case 2: // u = s + u
|
|
|
|
__x ^= std::numeric_limits<__ckd_intmax_t>::min();
|
|
|
|
return __truncated |
|
|
|
|
(static_cast<__ckd_intmax_t>((__z ^ __x) &
|
|
|
|
(__z ^ __y)) < 0);
|
|
|
|
case 3: // u = s + s
|
|
|
|
return __truncated |
|
|
|
|
(static_cast<__ckd_intmax_t>(((__z | __x) & __y) |
|
|
|
|
((__z & __x) & ~__y)) < 0);
|
|
|
|
case 4: // s = u + u
|
|
|
|
return __truncated | (__z < __x) | (static_cast<__ckd_intmax_t>(__z) < 0);
|
|
|
|
case 5: // s = u + s
|
|
|
|
__y ^= std::numeric_limits<__ckd_intmax_t>::min();
|
|
|
|
return __truncated | (__x + __y < __y);
|
|
|
|
case 6: // s = s + u
|
|
|
|
__x ^= std::numeric_limits<__ckd_intmax_t>::min();
|
|
|
|
return __truncated | (__x + __y < __x);
|
|
|
|
case 7: // s = s + s
|
|
|
|
return __truncated |
|
|
|
|
(static_cast<__ckd_intmax_t>((__z ^ __x) &
|
|
|
|
(__z ^ __y)) < 0);
|
|
|
|
default:
|
|
|
|
for (;;) (void)0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename __T, typename __U, typename __V>
|
|
|
|
inline 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,
|
|
|
|
"non-integral types not allowed");
|
|
|
|
static_assert(!std::is_same<__T, bool>::value &&
|
|
|
|
!std::is_same<__U, bool>::value &&
|
|
|
|
!std::is_same<__V, bool>::value,
|
|
|
|
"checked booleans not supported");
|
|
|
|
static_assert(!std::is_same<__T, char>::value &&
|
|
|
|
!std::is_same<__U, char>::value &&
|
|
|
|
!std::is_same<__V, char>::value,
|
|
|
|
"unqualified char type is ambiguous");
|
|
|
|
__ckd_uintmax_t __x = __a;
|
|
|
|
__ckd_uintmax_t __y = __b;
|
|
|
|
__ckd_uintmax_t __z = __x - __y;
|
|
|
|
*__res = __z;
|
|
|
|
bool __truncated = false;
|
|
|
|
if (sizeof(__T) < sizeof(__ckd_intmax_t)) {
|
|
|
|
__truncated = __z != static_cast<__ckd_uintmax_t>(static_cast<__T>(__z));
|
|
|
|
}
|
|
|
|
switch (std::is_signed<__T>::value << 2 | //
|
|
|
|
std::is_signed<__U>::value << 1 | //
|
|
|
|
std::is_signed<__V>::value) {
|
|
|
|
case 0: // u = u - u
|
|
|
|
return __truncated | (__x < __y);
|
|
|
|
case 1: // u = u - s
|
|
|
|
__y ^= std::numeric_limits<__ckd_intmax_t>::min();
|
|
|
|
return __truncated |
|
|
|
|
(static_cast<__ckd_intmax_t>((__x ^ __y) &
|
|
|
|
(__z ^ __x)) < 0);
|
|
|
|
case 2: // u = s - u
|
|
|
|
return __truncated | (__y > __x) | (static_cast<__ckd_intmax_t>(__x) < 0);
|
|
|
|
case 3: // u = s - s
|
|
|
|
return __truncated |
|
|
|
|
(static_cast<__ckd_intmax_t>(((__z & __x) & __y) |
|
|
|
|
((__z | __x) & ~__y)) < 0);
|
|
|
|
case 4: // s = u - u
|
|
|
|
return __truncated |
|
|
|
|
((__x < __y) ^ (static_cast<__ckd_intmax_t>(__z) < 0));
|
|
|
|
case 5: // s = u - s
|
|
|
|
__y ^= std::numeric_limits<__ckd_intmax_t>::min();
|
|
|
|
return __truncated | (__x >= __y);
|
|
|
|
case 6: // s = s - u
|
|
|
|
__x ^= std::numeric_limits<__ckd_intmax_t>::min();
|
|
|
|
return __truncated | (__x < __y);
|
|
|
|
case 7: // s = s - s
|
|
|
|
return __truncated |
|
|
|
|
(static_cast<__ckd_intmax_t>((__x ^ __y) &
|
|
|
|
(__z ^ __x)) < 0);
|
|
|
|
default:
|
|
|
|
for (;;) (void)0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename __T, typename __U, typename __V>
|
|
|
|
inline 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,
|
|
|
|
"non-integral types not allowed");
|
|
|
|
static_assert(!std::is_same<__T, bool>::value &&
|
|
|
|
!std::is_same<__U, bool>::value &&
|
|
|
|
!std::is_same<__V, bool>::value,
|
|
|
|
"checked booleans not supported");
|
|
|
|
static_assert(!std::is_same<__T, char>::value &&
|
|
|
|
!std::is_same<__U, char>::value &&
|
|
|
|
!std::is_same<__V, char>::value,
|
|
|
|
"unqualified char type is ambiguous");
|
|
|
|
__ckd_uintmax_t __x = __a;
|
|
|
|
__ckd_uintmax_t __y = __b;
|
|
|
|
if ((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) {
|
|
|
|
__ckd_intmax_t __z = __x * __y;
|
|
|
|
return __z != (*__res = __z);
|
|
|
|
} else if (!std::is_same<__T, __ckd_uintmax_t>::value) {
|
|
|
|
__ckd_uintmax_t __z = __x * __y;
|
|
|
|
*__res = __z;
|
|
|
|
return (__z != static_cast<__T>(__z) ||
|
|
|
|
((std::is_signed<__U>::value ||
|
|
|
|
std::is_signed<__V>::value) &&
|
|
|
|
static_cast<__ckd_intmax_t>(__z) < 0));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
switch (std::is_signed<__T>::value << 2 | //
|
|
|
|
std::is_signed<__U>::value << 1 | //
|
|
|
|
std::is_signed<__V>::value) {
|
|
|
|
case 0: { // u = u * u
|
|
|
|
__ckd_uintmax_t __z = __x * __y;
|
|
|
|
int __o = __x && __z / __x != __y;
|
|
|
|
*__res = __z;
|
|
|
|
return __o | (sizeof(__T) < sizeof(__z) &&
|
|
|
|
__z != static_cast<__ckd_uintmax_t>(*__res));
|
|
|
|
}
|
|
|
|
case 1: { // u = u * s
|
|
|
|
__ckd_uintmax_t __z = __x * __y;
|
|
|
|
int __o = __x && __z / __x != __y;
|
|
|
|
*__res = __z;
|
|
|
|
return (__o | ((static_cast<__ckd_intmax_t>(__y) < 0) & !!__x) |
|
|
|
|
(sizeof(__T) < sizeof(__z) &&
|
|
|
|
__z != static_cast<__ckd_uintmax_t>(*__res)));
|
|
|
|
}
|
|
|
|
case 2: { // u = s * u
|
|
|
|
__ckd_uintmax_t __z = __x * __y;
|
|
|
|
int __o = __x && __z / __x != __y;
|
|
|
|
*__res = __z;
|
|
|
|
return (__o | ((static_cast<__ckd_intmax_t>(__x) < 0) & !!__y) |
|
|
|
|
(sizeof(__T) < sizeof(__z) &&
|
|
|
|
__z != static_cast<__ckd_uintmax_t>(*__res)));
|
|
|
|
}
|
|
|
|
case 3: { // u = s * s
|
|
|
|
int __o = false;
|
|
|
|
if (static_cast<__ckd_intmax_t>(__x & __y) < 0) {
|
2024-11-20 23:56:56 +00:00
|
|
|
__x = 0 - __x;
|
|
|
|
__y = 0 - __y;
|
2023-07-30 18:05:05 +00:00
|
|
|
} else if (static_cast<__ckd_intmax_t>(__x ^ __y) < 0) {
|
|
|
|
__o = __x && __y;
|
|
|
|
}
|
|
|
|
__ckd_uintmax_t __z = __x * __y;
|
|
|
|
__o |= __x && __z / __x != __y;
|
|
|
|
*__res = __z;
|
|
|
|
return __o | (sizeof(__T) < sizeof(__z) &&
|
|
|
|
__z != static_cast<__ckd_uintmax_t>(*__res));
|
|
|
|
}
|
|
|
|
case 4: { // s = u * u
|
|
|
|
__ckd_uintmax_t __z = __x * __y;
|
|
|
|
int __o = __x && __z / __x != __y;
|
|
|
|
*__res = __z;
|
|
|
|
return (__o | (static_cast<__ckd_intmax_t>(__z) < 0) |
|
|
|
|
(sizeof(__T) < sizeof(__z) &&
|
|
|
|
__z != static_cast<__ckd_uintmax_t>(*__res)));
|
|
|
|
}
|
|
|
|
case 5: { // s = u * s
|
2024-11-20 23:56:56 +00:00
|
|
|
__ckd_uintmax_t __t = 0 - __y;
|
2023-07-30 18:05:05 +00:00
|
|
|
__t = static_cast<__ckd_intmax_t>(__t) < 0 ? __y : __t;
|
|
|
|
__ckd_uintmax_t __p = __t * __x;
|
|
|
|
int __o = __t && __p / __t != __x;
|
|
|
|
int __n = static_cast<__ckd_intmax_t>(__y) < 0;
|
2024-11-20 23:56:56 +00:00
|
|
|
__ckd_uintmax_t __z = __n ? 0 - __p : __p;
|
2023-07-30 18:05:05 +00:00
|
|
|
*__res = __z;
|
|
|
|
__ckd_uintmax_t __m = std::numeric_limits<__ckd_intmax_t>::max();
|
|
|
|
return (__o | (__p > __m + __n) |
|
|
|
|
(sizeof(__T) < sizeof(__z) &&
|
|
|
|
__z != static_cast<__ckd_uintmax_t>(*__res)));
|
|
|
|
}
|
|
|
|
case 6: { // s = s * u
|
2024-11-20 23:56:56 +00:00
|
|
|
__ckd_uintmax_t __t = 0 - __x;
|
2023-07-30 18:05:05 +00:00
|
|
|
__t = static_cast<__ckd_intmax_t>(__t) < 0 ? __x : __t;
|
|
|
|
__ckd_uintmax_t __p = __t * __y;
|
|
|
|
int __o = __t && __p / __t != __y;
|
|
|
|
int __n = static_cast<__ckd_intmax_t>(__x) < 0;
|
2024-11-20 23:56:56 +00:00
|
|
|
__ckd_uintmax_t __z = __n ? 0 - __p : __p;
|
2023-07-30 18:05:05 +00:00
|
|
|
*__res = __z;
|
|
|
|
__ckd_uintmax_t __m = std::numeric_limits<__ckd_intmax_t>::max();
|
|
|
|
return (__o | (__p > __m + __n) |
|
|
|
|
(sizeof(__T) < sizeof(__z) &&
|
|
|
|
__z != static_cast<__ckd_uintmax_t>(*__res)));
|
|
|
|
}
|
|
|
|
case 7: { // s = s * s
|
|
|
|
__ckd_uintmax_t __z = __x * __y;
|
|
|
|
*__res = __z;
|
|
|
|
return ((((static_cast<__ckd_intmax_t>(__y) < 0) &&
|
|
|
|
(static_cast<__ckd_intmax_t>(__x) ==
|
|
|
|
std::numeric_limits<__ckd_intmax_t>::min())) ||
|
|
|
|
(__y && ((static_cast<__ckd_intmax_t>(__z) /
|
|
|
|
static_cast<__ckd_intmax_t>(__y)) !=
|
|
|
|
static_cast<__ckd_intmax_t>(__x)))) |
|
|
|
|
(sizeof(__T) < sizeof(__z) &&
|
|
|
|
__z != static_cast<__ckd_uintmax_t>(*__res)));
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
for (;;) (void)0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
|
|
|
|
|
|
|
#define ckd_add(res, a, b) __ckd_expr(add, (res), (a), (b))
|
|
|
|
#define ckd_sub(res, a, b) __ckd_expr(sub, (res), (a), (b))
|
|
|
|
#define ckd_mul(res, a, b) __ckd_expr(mul, (res), (a), (b))
|
|
|
|
|
|
|
|
#if defined(__GNUC__) || defined(__llvm__)
|
|
|
|
#define __ckd_inline \
|
|
|
|
extern __inline __attribute__((__gnu_inline__, \
|
|
|
|
__always_inline__, \
|
|
|
|
__artificial__))
|
|
|
|
#else
|
|
|
|
#define __ckd_inline static inline
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef __ckd_have_int128
|
|
|
|
#define __ckd_generic_int128(x, y) , signed __int128: x, unsigned __int128: y
|
|
|
|
#else
|
|
|
|
#define __ckd_generic_int128(x, y)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define __ckd_sign(T) \
|
|
|
|
((T)1 << (sizeof(T) * 8 - 1))
|
|
|
|
|
|
|
|
#define __ckd_is_signed(x) \
|
|
|
|
_Generic(x, \
|
|
|
|
signed char: 1, \
|
|
|
|
unsigned char: 0, \
|
|
|
|
signed short: 1, \
|
|
|
|
unsigned short: 0, \
|
|
|
|
signed int: 1, \
|
|
|
|
unsigned int: 0, \
|
|
|
|
signed long: 1, \
|
|
|
|
unsigned long: 0, \
|
|
|
|
signed long long: 1, \
|
|
|
|
unsigned long long: 0 \
|
|
|
|
__ckd_generic_int128(1, 0))
|
|
|
|
|
|
|
|
#define __ckd_expr(op, res, a, b) \
|
|
|
|
(_Generic(*res, \
|
|
|
|
signed char: __ckd_##op##_schar, \
|
|
|
|
unsigned char: __ckd_##op##_uchar, \
|
|
|
|
signed short: __ckd_##op##_sshort, \
|
|
|
|
unsigned short: __ckd_##op##_ushort, \
|
|
|
|
signed int: __ckd_##op##_sint, \
|
|
|
|
unsigned int: __ckd_##op##_uint, \
|
|
|
|
signed long: __ckd_##op##_slong, \
|
|
|
|
unsigned long: __ckd_##op##_ulong, \
|
|
|
|
signed long long: __ckd_##op##_slonger, \
|
|
|
|
unsigned long long: __ckd_##op##_ulonger \
|
|
|
|
__ckd_generic_int128( \
|
|
|
|
__ckd_##op##_sint128, \
|
|
|
|
__ckd_##op##_uint128))( \
|
|
|
|
res, a, b, \
|
|
|
|
__ckd_is_signed(a), \
|
|
|
|
__ckd_is_signed(b)))
|
|
|
|
|
|
|
|
#define __ckd_declare_add(S, T) \
|
|
|
|
__ckd_inline char S(void *__res, \
|
|
|
|
__ckd_uintmax_t __x, \
|
|
|
|
__ckd_uintmax_t __y, \
|
|
|
|
char __a_signed, \
|
|
|
|
char __b_signed) { \
|
|
|
|
__ckd_uintmax_t __z = __x + __y; \
|
|
|
|
*(T *)__res = __z; \
|
|
|
|
char __truncated = 0; \
|
|
|
|
if (sizeof(T) < sizeof(__ckd_intmax_t)) { \
|
|
|
|
__truncated = __z != (__ckd_uintmax_t)(T)__z; \
|
|
|
|
} \
|
|
|
|
switch (__ckd_is_signed((T)0) << 2 | \
|
|
|
|
__a_signed << 1 | __b_signed) { \
|
|
|
|
case 0: /* u = u + u */ \
|
|
|
|
return __truncated | (__z < __x); \
|
|
|
|
case 1: /* u = u + s */ \
|
|
|
|
__y ^= __ckd_sign(__ckd_uintmax_t); \
|
|
|
|
return __truncated | \
|
|
|
|
((__ckd_intmax_t)((__z ^ __x) & \
|
|
|
|
(__z ^ __y)) < 0); \
|
|
|
|
case 2: /* u = s + u */ \
|
|
|
|
__x ^= __ckd_sign(__ckd_uintmax_t); \
|
|
|
|
return __truncated | \
|
|
|
|
((__ckd_intmax_t)((__z ^ __x) & \
|
|
|
|
(__z ^ __y)) < 0); \
|
|
|
|
case 3: /* u = s + s */ \
|
|
|
|
return __truncated | \
|
|
|
|
((__ckd_intmax_t)(((__z | __x) & __y) | \
|
|
|
|
((__z & __x) & ~__y)) < 0); \
|
|
|
|
case 4: /* s = u + u */ \
|
|
|
|
return __truncated | (__z < __x) | ((__ckd_intmax_t)__z < 0); \
|
|
|
|
case 5: /* s = u + s */ \
|
|
|
|
__y ^= __ckd_sign(__ckd_uintmax_t); \
|
|
|
|
return __truncated | (__x + __y < __y); \
|
|
|
|
case 6: /* s = s + u */ \
|
|
|
|
__x ^= __ckd_sign(__ckd_uintmax_t); \
|
|
|
|
return __truncated | (__x + __y < __x); \
|
|
|
|
case 7: /* s = s + s */ \
|
|
|
|
return __truncated | \
|
|
|
|
((__ckd_intmax_t)((__z ^ __x) & \
|
|
|
|
(__z ^ __y)) < 0); \
|
|
|
|
default: \
|
|
|
|
for (;;) (void)0; \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
__ckd_declare_add(__ckd_add_schar, signed char)
|
|
|
|
__ckd_declare_add(__ckd_add_uchar, unsigned char)
|
|
|
|
__ckd_declare_add(__ckd_add_sshort, signed short)
|
|
|
|
__ckd_declare_add(__ckd_add_ushort, unsigned short)
|
|
|
|
__ckd_declare_add(__ckd_add_sint, signed int)
|
|
|
|
__ckd_declare_add(__ckd_add_uint, unsigned int)
|
|
|
|
__ckd_declare_add(__ckd_add_slong, signed long)
|
|
|
|
__ckd_declare_add(__ckd_add_ulong, unsigned long)
|
|
|
|
__ckd_declare_add(__ckd_add_slonger, signed long long)
|
|
|
|
__ckd_declare_add(__ckd_add_ulonger, unsigned long long)
|
|
|
|
#ifdef __ckd_have_int128
|
|
|
|
__ckd_declare_add(__ckd_add_sint128, signed __int128)
|
|
|
|
__ckd_declare_add(__ckd_add_uint128, unsigned __int128)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define __ckd_declare_sub(S, T) \
|
|
|
|
__ckd_inline char S(void *__res, \
|
|
|
|
__ckd_uintmax_t __x, \
|
|
|
|
__ckd_uintmax_t __y, \
|
|
|
|
char __a_signed, \
|
|
|
|
char __b_signed) { \
|
|
|
|
__ckd_uintmax_t __z = __x - __y; \
|
|
|
|
*(T *)__res = __z; \
|
|
|
|
char __truncated = 0; \
|
|
|
|
if (sizeof(T) < sizeof(__ckd_intmax_t)) { \
|
|
|
|
__truncated = __z != (__ckd_uintmax_t)(T)__z; \
|
|
|
|
} \
|
|
|
|
switch (__ckd_is_signed((T)0) << 2 | \
|
|
|
|
__a_signed << 1 | __b_signed) { \
|
|
|
|
case 0: /* u = u - u */ \
|
|
|
|
return __truncated | (__x < __y); \
|
|
|
|
case 1: /* u = u - s */ \
|
|
|
|
__y ^= __ckd_sign(__ckd_uintmax_t); \
|
|
|
|
return __truncated | \
|
|
|
|
((__ckd_intmax_t)((__x ^ __y) & \
|
|
|
|
(__z ^ __x)) < 0); \
|
|
|
|
case 2: /* u = s - u */ \
|
|
|
|
return __truncated | (__y > __x) | ((__ckd_intmax_t)__x < 0); \
|
|
|
|
case 3: /* u = s - s */ \
|
|
|
|
return __truncated | \
|
|
|
|
((__ckd_intmax_t)(((__z & __x) & __y) | \
|
|
|
|
((__z | __x) & ~__y)) < 0); \
|
|
|
|
case 4: /* s = u - u */ \
|
|
|
|
return __truncated | ((__x < __y) ^ ((__ckd_intmax_t)__z < 0)); \
|
|
|
|
case 5: /* s = u - s */ \
|
|
|
|
__y ^= __ckd_sign(__ckd_uintmax_t); \
|
|
|
|
return __truncated | (__x >= __y); \
|
|
|
|
case 6: /* s = s - u */ \
|
|
|
|
__x ^= __ckd_sign(__ckd_uintmax_t); \
|
|
|
|
return __truncated | (__x < __y); \
|
|
|
|
case 7: /* s = s - s */ \
|
|
|
|
return __truncated | \
|
|
|
|
((__ckd_intmax_t)((__x ^ __y) & \
|
|
|
|
(__z ^ __x)) < 0); \
|
|
|
|
default: \
|
|
|
|
for (;;) (void)0; \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
__ckd_declare_sub(__ckd_sub_schar, signed char)
|
|
|
|
__ckd_declare_sub(__ckd_sub_uchar, unsigned char)
|
|
|
|
__ckd_declare_sub(__ckd_sub_sshort, signed short)
|
|
|
|
__ckd_declare_sub(__ckd_sub_ushort, unsigned short)
|
|
|
|
__ckd_declare_sub(__ckd_sub_sint, signed int)
|
|
|
|
__ckd_declare_sub(__ckd_sub_uint, unsigned int)
|
|
|
|
__ckd_declare_sub(__ckd_sub_slong, signed long)
|
|
|
|
__ckd_declare_sub(__ckd_sub_ulong, unsigned long)
|
|
|
|
__ckd_declare_sub(__ckd_sub_slonger, signed long long)
|
|
|
|
__ckd_declare_sub(__ckd_sub_ulonger, unsigned long long)
|
|
|
|
#ifdef __ckd_have_int128
|
|
|
|
__ckd_declare_sub(__ckd_sub_sint128, signed __int128)
|
|
|
|
__ckd_declare_sub(__ckd_sub_uint128, unsigned __int128)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define __ckd_declare_mul(S, T) \
|
|
|
|
__ckd_inline char S(void *__res, \
|
|
|
|
__ckd_uintmax_t __x, \
|
|
|
|
__ckd_uintmax_t __y, \
|
|
|
|
char __a_signed, \
|
|
|
|
char __b_signed) { \
|
|
|
|
switch (__ckd_is_signed((T)0) << 2 | \
|
|
|
|
__a_signed << 1 | __b_signed) { \
|
|
|
|
case 0: { /* u = u * u */ \
|
|
|
|
__ckd_uintmax_t __z = __x * __y; \
|
|
|
|
int __o = __x && __z / __x != __y; \
|
|
|
|
*(T *)__res = __z; \
|
|
|
|
return __o | (sizeof(T) < sizeof(__z) && \
|
|
|
|
__z != (__ckd_uintmax_t)*(T *)__res); \
|
|
|
|
} \
|
|
|
|
case 1: { /* u = u * s */ \
|
|
|
|
__ckd_uintmax_t __z = __x * __y; \
|
|
|
|
int __o = __x && __z / __x != __y; \
|
|
|
|
*(T *)__res = __z; \
|
|
|
|
return (__o | (((__ckd_intmax_t)__y < 0) & !!__x) | \
|
|
|
|
(sizeof(T) < sizeof(__z) && \
|
|
|
|
__z != (__ckd_uintmax_t)*(T *)__res)); \
|
|
|
|
} \
|
|
|
|
case 2: { /* u = s * u */ \
|
|
|
|
__ckd_uintmax_t __z = __x * __y; \
|
|
|
|
int __o = __x && __z / __x != __y; \
|
|
|
|
*(T *)__res = __z; \
|
|
|
|
return (__o | (((__ckd_intmax_t)__x < 0) & !!__y) | \
|
|
|
|
(sizeof(T) < sizeof(__z) && \
|
|
|
|
__z != (__ckd_uintmax_t)*(T *)__res)); \
|
|
|
|
} \
|
|
|
|
case 3: { /* u = s * s */ \
|
|
|
|
int __o = 0; \
|
|
|
|
if ((__ckd_intmax_t)(__x & __y) < 0) { \
|
2024-11-20 23:56:56 +00:00
|
|
|
__x = 0 - __x; \
|
|
|
|
__y = 0 - __y; \
|
2023-07-30 18:05:05 +00:00
|
|
|
} else if ((__ckd_intmax_t)(__x ^ __y) < 0) { \
|
|
|
|
__o = __x && __y; \
|
|
|
|
} \
|
|
|
|
__ckd_uintmax_t __z = __x * __y; \
|
|
|
|
__o |= __x && __z / __x != __y; \
|
|
|
|
*(T *)__res = __z; \
|
|
|
|
return __o | (sizeof(T) < sizeof(__z) && \
|
|
|
|
__z != (__ckd_uintmax_t)*(T *)__res); \
|
|
|
|
} \
|
|
|
|
case 4: { /* s = u * u */ \
|
|
|
|
__ckd_uintmax_t __z = __x * __y; \
|
|
|
|
int __o = __x && __z / __x != __y; \
|
|
|
|
*(T *)__res = __z; \
|
|
|
|
return (__o | ((__ckd_intmax_t)(__z) < 0) | \
|
|
|
|
(sizeof(T) < sizeof(__z) && \
|
|
|
|
__z != (__ckd_uintmax_t)*(T *)__res)); \
|
|
|
|
} \
|
|
|
|
case 5: { /* s = u * s */ \
|
2024-11-20 23:56:56 +00:00
|
|
|
__ckd_uintmax_t __t = 0 - __y; \
|
2023-07-30 18:05:05 +00:00
|
|
|
__t = (__ckd_intmax_t)(__t) < 0 ? __y : __t; \
|
|
|
|
__ckd_uintmax_t __p = __t * __x; \
|
|
|
|
int __o = __t && __p / __t != __x; \
|
|
|
|
int __n = (__ckd_intmax_t)__y < 0; \
|
2024-11-20 23:56:56 +00:00
|
|
|
__ckd_uintmax_t __z = __n ? 0 - __p : __p; \
|
2023-07-30 18:05:05 +00:00
|
|
|
*(T *)__res = __z; \
|
|
|
|
__ckd_uintmax_t __m = __ckd_sign(__ckd_uintmax_t) - 1; \
|
|
|
|
return (__o | (__p > __m + __n) | \
|
|
|
|
(sizeof(T) < sizeof(__z) && \
|
|
|
|
__z != (__ckd_uintmax_t)*(T *)__res)); \
|
|
|
|
} \
|
|
|
|
case 6: { /* s = s * u */ \
|
2024-11-20 23:56:56 +00:00
|
|
|
__ckd_uintmax_t __t = 0 - __x; \
|
2023-07-30 18:05:05 +00:00
|
|
|
__t = (__ckd_intmax_t)(__t) < 0 ? __x : __t; \
|
|
|
|
__ckd_uintmax_t __p = __t * __y; \
|
|
|
|
int __o = __t && __p / __t != __y; \
|
|
|
|
int __n = (__ckd_intmax_t)__x < 0; \
|
2024-11-20 23:56:56 +00:00
|
|
|
__ckd_uintmax_t __z = __n ? 0 - __p : __p; \
|
2023-07-30 18:05:05 +00:00
|
|
|
*(T *)__res = __z; \
|
|
|
|
__ckd_uintmax_t __m = __ckd_sign(__ckd_uintmax_t) - 1; \
|
|
|
|
return (__o | (__p > __m + __n) | \
|
|
|
|
(sizeof(T) < sizeof(__z) && \
|
|
|
|
__z != (__ckd_uintmax_t)*(T *)__res)); \
|
|
|
|
} \
|
|
|
|
case 7: { /* s = s * s */ \
|
|
|
|
__ckd_uintmax_t __z = __x * __y; \
|
|
|
|
*(T *)__res = __z; \
|
|
|
|
return (((((__ckd_intmax_t)__y < 0) && \
|
|
|
|
(__x == __ckd_sign(__ckd_uintmax_t))) || \
|
|
|
|
(__y && (((__ckd_intmax_t)__z / \
|
|
|
|
(__ckd_intmax_t)__y) != \
|
|
|
|
(__ckd_intmax_t)__x))) | \
|
|
|
|
(sizeof(T) < sizeof(__z) && \
|
|
|
|
__z != (__ckd_uintmax_t)*(T *)__res)); \
|
|
|
|
} \
|
|
|
|
default: \
|
|
|
|
for (;;) (void)0; \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
__ckd_declare_mul(__ckd_mul_schar, signed char)
|
|
|
|
__ckd_declare_mul(__ckd_mul_uchar, unsigned char)
|
|
|
|
__ckd_declare_mul(__ckd_mul_sshort, signed short)
|
|
|
|
__ckd_declare_mul(__ckd_mul_ushort, unsigned short)
|
|
|
|
__ckd_declare_mul(__ckd_mul_sint, signed int)
|
|
|
|
__ckd_declare_mul(__ckd_mul_uint, unsigned int)
|
|
|
|
__ckd_declare_mul(__ckd_mul_slong, signed long)
|
|
|
|
__ckd_declare_mul(__ckd_mul_ulong, unsigned long)
|
|
|
|
__ckd_declare_mul(__ckd_mul_slonger, signed long long)
|
|
|
|
__ckd_declare_mul(__ckd_mul_ulonger, unsigned long long)
|
|
|
|
#ifdef __ckd_have_int128
|
|
|
|
__ckd_declare_mul(__ckd_mul_sint128, signed __int128)
|
|
|
|
__ckd_declare_mul(__ckd_mul_uint128, unsigned __int128)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#else
|
|
|
|
#pragma message "checked integer arithmetic unsupported in this environment"
|
|
|
|
|
|
|
|
#define ckd_add(res, x, y) (*(res) = (x) + (y), 0)
|
|
|
|
#define ckd_sub(res, x, y) (*(res) = (x) - (y), 0)
|
|
|
|
#define ckd_mul(res, x, y) (*(res) = (x) * (y), 0)
|
|
|
|
|
|
|
|
#endif /* GNU */
|
2023-08-08 03:22:49 +00:00
|
|
|
#endif /* COSMOPOLITAN_LIBC_STDCKDINT_H_ */
|