diff options
39 files changed, 1081 insertions, 10 deletions
@@ -249,7 +249,29 @@ OBJ =\ libj2_slc_j2u_to_j2u.o\ libj2_j2u_has_j2u.o\ libj2_j2u_has_ju.o\ - libj2_j2u_has_high_ju.o + libj2_j2u_has_high_ju.o\ + libj2_j2u_lsh_overflow_p.o\ + libj2_ju_lsh_overflow_p.o\ + libj2_j2u_rsh_underflow_p.o\ + libj2_ju_rsh_underflow_p.o\ + libj2_j2u_add_ju_overflow_p.o\ + libj2_ju_add_j2u_overflow_p.o\ + libj2_j2u_add_j2u_overflow_p.o\ + libj2_j2u_sub_ju_overflow_p.o\ + libj2_ju_sub_j2u_overflow_p.o\ + libj2_ju_sub_ju_overflow_p.o\ + libj2_j2u_sub_j2u_overflow_p.o\ + libj2_j2u_rsub_j2u_overflow_p.o\ + libj2_j2u_rsub_ju_overflow_p.o\ + libj2_j2u_mul_j2u_overflow_p_quick.o\ + libj2_j2u_mul_ju_overflow_p_quick.o\ + libj2_ju_mul_j2u_overflow_p_quick.o\ + libj2_j2u_mul_j2u_overflow_p.o\ + libj2_j2u_mul_ju_overflow_p.o\ + libj2_ju_mul_j2u_overflow_p.o\ + libj2_j2u_mul_j2u_to_j2u_overflow_p.o\ + libj2_j2u_mul_ju_to_j2u_overflow_p.o\ + libj2_ju_mul_j2u_to_j2u_overflow_p.o SUBHDR =\ libj2/constants.h\ @@ -52,6 +52,32 @@ struct libj2_j2u { }; +/** + * Arithmetic overflow prediction result + * + * Use by some functions for which prediction + * is costly in edge cases, and thus stopped + * as soon as such an edge case is detected + */ +enum libj2_overflow { + /** + * Where will not be an overflow + */ + LIBJ2_NO_OVERFLOW = 0, + + /** + * Where will be an overflow + */ + LIBJ2_OVERFLOW = 1, + + /** + * Overflow prediction stopped + * (due to high cost) + */ + LIBJ2_OVERFLOW_UNKNOWN +}; + + #include "libj2/constants.h" #include "libj2/signum.h" #include "libj2/constructors.h" diff --git a/libj2/addition.h b/libj2/addition.h index d900622..d0a57bf 100644 --- a/libj2/addition.h +++ b/libj2/addition.h @@ -311,3 +311,67 @@ libj2_j2u_add_j2u_to_j2u_overflow(const struct libj2_j2u *a, const struct libj2_ #endif } } + + +/** + * Predict whether `libj2_j2u_add_ju_to_j2u_overflow` + * or `libj2_j2u_add_ju_overflow` will return a + * result-overflow signal + * + * `libj2_j2u_add_ju_overflow_p(a, b)` implements + * `libj2_j2u_add_ju_to_j2u_overflow(a, b, &(struct libj2_j2u){})` + * in an efficient manner + * + * @param a The augend + * @param b The addend + * @return 1 if the addition would overflow, 0 otherwise + */ +inline int +libj2_j2u_add_ju_overflow_p(const struct libj2_j2u *a, uintmax_t b) +{ + return a->low > UINTMAX_MAX - b && a->high == UINTMAX_MAX; +} + + +/** + * Predict whether `libj2_ju_add_j2u_to_j2u_overflow` + * will return a result-overflow signal + * + * `libj2_ju_add_j2u_overflow_p(a, b)` implements + * `libj2_ju_add_j2u_to_j2u_overflow(a, b, &(struct libj2_j2u){})` + * in an efficient manner + * + * @param a The augend + * @param b The addend + * @return 1 if the addition would overflow, 0 otherwise + */ +inline int +libj2_ju_add_j2u_overflow_p(uintmax_t a, const struct libj2_j2u *b) +{ + return libj2_j2u_add_ju_overflow_p(b, a); +} + + +/** + * Predict whether `libj2_j2u_add_j2u_to_j2u_overflow` + * or `libj2_j2u_add_j2u_overflow` will return a + * result-overflow signal + * + * `libj2_j2u_add_j2u_overflow_p(a, b)` implements + * `libj2_j2u_add_j2u_to_j2u_overflow(a, b, &(struct libj2_j2u){})` + * in an efficient manner + * + * @param a The augend + * @param b The addend + * @return 1 if the addition would overflow, 0 otherwise + */ +inline int +libj2_j2u_add_j2u_overflow_p(const struct libj2_j2u *a, const struct libj2_j2u *b) +{ + if (a == b) + return (int)(a->high >> (LIBJ2_JU_BIT - 1U)); + else if (libj2_j2u_add_ju_overflow_p(a, b->low)) + return 1; + else + return a->high > UINTMAX_MAX - b->high; +} diff --git a/libj2/bit-shifting.h b/libj2/bit-shifting.h index a0c36d1..bb691bc 100644 --- a/libj2/bit-shifting.h +++ b/libj2/bit-shifting.h @@ -571,3 +571,109 @@ libj2_ju_rrot_to_j2u(uintmax_t a, unsigned b, struct libj2_j2u *res) libj2_ju_to_j2u(a, res); libj2_j2u_rrot(res, b); } + + +/** + * Predict whether `libj2_j2u_lsh_overflow` or + * `libj2_j2u_lsh_to_j2u_overflow` will return + * a result-overflow signal + * + * `libj2_j2u_lsh_overflow_p(a, b)` implements + * `libj2_j2u_lsh_to_j2u_overflow(a, b, &(struct libj2_j2u){})` + * in an efficient manner + * + * @param a The integer to shift (dry-run) + * @param b The number of positions to shift each bit + * @return 1 if set bit would be be shifted out, 0 otherwise + */ +inline int +libj2_j2u_lsh_overflow_p(const struct libj2_j2u *a, unsigned b) +{ + if (b >= LIBJ2_J2U_BIT) + return a->high || a->low; + else if (b > LIBJ2_JU_BIT) + return a->high || a->low >> (LIBJ2_J2U_BIT - b); + else if (b == LIBJ2_JU_BIT) + return !!a->high; + else if (b) + return !!(a->high >> (LIBJ2_JU_BIT - b)); + else + return 0; +} + + +/** + * Predict whether `libj2_ju_lsh_to_j2u_overflow` + * will return a result-overflow signal + * + * `libj2_ju_lsh_overflow_p(a, b)` implements + * `libj2_ju_lsh_to_j2u_overflow(a, b, &(struct libj2_j2u){})` + * in an efficient manner + * + * @param a The integer to shift (dry-run) + * @param b The number of positions to shift each bit + * @return 1 if set bit would be be shifted out, 0 otherwise + */ +inline int +libj2_ju_lsh_overflow_p(uintmax_t a, unsigned b) +{ + if (b >= LIBJ2_J2U_BIT) + return !!a; + else if (b > LIBJ2_JU_BIT) + return !!(a >> (LIBJ2_J2U_BIT - b)); + else + return 0; +} + + +/** + * Predict whether `libj2_j2u_rsh_underflow` or + * `libj2_j2u_rsh_to_j2u_underflow` will return + * a result-underflow signal + * + * `libj2_j2u_rsh_underflow_p(a, b)` implements + * `libj2_j2u_rsh_to_j2u_underflow(a, b, &(struct libj2_j2u){})` + * in an efficient manner + * + * @param a The integer to shift (dry-run) + * @param b The number of positions to shift each bit + * @return 1 if set bit would be be shifted out, 0 otherwise + */ +inline int +libj2_j2u_rsh_underflow_p(const struct libj2_j2u *a, unsigned b) +{ + if (b >= LIBJ2_J2U_BIT) + return a->high || a->low; + else if (b > LIBJ2_JU_BIT) + return a->low || a->high >> (LIBJ2_J2U_BIT - b); + else if (b == LIBJ2_JU_BIT) + return !!a->low; + else if (b) + return !!(a->low << (LIBJ2_JU_BIT - b)); + else + return 0; +} + + +/** + * Predict whether `libj2_ju_rsh_to_j2u_underflow` + * will return a result-underflowflow signal + * + * `libj2_ju_rsh_underflow_p(a, b)` implements + * `libj2_ju_rsh_to_j2u_underflow(a, b, &(struct libj2_j2u){})` + * in an efficient manner + * + * @param a The integer to shift (dry-run) + * @param b The number of positions to shift each bit + * @return 1 if set bit would be be shifted out, 0 otherwise + */ +inline int +libj2_ju_rsh_underflow_p(uintmax_t a, unsigned b) +{ + if (b >= LIBJ2_JU_BIT) + return !!a; + else if (b) + return !!(a << (LIBJ2_JU_BIT - b)); + else + return 0; +} diff --git a/libj2/multiplication.h b/libj2/multiplication.h index 005fa5d..09ead3c 100644 --- a/libj2/multiplication.h +++ b/libj2/multiplication.h @@ -364,3 +364,238 @@ libj2_j2u_mul_j2u_to_j2u_overflow(const struct libj2_j2u *a, const struct libj2_ *res = *a; return libj2_j2u_mul_j2u_overflow_destructive(res, &c); } + + +/** + * Variant of `libj2_j2u_mul_j2u_overflow_p` that + * that stops the overflow-prediction is costly + * + * @param a The multiplier + * @param b The multiplicand + * @return `LIBJ2_OVERFLOW` (= 1) if the multiplication would overflow, + * `LIBJ2_NO_OVERFLOW` (= 0) if the multiplication would not overflow, + * or `LIBJ2_OVERFLOW_UNKNOWN` if the prediction was not made + */ +inline enum libj2_overflow +libj2_j2u_mul_j2u_overflow_p_quick(const struct libj2_j2u *a, const struct libj2_j2u *b) +{ + unsigned lz; + + if (!a->high == !b->high) + return a->high > 0 ? LIBJ2_OVERFLOW : LIBJ2_NO_OVERFLOW; + if (!a->high && a->low <= 1U) + return LIBJ2_NO_OVERFLOW; + if (!b->high && b->low <= 1U) + return LIBJ2_NO_OVERFLOW; + + lz = libj2_clz_j2u(a) + libj2_clz_j2u(b); + if (lz <= LIBJ2_J2U_BIT) + return LIBJ2_OVERFLOW; + if (lz > LIBJ2_J2U_BIT - 1U) + return LIBJ2_NO_OVERFLOW; + + return LIBJ2_OVERFLOW_UNKNOWN; +} + + +/** + * Variant of `libj2_j2u_mul_ju_overflow_p` that + * that stops the overflow-prediction is costly + * + * @param a The multiplier + * @param b The multiplicand + * @return `LIBJ2_OVERFLOW` (= 1) if the multiplication would overflow, + * `LIBJ2_NO_OVERFLOW` (= 0) if the multiplication would not overflow, + * or `LIBJ2_OVERFLOW_UNKNOWN` if the prediction was not made + */ +inline enum libj2_overflow +libj2_j2u_mul_ju_overflow_p_quick(const struct libj2_j2u *a, uintmax_t b) +{ + return libj2_j2u_mul_j2u_overflow_p_quick(a, &(struct libj2_j2u){.high = 0, .low = b}); +} + + +/** + * Variant of `libj2_ju_mul_j2u_overflow_p` that + * that stops the overflow-prediction is costly + * + * @param a The multiplier + * @param b The multiplicand + * @return `LIBJ2_OVERFLOW` (= 1) if the multiplication would overflow, + * `LIBJ2_NO_OVERFLOW` (= 0) if the multiplication would not overflow, + * or `LIBJ2_OVERFLOW_UNKNOWN` if the prediction was not made + */ +inline enum libj2_overflow +libj2_ju_mul_j2u_overflow_p_quick(uintmax_t a, const struct libj2_j2u *b) +{ + return libj2_j2u_mul_ju_overflow_p_quick(b, a); +} + + +/** + * Predict whether `libj2_j2u_mul_j2u_overflow_destructive` + * `libj2_j2u_mul_j2u_overflow`, or `libj2_j2u_mul_j2u_to_j2u_overflow` + * will return a result-overflow signal + * + * `libj2_j2u_mul_j2u_overflow_p(a, b)` implements + * `libj2_j2u_mul_j2u_to_j2u_overflow(a, b, &(struct libj2_j2u){})` + * in an efficient manner for most cases + * + * @param a The multiplier + * @param b The multiplicand + * @return 1 if the multiplication would overflow, 0 otherwise + */ +inline int +libj2_j2u_mul_j2u_overflow_p(const struct libj2_j2u *a, const struct libj2_j2u *b) +{ + enum libj2_overflow overflow; + struct libj2_j2u j2u; + uintmax_t ju, c; + + overflow = libj2_j2u_mul_j2u_overflow_p_quick(a, b); + if (overflow != LIBJ2_OVERFLOW_UNKNOWN) + return (int)overflow; + + if (a->high) { + j2u = *a; + ju = b->low; + } else { + j2u = *b; + ju = a->low; + } + +#if defined(LIBJ2_USE_GCC_INTRINSIC_FUNCTIONS_) + if (__builtin_mul_overflow(j2u.high, ju, &c)) + return 1; +#else + if (j2u.high > UINTMAX_MAX / ju) + return 1; + c = j2u.high * ju; +#endif + + libj2_ju_mul_ju_to_j2u(j2u.low, ju, &j2u); + return j2u.high > UINTMAX_MAX - c; +} + + +/** + * Predict whether `libj2_j2u_mul_ju_overflow` + * or `libj2_j2u_mul_ju_to_j2u_overflow` + * will return a result-overflow signal + * + * `libj2_j2u_mul_ju_overflow_p(a, b)` implements + * `libj2_j2u_mul_ju_to_j2u_overflow(a, b, &(struct libj2_j2u){})` + * in an efficient manner for most cases + * + * @param a The multiplier + * @param b The multiplicand + * @return 1 if the multiplication would overflow, 0 otherwise + */ +inline int +libj2_j2u_mul_ju_overflow_p(const struct libj2_j2u *a, uintmax_t b) +{ + return libj2_j2u_mul_j2u_overflow_p(a, &(struct libj2_j2u){.high = 0, .low = b}); +} + + +/** + * Predict whether `libj2_ju_mul_j2u_overflow` + * will return a result-overflow signal + * + * `libj2_ju_mul_j2u_overflow_p(a, b)` implements + * `libj2_ju_mul_j2u(&(struct libj2_j2u){.high = a->high, .low = a->low}, b)` + * in an efficient manner for most cases + * + * @param a The multiplier + * @param b The multiplicand + * @return 1 if the multiplication would overflow, 0 otherwise + */ +inline int +libj2_ju_mul_j2u_overflow_p(uintmax_t a, const struct libj2_j2u *b) +{ + return libj2_j2u_mul_ju_overflow_p(b, a); +} + + +/** + * Variant of `libj2_j2u_mul_j2u_overflow_p` that + * that performs the multiplication if the + * overflow-prediction is costly + * + * @param a The multiplier + * @param b The multiplicand + * @param res Output parameter for the product + * @param res_set Output parameter for whether `*res` is set, + * if set to 1 when the function returns, + * `*res` will be set to the product, + * if set to 0 when the function returns, + * `*res` will be unmodified; + * will never be set to any other value + * @return 1 if the multiplication would overflow + * (did overflow), 0 otherwise + */ +inline int +libj2_j2u_mul_j2u_to_j2u_overflow_p(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *res, int *res_set) +{ + enum libj2_overflow overflow; + + overflow = libj2_j2u_mul_j2u_overflow_p_quick(a, b); + if (overflow != LIBJ2_OVERFLOW_UNKNOWN) { + *res_set = 0; + return (int)overflow; + } + + *res_set = 1; + if (a->high) + return libj2_j2u_mul_ju_to_j2u_overflow(a, b->low, res); + else + return libj2_j2u_mul_ju_to_j2u_overflow(b, a->low, res); +} + + +/** + * Variant of `libj2_j2u_mul_ju_overflow_p` that + * that performs the multiplication if the + * overflow-prediction is costly + * + * @param a The multiplier + * @param b The multiplicand + * @param res Output parameter for the product + * @param res_set Output parameter for whether `*res` is set, + * if set to 1 when the function returns, + * `*res` will be set to the product, + * if set to 0 when the function returns, + * `*res` will be unmodified; + * will never be set to any other value + * @return 1 if the multiplication would overflow + * (did overflow), 0 otherwise + */ +inline int +libj2_j2u_mul_ju_to_j2u_overflow_p(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res, int *res_set) +{ + return libj2_j2u_mul_j2u_to_j2u_overflow_p(a, &(struct libj2_j2u){.high = 0, .low = b}, res, res_set); +} + + +/** + * Variant of `libj2_ju_mul_j2u_overflow_p` that + * that performs the multiplication if the + * overflow-prediction is costly + * + * @param a The multiplier + * @param b The multiplicand + * @param res Output parameter for the product + * @param res_set Output parameter for whether `*res` is set, + * if set to 1 when the function returns, + * `*res` will be set to the product, + * if set to 0 when the function returns, + * `*res` will be unmodified; + * will never be set to any other value + * @return 1 if the multiplication would overflow + * (did overflow), 0 otherwise + */ +inline int +libj2_ju_mul_j2u_to_j2u_overflow_p(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res, int *res_set) +{ + return libj2_j2u_mul_ju_to_j2u_overflow_p(b, a, res, res_set); +} diff --git a/libj2/subtraction.h b/libj2/subtraction.h index 27ae9d6..7f0bbce 100644 --- a/libj2/subtraction.h +++ b/libj2/subtraction.h @@ -491,3 +491,119 @@ libj2_j2u_rsub_ju_overflow(struct libj2_j2u *a, uintmax_t b) #endif return overflow; } + + +/** + * Predict whether `libj2_j2u_sub_ju_to_j2u_overflow` + * or `libj2_j2u_sub_ju_overflow` will return a + * result-overflow signal + * + * `libj2_j2u_sub_ju_overflow_p(a, b)` implements + * `libj2_j2u_sub_ju_to_j2u_overflow(a, b, &(struct libj2_j2u){})` + * in an efficient manner + * + * @param a The minuend (left-hand) + * @param b The subtrahend (right-hand) + * @return 1 if the subtraction would overflow, 0 otherwise + */ +inline int +libj2_j2u_sub_ju_overflow_p(const struct libj2_j2u *a, uintmax_t b) +{ + return a->low < b && !a->high; +} + + +/** + * Predict whether `libj2_ju_sub_j2u_to_j2u_overflow` + * will return a result-overflow signal + * + * `libj2_ju_sub_j2u_overflow_p(a, b)` implements + * `libj2_ju_sub_j2u_to_j2u_overflow(a, b, &(struct libj2_j2u){})` + * in an efficient manner + * + * @param a The minuend (left-hand) + * @param b The subtrahend (right-hand) + * @return 1 if the subtraction would overflow, 0 otherwise + */ +inline int +libj2_ju_sub_j2u_overflow_p(uintmax_t a, const struct libj2_j2u *b) +{ + return b->high || b->low > a; +} + + +/** + * Predict whether `libj2_ju_sub_ju_to_j2u_overflow` + * will return a result-overflow signal + * + * `libj2_ju_sub_ju_overflow_p(a, b)` implements + * `libj2_ju_sub_ju_to_j2u_overflow(a, b, &(struct libj2_j2u){})` + * in an efficient manner + * + * @param a The minuend (left-hand) + * @param b The subtrahend (right-hand) + * @return 1 if the subtraction would overflow, 0 otherwise + */ +inline int +libj2_ju_sub_ju_overflow_p(uintmax_t a, uintmax_t b) +{ + return a < b; +} + + +/** + * Predict whether `libj2_j2u_sub_j2u_to_j2u_overflow` + * or `libj2_j2u_sub_j2u_overflow` will return a + * result-overflow signal + * + * `libj2_j2u_sub_j2u_overflow_p(a, b)` implements + * `libj2_j2u_sub_j2u_to_j2u_overflow(a, b, &(struct libj2_j2u){})` + * in an efficient manner + * + * @param a The minuend (left-hand) + * @param b The subtrahend (right-hand) + * @return 1 if the subtraction would overflow, 0 otherwise + */ +inline int +libj2_j2u_sub_j2u_overflow_p(const struct libj2_j2u *a, const struct libj2_j2u *b) +{ + return libj2_j2u_sub_ju_overflow_p(a, b->low) || a->high < b->high; +} + + +/** + * Predict whether `libj2_j2u_rsub_j2u_overflow` + * will return a result-overflow signal + * + * `libj2_j2u_rsub_j2u_overflow_p(a, b)` implements + * `libj2_j2u_rsub_j2u_overflow(&(struct libj2_j2u){.high = a->high, .low = a->low}, b)` + * in an efficient manner + * + * @param a The subtrahend (right-hand) + * @param b The minuend (left-hand) + * @return 1 if the subtraction would overflow, 0 otherwise + */ +inline int +libj2_j2u_rsub_j2u_overflow_p(const struct libj2_j2u *a, const struct libj2_j2u *b) +{ + return libj2_j2u_sub_j2u_overflow_p(b, a); +} + + +/** + * Predict whether `libj2_j2u_rsub_ju_overflow` + * will return a result-overflow signal + * + * `libj2_j2u_rsub_ju_overflow_p(a, b)` implements + * `libj2_j2u_rsub_ju_overflow(&(struct libj2_j2u){.high = a->high, .low = a->low}, b)` + * in an efficient manner + * + * @param a The subtrahend (right-hand) + * @param b The minuend (left-hand) + * @return 1 if the subtraction would overflow, 0 otherwise + */ +inline int +libj2_j2u_rsub_ju_overflow_p(const struct libj2_j2u *a, uintmax_t b) +{ + return libj2_ju_sub_j2u_overflow_p(b, a); +} diff --git a/libj2_j2u_add_j2u.c b/libj2_j2u_add_j2u.c index bd783a0..8aca375 100644 --- a/libj2_j2u_add_j2u.c +++ b/libj2_j2u_add_j2u.c @@ -56,13 +56,18 @@ check_(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low, EXPECT(libj2_j2u_eq_j2u(&b, &expected)); EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); - r = (struct libj2_j2u){111, 222}; a = a_saved; b = b_saved; EXPECT(libj2_j2u_add_j2u_overflow(&a, &b) == r_overflow); EXPECT(libj2_j2u_eq_j2u(&a, &expected)); EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + a = a_saved; + b = b_saved; + EXPECT(libj2_j2u_add_j2u_overflow_p((const struct libj2_j2u *)&a, (const struct libj2_j2u *)&b) == r_overflow); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + r = (struct libj2_j2u){111, 222}; a = a_saved; b = b_saved; @@ -150,11 +155,14 @@ check_double(uintmax_t high, uintmax_t low) libj2_j2u_add_j2u_to_j2u(&a, &a, &a); EXPECT(libj2_j2u_eq_j2u(&a, &expected)); - r = (struct libj2_j2u){111, 222}; a = a_saved; EXPECT(libj2_j2u_add_j2u_overflow(&a, &a) == expected_overflow); EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + a = a_saved; + EXPECT(libj2_j2u_add_j2u_overflow_p((const struct libj2_j2u *)&a, (const struct libj2_j2u *)&a) == expected_overflow); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + r = (struct libj2_j2u){111, 222}; a = a_saved; EXPECT(libj2_j2u_add_j2u_to_j2u_overflow(&a, &a, &r) == expected_overflow); diff --git a/libj2_j2u_add_j2u_overflow_p.c b/libj2_j2u_add_j2u_overflow_p.c new file mode 100644 index 0000000..eea2fe6 --- /dev/null +++ b/libj2_j2u_add_j2u_overflow_p.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_add_j2u_overflow_p(const struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_add_j2u.c */ + +#endif diff --git a/libj2_j2u_add_ju.c b/libj2_j2u_add_ju.c index 8592662..f368857 100644 --- a/libj2_j2u_add_ju.c +++ b/libj2_j2u_add_ju.c @@ -35,6 +35,11 @@ check_zero_low(uintmax_t high, uintmax_t low) EXPECT(a.high == high); EXPECT(a.low == low); + a = (struct libj2_j2u){.high = high, .low = 0}; + EXPECT(libj2_j2u_add_ju_overflow_p((const struct libj2_j2u *)&a, low) == 0); + EXPECT(a.high == high); + EXPECT(a.low == 0); + r = (struct libj2_j2u){111, 222}; a = (struct libj2_j2u){.high = high, .low = 0}; libj2_j2u_add_ju_to_j2u(&a, low, &r); @@ -86,6 +91,11 @@ check_zero_low(uintmax_t high, uintmax_t low) EXPECT(libj2_ju_add_j2u_to_j2u_overflow(low, &a, &a) == 0); EXPECT(a.high == high); EXPECT(a.low == low); + + a = (struct libj2_j2u){.high = high, .low = 0}; + EXPECT(libj2_ju_add_j2u_overflow_p(low, (const struct libj2_j2u *)&a) == 0); + EXPECT(a.high == high); + EXPECT(a.low == 0); } @@ -107,6 +117,11 @@ check_max_low(uintmax_t high, uintmax_t low) EXPECT(a.high == expected_high); EXPECT(a.low == expected_low); + a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX}; + EXPECT(libj2_j2u_add_ju_overflow_p((const struct libj2_j2u *)&a, low) == expected_overflow); + EXPECT(a.high == high); + EXPECT(a.low == UINTMAX_MAX); + r = (struct libj2_j2u){111, 222}; a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX}; libj2_j2u_add_ju_to_j2u(&a, low, &r); @@ -158,6 +173,11 @@ check_max_low(uintmax_t high, uintmax_t low) EXPECT(libj2_ju_add_j2u_to_j2u_overflow(low, &a, &a) == expected_overflow); EXPECT(a.high == expected_high); EXPECT(a.low == expected_low); + + a = (struct libj2_j2u){.high = high, .low = UINTMAX_MAX}; + EXPECT(libj2_ju_add_j2u_overflow_p(low, (const struct libj2_j2u *)&a) == expected_overflow); + EXPECT(a.high == high); + EXPECT(a.low == UINTMAX_MAX); } @@ -206,6 +226,11 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t b) EXPECT(a.high == expected_high); EXPECT(a.low == expected_low); + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + EXPECT(libj2_j2u_add_ju_overflow_p((const struct libj2_j2u *)&a, b) == expected_overflow); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + r = (struct libj2_j2u){111, 222}; a = (struct libj2_j2u){.high = a_high, .low = a_low}; libj2_j2u_add_ju_to_j2u(&a, b, &r); @@ -257,6 +282,11 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t b) EXPECT(libj2_ju_add_j2u_to_j2u_overflow(b, &a, &a) == expected_overflow); EXPECT(a.high == expected_high); EXPECT(a.low == expected_low); + + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + EXPECT(libj2_ju_add_j2u_overflow_p(b, (const struct libj2_j2u *)&a) == expected_overflow); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); } diff --git a/libj2_j2u_add_ju_overflow_p.c b/libj2_j2u_add_ju_overflow_p.c new file mode 100644 index 0000000..11d436f --- /dev/null +++ b/libj2_j2u_add_ju_overflow_p.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_add_ju_overflow_p(const struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_add_ju.c */ + +#endif diff --git a/libj2_j2u_lsh.c b/libj2_j2u_lsh.c index 85ca72b..914c3b2 100644 --- a/libj2_j2u_lsh.c +++ b/libj2_j2u_lsh.c @@ -126,6 +126,10 @@ check(const char *pattern) EXPECT(libj2_j2u_lsh_overflow(&r, i) == overflows); EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + r = a; + EXPECT(libj2_j2u_lsh_overflow_p((const struct libj2_j2u *)&r, i) == overflows); + EXPECT(libj2_j2u_eq_j2u(&r, &a)); + r = (struct libj2_j2u){111, 222}; libj2_j2u_lsh_to_j2u(&a, i, &r); EXPECT(libj2_j2u_eq_j2u(&r, &expected)); diff --git a/libj2_j2u_lsh_overflow_p.c b/libj2_j2u_lsh_overflow_p.c new file mode 100644 index 0000000..3dbe8dc --- /dev/null +++ b/libj2_j2u_lsh_overflow_p.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_lsh_overflow_p(const struct libj2_j2u *a, unsigned b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_lsh.c */ + +#endif diff --git a/libj2_j2u_mul_j2u_destructive.c b/libj2_j2u_mul_j2u_destructive.c index cfa36a2..ba986da 100644 --- a/libj2_j2u_mul_j2u_destructive.c +++ b/libj2_j2u_mul_j2u_destructive.c @@ -60,7 +60,9 @@ refmul(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *e static void mul_(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *expected, int expect_overflow) { - struct libj2_j2u t, x, a_saved = *a, b_saved = *b; + struct libj2_j2u t, x, a_saved = *a, b_saved = *b, t_saved; + enum libj2_overflow ofp; + int set; *expected = *a; libj2_j2u_mul_j2u(expected, b); @@ -72,10 +74,53 @@ mul_(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *exp EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); t = *a; + libj2_j2u_mul_j2u_to_j2u(&t, b, &t); + EXPECT(libj2_j2u_eq_j2u(&t, expected)); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + + t = *b; + libj2_j2u_mul_j2u_to_j2u(a, &t, &t); + EXPECT(libj2_j2u_eq_j2u(&t, expected)); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + + t = *a; EXPECT(libj2_j2u_mul_j2u_overflow(&t, b) == expect_overflow); EXPECT(libj2_j2u_eq_j2u(&t, expected)); EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + t = *a; + EXPECT(libj2_j2u_mul_j2u_overflow_p(&t, b) == expect_overflow); + EXPECT(libj2_j2u_eq_j2u(&t, a)); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + + ofp = libj2_j2u_mul_j2u_overflow_p_quick(&t, b); + EXPECT(ofp == LIBJ2_OVERFLOW_UNKNOWN || (int)ofp == expect_overflow); + EXPECT(libj2_j2u_eq_j2u(&t, a)); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + + set = 999; + t = (struct libj2_j2u){111, 222}; + t_saved = t; + EXPECT(libj2_j2u_mul_j2u_to_j2u_overflow_p(a, b, &t, &set) == expect_overflow); + EXPECT(set == 0 || set == 1); + EXPECT(libj2_j2u_eq_j2u(&t, set ? expected : &t_saved)); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + + set = 999; + t = *a; + EXPECT(libj2_j2u_mul_j2u_to_j2u_overflow_p(&t, b, &t, &set) == expect_overflow); + EXPECT(set == 0 || set == 1); + EXPECT(libj2_j2u_eq_j2u(&t, set ? expected : &a_saved)); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + + set = 999; + t = *b; + EXPECT(libj2_j2u_mul_j2u_to_j2u_overflow_p(a, &t, &t, &set) == expect_overflow); + EXPECT(set == 0 || set == 1); + EXPECT(libj2_j2u_eq_j2u(&t, set ? expected : &b_saved)); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + t = (struct libj2_j2u){111, 222}; EXPECT(libj2_j2u_mul_j2u_to_j2u_overflow(a, b, &t) == expect_overflow); EXPECT(libj2_j2u_eq_j2u(&t, expected)); @@ -83,6 +128,16 @@ mul_(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *exp EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); t = *a; + EXPECT(libj2_j2u_mul_j2u_to_j2u_overflow(&t, b, &t) == expect_overflow); + EXPECT(libj2_j2u_eq_j2u(&t, expected)); + EXPECT(libj2_j2u_eq_j2u(b, &b_saved)); + + t = *b; + EXPECT(libj2_j2u_mul_j2u_to_j2u_overflow(a, &t, &t) == expect_overflow); + EXPECT(libj2_j2u_eq_j2u(&t, expected)); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + + t = *a; x = *b; libj2_j2u_mul_j2u_destructive(&t, &x); EXPECT(libj2_j2u_eq_j2u(&t, expected)); @@ -106,6 +161,21 @@ mul_(const struct libj2_j2u *a, const struct libj2_j2u *b, struct libj2_j2u *exp EXPECT(libj2_j2u_eq_j2u(&t, expected)); t = *a; + EXPECT(libj2_j2u_mul_j2u_overflow_p(&t, &t) == expect_overflow); + EXPECT(libj2_j2u_eq_j2u(&t, a)); + + t = *a; + ofp = libj2_j2u_mul_j2u_overflow_p_quick(&t, &t); + EXPECT(ofp == LIBJ2_OVERFLOW_UNKNOWN || (int)ofp == expect_overflow); + EXPECT(libj2_j2u_eq_j2u(&t, a)); + + set = 999; + t = *a; + EXPECT(libj2_j2u_mul_j2u_to_j2u_overflow_p(&t, &t, &t, &set) == expect_overflow); + EXPECT(set == 0 || set == 1); + EXPECT(libj2_j2u_eq_j2u(&t, set ? expected : a)); + + t = *a; EXPECT(libj2_j2u_mul_j2u_to_j2u_overflow(&t, &t, &t) == expect_overflow); EXPECT(libj2_j2u_eq_j2u(&t, expected)); }} diff --git a/libj2_j2u_mul_j2u_overflow_p.c b/libj2_j2u_mul_j2u_overflow_p.c new file mode 100644 index 0000000..5fa95c6 --- /dev/null +++ b/libj2_j2u_mul_j2u_overflow_p.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_mul_j2u_overflow_p(const struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_j2u_destructive.c */ + +#endif diff --git a/libj2_j2u_mul_j2u_overflow_p_quick.c b/libj2_j2u_mul_j2u_overflow_p_quick.c new file mode 100644 index 0000000..d26145b --- /dev/null +++ b/libj2_j2u_mul_j2u_overflow_p_quick.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline enum libj2_overflow libj2_j2u_mul_j2u_overflow_p_quick(const struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_j2u_destructive.c */ + +#endif diff --git a/libj2_j2u_mul_j2u_to_j2u_overflow_p.c b/libj2_j2u_mul_j2u_to_j2u_overflow_p.c new file mode 100644 index 0000000..db87add --- /dev/null +++ b/libj2_j2u_mul_j2u_to_j2u_overflow_p.c @@ -0,0 +1,14 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_mul_j2u_to_j2u_overflow_p(const struct libj2_j2u *a, const struct libj2_j2u *b, + struct libj2_j2u *res, int *res_set); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_j2u_destructive.c */ + +#endif diff --git a/libj2_j2u_mul_ju.c b/libj2_j2u_mul_ju.c index 17fc453..6be737c 100644 --- a/libj2_j2u_mul_ju.c +++ b/libj2_j2u_mul_ju.c @@ -53,7 +53,9 @@ refmul(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *expected) static void mul(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *expected, int expect_overflow) { - struct libj2_j2u t, a_saved = *a; + struct libj2_j2u t, a_saved = *a, t_saved; + enum libj2_overflow ofp; + int set; *expected = *a; libj2_j2u_mul_ju(expected, b); @@ -63,24 +65,84 @@ mul(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *expected, int expe EXPECT(libj2_j2u_eq_j2u(&t, expected)); EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + t = *a; + libj2_j2u_mul_ju_to_j2u(&t, b, &t); + EXPECT(libj2_j2u_eq_j2u(&t, expected)); + t = (struct libj2_j2u){111, 222}; libj2_ju_mul_j2u_to_j2u(b, a, &t); EXPECT(libj2_j2u_eq_j2u(&t, expected)); EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); t = *a; + libj2_ju_mul_j2u_to_j2u(b, &t, &t); + EXPECT(libj2_j2u_eq_j2u(&t, expected)); + + t = *a; EXPECT(libj2_j2u_mul_ju_overflow(&t, b) == expect_overflow); EXPECT(libj2_j2u_eq_j2u(&t, expected)); + t = *a; + EXPECT(libj2_j2u_mul_ju_overflow_p((const struct libj2_j2u *)&t, b) == expect_overflow); + EXPECT(libj2_j2u_eq_j2u(&t, a)); + + t = *a; + ofp = libj2_j2u_mul_ju_overflow_p_quick((const struct libj2_j2u *)&t, b); + EXPECT(ofp == LIBJ2_OVERFLOW_UNKNOWN || (int)ofp == expect_overflow); + EXPECT(libj2_j2u_eq_j2u(&t, a)); + + set = 999; + t = (struct libj2_j2u){111, 222}; + t_saved = t; + EXPECT(libj2_j2u_mul_ju_to_j2u_overflow_p((const struct libj2_j2u *)a, b, &t, &set) == expect_overflow); + EXPECT(set == 0 || set == 1); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&t, set ? expected : &t_saved)); + + set = 999; + t = *a; + EXPECT(libj2_j2u_mul_ju_to_j2u_overflow_p((const struct libj2_j2u *)&t, b, &t, &set) == expect_overflow); + EXPECT(set == 0 || set == 1); + EXPECT(libj2_j2u_eq_j2u(&t, set ? expected : a)); + t = (struct libj2_j2u){111, 222}; EXPECT(libj2_j2u_mul_ju_to_j2u_overflow(a, b, &t) == expect_overflow); EXPECT(libj2_j2u_eq_j2u(&t, expected)); EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + t = *a; + EXPECT(libj2_j2u_mul_ju_to_j2u_overflow(&t, b, &t) == expect_overflow); + EXPECT(libj2_j2u_eq_j2u(&t, expected)); + t = (struct libj2_j2u){111, 222}; EXPECT(libj2_ju_mul_j2u_to_j2u_overflow(b, a, &t) == expect_overflow); EXPECT(libj2_j2u_eq_j2u(&t, expected)); EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + + t = *a; + EXPECT(libj2_ju_mul_j2u_to_j2u_overflow(b, &t, &t) == expect_overflow); + EXPECT(libj2_j2u_eq_j2u(&t, expected)); + + set = 999; + t = (struct libj2_j2u){111, 222}; + t_saved = t; + EXPECT(libj2_ju_mul_j2u_to_j2u_overflow_p(b, a, &t, &set) == expect_overflow); + EXPECT(set == 0 || set == 1); + EXPECT(libj2_j2u_eq_j2u(&t, set ? expected : &t_saved)); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + + set = 999; + t = *a; + EXPECT(libj2_ju_mul_j2u_to_j2u_overflow_p(b, &t, &t, &set) == expect_overflow); + EXPECT(set == 0 || set == 1); + EXPECT(libj2_j2u_eq_j2u(&t, set ? expected : a)); + + EXPECT(libj2_ju_mul_j2u_overflow_p(b, (const struct libj2_j2u *)a) == expect_overflow); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); + + ofp = libj2_ju_mul_j2u_overflow_p_quick(b, (const struct libj2_j2u *)a); + EXPECT(ofp == LIBJ2_OVERFLOW_UNKNOWN || (int)ofp == expect_overflow); + EXPECT(libj2_j2u_eq_j2u(a, &a_saved)); } diff --git a/libj2_j2u_mul_ju_overflow_p.c b/libj2_j2u_mul_ju_overflow_p.c new file mode 100644 index 0000000..aa25a2b --- /dev/null +++ b/libj2_j2u_mul_ju_overflow_p.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_mul_ju_overflow_p(const struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_ju.c */ + +#endif diff --git a/libj2_j2u_mul_ju_overflow_p_quick.c b/libj2_j2u_mul_ju_overflow_p_quick.c new file mode 100644 index 0000000..be12c11 --- /dev/null +++ b/libj2_j2u_mul_ju_overflow_p_quick.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline enum libj2_overflow libj2_j2u_mul_ju_overflow_p_quick(const struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_ju.c */ + +#endif diff --git a/libj2_j2u_mul_ju_to_j2u_overflow_p.c b/libj2_j2u_mul_ju_to_j2u_overflow_p.c new file mode 100644 index 0000000..11b4216 --- /dev/null +++ b/libj2_j2u_mul_ju_to_j2u_overflow_p.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_mul_ju_to_j2u_overflow_p(const struct libj2_j2u *a, uintmax_t b, struct libj2_j2u *res, int *res_set); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_ju.c */ + +#endif diff --git a/libj2_j2u_rsh.c b/libj2_j2u_rsh.c index 2a5ed50..3dc18e9 100644 --- a/libj2_j2u_rsh.c +++ b/libj2_j2u_rsh.c @@ -84,6 +84,10 @@ check(const char *pattern) EXPECT(libj2_j2u_rsh_underflow(&r, i) == underflows); EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + r = a; + EXPECT(libj2_j2u_rsh_underflow_p((const struct libj2_j2u *)&r, i) == underflows); + EXPECT(libj2_j2u_eq_j2u(&r, &a)); + r = (struct libj2_j2u){111, 222}; libj2_j2u_rsh_to_j2u(&a, i, &r); EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); diff --git a/libj2_j2u_rsh_underflow_p.c b/libj2_j2u_rsh_underflow_p.c new file mode 100644 index 0000000..6e00eae --- /dev/null +++ b/libj2_j2u_rsh_underflow_p.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_rsh_underflow_p(const struct libj2_j2u *a, unsigned b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_rsh.c */ + +#endif diff --git a/libj2_j2u_rsub_j2u_overflow_p.c b/libj2_j2u_rsub_j2u_overflow_p.c new file mode 100644 index 0000000..4bf6cab --- /dev/null +++ b/libj2_j2u_rsub_j2u_overflow_p.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_rsub_j2u_overflow_p(const struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_j2u.c */ + +#endif diff --git a/libj2_j2u_rsub_ju_overflow_p.c b/libj2_j2u_rsub_ju_overflow_p.c new file mode 100644 index 0000000..9666070 --- /dev/null +++ b/libj2_j2u_rsub_ju_overflow_p.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_rsub_ju_overflow_p(const struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_ju.c */ + +#endif diff --git a/libj2_j2u_sub_j2u.c b/libj2_j2u_sub_j2u.c index 6727c71..bd645e2 100644 --- a/libj2_j2u_sub_j2u.c +++ b/libj2_j2u_sub_j2u.c @@ -56,13 +56,18 @@ check_(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low, EXPECT(libj2_j2u_eq_j2u(&b, &expected)); EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); - r = (struct libj2_j2u){111, 222}; a = a_saved; b = b_saved; EXPECT(libj2_j2u_sub_j2u_overflow(&a, &b) == r_overflow); EXPECT(libj2_j2u_eq_j2u(&a, &expected)); EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + a = a_saved; + b = b_saved; + EXPECT(libj2_j2u_sub_j2u_overflow_p((const struct libj2_j2u *)&a, (const struct libj2_j2u *)&b) == r_overflow); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + r = (struct libj2_j2u){111, 222}; a = a_saved; b = b_saved; @@ -89,12 +94,17 @@ check_(uintmax_t a_high, uintmax_t a_low, uintmax_t b_high, uintmax_t b_low, EXPECT(libj2_j2u_eq_j2u(&b, &expected)); EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); - r = (struct libj2_j2u){111, 222}; a = a_saved; b = b_saved; EXPECT(libj2_j2u_rsub_j2u_overflow(&b, &a) == r_overflow); EXPECT(libj2_j2u_eq_j2u(&b, &expected)); EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + + a = a_saved; + b = b_saved; + EXPECT(libj2_j2u_rsub_j2u_overflow_p(&b, &a) == r_overflow); + EXPECT(libj2_j2u_eq_j2u(&b, &b_saved)); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); } @@ -146,11 +156,14 @@ check_double(uintmax_t high, uintmax_t low) libj2_j2u_sub_j2u_to_j2u(&a, &a, &a); EXPECT(libj2_j2u_is_zero(&a)); - r = (struct libj2_j2u){111, 222}; a = a_saved; EXPECT(libj2_j2u_sub_j2u_overflow(&a, &a) == 0); EXPECT(libj2_j2u_is_zero(&a)); + a = a_saved; + EXPECT(libj2_j2u_sub_j2u_overflow_p((const struct libj2_j2u *)&a, (const struct libj2_j2u *)&a) == 0); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); + r = (struct libj2_j2u){111, 222}; a = a_saved; EXPECT(libj2_j2u_sub_j2u_to_j2u_overflow(&a, &a, &r) == 0); @@ -165,10 +178,13 @@ check_double(uintmax_t high, uintmax_t low) libj2_j2u_rsub_j2u(&a, &a); EXPECT(libj2_j2u_is_zero(&a)); - r = (struct libj2_j2u){111, 222}; a = a_saved; EXPECT(libj2_j2u_rsub_j2u_overflow(&a, &a) == 0); EXPECT(libj2_j2u_is_zero(&a)); + + a = a_saved; + EXPECT(libj2_j2u_rsub_j2u_overflow_p((const struct libj2_j2u *)&a, (const struct libj2_j2u *)&a) == 0); + EXPECT(libj2_j2u_eq_j2u(&a, &a_saved)); } diff --git a/libj2_j2u_sub_j2u_overflow_p.c b/libj2_j2u_sub_j2u_overflow_p.c new file mode 100644 index 0000000..424b9a0 --- /dev/null +++ b/libj2_j2u_sub_j2u_overflow_p.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_sub_j2u_overflow_p(const struct libj2_j2u *a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_j2u.c */ + +#endif diff --git a/libj2_j2u_sub_ju.c b/libj2_j2u_sub_ju.c index b2a3f47..0cd0343 100644 --- a/libj2_j2u_sub_ju.c +++ b/libj2_j2u_sub_ju.c @@ -41,6 +41,11 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t b) EXPECT(libj2_j2u_sub_ju_overflow(&a, b) == expected_overflow); EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + EXPECT(libj2_j2u_sub_ju_overflow_p((const struct libj2_j2u *)&a, b) == expected_overflow); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + r = (struct libj2_j2u){111, 222}; a = (struct libj2_j2u){.high = a_high, .low = a_low}; libj2_j2u_sub_ju_to_j2u(&a, b, &r); @@ -86,6 +91,11 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t b) libj2_minus_j2u(&a); EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + EXPECT(libj2_j2u_rsub_ju_overflow_p((const struct libj2_j2u *)&a, b) == expected_roverflow); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); + r = (struct libj2_j2u){111, 222}; a = (struct libj2_j2u){.high = a_high, .low = a_low}; EXPECT(libj2_ju_sub_j2u_to_j2u_overflow(b, &a, &r) == expected_roverflow); @@ -97,7 +107,12 @@ check(uintmax_t a_high, uintmax_t a_low, uintmax_t b) a = (struct libj2_j2u){.high = a_high, .low = a_low}; EXPECT(libj2_ju_sub_j2u_to_j2u_overflow(b, &a, &a) == expected_roverflow); libj2_minus_j2u(&a); - EXPECT(libj2_j2u_eq_j2u(&a, &expected)); + EXPECT(libj2_j2u_eq_j2u(&a, &expected));; + + a = (struct libj2_j2u){.high = a_high, .low = a_low}; + EXPECT(libj2_ju_sub_j2u_overflow_p(b, (const struct libj2_j2u *)&a) == expected_roverflow); + EXPECT(a.high == a_high); + EXPECT(a.low == a_low); } diff --git a/libj2_j2u_sub_ju_overflow_p.c b/libj2_j2u_sub_ju_overflow_p.c new file mode 100644 index 0000000..54b037d --- /dev/null +++ b/libj2_j2u_sub_ju_overflow_p.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_j2u_sub_ju_overflow_p(const struct libj2_j2u *a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_ju.c */ + +#endif diff --git a/libj2_ju_add_j2u_overflow_p.c b/libj2_ju_add_j2u_overflow_p.c new file mode 100644 index 0000000..bc827c8 --- /dev/null +++ b/libj2_ju_add_j2u_overflow_p.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_ju_add_j2u_overflow_p(uintmax_t a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_add_ju.c */ + +#endif diff --git a/libj2_ju_lsh_overflow_p.c b/libj2_ju_lsh_overflow_p.c new file mode 100644 index 0000000..a10491c --- /dev/null +++ b/libj2_ju_lsh_overflow_p.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_ju_lsh_overflow_p(uintmax_t a, unsigned b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_ju_lsh_to_j2u.c */ + +#endif diff --git a/libj2_ju_lsh_to_j2u.c b/libj2_ju_lsh_to_j2u.c index 82aa61f..ca05fbf 100644 --- a/libj2_ju_lsh_to_j2u.c +++ b/libj2_ju_lsh_to_j2u.c @@ -142,6 +142,8 @@ check(const char *pattern) r = (struct libj2_j2u){111, 222}; EXPECT(libj2_ju_lsh_to_j2u_overflow(a.low, i, &r) == overflows); EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + EXPECT(libj2_ju_lsh_overflow_p(a.low, i) == overflows); } } diff --git a/libj2_ju_mul_j2u_overflow_p.c b/libj2_ju_mul_j2u_overflow_p.c new file mode 100644 index 0000000..93a6328 --- /dev/null +++ b/libj2_ju_mul_j2u_overflow_p.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_ju_mul_j2u_overflow_p(uintmax_t a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_ju.c */ + +#endif diff --git a/libj2_ju_mul_j2u_overflow_p_quick.c b/libj2_ju_mul_j2u_overflow_p_quick.c new file mode 100644 index 0000000..8e7a71d --- /dev/null +++ b/libj2_ju_mul_j2u_overflow_p_quick.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline enum libj2_overflow libj2_ju_mul_j2u_overflow_p_quick(uintmax_t a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_ju.c */ + +#endif diff --git a/libj2_ju_mul_j2u_to_j2u_overflow_p.c b/libj2_ju_mul_j2u_to_j2u_overflow_p.c new file mode 100644 index 0000000..2cd8d72 --- /dev/null +++ b/libj2_ju_mul_j2u_to_j2u_overflow_p.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_ju_mul_j2u_to_j2u_overflow_p(uintmax_t a, const struct libj2_j2u *b, struct libj2_j2u *res, int *res_set); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_mul_ju.c */ + +#endif diff --git a/libj2_ju_rsh_to_j2u.c b/libj2_ju_rsh_to_j2u.c index 7c5913f..5c4c891 100644 --- a/libj2_ju_rsh_to_j2u.c +++ b/libj2_ju_rsh_to_j2u.c @@ -93,6 +93,8 @@ check(const char *pattern) r = (struct libj2_j2u){111, 222}; EXPECT(libj2_ju_rsh_to_j2u_underflow(a.low, i, &r) == underflows); EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + EXPECT(libj2_ju_rsh_underflow_p(a.low, i) == underflows); } } diff --git a/libj2_ju_rsh_underflow_p.c b/libj2_ju_rsh_underflow_p.c new file mode 100644 index 0000000..e5bd73d --- /dev/null +++ b/libj2_ju_rsh_underflow_p.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_ju_rsh_underflow_p(uintmax_t a, unsigned b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_ju_rsh_to_j2u.c */ + +#endif diff --git a/libj2_ju_sub_j2u_overflow_p.c b/libj2_ju_sub_j2u_overflow_p.c new file mode 100644 index 0000000..90fe79c --- /dev/null +++ b/libj2_ju_sub_j2u_overflow_p.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_ju_sub_j2u_overflow_p(uintmax_t a, const struct libj2_j2u *b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_j2u_sub_ju.c */ + +#endif diff --git a/libj2_ju_sub_ju_overflow_p.c b/libj2_ju_sub_ju_overflow_p.c new file mode 100644 index 0000000..05bc298 --- /dev/null +++ b/libj2_ju_sub_ju_overflow_p.c @@ -0,0 +1,13 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libj2_ju_sub_ju_overflow_p(uintmax_t a, uintmax_t b); +/* TODO Add man page */ + + +#else + +CONST int main(void) { return 0; } /* Tested in libj2_ju_sub_ju_to_j2u.c */ + +#endif diff --git a/libj2_ju_sub_ju_to_j2u.c b/libj2_ju_sub_ju_to_j2u.c index b61e96a..5de5046 100644 --- a/libj2_ju_sub_ju_to_j2u.c +++ b/libj2_ju_sub_ju_to_j2u.c @@ -36,6 +36,8 @@ check(uintmax_t a, uintmax_t b) r = (struct libj2_j2u){111, 222}; EXPECT(libj2_ju_sub_ju_to_j2u_overflow(a, b, &r) == expected_overflow); EXPECT(libj2_j2u_eq_j2u(&r, &expected)); + + EXPECT(libj2_ju_sub_ju_overflow_p(a, b) == expected_overflow); } |
