diff options
Diffstat (limited to 'src/include/common/int.h')
-rw-r--r-- | src/include/common/int.h | 131 |
1 files changed, 123 insertions, 8 deletions
diff --git a/src/include/common/int.h b/src/include/common/int.h index 7fc046e78af..3b1590d676f 100644 --- a/src/include/common/int.h +++ b/src/include/common/int.h @@ -23,15 +23,35 @@ /*--------- * The following guidelines apply to all the overflow routines: - * - If a + b overflows, return true, otherwise store the result of a + b - * into *result. The content of *result is implementation defined in case of - * overflow. - * - If a - b overflows, return true, otherwise store the result of a - b - * into *result. The content of *result is implementation defined in case of - * overflow. - * - If a * b overflows, return true, otherwise store the result of a * b - * into *result. The content of *result is implementation defined in case of + * + * If the result overflows, return true, otherwise store the result into + * *result. The content of *result is implementation defined in case of * overflow. + * + * bool pg_add_*_overflow(a, b, *result) + * + * Calculate a + b + * + * bool pg_sub_*_overflow(a, b, *result) + * + * Calculate a - b + * + * bool pg_mul_*_overflow(a, b, *result) + * + * Calculate a * b + * + * bool pg_neg_*_overflow(a, *result) + * + * Calculate -a + * + * + * In addition, this file contains: + * + * <unsigned int type> pg_abs_*(<signed int type> a) + * + * Calculate absolute value of a. Unlike the standard library abs() + * and labs() functions, the return type is unsigned, so the operation + * cannot overflow. *--------- */ @@ -97,6 +117,17 @@ pg_mul_s16_overflow(int16 a, int16 b, int16 *result) #endif } +static inline uint16 +pg_abs_s16(int16 a) +{ + /* + * This first widens the argument from int16 to int32 for use with abs(). + * The result is then narrowed from int32 to uint16. This prevents any + * possibility of overflow. + */ + return (uint16) abs((int32) a); +} + /* * INT32 */ @@ -154,6 +185,17 @@ pg_mul_s32_overflow(int32 a, int32 b, int32 *result) #endif } +static inline uint32 +pg_abs_s32(int32 a) +{ + /* + * This first widens the argument from int32 to int64 for use with + * i64abs(). The result is then narrowed from int64 to uint32. This + * prevents any possibility of overflow. + */ + return (uint32) i64abs((int64) a); +} + /* * INT64 */ @@ -258,6 +300,14 @@ pg_mul_s64_overflow(int64 a, int64 b, int64 *result) #endif } +static inline uint64 +pg_abs_s64(int64 a) +{ + if (unlikely(a == PG_INT64_MIN)) + return (uint64) PG_INT64_MAX + 1; + return (uint64) i64abs(a); +} + /*------------------------------------------------------------------------ * Overflow routines for unsigned integers *------------------------------------------------------------------------ @@ -318,6 +368,24 @@ pg_mul_u16_overflow(uint16 a, uint16 b, uint16 *result) #endif } +static inline bool +pg_neg_u16_overflow(uint16 a, int16 *result) +{ +#if defined(HAVE__BUILTIN_OP_OVERFLOW) + return __builtin_sub_overflow(0, a, result); +#else + int32 res = -((int32) a); + + if (unlikely(res < PG_INT16_MIN)) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = res; + return false; +#endif +} + /* * INT32 */ @@ -373,6 +441,24 @@ pg_mul_u32_overflow(uint32 a, uint32 b, uint32 *result) #endif } +static inline bool +pg_neg_u32_overflow(uint32 a, int32 *result) +{ +#if defined(HAVE__BUILTIN_OP_OVERFLOW) + return __builtin_sub_overflow(0, a, result); +#else + int64 res = -((int64) a); + + if (unlikely(res < PG_INT32_MIN)) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = res; + return false; +#endif +} + /* * UINT64 */ @@ -438,6 +524,35 @@ pg_mul_u64_overflow(uint64 a, uint64 b, uint64 *result) #endif } +static inline bool +pg_neg_u64_overflow(uint64 a, int64 *result) +{ +#if defined(HAVE__BUILTIN_OP_OVERFLOW) + return __builtin_sub_overflow(0, a, result); +#elif defined(HAVE_INT128) + int128 res = -((int128) a); + + if (unlikely(res < PG_INT64_MIN)) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + *result = res; + return false; +#else + if (unlikely(a > (uint64) PG_INT64_MAX + 1)) + { + *result = 0x5EED; /* to avoid spurious warnings */ + return true; + } + if (unlikely(a == (uint64) PG_INT64_MAX + 1)) + *result = PG_INT64_MIN; + else + *result = -((int64) a); + return false; +#endif +} + /*------------------------------------------------------------------------ * * Comparison routines for integer types. |