diff options
| -rw-r--r-- | include/mruby/numeric.h | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/include/mruby/numeric.h b/include/mruby/numeric.h index 94cdbccee..237119bf2 100644 --- a/include/mruby/numeric.h +++ b/include/mruby/numeric.h @@ -36,6 +36,47 @@ mrb_value mrb_num_div(mrb_state *mrb, mrb_value x, mrb_value y); # define MRB_INT_OVERFLOW_MASK ((mrb_uint)1 << (MRB_INT_BIT - 1)) #endif +/* Idea from Potion: https://github.com/perl11/potion (MIT) */ +#if (defined(__clang__) && ((__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ >= 4))) \ + || (defined(__GNUC__) && __GNUC__ >= 5) + +static inline mrb_bool +mrb_int_add_overflow(mrb_int augend, mrb_int addend, mrb_int *sum) +{ + mrb_bool of; + +#ifdef MRB_INT64 + long long val; + of = __builtin_saddll_overflow(augend, addend, &val) || +#else + int val; + of = __builtin_sadd_overflow(augend, addend, &val) || +#endif + (val > MRB_INT_MAX) || (val < MRB_INT_MIN); + + *sum = (mrb_int) val; + return of; +} + +static inline mrb_bool +mrb_int_sub_overflow(mrb_int minuend, mrb_int subtrahend, mrb_int *difference) +{ + mrb_bool of; + +#ifdef MRB_INT64 + long long val; + of = __builtin_ssubll_overflow(minuend, subtrahend, &val) || +#else + int val; + of = __builtin_ssub_overflow(minuend, subtrahend, &val) || +#endif + (val > MRB_INT_MAX) || (val < MRB_INT_MIN); + + *difference = (mrb_int) val; + return of; +} +#else + static inline mrb_bool mrb_int_add_overflow(mrb_int augend, mrb_int addend, mrb_int *sum) { @@ -56,6 +97,8 @@ mrb_int_sub_overflow(mrb_int minuend, mrb_int subtrahend, mrb_int *difference) return !!(((x ^ z) & (~y ^ z)) & MRB_INT_OVERFLOW_MASK); } +#endif + #undef MRB_INT_OVERFLOW_MASK #undef mrb_uint #undef MRB_UINT_MAKE |
