Add checked mul arithmetic
This commit is contained in:
parent
9c417d2aa1
commit
873cdf20b1
@ -18,6 +18,11 @@ typedef enum guf_math_ckd_result {GUF_MATH_CKD_SUCCESS = 0, GUF_MATH_CKD_OVERFLO
|
|||||||
- if a - b overflows TYPE: return GUF_MATH_CKD_OVERFLOW (truthy)
|
- if a - b overflows TYPE: return GUF_MATH_CKD_OVERFLOW (truthy)
|
||||||
- if a - b underflows TYPE: return GUF_MATH_CKD_UNDERFLOW (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
|
// 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))
|
// (cf. https://doc.rust-lang.org/std/intrinsics/fn.saturating_add.html (last-retrieved 2025-05-10))
|
||||||
@ -32,6 +37,11 @@ typedef enum guf_math_ckd_result {GUF_MATH_CKD_SUCCESS = 0, GUF_MATH_CKD_OVERFLO
|
|||||||
- 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 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).
|
- 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
|
// 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))
|
// (cf. https://doc.rust-lang.org/std/intrinsics/fn.wrapping_add.html (last-retrieved 2025-05-10))
|
||||||
@ -46,9 +56,18 @@ typedef enum guf_math_ckd_result {GUF_MATH_CKD_SUCCESS = 0, GUF_MATH_CKD_OVERFLO
|
|||||||
- 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 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).
|
- 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/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/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)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@ -74,6 +93,30 @@ static inline guf_math_ckd_result guf_ckd_sub_int(int a, int b)
|
|||||||
return GUF_MATH_CKD_SUCCESS;
|
return GUF_MATH_CKD_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_ckd_add_i8(int8_t a, int8_t b)
|
static inline guf_math_ckd_result guf_ckd_add_i8(int8_t a, int8_t b)
|
||||||
{
|
{
|
||||||
@ -95,6 +138,30 @@ static inline guf_math_ckd_result guf_ckd_sub_i8(int8_t a, int8_t b)
|
|||||||
return GUF_MATH_CKD_SUCCESS;
|
return GUF_MATH_CKD_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_ckd_add_i16(int16_t a, int16_t b)
|
static inline guf_math_ckd_result guf_ckd_add_i16(int16_t a, int16_t b)
|
||||||
{
|
{
|
||||||
@ -116,6 +183,30 @@ static inline guf_math_ckd_result guf_ckd_sub_i16(int16_t a, int16_t b)
|
|||||||
return GUF_MATH_CKD_SUCCESS;
|
return GUF_MATH_CKD_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_ckd_add_i32(int32_t a, int32_t b)
|
static inline guf_math_ckd_result guf_ckd_add_i32(int32_t a, int32_t b)
|
||||||
{
|
{
|
||||||
@ -137,6 +228,30 @@ static inline guf_math_ckd_result guf_ckd_sub_i32(int32_t a, int32_t b)
|
|||||||
return GUF_MATH_CKD_SUCCESS;
|
return GUF_MATH_CKD_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_ckd_add_i64(int64_t a, int64_t b)
|
static inline guf_math_ckd_result guf_ckd_add_i64(int64_t a, int64_t b)
|
||||||
{
|
{
|
||||||
@ -158,6 +273,30 @@ static inline guf_math_ckd_result guf_ckd_sub_i64(int64_t a, int64_t b)
|
|||||||
return GUF_MATH_CKD_SUCCESS;
|
return GUF_MATH_CKD_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_ckd_add_ptrdiff_t(ptrdiff_t a, ptrdiff_t b)
|
static inline guf_math_ckd_result guf_ckd_add_ptrdiff_t(ptrdiff_t a, ptrdiff_t b)
|
||||||
{
|
{
|
||||||
@ -179,6 +318,30 @@ static inline guf_math_ckd_result guf_ckd_sub_ptrdiff_t(ptrdiff_t a, ptrdiff_t b
|
|||||||
return GUF_MATH_CKD_SUCCESS;
|
return GUF_MATH_CKD_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static inline 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 add/sub checks (generated with libguf/tools/ckdint-gen.py)
|
// Unsigned integer add/sub checks (generated with libguf/tools/ckdint-gen.py)
|
||||||
|
|
||||||
@ -198,6 +361,11 @@ static inline guf_math_ckd_result guf_ckd_sub_uchar(unsigned char a, unsigned ch
|
|||||||
return GUF_MATH_CKD_SUCCESS;
|
return GUF_MATH_CKD_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_ckd_add_unsigned(unsigned a, unsigned b)
|
static inline guf_math_ckd_result guf_ckd_add_unsigned(unsigned a, unsigned b)
|
||||||
{
|
{
|
||||||
@ -215,6 +383,11 @@ static inline guf_math_ckd_result guf_ckd_sub_unsigned(unsigned a, unsigned b)
|
|||||||
return GUF_MATH_CKD_SUCCESS;
|
return GUF_MATH_CKD_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_ckd_add_u8(uint8_t a, uint8_t b)
|
static inline guf_math_ckd_result guf_ckd_add_u8(uint8_t a, uint8_t b)
|
||||||
{
|
{
|
||||||
@ -232,6 +405,11 @@ static inline guf_math_ckd_result guf_ckd_sub_u8(uint8_t a, uint8_t b)
|
|||||||
return GUF_MATH_CKD_SUCCESS;
|
return GUF_MATH_CKD_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_ckd_add_u16(uint16_t a, uint16_t b)
|
static inline guf_math_ckd_result guf_ckd_add_u16(uint16_t a, uint16_t b)
|
||||||
{
|
{
|
||||||
@ -249,6 +427,11 @@ static inline guf_math_ckd_result guf_ckd_sub_u16(uint16_t a, uint16_t b)
|
|||||||
return GUF_MATH_CKD_SUCCESS;
|
return GUF_MATH_CKD_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_ckd_add_u32(uint32_t a, uint32_t b)
|
static inline guf_math_ckd_result guf_ckd_add_u32(uint32_t a, uint32_t b)
|
||||||
{
|
{
|
||||||
@ -266,6 +449,11 @@ static inline guf_math_ckd_result guf_ckd_sub_u32(uint32_t a, uint32_t b)
|
|||||||
return GUF_MATH_CKD_SUCCESS;
|
return GUF_MATH_CKD_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_ckd_add_u64(uint64_t a, uint64_t b)
|
static inline guf_math_ckd_result guf_ckd_add_u64(uint64_t a, uint64_t b)
|
||||||
{
|
{
|
||||||
@ -283,6 +471,11 @@ static inline guf_math_ckd_result guf_ckd_sub_u64(uint64_t a, uint64_t b)
|
|||||||
return GUF_MATH_CKD_SUCCESS;
|
return GUF_MATH_CKD_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_ckd_add_size_t(size_t a, size_t b)
|
static inline guf_math_ckd_result guf_ckd_add_size_t(size_t a, size_t b)
|
||||||
{
|
{
|
||||||
@ -300,6 +493,11 @@ static inline guf_math_ckd_result guf_ckd_sub_size_t(size_t a, size_t b)
|
|||||||
return GUF_MATH_CKD_SUCCESS;
|
return GUF_MATH_CKD_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static inline 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 add/sub (generated with libguf/tools/ckdint-gen.py)
|
// Signed saturating/wrapping add/sub (generated with libguf/tools/ckdint-gen.py)
|
||||||
@ -344,6 +542,26 @@ static inline guf_math_ckd_result guf_saturating_sub_int(int a, int b, int *resu
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_wrapping_add_int(int a, int b, int *result)
|
static inline guf_math_ckd_result guf_wrapping_add_int(int a, int b, int *result)
|
||||||
{
|
{
|
||||||
@ -387,6 +605,24 @@ static inline guf_math_ckd_result guf_wrapping_sub_int(int a, int b, int *result
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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:
|
||||||
|
*result = (int)((unsigned)a * (unsigned)b); // TODO: Implementation defined...
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GUF_ASSERT(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return check;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_saturating_add_i8(int8_t a, int8_t b, int8_t *result)
|
static inline guf_math_ckd_result guf_saturating_add_i8(int8_t a, int8_t b, int8_t *result)
|
||||||
@ -429,6 +665,26 @@ static inline guf_math_ckd_result guf_saturating_sub_i8(int8_t a, int8_t b, int8
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_wrapping_add_i8(int8_t a, int8_t b, int8_t *result)
|
static inline guf_math_ckd_result guf_wrapping_add_i8(int8_t a, int8_t b, int8_t *result)
|
||||||
{
|
{
|
||||||
@ -472,6 +728,24 @@ static inline guf_math_ckd_result guf_wrapping_sub_i8(int8_t a, int8_t b, int8_t
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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:
|
||||||
|
*result = (int8_t)((uint8_t)a * (uint8_t)b); // TODO: Implementation defined...
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GUF_ASSERT(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return check;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_saturating_add_i16(int16_t a, int16_t b, int16_t *result)
|
static inline guf_math_ckd_result guf_saturating_add_i16(int16_t a, int16_t b, int16_t *result)
|
||||||
@ -514,6 +788,26 @@ static inline guf_math_ckd_result guf_saturating_sub_i16(int16_t a, int16_t b, i
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_wrapping_add_i16(int16_t a, int16_t b, int16_t *result)
|
static inline guf_math_ckd_result guf_wrapping_add_i16(int16_t a, int16_t b, int16_t *result)
|
||||||
{
|
{
|
||||||
@ -557,6 +851,24 @@ static inline guf_math_ckd_result guf_wrapping_sub_i16(int16_t a, int16_t b, int
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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:
|
||||||
|
*result = (int16_t)((uint16_t)a * (uint16_t)b); // TODO: Implementation defined...
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GUF_ASSERT(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return check;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_saturating_add_i32(int32_t a, int32_t b, int32_t *result)
|
static inline guf_math_ckd_result guf_saturating_add_i32(int32_t a, int32_t b, int32_t *result)
|
||||||
@ -599,6 +911,26 @@ static inline guf_math_ckd_result guf_saturating_sub_i32(int32_t a, int32_t b, i
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_wrapping_add_i32(int32_t a, int32_t b, int32_t *result)
|
static inline guf_math_ckd_result guf_wrapping_add_i32(int32_t a, int32_t b, int32_t *result)
|
||||||
{
|
{
|
||||||
@ -642,6 +974,24 @@ static inline guf_math_ckd_result guf_wrapping_sub_i32(int32_t a, int32_t b, int
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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:
|
||||||
|
*result = (int32_t)((uint32_t)a * (uint32_t)b); // TODO: Implementation defined...
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GUF_ASSERT(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return check;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_saturating_add_i64(int64_t a, int64_t b, int64_t *result)
|
static inline guf_math_ckd_result guf_saturating_add_i64(int64_t a, int64_t b, int64_t *result)
|
||||||
@ -684,6 +1034,26 @@ static inline guf_math_ckd_result guf_saturating_sub_i64(int64_t a, int64_t b, i
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_wrapping_add_i64(int64_t a, int64_t b, int64_t *result)
|
static inline guf_math_ckd_result guf_wrapping_add_i64(int64_t a, int64_t b, int64_t *result)
|
||||||
{
|
{
|
||||||
@ -727,6 +1097,24 @@ static inline guf_math_ckd_result guf_wrapping_sub_i64(int64_t a, int64_t b, int
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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:
|
||||||
|
*result = (int64_t)((uint64_t)a * (uint64_t)b); // TODO: Implementation defined...
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GUF_ASSERT(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return check;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_saturating_add_ptrdiff_t(ptrdiff_t a, ptrdiff_t b, ptrdiff_t *result)
|
static inline guf_math_ckd_result guf_saturating_add_ptrdiff_t(ptrdiff_t a, ptrdiff_t b, ptrdiff_t *result)
|
||||||
@ -769,6 +1157,26 @@ static inline guf_math_ckd_result guf_saturating_sub_ptrdiff_t(ptrdiff_t a, ptrd
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_wrapping_add_ptrdiff_t(ptrdiff_t a, ptrdiff_t b, ptrdiff_t *result)
|
static inline guf_math_ckd_result guf_wrapping_add_ptrdiff_t(ptrdiff_t a, ptrdiff_t b, ptrdiff_t *result)
|
||||||
{
|
{
|
||||||
@ -812,6 +1220,24 @@ static inline guf_math_ckd_result guf_wrapping_sub_ptrdiff_t(ptrdiff_t a, ptrdif
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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:
|
||||||
|
*result = (ptrdiff_t)((size_t)a * (size_t)b); // TODO: Implementation defined...
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GUF_ASSERT(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return check;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Unsigned saturating/wrapping add/sub (generated with libguf/tools/ckdint-gen.py)
|
// Unsigned saturating/wrapping add/sub (generated with libguf/tools/ckdint-gen.py)
|
||||||
@ -852,6 +1278,24 @@ static inline guf_math_ckd_result guf_saturating_sub_uchar(unsigned char a, unsi
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_wrapping_add_uchar(unsigned char a, unsigned char b, unsigned char *result)
|
static inline guf_math_ckd_result guf_wrapping_add_uchar(unsigned char a, unsigned char b, unsigned char *result)
|
||||||
{
|
{
|
||||||
@ -869,6 +1313,14 @@ static inline guf_math_ckd_result guf_wrapping_sub_uchar(unsigned char a, unsign
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_saturating_add_unsigned(unsigned a, unsigned b, unsigned *result)
|
static inline guf_math_ckd_result guf_saturating_add_unsigned(unsigned a, unsigned b, unsigned *result)
|
||||||
@ -907,6 +1359,24 @@ static inline guf_math_ckd_result guf_saturating_sub_unsigned(unsigned a, unsign
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_wrapping_add_unsigned(unsigned a, unsigned b, unsigned *result)
|
static inline guf_math_ckd_result guf_wrapping_add_unsigned(unsigned a, unsigned b, unsigned *result)
|
||||||
{
|
{
|
||||||
@ -924,6 +1394,14 @@ static inline guf_math_ckd_result guf_wrapping_sub_unsigned(unsigned a, unsigned
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_saturating_add_u8(uint8_t a, uint8_t b, uint8_t *result)
|
static inline guf_math_ckd_result guf_saturating_add_u8(uint8_t a, uint8_t b, uint8_t *result)
|
||||||
@ -962,6 +1440,24 @@ static inline guf_math_ckd_result guf_saturating_sub_u8(uint8_t a, uint8_t b, ui
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_wrapping_add_u8(uint8_t a, uint8_t b, uint8_t *result)
|
static inline guf_math_ckd_result guf_wrapping_add_u8(uint8_t a, uint8_t b, uint8_t *result)
|
||||||
{
|
{
|
||||||
@ -979,6 +1475,14 @@ static inline guf_math_ckd_result guf_wrapping_sub_u8(uint8_t a, uint8_t b, uint
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_saturating_add_u16(uint16_t a, uint16_t b, uint16_t *result)
|
static inline guf_math_ckd_result guf_saturating_add_u16(uint16_t a, uint16_t b, uint16_t *result)
|
||||||
@ -1017,6 +1521,24 @@ static inline guf_math_ckd_result guf_saturating_sub_u16(uint16_t a, uint16_t b,
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_wrapping_add_u16(uint16_t a, uint16_t b, uint16_t *result)
|
static inline guf_math_ckd_result guf_wrapping_add_u16(uint16_t a, uint16_t b, uint16_t *result)
|
||||||
{
|
{
|
||||||
@ -1034,6 +1556,14 @@ static inline guf_math_ckd_result guf_wrapping_sub_u16(uint16_t a, uint16_t b, u
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_saturating_add_u32(uint32_t a, uint32_t b, uint32_t *result)
|
static inline guf_math_ckd_result guf_saturating_add_u32(uint32_t a, uint32_t b, uint32_t *result)
|
||||||
@ -1072,6 +1602,24 @@ static inline guf_math_ckd_result guf_saturating_sub_u32(uint32_t a, uint32_t b,
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_wrapping_add_u32(uint32_t a, uint32_t b, uint32_t *result)
|
static inline guf_math_ckd_result guf_wrapping_add_u32(uint32_t a, uint32_t b, uint32_t *result)
|
||||||
{
|
{
|
||||||
@ -1089,6 +1637,14 @@ static inline guf_math_ckd_result guf_wrapping_sub_u32(uint32_t a, uint32_t b, u
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_saturating_add_u64(uint64_t a, uint64_t b, uint64_t *result)
|
static inline guf_math_ckd_result guf_saturating_add_u64(uint64_t a, uint64_t b, uint64_t *result)
|
||||||
@ -1127,6 +1683,24 @@ static inline guf_math_ckd_result guf_saturating_sub_u64(uint64_t a, uint64_t b,
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_wrapping_add_u64(uint64_t a, uint64_t b, uint64_t *result)
|
static inline guf_math_ckd_result guf_wrapping_add_u64(uint64_t a, uint64_t b, uint64_t *result)
|
||||||
{
|
{
|
||||||
@ -1144,6 +1718,14 @@ static inline guf_math_ckd_result guf_wrapping_sub_u64(uint64_t a, uint64_t b, u
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_saturating_add_size_t(size_t a, size_t b, size_t *result)
|
static inline guf_math_ckd_result guf_saturating_add_size_t(size_t a, size_t b, size_t *result)
|
||||||
@ -1182,6 +1764,24 @@ static inline guf_math_ckd_result guf_saturating_sub_size_t(size_t a, size_t b,
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_wrapping_add_size_t(size_t a, size_t b, size_t *result)
|
static inline guf_math_ckd_result guf_wrapping_add_size_t(size_t a, size_t b, size_t *result)
|
||||||
{
|
{
|
||||||
@ -1199,5 +1799,13 @@ static inline guf_math_ckd_result guf_wrapping_sub_size_t(size_t a, size_t b, si
|
|||||||
}
|
}
|
||||||
return check;
|
return check;
|
||||||
}
|
}
|
||||||
|
static inline 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
|
#endif
|
||||||
|
|||||||
3
todo.txt
3
todo.txt
@ -1,5 +1,4 @@
|
|||||||
- abs functions with signed result assume two's complement (x)
|
- guf_wrapping_mul_TYPE: Don't rely on implementation defined behaviour
|
||||||
- abs functions with unsigned result assume two's complement (x)
|
|
||||||
|
|
||||||
- header guards for optional int64_t types maybe...
|
- header guards for optional int64_t types maybe...
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,7 @@ class IntType:
|
|||||||
INT_TYPE_ABBR: str
|
INT_TYPE_ABBR: str
|
||||||
INT_MIN: str
|
INT_MIN: str
|
||||||
INT_MAX: str
|
INT_MAX: str
|
||||||
|
UINT_TYPE: str = "size_t"
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class UintType:
|
class UintType:
|
||||||
@ -38,6 +39,11 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> str:
|
|||||||
return GUF_MATH_CKD_SUCCESS;
|
return GUF_MATH_CKD_SUCCESS;
|
||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
|
static inline guf_math_ckd_result guf_ckd_mul_{type_abbr}({type} a, {type} b)
|
||||||
|
{{
|
||||||
|
const {type} c = a * b;
|
||||||
|
return a != 0 && ((c / a) != b) ? GUF_MATH_CKD_OVERFLOW : GUF_MATH_CKD_SUCCESS;
|
||||||
|
}}
|
||||||
""")
|
""")
|
||||||
|
|
||||||
ckd_add_sub_int = textwrap.dedent("""
|
ckd_add_sub_int = textwrap.dedent("""
|
||||||
@ -61,6 +67,30 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> str:
|
|||||||
return GUF_MATH_CKD_SUCCESS;
|
return GUF_MATH_CKD_SUCCESS;
|
||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
|
static inline guf_math_ckd_result guf_ckd_mul_{type_abbr}({type} a, {type} 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;
|
||||||
|
}}
|
||||||
|
}}
|
||||||
""")
|
""")
|
||||||
|
|
||||||
saturating_wrapping_int = textwrap.dedent("""
|
saturating_wrapping_int = textwrap.dedent("""
|
||||||
@ -104,6 +134,26 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> str:
|
|||||||
}}
|
}}
|
||||||
return check;
|
return check;
|
||||||
}}
|
}}
|
||||||
|
static inline guf_math_ckd_result guf_saturating_mul_{type_abbr}({type} a, {type} b, {type} *result)
|
||||||
|
{{
|
||||||
|
const guf_math_ckd_result check = guf_ckd_mul_{type_abbr}(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;
|
||||||
|
}}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_wrapping_add_{type_abbr}({type} a, {type} b, {type} *result)
|
static inline guf_math_ckd_result guf_wrapping_add_{type_abbr}({type} a, {type} b, {type} *result)
|
||||||
{{
|
{{
|
||||||
@ -147,6 +197,24 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> str:
|
|||||||
}}
|
}}
|
||||||
return check;
|
return check;
|
||||||
}}
|
}}
|
||||||
|
static inline guf_math_ckd_result guf_wrapping_mul_{type_abbr}({type} a, {type} b, {type} *result)
|
||||||
|
{{
|
||||||
|
const guf_math_ckd_result check = guf_ckd_mul_{type_abbr}(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:
|
||||||
|
*result = ({type})(({uint_type})a * ({uint_type})b); // TODO: Implementation defined...
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GUF_ASSERT(false);
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
return check;
|
||||||
|
}}
|
||||||
""")
|
""")
|
||||||
|
|
||||||
saturating_wrapping_uint = textwrap.dedent("""
|
saturating_wrapping_uint = textwrap.dedent("""
|
||||||
@ -186,6 +254,24 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> str:
|
|||||||
}}
|
}}
|
||||||
return check;
|
return check;
|
||||||
}}
|
}}
|
||||||
|
static inline guf_math_ckd_result guf_saturating_mul_{type_abbr}({type} a, {type} b, {type} *result)
|
||||||
|
{{
|
||||||
|
const guf_math_ckd_result check = guf_ckd_mul_{type_abbr}(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 = {int_max};
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GUF_ASSERT(false);
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
return check;
|
||||||
|
}}
|
||||||
|
|
||||||
static inline guf_math_ckd_result guf_wrapping_add_{type_abbr}({type} a, {type} b, {type} *result)
|
static inline guf_math_ckd_result guf_wrapping_add_{type_abbr}({type} a, {type} b, {type} *result)
|
||||||
{{
|
{{
|
||||||
@ -203,6 +289,14 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> str:
|
|||||||
}}
|
}}
|
||||||
return check;
|
return check;
|
||||||
}}
|
}}
|
||||||
|
static inline guf_math_ckd_result guf_wrapping_mul_{type_abbr}({type} a, {type} b, {type} *result)
|
||||||
|
{{
|
||||||
|
const guf_math_ckd_result check = guf_ckd_mul_{type_abbr}(a, b);
|
||||||
|
if (result) {{
|
||||||
|
*result = a * b;
|
||||||
|
}}
|
||||||
|
return check;
|
||||||
|
}}
|
||||||
""")
|
""")
|
||||||
|
|
||||||
text_result = "// Signed integer add/sub checks (generated with libguf/tools/ckdint-gen.py)\n"
|
text_result = "// Signed integer add/sub checks (generated with libguf/tools/ckdint-gen.py)\n"
|
||||||
@ -216,7 +310,7 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> str:
|
|||||||
|
|
||||||
text_result += "\n\n// Signed saturating/wrapping add/sub (generated with libguf/tools/ckdint-gen.py)\n"
|
text_result += "\n\n// Signed saturating/wrapping add/sub (generated with libguf/tools/ckdint-gen.py)\n"
|
||||||
for type in int_types:
|
for type in int_types:
|
||||||
text_result += saturating_wrapping_int.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX) + "\n"
|
text_result += saturating_wrapping_int.format(type = type.INT_TYPE, type_abbr = type.INT_TYPE_ABBR, int_min = type.INT_MIN, int_max = type.INT_MAX, uint_type = type.UINT_TYPE) + "\n"
|
||||||
|
|
||||||
text_result += "\n// Unsigned saturating/wrapping add/sub (generated with libguf/tools/ckdint-gen.py)\n"
|
text_result += "\n// Unsigned saturating/wrapping add/sub (generated with libguf/tools/ckdint-gen.py)\n"
|
||||||
for type in uint_types:
|
for type in uint_types:
|
||||||
@ -229,12 +323,12 @@ def generate_ckdint_functions(int_types: list, uint_types: list) -> str:
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
int_types = [
|
int_types = [
|
||||||
IntType(INT_TYPE = "int", INT_TYPE_ABBR = "int", INT_MIN = "INT_MIN", INT_MAX = "INT_MAX"),
|
IntType(INT_TYPE = "int", INT_TYPE_ABBR = "int", INT_MIN = "INT_MIN", INT_MAX = "INT_MAX", UINT_TYPE = "unsigned"),
|
||||||
IntType(INT_TYPE = "int8_t", INT_TYPE_ABBR = "i8", INT_MIN = "INT8_MIN", INT_MAX = "INT8_MAX"),
|
IntType(INT_TYPE = "int8_t", INT_TYPE_ABBR = "i8", INT_MIN = "INT8_MIN", INT_MAX = "INT8_MAX", UINT_TYPE = "uint8_t"),
|
||||||
IntType(INT_TYPE = "int16_t", INT_TYPE_ABBR = "i16", INT_MIN = "INT16_MIN", INT_MAX = "INT16_MAX"),
|
IntType(INT_TYPE = "int16_t", INT_TYPE_ABBR = "i16", INT_MIN = "INT16_MIN", INT_MAX = "INT16_MAX", UINT_TYPE = "uint16_t"),
|
||||||
IntType(INT_TYPE = "int32_t", INT_TYPE_ABBR = "i32", INT_MIN = "INT32_MIN", INT_MAX = "INT32_MAX"),
|
IntType(INT_TYPE = "int32_t", INT_TYPE_ABBR = "i32", INT_MIN = "INT32_MIN", INT_MAX = "INT32_MAX", UINT_TYPE = "uint32_t"),
|
||||||
IntType(INT_TYPE = "int64_t", INT_TYPE_ABBR = "i64", INT_MIN = "INT64_MIN", INT_MAX = "INT64_MAX"),
|
IntType(INT_TYPE = "int64_t", INT_TYPE_ABBR = "i64", INT_MIN = "INT64_MIN", INT_MAX = "INT64_MAX", UINT_TYPE = "uint64_t"),
|
||||||
IntType(INT_TYPE = "ptrdiff_t", INT_TYPE_ABBR = "ptrdiff_t", INT_MIN = "PTRDIFF_MIN", INT_MAX = "PTRDIFF_MAX"),
|
IntType(INT_TYPE = "ptrdiff_t", INT_TYPE_ABBR = "ptrdiff_t", INT_MIN = "PTRDIFF_MIN", INT_MAX = "PTRDIFF_MAX", UINT_TYPE = "size_t"), # TODO: size_t is not necessarily the unsigned ptrdiff_t equivalent
|
||||||
]
|
]
|
||||||
|
|
||||||
uint_types = [
|
uint_types = [
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user