/* is parametrized: no */ /* // Functions for safely checking for over- and underflow of arithmetic operations guf_math_ckd_result guf_ckd_add_TYPE(TYPE a, TYPE b); - if a + b doesn't over/underflow TYPE: return GUF_MATH_CKD_SUCCESS (falsy) - if a + b overflows TYPE: return GUF_MATH_CKD_OVERFLOW (truthy) - if a + b underflows TYPE: return GUF_MATH_CKD_UNDERFLOW (truthy) guf_math_ckd_result guf_ckd_sub_TYPE(TYPE a, TYPE b); - if a - b doesn't over/underflow TYPE: return GUF_MATH_CKD_SUCCESS (falsy) - if a - b overflows TYPE: return GUF_MATH_CKD_OVERFLOW (truthy) - if a - b underflows TYPE: return GUF_MATH_CKD_UNDERFLOW (truthy) guf_math_ckd_result guf_ckd_mul_TYPE(TYPE a, TYPE b); - if a * b doesn't over/underflow TYPE: return GUF_MATH_CKD_SUCCESS (falsy) - if a * b overflows TYPE: return GUF_MATH_CKD_OVERFLOW (truthy) - if a * b underflows TYPE: return GUF_MATH_CKD_UNDERFLOW (truthy) // Functions for safely computing arithmetic operations with saturating over- and underflow semantics // (cf. https://doc.rust-lang.org/std/intrinsics/fn.saturating_add.html (last-retrieved 2025-05-10)) guf_math_ckd_result guf_saturating_add_TYPE(TYPE a, TYPE b, TYPE *result); - if a + b does not over-/underflow TYPE: return GUF_MATH_CKD_SUCCESS (if result is not NULL, set result to a + b) - if a + b overflows TYPE: return GUF_MATH_CKD_OVERFLOW (if result is not NULL, set result to TYPE_MAX, i.e. use saturating overflow semantics). - if a + b underflows TYPE: return GUF_MATH_CKD_UNDERFLOW (if result is not NULL, set result to TYPE_MIN, i.e. use saturating underflow semantics). guf_math_ckd_result guf_saturating_sub_TYPE(TYPE a, TYPE b, TYPE *result); - if a - b does not over-/underflow TYPE: return GUF_MATH_CKD_SUCCESS (if result is not NULL, set result to a - b) - if a - b overflows TYPE: return GUF_MATH_CKD_OVERFLOW (if result is not NULL, set result to TYPE_MAX, i.e. use saturating overflow semantics). - if a - b underflows TYPE: return GUF_MATH_CKD_UNDERFLOW (if result is not NULL, set result to TYPE_MIN, i.e. use saturating underflow semantics). guf_math_ckd_result guf_saturating_mul_TYPE(TYPE a, TYPE b, TYPE *result); - if a * b does not over-/underflow TYPE: return GUF_MATH_CKD_SUCCESS (if result is not NULL, set result to a * b) - if a * b overflows TYPE: return GUF_MATH_CKD_OVERFLOW (if result is not NULL, set result to TYPE_MAX, i.e. use saturating overflow semantics). - if a * b underflows TYPE: return GUF_MATH_CKD_UNDERFLOW (if result is not NULL, set result to TYPE_MIN, i.e. use saturating underflow semantics). // Functions for safely computing arithmetic operations with wrapping over- and underflow semantics // (cf. https://doc.rust-lang.org/std/intrinsics/fn.wrapping_add.html (last-retrieved 2025-05-10)) guf_math_ckd_result guf_wrapping_add_TYPE(TYPE a, TYPE b, TYPE *result); - if a + b does not over-/underflow TYPE: return GUF_MATH_CKD_SUCCESS (if result is not NULL, set result to a + b) - if a + b overflows TYPE: return GUF_MATH_CKD_OVERFLOW (if result is not NULL, set result using two's complement wrap-around overflow semantics). - if a + b underflows TYPE: return GUF_MATH_CKD_UNDERFLOW (if result is not NULL, set result using two's complement wrap-around underflow semantics). guf_math_ckd_result guf_wrapping_sub_TYPE(TYPE a, TYPE b, TYPE *result); - if a - b doesn't over-/underflow TYPE: return GUF_MATH_CKD_SUCCESS (if result is not NULL, set result to a - b) - if a - b overflows TYPE: return GUF_MATH_CKD_OVERFLOW (if result is not NULL, set result using two's complement wrap-around overflow semantics). - if a - b underflows TYPE: return GUF_MATH_CKD_UNDERFLOW (if result is not NULL, set result using two's complement wrap-around underflow semantics). guf_math_ckd_result guf_wrapping_mul_TYPE(TYPE a, TYPE b, TYPE *result); // NOTE/TODO: guf_wrapping_mul_TYPE relies on implementation-defined unsigned-to-signed two's complement conversion on over/underflow // cf. https://stackoverflow.com/questions/76900522/can-you-ensure-overflow-wrapping-behavior-for-signed-integer-arithmetic-in-c (last-retrieved 2025-05-13) - if a * b doesn't over-/underflow TYPE: return GUF_MATH_CKD_SUCCESS (if result is not NULL, set result to a * b) - if a * b overflows TYPE: return GUF_MATH_CKD_OVERFLOW (if result is not NULL, set result using two's complement wrap-around overflow semantics). - if a * b underflows TYPE: return GUF_MATH_CKD_UNDERFLOW (if result is not NULL, set result using two's complement wrap-around underflow semantics). cf. https://stackoverflow.com/questions/199333/how-do-i-detect-unsigned-integer-overflow (last-retrieved 2025-03-17) cf. https://stackoverflow.com/questions/59307930/how-to-implement-wrapping-signed-int-addition-in-c (last-retrieved 2025-05-10) cf. https://stackoverflow.com/questions/54318815/integer-overflow-w-multiplication-in-c (last-retrieved 2025-05-11) cf. https://stackoverflow.com/questions/29808397/how-to-portably-find-out-minint-max-absint-min (last-retrieved 2025-05-11) */ #if defined(GUF_MATH_CKDINT_IMPL_STATIC) #define GUF_MATH_CKDINT_KWRDS static inline #else #define GUF_MATH_CKDINT_KWRDS #endif #ifndef GUF_MATH_CKDINT_H #define GUF_MATH_CKDINT_H #include "guf_common.h" typedef enum guf_math_ckd_result {GUF_MATH_CKD_SUCCESS = 0, GUF_MATH_CKD_OVERFLOW, GUF_MATH_CKD_UNDERFLOW} guf_math_ckd_result; #if !defined(GUF_MATH_CKDINT_IMPL_STATIC) && !defined(GUF_MATH_CKDINT_IMPL) // Signed integer arithmetic checks (generated with libguf/tools/ckdint-gen.py) GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_int(int a, int b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_int(int a, int b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_int(int a, int b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_i8(int8_t a, int8_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_i8(int8_t a, int8_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_i8(int8_t a, int8_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_i16(int16_t a, int16_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_i16(int16_t a, int16_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_i16(int16_t a, int16_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_i32(int32_t a, int32_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_i32(int32_t a, int32_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_i32(int32_t a, int32_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_i64(int64_t a, int64_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_i64(int64_t a, int64_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_i64(int64_t a, int64_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_ptrdiff_t(ptrdiff_t a, ptrdiff_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_ptrdiff_t(ptrdiff_t a, ptrdiff_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_ptrdiff_t(ptrdiff_t a, ptrdiff_t b); // Unsigned integer arithmetic checks (generated with libguf/tools/ckdint-gen.py) GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_uchar(unsigned char a, unsigned char b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_uchar(unsigned char a, unsigned char b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_uchar(unsigned char a, unsigned char b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_unsigned(unsigned a, unsigned b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_unsigned(unsigned a, unsigned b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_unsigned(unsigned a, unsigned b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_u8(uint8_t a, uint8_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_u8(uint8_t a, uint8_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_u8(uint8_t a, uint8_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_u16(uint16_t a, uint16_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_u16(uint16_t a, uint16_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_u16(uint16_t a, uint16_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_u32(uint32_t a, uint32_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_u32(uint32_t a, uint32_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_u32(uint32_t a, uint32_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_u64(uint64_t a, uint64_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_u64(uint64_t a, uint64_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_u64(uint64_t a, uint64_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_size_t(size_t a, size_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_size_t(size_t a, size_t b); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_size_t(size_t a, size_t b); // Signed saturating/wrapping arithmetic (generated with libguf/tools/ckdint-gen.py) GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_int(int a, int b, int *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_int(int a, int b, int *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_int(int a, int b, int *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_int(int a, int b, int *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_int(int a, int b, int *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_int(int a, int b, int *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_i8(int8_t a, int8_t b, int8_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_i8(int8_t a, int8_t b, int8_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_i8(int8_t a, int8_t b, int8_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_i8(int8_t a, int8_t b, int8_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_i8(int8_t a, int8_t b, int8_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_i8(int8_t a, int8_t b, int8_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_i16(int16_t a, int16_t b, int16_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_i16(int16_t a, int16_t b, int16_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_i16(int16_t a, int16_t b, int16_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_i16(int16_t a, int16_t b, int16_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_i16(int16_t a, int16_t b, int16_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_i16(int16_t a, int16_t b, int16_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_i32(int32_t a, int32_t b, int32_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_i32(int32_t a, int32_t b, int32_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_i32(int32_t a, int32_t b, int32_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_i32(int32_t a, int32_t b, int32_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_i32(int32_t a, int32_t b, int32_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_i32(int32_t a, int32_t b, int32_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_i64(int64_t a, int64_t b, int64_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_i64(int64_t a, int64_t b, int64_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_i64(int64_t a, int64_t b, int64_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_i64(int64_t a, int64_t b, int64_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_i64(int64_t a, int64_t b, int64_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_i64(int64_t a, int64_t b, int64_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_ptrdiff_t(ptrdiff_t a, ptrdiff_t b, ptrdiff_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_ptrdiff_t(ptrdiff_t a, ptrdiff_t b, ptrdiff_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_ptrdiff_t(ptrdiff_t a, ptrdiff_t b, ptrdiff_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_ptrdiff_t(ptrdiff_t a, ptrdiff_t b, ptrdiff_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_ptrdiff_t(ptrdiff_t a, ptrdiff_t b, ptrdiff_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_ptrdiff_t(ptrdiff_t a, ptrdiff_t b, ptrdiff_t *result); // Unsigned saturating/wrapping arithmetic (generated with libguf/tools/ckdint-gen.py) GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_uchar(unsigned char a, unsigned char b, unsigned char *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_uchar(unsigned char a, unsigned char b, unsigned char *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_uchar(unsigned char a, unsigned char b, unsigned char *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_uchar(unsigned char a, unsigned char b, unsigned char *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_uchar(unsigned char a, unsigned char b, unsigned char *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_uchar(unsigned char a, unsigned char b, unsigned char *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_unsigned(unsigned a, unsigned b, unsigned *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_unsigned(unsigned a, unsigned b, unsigned *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_unsigned(unsigned a, unsigned b, unsigned *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_unsigned(unsigned a, unsigned b, unsigned *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_unsigned(unsigned a, unsigned b, unsigned *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_unsigned(unsigned a, unsigned b, unsigned *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_u8(uint8_t a, uint8_t b, uint8_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_u8(uint8_t a, uint8_t b, uint8_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_u8(uint8_t a, uint8_t b, uint8_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_u8(uint8_t a, uint8_t b, uint8_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_u8(uint8_t a, uint8_t b, uint8_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_u8(uint8_t a, uint8_t b, uint8_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_u16(uint16_t a, uint16_t b, uint16_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_u16(uint16_t a, uint16_t b, uint16_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_u16(uint16_t a, uint16_t b, uint16_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_u16(uint16_t a, uint16_t b, uint16_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_u16(uint16_t a, uint16_t b, uint16_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_u16(uint16_t a, uint16_t b, uint16_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_u32(uint32_t a, uint32_t b, uint32_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_u32(uint32_t a, uint32_t b, uint32_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_u32(uint32_t a, uint32_t b, uint32_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_u32(uint32_t a, uint32_t b, uint32_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_u32(uint32_t a, uint32_t b, uint32_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_u32(uint32_t a, uint32_t b, uint32_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_u64(uint64_t a, uint64_t b, uint64_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_u64(uint64_t a, uint64_t b, uint64_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_u64(uint64_t a, uint64_t b, uint64_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_u64(uint64_t a, uint64_t b, uint64_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_u64(uint64_t a, uint64_t b, uint64_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_u64(uint64_t a, uint64_t b, uint64_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_size_t(size_t a, size_t b, size_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_size_t(size_t a, size_t b, size_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_size_t(size_t a, size_t b, size_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_size_t(size_t a, size_t b, size_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_size_t(size_t a, size_t b, size_t *result); GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_size_t(size_t a, size_t b, size_t *result); #endif #if defined(GUF_MATH_CKDINT_IMPL) || defined(GUF_MATH_CKDINT_IMPL_STATIC) #include "guf_assert.h" // Signed integer arithmetic checks (generated with libguf/tools/ckdint-gen.py) GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_int(int a, int b) { if (b > 0 && a > INT_MAX - b) { return GUF_MATH_CKD_OVERFLOW; } else if (b < 0 && a < INT_MIN - b) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_int(int a, int b) { if (b < 0 && a > INT_MAX + b) { return GUF_MATH_CKD_OVERFLOW; } else if (b > 0 && a < INT_MIN + b) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_int(int a, int b) { if (b > 0) { if (a > INT_MAX / b) { return GUF_MATH_CKD_OVERFLOW; } else if (a < INT_MIN / b) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } else if (b < 0) { if (INT_MIN != -INT_MAX && b == -1) { // Prevent potential (INT_MIN / b) overflow for b == -1 return a == INT_MIN ? GUF_MATH_CKD_OVERFLOW : GUF_MATH_CKD_SUCCESS; } else if (a < INT_MAX / b) { return GUF_MATH_CKD_OVERFLOW; } else if (a > INT_MIN / b) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_i8(int8_t a, int8_t b) { if (b > 0 && a > INT8_MAX - b) { return GUF_MATH_CKD_OVERFLOW; } else if (b < 0 && a < INT8_MIN - b) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_i8(int8_t a, int8_t b) { if (b < 0 && a > INT8_MAX + b) { return GUF_MATH_CKD_OVERFLOW; } else if (b > 0 && a < INT8_MIN + b) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_i8(int8_t a, int8_t b) { if (b > 0) { if (a > INT8_MAX / b) { return GUF_MATH_CKD_OVERFLOW; } else if (a < INT8_MIN / b) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } else if (b < 0) { if (INT8_MIN != -INT8_MAX && b == -1) { // Prevent potential (INT8_MIN / b) overflow for b == -1 return a == INT8_MIN ? GUF_MATH_CKD_OVERFLOW : GUF_MATH_CKD_SUCCESS; } else if (a < INT8_MAX / b) { return GUF_MATH_CKD_OVERFLOW; } else if (a > INT8_MIN / b) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_i16(int16_t a, int16_t b) { if (b > 0 && a > INT16_MAX - b) { return GUF_MATH_CKD_OVERFLOW; } else if (b < 0 && a < INT16_MIN - b) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_i16(int16_t a, int16_t b) { if (b < 0 && a > INT16_MAX + b) { return GUF_MATH_CKD_OVERFLOW; } else if (b > 0 && a < INT16_MIN + b) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_i16(int16_t a, int16_t b) { if (b > 0) { if (a > INT16_MAX / b) { return GUF_MATH_CKD_OVERFLOW; } else if (a < INT16_MIN / b) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } else if (b < 0) { if (INT16_MIN != -INT16_MAX && b == -1) { // Prevent potential (INT16_MIN / b) overflow for b == -1 return a == INT16_MIN ? GUF_MATH_CKD_OVERFLOW : GUF_MATH_CKD_SUCCESS; } else if (a < INT16_MAX / b) { return GUF_MATH_CKD_OVERFLOW; } else if (a > INT16_MIN / b) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_i32(int32_t a, int32_t b) { if (b > 0 && a > INT32_MAX - b) { return GUF_MATH_CKD_OVERFLOW; } else if (b < 0 && a < INT32_MIN - b) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_i32(int32_t a, int32_t b) { if (b < 0 && a > INT32_MAX + b) { return GUF_MATH_CKD_OVERFLOW; } else if (b > 0 && a < INT32_MIN + b) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_i32(int32_t a, int32_t b) { if (b > 0) { if (a > INT32_MAX / b) { return GUF_MATH_CKD_OVERFLOW; } else if (a < INT32_MIN / b) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } else if (b < 0) { if (INT32_MIN != -INT32_MAX && b == -1) { // Prevent potential (INT32_MIN / b) overflow for b == -1 return a == INT32_MIN ? GUF_MATH_CKD_OVERFLOW : GUF_MATH_CKD_SUCCESS; } else if (a < INT32_MAX / b) { return GUF_MATH_CKD_OVERFLOW; } else if (a > INT32_MIN / b) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_i64(int64_t a, int64_t b) { if (b > 0 && a > INT64_MAX - b) { return GUF_MATH_CKD_OVERFLOW; } else if (b < 0 && a < INT64_MIN - b) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_i64(int64_t a, int64_t b) { if (b < 0 && a > INT64_MAX + b) { return GUF_MATH_CKD_OVERFLOW; } else if (b > 0 && a < INT64_MIN + b) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_i64(int64_t a, int64_t b) { if (b > 0) { if (a > INT64_MAX / b) { return GUF_MATH_CKD_OVERFLOW; } else if (a < INT64_MIN / b) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } else if (b < 0) { if (INT64_MIN != -INT64_MAX && b == -1) { // Prevent potential (INT64_MIN / b) overflow for b == -1 return a == INT64_MIN ? GUF_MATH_CKD_OVERFLOW : GUF_MATH_CKD_SUCCESS; } else if (a < INT64_MAX / b) { return GUF_MATH_CKD_OVERFLOW; } else if (a > INT64_MIN / b) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_ptrdiff_t(ptrdiff_t a, ptrdiff_t b) { if (b > 0 && a > PTRDIFF_MAX - b) { return GUF_MATH_CKD_OVERFLOW; } else if (b < 0 && a < PTRDIFF_MIN - b) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_ptrdiff_t(ptrdiff_t a, ptrdiff_t b) { if (b < 0 && a > PTRDIFF_MAX + b) { return GUF_MATH_CKD_OVERFLOW; } else if (b > 0 && a < PTRDIFF_MIN + b) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_ptrdiff_t(ptrdiff_t a, ptrdiff_t b) { if (b > 0) { if (a > PTRDIFF_MAX / b) { return GUF_MATH_CKD_OVERFLOW; } else if (a < PTRDIFF_MIN / b) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } else if (b < 0) { if (PTRDIFF_MIN != -PTRDIFF_MAX && b == -1) { // Prevent potential (PTRDIFF_MIN / b) overflow for b == -1 return a == PTRDIFF_MIN ? GUF_MATH_CKD_OVERFLOW : GUF_MATH_CKD_SUCCESS; } else if (a < PTRDIFF_MAX / b) { return GUF_MATH_CKD_OVERFLOW; } else if (a > PTRDIFF_MIN / b) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } else { return GUF_MATH_CKD_SUCCESS; } } // Unsigned integer arithmetic checks (generated with libguf/tools/ckdint-gen.py) GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_uchar(unsigned char a, unsigned char b) { if (b > 0 && a > UCHAR_MAX - b) { return GUF_MATH_CKD_OVERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_uchar(unsigned char a, unsigned char b) { if (b > a) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_uchar(unsigned char a, unsigned char b) { const unsigned char c = a * b; return a != 0 && ((c / a) != b) ? GUF_MATH_CKD_OVERFLOW : GUF_MATH_CKD_SUCCESS; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_unsigned(unsigned a, unsigned b) { if (b > 0 && a > UINT_MAX - b) { return GUF_MATH_CKD_OVERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_unsigned(unsigned a, unsigned b) { if (b > a) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_unsigned(unsigned a, unsigned b) { const unsigned c = a * b; return a != 0 && ((c / a) != b) ? GUF_MATH_CKD_OVERFLOW : GUF_MATH_CKD_SUCCESS; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_u8(uint8_t a, uint8_t b) { if (b > 0 && a > UINT8_MAX - b) { return GUF_MATH_CKD_OVERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_u8(uint8_t a, uint8_t b) { if (b > a) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_u8(uint8_t a, uint8_t b) { const uint8_t c = a * b; return a != 0 && ((c / a) != b) ? GUF_MATH_CKD_OVERFLOW : GUF_MATH_CKD_SUCCESS; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_u16(uint16_t a, uint16_t b) { if (b > 0 && a > UINT16_MAX - b) { return GUF_MATH_CKD_OVERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_u16(uint16_t a, uint16_t b) { if (b > a) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_u16(uint16_t a, uint16_t b) { const uint16_t c = a * b; return a != 0 && ((c / a) != b) ? GUF_MATH_CKD_OVERFLOW : GUF_MATH_CKD_SUCCESS; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_u32(uint32_t a, uint32_t b) { if (b > 0 && a > UINT32_MAX - b) { return GUF_MATH_CKD_OVERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_u32(uint32_t a, uint32_t b) { if (b > a) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_u32(uint32_t a, uint32_t b) { const uint32_t c = a * b; return a != 0 && ((c / a) != b) ? GUF_MATH_CKD_OVERFLOW : GUF_MATH_CKD_SUCCESS; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_u64(uint64_t a, uint64_t b) { if (b > 0 && a > UINT64_MAX - b) { return GUF_MATH_CKD_OVERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_u64(uint64_t a, uint64_t b) { if (b > a) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_u64(uint64_t a, uint64_t b) { const uint64_t c = a * b; return a != 0 && ((c / a) != b) ? GUF_MATH_CKD_OVERFLOW : GUF_MATH_CKD_SUCCESS; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_size_t(size_t a, size_t b) { if (b > 0 && a > SIZE_MAX - b) { return GUF_MATH_CKD_OVERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_size_t(size_t a, size_t b) { if (b > a) { return GUF_MATH_CKD_UNDERFLOW; } else { return GUF_MATH_CKD_SUCCESS; } } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_size_t(size_t a, size_t b) { const size_t c = a * b; return a != 0 && ((c / a) != b) ? GUF_MATH_CKD_OVERFLOW : GUF_MATH_CKD_SUCCESS; } // Signed saturating/wrapping arithmetic (generated with libguf/tools/ckdint-gen.py) GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_int(int a, int b, int *result) { const guf_math_ckd_result check = guf_ckd_add_int(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a + b; break; case GUF_MATH_CKD_OVERFLOW: *result = INT_MAX; break; case GUF_MATH_CKD_UNDERFLOW: *result = INT_MIN; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_int(int a, int b, int *result) { const guf_math_ckd_result check = guf_ckd_sub_int(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a - b; break; case GUF_MATH_CKD_OVERFLOW: *result = INT_MAX; break; case GUF_MATH_CKD_UNDERFLOW: *result = INT_MIN; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_int(int a, int b, int *result) { const guf_math_ckd_result check = guf_ckd_mul_int(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a * b; break; case GUF_MATH_CKD_OVERFLOW: *result = INT_MAX; break; case GUF_MATH_CKD_UNDERFLOW: *result = INT_MIN; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_int(int a, int b, int *result) { const guf_math_ckd_result check = guf_ckd_add_int(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a + b; break; case GUF_MATH_CKD_OVERFLOW: *result = (a + INT_MIN) + (b + INT_MIN); break; case GUF_MATH_CKD_UNDERFLOW: *result = (a - INT_MIN) + (b - INT_MIN); break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_int(int a, int b, int *result) { const guf_math_ckd_result check = guf_ckd_sub_int(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a - b; break; case GUF_MATH_CKD_OVERFLOW: GUF_ASSERT(b < 0); *result = (a + INT_MIN) - (b - INT_MIN); // TODO: not sure break; case GUF_MATH_CKD_UNDERFLOW: GUF_ASSERT(b > 0); *result = (a - INT_MIN) - (b + INT_MIN); // TODO: not sure break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_int(int a, int b, int *result) { const guf_math_ckd_result check = guf_ckd_mul_int(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a * b; break; case GUF_MATH_CKD_OVERFLOW: case GUF_MATH_CKD_UNDERFLOW: { unsigned res = (unsigned)a * (unsigned)b; if (res > INT_MAX) { // This is the fix for implementation defined conversion from unsigned to signed. const unsigned mod = ((unsigned)INT_MAX + 1u); GUF_ASSERT(mod > 0 && mod > INT_MAX); res = res % mod; *result = INT_MIN + (int)res; } else { *result = (int)res; } break; } default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_i8(int8_t a, int8_t b, int8_t *result) { const guf_math_ckd_result check = guf_ckd_add_i8(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a + b; break; case GUF_MATH_CKD_OVERFLOW: *result = INT8_MAX; break; case GUF_MATH_CKD_UNDERFLOW: *result = INT8_MIN; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_i8(int8_t a, int8_t b, int8_t *result) { const guf_math_ckd_result check = guf_ckd_sub_i8(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a - b; break; case GUF_MATH_CKD_OVERFLOW: *result = INT8_MAX; break; case GUF_MATH_CKD_UNDERFLOW: *result = INT8_MIN; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_i8(int8_t a, int8_t b, int8_t *result) { const guf_math_ckd_result check = guf_ckd_mul_i8(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a * b; break; case GUF_MATH_CKD_OVERFLOW: *result = INT8_MAX; break; case GUF_MATH_CKD_UNDERFLOW: *result = INT8_MIN; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_i8(int8_t a, int8_t b, int8_t *result) { const guf_math_ckd_result check = guf_ckd_add_i8(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a + b; break; case GUF_MATH_CKD_OVERFLOW: *result = (a + INT8_MIN) + (b + INT8_MIN); break; case GUF_MATH_CKD_UNDERFLOW: *result = (a - INT8_MIN) + (b - INT8_MIN); break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_i8(int8_t a, int8_t b, int8_t *result) { const guf_math_ckd_result check = guf_ckd_sub_i8(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a - b; break; case GUF_MATH_CKD_OVERFLOW: GUF_ASSERT(b < 0); *result = (a + INT8_MIN) - (b - INT8_MIN); // TODO: not sure break; case GUF_MATH_CKD_UNDERFLOW: GUF_ASSERT(b > 0); *result = (a - INT8_MIN) - (b + INT8_MIN); // TODO: not sure break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_i8(int8_t a, int8_t b, int8_t *result) { const guf_math_ckd_result check = guf_ckd_mul_i8(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a * b; break; case GUF_MATH_CKD_OVERFLOW: case GUF_MATH_CKD_UNDERFLOW: { uint8_t res = (uint8_t)a * (uint8_t)b; if (res > INT8_MAX) { // This is the fix for implementation defined conversion from unsigned to signed. const uint8_t mod = ((uint8_t)INT8_MAX + 1u); GUF_ASSERT(mod > 0 && mod > INT8_MAX); res = res % mod; *result = INT8_MIN + (int8_t)res; } else { *result = (int8_t)res; } break; } default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_i16(int16_t a, int16_t b, int16_t *result) { const guf_math_ckd_result check = guf_ckd_add_i16(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a + b; break; case GUF_MATH_CKD_OVERFLOW: *result = INT16_MAX; break; case GUF_MATH_CKD_UNDERFLOW: *result = INT16_MIN; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_i16(int16_t a, int16_t b, int16_t *result) { const guf_math_ckd_result check = guf_ckd_sub_i16(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a - b; break; case GUF_MATH_CKD_OVERFLOW: *result = INT16_MAX; break; case GUF_MATH_CKD_UNDERFLOW: *result = INT16_MIN; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_i16(int16_t a, int16_t b, int16_t *result) { const guf_math_ckd_result check = guf_ckd_mul_i16(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a * b; break; case GUF_MATH_CKD_OVERFLOW: *result = INT16_MAX; break; case GUF_MATH_CKD_UNDERFLOW: *result = INT16_MIN; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_i16(int16_t a, int16_t b, int16_t *result) { const guf_math_ckd_result check = guf_ckd_add_i16(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a + b; break; case GUF_MATH_CKD_OVERFLOW: *result = (a + INT16_MIN) + (b + INT16_MIN); break; case GUF_MATH_CKD_UNDERFLOW: *result = (a - INT16_MIN) + (b - INT16_MIN); break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_i16(int16_t a, int16_t b, int16_t *result) { const guf_math_ckd_result check = guf_ckd_sub_i16(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a - b; break; case GUF_MATH_CKD_OVERFLOW: GUF_ASSERT(b < 0); *result = (a + INT16_MIN) - (b - INT16_MIN); // TODO: not sure break; case GUF_MATH_CKD_UNDERFLOW: GUF_ASSERT(b > 0); *result = (a - INT16_MIN) - (b + INT16_MIN); // TODO: not sure break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_i16(int16_t a, int16_t b, int16_t *result) { const guf_math_ckd_result check = guf_ckd_mul_i16(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a * b; break; case GUF_MATH_CKD_OVERFLOW: case GUF_MATH_CKD_UNDERFLOW: { uint16_t res = (uint16_t)a * (uint16_t)b; if (res > INT16_MAX) { // This is the fix for implementation defined conversion from unsigned to signed. const uint16_t mod = ((uint16_t)INT16_MAX + 1u); GUF_ASSERT(mod > 0 && mod > INT16_MAX); res = res % mod; *result = INT16_MIN + (int16_t)res; } else { *result = (int16_t)res; } break; } default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_i32(int32_t a, int32_t b, int32_t *result) { const guf_math_ckd_result check = guf_ckd_add_i32(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a + b; break; case GUF_MATH_CKD_OVERFLOW: *result = INT32_MAX; break; case GUF_MATH_CKD_UNDERFLOW: *result = INT32_MIN; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_i32(int32_t a, int32_t b, int32_t *result) { const guf_math_ckd_result check = guf_ckd_sub_i32(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a - b; break; case GUF_MATH_CKD_OVERFLOW: *result = INT32_MAX; break; case GUF_MATH_CKD_UNDERFLOW: *result = INT32_MIN; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_i32(int32_t a, int32_t b, int32_t *result) { const guf_math_ckd_result check = guf_ckd_mul_i32(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a * b; break; case GUF_MATH_CKD_OVERFLOW: *result = INT32_MAX; break; case GUF_MATH_CKD_UNDERFLOW: *result = INT32_MIN; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_i32(int32_t a, int32_t b, int32_t *result) { const guf_math_ckd_result check = guf_ckd_add_i32(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a + b; break; case GUF_MATH_CKD_OVERFLOW: *result = (a + INT32_MIN) + (b + INT32_MIN); break; case GUF_MATH_CKD_UNDERFLOW: *result = (a - INT32_MIN) + (b - INT32_MIN); break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_i32(int32_t a, int32_t b, int32_t *result) { const guf_math_ckd_result check = guf_ckd_sub_i32(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a - b; break; case GUF_MATH_CKD_OVERFLOW: GUF_ASSERT(b < 0); *result = (a + INT32_MIN) - (b - INT32_MIN); // TODO: not sure break; case GUF_MATH_CKD_UNDERFLOW: GUF_ASSERT(b > 0); *result = (a - INT32_MIN) - (b + INT32_MIN); // TODO: not sure break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_i32(int32_t a, int32_t b, int32_t *result) { const guf_math_ckd_result check = guf_ckd_mul_i32(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a * b; break; case GUF_MATH_CKD_OVERFLOW: case GUF_MATH_CKD_UNDERFLOW: { uint32_t res = (uint32_t)a * (uint32_t)b; if (res > INT32_MAX) { // This is the fix for implementation defined conversion from unsigned to signed. const uint32_t mod = ((uint32_t)INT32_MAX + 1u); GUF_ASSERT(mod > 0 && mod > INT32_MAX); res = res % mod; *result = INT32_MIN + (int32_t)res; } else { *result = (int32_t)res; } break; } default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_i64(int64_t a, int64_t b, int64_t *result) { const guf_math_ckd_result check = guf_ckd_add_i64(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a + b; break; case GUF_MATH_CKD_OVERFLOW: *result = INT64_MAX; break; case GUF_MATH_CKD_UNDERFLOW: *result = INT64_MIN; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_i64(int64_t a, int64_t b, int64_t *result) { const guf_math_ckd_result check = guf_ckd_sub_i64(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a - b; break; case GUF_MATH_CKD_OVERFLOW: *result = INT64_MAX; break; case GUF_MATH_CKD_UNDERFLOW: *result = INT64_MIN; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_i64(int64_t a, int64_t b, int64_t *result) { const guf_math_ckd_result check = guf_ckd_mul_i64(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a * b; break; case GUF_MATH_CKD_OVERFLOW: *result = INT64_MAX; break; case GUF_MATH_CKD_UNDERFLOW: *result = INT64_MIN; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_i64(int64_t a, int64_t b, int64_t *result) { const guf_math_ckd_result check = guf_ckd_add_i64(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a + b; break; case GUF_MATH_CKD_OVERFLOW: *result = (a + INT64_MIN) + (b + INT64_MIN); break; case GUF_MATH_CKD_UNDERFLOW: *result = (a - INT64_MIN) + (b - INT64_MIN); break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_i64(int64_t a, int64_t b, int64_t *result) { const guf_math_ckd_result check = guf_ckd_sub_i64(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a - b; break; case GUF_MATH_CKD_OVERFLOW: GUF_ASSERT(b < 0); *result = (a + INT64_MIN) - (b - INT64_MIN); // TODO: not sure break; case GUF_MATH_CKD_UNDERFLOW: GUF_ASSERT(b > 0); *result = (a - INT64_MIN) - (b + INT64_MIN); // TODO: not sure break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_i64(int64_t a, int64_t b, int64_t *result) { const guf_math_ckd_result check = guf_ckd_mul_i64(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a * b; break; case GUF_MATH_CKD_OVERFLOW: case GUF_MATH_CKD_UNDERFLOW: { uint64_t res = (uint64_t)a * (uint64_t)b; if (res > INT64_MAX) { // This is the fix for implementation defined conversion from unsigned to signed. const uint64_t mod = ((uint64_t)INT64_MAX + 1u); GUF_ASSERT(mod > 0 && mod > INT64_MAX); res = res % mod; *result = INT64_MIN + (int64_t)res; } else { *result = (int64_t)res; } break; } default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_ptrdiff_t(ptrdiff_t a, ptrdiff_t b, ptrdiff_t *result) { const guf_math_ckd_result check = guf_ckd_add_ptrdiff_t(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a + b; break; case GUF_MATH_CKD_OVERFLOW: *result = PTRDIFF_MAX; break; case GUF_MATH_CKD_UNDERFLOW: *result = PTRDIFF_MIN; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_ptrdiff_t(ptrdiff_t a, ptrdiff_t b, ptrdiff_t *result) { const guf_math_ckd_result check = guf_ckd_sub_ptrdiff_t(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a - b; break; case GUF_MATH_CKD_OVERFLOW: *result = PTRDIFF_MAX; break; case GUF_MATH_CKD_UNDERFLOW: *result = PTRDIFF_MIN; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_ptrdiff_t(ptrdiff_t a, ptrdiff_t b, ptrdiff_t *result) { const guf_math_ckd_result check = guf_ckd_mul_ptrdiff_t(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a * b; break; case GUF_MATH_CKD_OVERFLOW: *result = PTRDIFF_MAX; break; case GUF_MATH_CKD_UNDERFLOW: *result = PTRDIFF_MIN; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_ptrdiff_t(ptrdiff_t a, ptrdiff_t b, ptrdiff_t *result) { const guf_math_ckd_result check = guf_ckd_add_ptrdiff_t(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a + b; break; case GUF_MATH_CKD_OVERFLOW: *result = (a + PTRDIFF_MIN) + (b + PTRDIFF_MIN); break; case GUF_MATH_CKD_UNDERFLOW: *result = (a - PTRDIFF_MIN) + (b - PTRDIFF_MIN); break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_ptrdiff_t(ptrdiff_t a, ptrdiff_t b, ptrdiff_t *result) { const guf_math_ckd_result check = guf_ckd_sub_ptrdiff_t(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a - b; break; case GUF_MATH_CKD_OVERFLOW: GUF_ASSERT(b < 0); *result = (a + PTRDIFF_MIN) - (b - PTRDIFF_MIN); // TODO: not sure break; case GUF_MATH_CKD_UNDERFLOW: GUF_ASSERT(b > 0); *result = (a - PTRDIFF_MIN) - (b + PTRDIFF_MIN); // TODO: not sure break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_ptrdiff_t(ptrdiff_t a, ptrdiff_t b, ptrdiff_t *result) { const guf_math_ckd_result check = guf_ckd_mul_ptrdiff_t(a, b); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a * b; break; case GUF_MATH_CKD_OVERFLOW: case GUF_MATH_CKD_UNDERFLOW: { size_t res = (size_t)a * (size_t)b; if (res > PTRDIFF_MAX) { // This is the fix for implementation defined conversion from unsigned to signed. const size_t mod = ((size_t)PTRDIFF_MAX + 1u); GUF_ASSERT(mod > 0 && mod > PTRDIFF_MAX); res = res % mod; *result = PTRDIFF_MIN + (ptrdiff_t)res; } else { *result = (ptrdiff_t)res; } break; } default: GUF_ASSERT(false); } } return check; } // Unsigned saturating/wrapping arithmetic (generated with libguf/tools/ckdint-gen.py) GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_uchar(unsigned char a, unsigned char b, unsigned char *result) { const guf_math_ckd_result check = guf_ckd_add_uchar(a, b); GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a + b; break; case GUF_MATH_CKD_OVERFLOW: *result = UCHAR_MAX; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_uchar(unsigned char a, unsigned char b, unsigned char *result) { const guf_math_ckd_result check = guf_ckd_sub_uchar(a, b); GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_UNDERFLOW); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a - b; break; case GUF_MATH_CKD_UNDERFLOW: *result = 0; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_uchar(unsigned char a, unsigned char b, unsigned char *result) { const guf_math_ckd_result check = guf_ckd_mul_uchar(a, b); GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a * b; break; case GUF_MATH_CKD_OVERFLOW: *result = UCHAR_MAX; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_uchar(unsigned char a, unsigned char b, unsigned char *result) { const guf_math_ckd_result check = guf_ckd_add_uchar(a, b); if (result) { *result = a + b; } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_uchar(unsigned char a, unsigned char b, unsigned char *result) { const guf_math_ckd_result check = guf_ckd_sub_uchar(a, b); if (result) { *result = a - b; } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_uchar(unsigned char a, unsigned char b, unsigned char *result) { const guf_math_ckd_result check = guf_ckd_mul_uchar(a, b); if (result) { *result = a * b; } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_unsigned(unsigned a, unsigned b, unsigned *result) { const guf_math_ckd_result check = guf_ckd_add_unsigned(a, b); GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a + b; break; case GUF_MATH_CKD_OVERFLOW: *result = UINT_MAX; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_unsigned(unsigned a, unsigned b, unsigned *result) { const guf_math_ckd_result check = guf_ckd_sub_unsigned(a, b); GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_UNDERFLOW); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a - b; break; case GUF_MATH_CKD_UNDERFLOW: *result = 0; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_unsigned(unsigned a, unsigned b, unsigned *result) { const guf_math_ckd_result check = guf_ckd_mul_unsigned(a, b); GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a * b; break; case GUF_MATH_CKD_OVERFLOW: *result = UINT_MAX; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_unsigned(unsigned a, unsigned b, unsigned *result) { const guf_math_ckd_result check = guf_ckd_add_unsigned(a, b); if (result) { *result = a + b; } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_unsigned(unsigned a, unsigned b, unsigned *result) { const guf_math_ckd_result check = guf_ckd_sub_unsigned(a, b); if (result) { *result = a - b; } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_unsigned(unsigned a, unsigned b, unsigned *result) { const guf_math_ckd_result check = guf_ckd_mul_unsigned(a, b); if (result) { *result = a * b; } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_u8(uint8_t a, uint8_t b, uint8_t *result) { const guf_math_ckd_result check = guf_ckd_add_u8(a, b); GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a + b; break; case GUF_MATH_CKD_OVERFLOW: *result = UINT8_MAX; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_u8(uint8_t a, uint8_t b, uint8_t *result) { const guf_math_ckd_result check = guf_ckd_sub_u8(a, b); GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_UNDERFLOW); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a - b; break; case GUF_MATH_CKD_UNDERFLOW: *result = 0; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_u8(uint8_t a, uint8_t b, uint8_t *result) { const guf_math_ckd_result check = guf_ckd_mul_u8(a, b); GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a * b; break; case GUF_MATH_CKD_OVERFLOW: *result = UINT8_MAX; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_u8(uint8_t a, uint8_t b, uint8_t *result) { const guf_math_ckd_result check = guf_ckd_add_u8(a, b); if (result) { *result = a + b; } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_u8(uint8_t a, uint8_t b, uint8_t *result) { const guf_math_ckd_result check = guf_ckd_sub_u8(a, b); if (result) { *result = a - b; } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_u8(uint8_t a, uint8_t b, uint8_t *result) { const guf_math_ckd_result check = guf_ckd_mul_u8(a, b); if (result) { *result = a * b; } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_u16(uint16_t a, uint16_t b, uint16_t *result) { const guf_math_ckd_result check = guf_ckd_add_u16(a, b); GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a + b; break; case GUF_MATH_CKD_OVERFLOW: *result = UINT16_MAX; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_u16(uint16_t a, uint16_t b, uint16_t *result) { const guf_math_ckd_result check = guf_ckd_sub_u16(a, b); GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_UNDERFLOW); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a - b; break; case GUF_MATH_CKD_UNDERFLOW: *result = 0; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_u16(uint16_t a, uint16_t b, uint16_t *result) { const guf_math_ckd_result check = guf_ckd_mul_u16(a, b); GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a * b; break; case GUF_MATH_CKD_OVERFLOW: *result = UINT16_MAX; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_u16(uint16_t a, uint16_t b, uint16_t *result) { const guf_math_ckd_result check = guf_ckd_add_u16(a, b); if (result) { *result = a + b; } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_u16(uint16_t a, uint16_t b, uint16_t *result) { const guf_math_ckd_result check = guf_ckd_sub_u16(a, b); if (result) { *result = a - b; } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_u16(uint16_t a, uint16_t b, uint16_t *result) { const guf_math_ckd_result check = guf_ckd_mul_u16(a, b); if (result) { *result = a * b; } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_u32(uint32_t a, uint32_t b, uint32_t *result) { const guf_math_ckd_result check = guf_ckd_add_u32(a, b); GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a + b; break; case GUF_MATH_CKD_OVERFLOW: *result = UINT32_MAX; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_u32(uint32_t a, uint32_t b, uint32_t *result) { const guf_math_ckd_result check = guf_ckd_sub_u32(a, b); GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_UNDERFLOW); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a - b; break; case GUF_MATH_CKD_UNDERFLOW: *result = 0; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_u32(uint32_t a, uint32_t b, uint32_t *result) { const guf_math_ckd_result check = guf_ckd_mul_u32(a, b); GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a * b; break; case GUF_MATH_CKD_OVERFLOW: *result = UINT32_MAX; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_u32(uint32_t a, uint32_t b, uint32_t *result) { const guf_math_ckd_result check = guf_ckd_add_u32(a, b); if (result) { *result = a + b; } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_u32(uint32_t a, uint32_t b, uint32_t *result) { const guf_math_ckd_result check = guf_ckd_sub_u32(a, b); if (result) { *result = a - b; } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_u32(uint32_t a, uint32_t b, uint32_t *result) { const guf_math_ckd_result check = guf_ckd_mul_u32(a, b); if (result) { *result = a * b; } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_u64(uint64_t a, uint64_t b, uint64_t *result) { const guf_math_ckd_result check = guf_ckd_add_u64(a, b); GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a + b; break; case GUF_MATH_CKD_OVERFLOW: *result = UINT64_MAX; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_u64(uint64_t a, uint64_t b, uint64_t *result) { const guf_math_ckd_result check = guf_ckd_sub_u64(a, b); GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_UNDERFLOW); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a - b; break; case GUF_MATH_CKD_UNDERFLOW: *result = 0; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_u64(uint64_t a, uint64_t b, uint64_t *result) { const guf_math_ckd_result check = guf_ckd_mul_u64(a, b); GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a * b; break; case GUF_MATH_CKD_OVERFLOW: *result = UINT64_MAX; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_u64(uint64_t a, uint64_t b, uint64_t *result) { const guf_math_ckd_result check = guf_ckd_add_u64(a, b); if (result) { *result = a + b; } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_u64(uint64_t a, uint64_t b, uint64_t *result) { const guf_math_ckd_result check = guf_ckd_sub_u64(a, b); if (result) { *result = a - b; } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_u64(uint64_t a, uint64_t b, uint64_t *result) { const guf_math_ckd_result check = guf_ckd_mul_u64(a, b); if (result) { *result = a * b; } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_size_t(size_t a, size_t b, size_t *result) { const guf_math_ckd_result check = guf_ckd_add_size_t(a, b); GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a + b; break; case GUF_MATH_CKD_OVERFLOW: *result = SIZE_MAX; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_size_t(size_t a, size_t b, size_t *result) { const guf_math_ckd_result check = guf_ckd_sub_size_t(a, b); GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_UNDERFLOW); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a - b; break; case GUF_MATH_CKD_UNDERFLOW: *result = 0; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_size_t(size_t a, size_t b, size_t *result) { const guf_math_ckd_result check = guf_ckd_mul_size_t(a, b); GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW); if (result) { switch (check) { case GUF_MATH_CKD_SUCCESS: *result = a * b; break; case GUF_MATH_CKD_OVERFLOW: *result = SIZE_MAX; break; default: GUF_ASSERT(false); } } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_size_t(size_t a, size_t b, size_t *result) { const guf_math_ckd_result check = guf_ckd_add_size_t(a, b); if (result) { *result = a + b; } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_size_t(size_t a, size_t b, size_t *result) { const guf_math_ckd_result check = guf_ckd_sub_size_t(a, b); if (result) { *result = a - b; } return check; } GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_size_t(size_t a, size_t b, size_t *result) { const guf_math_ckd_result check = guf_ckd_mul_size_t(a, b); if (result) { *result = a * b; } return check; } #endif /* End impl */ #endif /* End header-guard */ #undef GUF_MATH_CKDINT_IMPL #undef GUF_MATH_CKDINT_IMPL_STATIC #undef GUF_MATH_CKDINT_KWRDS