From f539c11a34723c5697cf556821324d668f8341ec Mon Sep 17 00:00:00 2001 From: tcbrindle Date: Wed, 27 Nov 2024 09:21:36 +0000 Subject: [PATCH] Update single header --- single_include/flux.hpp | 686 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 685 insertions(+), 1 deletion(-) diff --git a/single_include/flux.hpp b/single_include/flux.hpp index 7a40e414..a6588f5c 100644 --- a/single_include/flux.hpp +++ b/single_include/flux.hpp @@ -965,7 +965,691 @@ concept optional_like = -#include +/* + * Copyright 2023 Justine Alexandra Roberts Tunney + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * 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 before 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 + * + * 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 + * @version 0.1 (2023-07-22) + */ + +#ifndef JTCKDINT_H_ +#define JTCKDINT_H_ + +#ifdef __has_include +#define __ckd_has_include(x) __has_include(x) +#else +#define __ckd_has_include(x) 0 +#endif + +#if __ckd_has_include() +#include +#include +#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__)) +#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; + +#ifdef __has_builtin +#define __ckd_has_builtin(x) __has_builtin(x) +#else +#define __ckd_has_builtin(x) 0 +#endif + +#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))) +#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)) + +#elif (defined(__cplusplus) && \ + (__cplusplus >= 201103L || \ + (defined(_MSC_VER) && __cplusplus >= 199711L && \ + __ckd_has_include() && \ + __ckd_has_include()))) +#include +#include + +template +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, + "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 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) || + ((std::is_signed<__U>::value || + std::is_signed<__V>::value) && + static_cast<__ckd_intmax_t>(__z) < 0)); + } + } + bool __truncated = false; + 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 | // + 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 +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, + "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 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) || + ((std::is_signed<__U>::value || + std::is_signed<__V>::value) && + static_cast<__ckd_intmax_t>(__z) < 0)); + } + } + bool __truncated = false; + 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 | // + 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 +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, + "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 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 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) { + __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) { + __x = -__x; + __y = -__y; + } 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 + __ckd_uintmax_t __t = -__y; + __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; + __ckd_uintmax_t __z = __n ? -__p : __p; + *__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 + __ckd_uintmax_t __t = -__x; + __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; + __ckd_uintmax_t __z = __n ? -__p : __p; + *__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) { \ + __x = -__x; \ + __y = -__y; \ + } 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 */ \ + __ckd_uintmax_t __t = -__y; \ + __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; \ + __ckd_uintmax_t __z = __n ? -__p : __p; \ + *(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 */ \ + __ckd_uintmax_t __t = -__x; \ + __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; \ + __ckd_uintmax_t __z = __n ? -__p : __p; \ + *(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 */ + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#endif /* stdckdint.h */ +#endif /* JTCKDINT_H_ */ + #include #include