#ifndef R_TYPES_OVERFLOW_H #define R_TYPES_OVERFLOW_H #ifdef __cplusplus extern "C" { #endif #if defined(__has_builtin) # if __has_builtin(__builtin_add_overflow) && \ __has_builtin(__builtin_sub_overflow) && \ __has_builtin(__builtin_mul_overflow) # define R_HAVE_BUILTIN_OVERFLOW 1 # endif #endif #if defined(__GNUC__) && !defined(R_HAVE_BUILTIN_OVERFLOW) # define R_HAVE_BUILTIN_OVERFLOW 1 #endif #define R_DEFINE_UNSIGNED_OVERFLOW(T, TMAX) \ static inline bool r_add_overflow_##T(T a, T b, T *res) { \ *res = a + b; \ return *res < a; \ } \ static inline bool r_sub_overflow_##T(T a, T b, T *res) { \ *res = a - b; \ return a < b; \ } \ static inline bool r_mul_overflow_##T(T a, T b, T *res) { \ if (a == 0 || b == 0) { \ *res = 0; \ return false; \ } \ if (a > (TMAX) / b) { \ return true; \ } \ *res = a * b; \ return false; \ } #define R_DEFINE_SIGNED_OVERFLOW(T, TMAX, TMIN) \ static inline bool r_add_overflow_##T(T a, T b, T *res) { \ if ((b > 0 && a > (TMAX) - b) || \ (b < 0 && a < (TMIN) - b)) { \ return true; \ } \ *res = a + b; \ return false; \ } \ static inline bool r_sub_overflow_##T(T a, T b, T *res) { \ if ((b < 0 && a > (TMAX) + b) || \ (b > 0 && a < (TMIN) + b)) { \ return true; \ } \ *res = a - b; \ return false; \ } \ static inline bool r_mul_overflow_##T(T a, T b, T *res) { \ if (a == 0 || b == 0) { \ *res = 0; \ return false; \ } \ if (a == -1 && b == (TMIN)) { return true; } \ if (b == -1 && a == (TMIN)) { return true; } \ if (a > 0) { \ if (b > 0) { \ if (a > (TMAX) / b) { return true; } \ } else { \ if (b < (TMIN) / a) { return true; } \ } \ } else { \ if (b > 0) { \ if (a < (TMIN) / b) { return true; } \ } else { \ if (a != 0 && b < (TMAX) / a) { return true; } \ } \ } \ *res = a * b; \ return false; \ } R_DEFINE_UNSIGNED_OVERFLOW(ut8, UT8_MAX) R_DEFINE_UNSIGNED_OVERFLOW(ut16, UT16_MAX) R_DEFINE_UNSIGNED_OVERFLOW(ut32, UT32_MAX) R_DEFINE_UNSIGNED_OVERFLOW(ut64, UT64_MAX) R_DEFINE_UNSIGNED_OVERFLOW(size_t, SIZE_MAX) R_DEFINE_SIGNED_OVERFLOW(st8, ST8_MAX, ST8_MIN) R_DEFINE_SIGNED_OVERFLOW(st16, ST16_MAX, ST16_MIN) R_DEFINE_SIGNED_OVERFLOW(st32, ST32_MAX, ST32_MIN) R_DEFINE_SIGNED_OVERFLOW(st64, ST64_MAX, ST64_MIN) // ssize_t overflow not supported: use st32/st64 instead (MSVC lacks ssize_t) #if R_HAVE_BUILTIN_OVERFLOW #define r_add_overflow(a,b,res) __builtin_add_overflow((a),(b),(res)) #define r_sub_overflow(a,b,res) __builtin_sub_overflow((a),(b),(res)) #define r_mul_overflow(a,b,res) __builtin_mul_overflow((a),(b),(res)) #elif defined(_MSC_VER) || !defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112L #define r_add_overflow(a,b,res) \ (sizeof(*(res)) == 1 && sizeof(a) == 1 && sizeof(b) == 1 \ ? (*(res) = (a) + (b), *(res) < (a)) \ : (sizeof(*(res)) == 2 ? r_add_overflow_ut16((ut16)(a), (ut16)(b), (ut16*)(res)) \ : (sizeof(*(res)) == 4 ? r_add_overflow_ut32((ut32)(a), (ut32)(b), (ut32*)(res)) \ : r_add_overflow_ut64((ut64)(a), (ut64)(b), (ut64*)(res))))) #define r_sub_overflow(a,b,res) \ (sizeof(*(res)) == 1 && sizeof(a) == 1 && sizeof(b) == 1 \ ? (*(res) = (a) - (b), (a) < (b)) \ : (sizeof(*(res)) == 2 ? r_sub_overflow_ut16((ut16)(a), (ut16)(b), (ut16*)(res)) \ : (sizeof(*(res)) == 4 ? r_sub_overflow_ut32((ut32)(a), (ut32)(b), (ut32*)(res)) \ : r_sub_overflow_ut64((ut64)(a), (ut64)(b), (ut64*)(res))))) #define r_mul_overflow(a,b,res) \ (sizeof(*(res)) == 1 && sizeof(a) == 1 && sizeof(b) == 1 \ ? r_mul_overflow_ut8((ut8)(a), (ut8)(b), (ut8*)(res)) \ : (sizeof(*(res)) == 2 ? r_mul_overflow_ut16((ut16)(a), (ut16)(b), (ut16*)(res)) \ : (sizeof(*(res)) == 4 ? r_mul_overflow_ut32((ut32)(a), (ut32)(b), (ut32*)(res)) \ : r_mul_overflow_ut64((ut64)(a), (ut64)(b), (ut64*)(res))))) #else #define r_add_overflow(a,b,res) _Generic(*(res), \ ut8: r_add_overflow_ut8, \ ut16: r_add_overflow_ut16, \ ut32: r_add_overflow_ut32, \ ut64: r_add_overflow_ut64, \ size_t: r_add_overflow_size_t, \ st8: r_add_overflow_st8, \ st16: r_add_overflow_st16, \ st32: r_add_overflow_st32, \ st64: r_add_overflow_st64 \ )(a,b,res) #define r_sub_overflow(a,b,res) _Generic(*(res), \ ut8: r_sub_overflow_ut8, \ ut16: r_sub_overflow_ut16, \ ut32: r_sub_overflow_ut32, \ ut64: r_sub_overflow_ut64, \ size_t: r_sub_overflow_size_t, \ st8: r_sub_overflow_st8, \ st16: r_sub_overflow_st16, \ st32: r_sub_overflow_st32, \ st64: r_sub_overflow_st64 \ )(a,b,res) #define r_mul_overflow(a,b,res) _Generic(*(res), \ ut8: r_mul_overflow_ut8, \ ut16: r_mul_overflow_ut16, \ ut32: r_mul_overflow_ut32, \ ut64: r_mul_overflow_ut64, \ size_t: r_mul_overflow_size_t, \ st8: r_mul_overflow_st8, \ st16: r_mul_overflow_st16, \ st32: r_mul_overflow_st32, \ st64: r_mul_overflow_st64 \ )(a,b,res) #endif static inline bool r_div_overflow_st8(st8 a, st8 b) { return (!b || (a == ST8_MIN && b == -1)); } static inline bool r_div_overflow_st16(st16 a, st16 b) { return (!b || (a == ST16_MIN && b == -1)); } static inline bool r_div_overflow_st32(st32 a, st32 b) { return (!b || (a == ST32_MIN && b == -1)); } static inline bool r_div_overflow_st64(st64 a, st64 b) { return (!b || (a == ST64_MIN && b == -1)); } static inline bool r_div_overflow_ut8(ut8 a, ut8 b) { (void)(a); return !b; } static inline bool r_div_overflow_ut16(ut16 a, ut16 b) { (void)(a); return !b; } static inline bool r_div_overflow_ut32(ut32 a, ut32 b) { (void)(a); return !b; } static inline bool r_div_overflow_ut64(ut64 a, ut64 b) { (void)(a); return !b; } #ifdef __cplusplus } #endif #endif