| 1 | #pragma once |
| 2 | |
| 3 | namespace common |
| 4 | { |
| 5 | template <typename T> |
| 6 | inline bool addOverflow(T x, T y, T & res) |
| 7 | { |
| 8 | return __builtin_add_overflow(x, y, &res); |
| 9 | } |
| 10 | |
| 11 | template <> |
| 12 | inline bool addOverflow(int x, int y, int & res) |
| 13 | { |
| 14 | return __builtin_sadd_overflow(x, y, &res); |
| 15 | } |
| 16 | |
| 17 | template <> |
| 18 | inline bool addOverflow(long x, long y, long & res) |
| 19 | { |
| 20 | return __builtin_saddl_overflow(x, y, &res); |
| 21 | } |
| 22 | |
| 23 | template <> |
| 24 | inline bool addOverflow(long long x, long long y, long long & res) |
| 25 | { |
| 26 | return __builtin_saddll_overflow(x, y, &res); |
| 27 | } |
| 28 | |
| 29 | template <> |
| 30 | inline bool addOverflow(__int128 x, __int128 y, __int128 & res) |
| 31 | { |
| 32 | static constexpr __int128 min_int128 = __int128(0x8000000000000000ll) << 64; |
| 33 | static constexpr __int128 max_int128 = (__int128(0x7fffffffffffffffll) << 64) + 0xffffffffffffffffll; |
| 34 | res = x + y; |
| 35 | return (y > 0 && x > max_int128 - y) || (y < 0 && x < min_int128 - y); |
| 36 | } |
| 37 | |
| 38 | template <typename T> |
| 39 | inline bool subOverflow(T x, T y, T & res) |
| 40 | { |
| 41 | return __builtin_sub_overflow(x, y, &res); |
| 42 | } |
| 43 | |
| 44 | template <> |
| 45 | inline bool subOverflow(int x, int y, int & res) |
| 46 | { |
| 47 | return __builtin_ssub_overflow(x, y, &res); |
| 48 | } |
| 49 | |
| 50 | template <> |
| 51 | inline bool subOverflow(long x, long y, long & res) |
| 52 | { |
| 53 | return __builtin_ssubl_overflow(x, y, &res); |
| 54 | } |
| 55 | |
| 56 | template <> |
| 57 | inline bool subOverflow(long long x, long long y, long long & res) |
| 58 | { |
| 59 | return __builtin_ssubll_overflow(x, y, &res); |
| 60 | } |
| 61 | |
| 62 | template <> |
| 63 | inline bool subOverflow(__int128 x, __int128 y, __int128 & res) |
| 64 | { |
| 65 | static constexpr __int128 min_int128 = __int128(0x8000000000000000ll) << 64; |
| 66 | static constexpr __int128 max_int128 = (__int128(0x7fffffffffffffffll) << 64) + 0xffffffffffffffffll; |
| 67 | res = x - y; |
| 68 | return (y < 0 && x > max_int128 + y) || (y > 0 && x < min_int128 + y); |
| 69 | } |
| 70 | |
| 71 | template <typename T> |
| 72 | inline bool mulOverflow(T x, T y, T & res) |
| 73 | { |
| 74 | return __builtin_mul_overflow(x, y, &res); |
| 75 | } |
| 76 | |
| 77 | template <> |
| 78 | inline bool mulOverflow(int x, int y, int & res) |
| 79 | { |
| 80 | return __builtin_smul_overflow(x, y, &res); |
| 81 | } |
| 82 | |
| 83 | template <> |
| 84 | inline bool mulOverflow(long x, long y, long & res) |
| 85 | { |
| 86 | return __builtin_smull_overflow(x, y, &res); |
| 87 | } |
| 88 | |
| 89 | template <> |
| 90 | inline bool mulOverflow(long long x, long long y, long long & res) |
| 91 | { |
| 92 | return __builtin_smulll_overflow(x, y, &res); |
| 93 | } |
| 94 | |
| 95 | template <> |
| 96 | inline bool mulOverflow(__int128 x, __int128 y, __int128 & res) |
| 97 | { |
| 98 | res = static_cast<unsigned __int128>(x) * static_cast<unsigned __int128>(y); /// Avoid signed integer overflow. |
| 99 | if (!x || !y) |
| 100 | return false; |
| 101 | |
| 102 | unsigned __int128 a = (x > 0) ? x : -x; |
| 103 | unsigned __int128 b = (y > 0) ? y : -y; |
| 104 | return (a * b) / b != a; |
| 105 | } |
| 106 | } |
| 107 | |