|
35 | 35 | #include <SafeInt.hpp> |
36 | 36 | #endif |
37 | 37 |
|
38 | | -namespace mongo { |
| 38 | +#include "mongo/stdx/type_traits.h" |
39 | 39 |
|
40 | | -/** |
41 | | - * Returns true if multiplying lhs by rhs would overflow. Otherwise, multiplies 64-bit signed |
42 | | - * or unsigned integers lhs by rhs and stores the result in *product. |
43 | | - */ |
44 | | -constexpr bool mongoSignedMultiplyOverflow64(int64_t lhs, int64_t rhs, int64_t* product); |
45 | | -constexpr bool mongoUnsignedMultiplyOverflow64(uint64_t lhs, uint64_t rhs, uint64_t* product); |
| 40 | +namespace mongo::overflow { |
46 | 41 |
|
47 | 42 | /** |
48 | | - * Returns true if adding lhs and rhs would overflow. Otherwise, adds 64-bit signed or unsigned |
49 | | - * integers lhs and rhs and stores the result in *sum. |
50 | | - */ |
51 | | -constexpr bool mongoSignedAddOverflow64(int64_t lhs, int64_t rhs, int64_t* sum); |
52 | | -constexpr bool mongoUnsignedAddOverflow64(uint64_t lhs, uint64_t rhs, uint64_t* sum); |
53 | | - |
54 | | -/** |
55 | | - * Returns true if subtracting rhs from lhs would overflow. Otherwise, subtracts 64-bit signed or |
56 | | - * unsigned integers rhs from lhs and stores the result in *difference. |
| 43 | + * Synopsis: |
| 44 | + * |
| 45 | + * bool mul(A a, A b, T* r); |
| 46 | + * bool add(A a, A b, T* r); |
| 47 | + * bool sub(A a, A b, T* r); |
| 48 | + * |
| 49 | + * The domain type `A` evaluates to `T`, which is deduced from the `r` parameter. |
| 50 | + * That is, the input parameters are coerced into the type accepted by the output parameter. |
| 51 | + * All functions return true if operation would overflow, otherwise they store result in `*r`. |
57 | 52 | */ |
58 | | -constexpr bool mongoSignedSubtractOverflow64(int64_t lhs, int64_t rhs, int64_t* difference); |
59 | | -constexpr bool mongoUnsignedSubtractOverflow64(uint64_t lhs, uint64_t rhs, uint64_t* difference); |
60 | 53 |
|
| 54 | +// MSVC : The SafeInt functions return false on overflow. |
| 55 | +// GCC, Clang: The __builtin_*_overflow functions return true on overflow. |
61 | 56 |
|
| 57 | +template <typename T> |
| 58 | +constexpr bool mul(stdx::type_identity_t<T> a, stdx::type_identity_t<T> b, T* r) { |
62 | 59 | #ifdef _MSC_VER |
63 | | - |
64 | | -// The SafeInt functions return true on success, false on overflow. |
65 | | - |
66 | | -constexpr bool mongoSignedMultiplyOverflow64(int64_t lhs, int64_t rhs, int64_t* product) { |
67 | | - return !SafeMultiply(lhs, rhs, *product); |
68 | | -} |
69 | | - |
70 | | -constexpr bool mongoUnsignedMultiplyOverflow64(uint64_t lhs, uint64_t rhs, uint64_t* product) { |
71 | | - return !SafeMultiply(lhs, rhs, *product); |
72 | | -} |
73 | | - |
74 | | -constexpr bool mongoSignedAddOverflow64(int64_t lhs, int64_t rhs, int64_t* sum) { |
75 | | - return !SafeAdd(lhs, rhs, *sum); |
76 | | -} |
77 | | - |
78 | | -constexpr bool mongoUnsignedAddOverflow64(uint64_t lhs, uint64_t rhs, uint64_t* sum) { |
79 | | - return !SafeAdd(lhs, rhs, *sum); |
80 | | -} |
81 | | - |
82 | | -constexpr bool mongoSignedSubtractOverflow64(int64_t lhs, int64_t rhs, int64_t* difference) { |
83 | | - return !SafeSubtract(lhs, rhs, *difference); |
84 | | -} |
85 | | - |
86 | | -constexpr bool mongoUnsignedSubtractOverflow64(uint64_t lhs, uint64_t rhs, uint64_t* difference) { |
87 | | - return !SafeSubtract(lhs, rhs, *difference); |
88 | | -} |
89 | | - |
| 60 | + return !SafeMultiply(a, b, *r); |
90 | 61 | #else |
91 | | - |
92 | | -// On GCC and CLANG we can use __builtin functions to perform these calculations. These return true |
93 | | -// on overflow and false on success. |
94 | | - |
95 | | -constexpr bool mongoSignedMultiplyOverflow64(long lhs, long rhs, long* product) { |
96 | | - return __builtin_mul_overflow(lhs, rhs, product); |
97 | | -} |
98 | | - |
99 | | -constexpr bool mongoSignedMultiplyOverflow64(long long lhs, long long rhs, long long* product) { |
100 | | - return __builtin_mul_overflow(lhs, rhs, product); |
101 | | -} |
102 | | - |
103 | | -constexpr bool mongoUnsignedMultiplyOverflow64(unsigned long lhs, |
104 | | - unsigned long rhs, |
105 | | - unsigned long* product) { |
106 | | - return __builtin_mul_overflow(lhs, rhs, product); |
107 | | -} |
108 | | - |
109 | | -constexpr bool mongoUnsignedMultiplyOverflow64(unsigned long long lhs, |
110 | | - unsigned long long rhs, |
111 | | - unsigned long long* product) { |
112 | | - return __builtin_mul_overflow(lhs, rhs, product); |
113 | | -} |
114 | | - |
115 | | -constexpr bool mongoSignedAddOverflow64(long lhs, long rhs, long* sum) { |
116 | | - return __builtin_add_overflow(lhs, rhs, sum); |
117 | | -} |
118 | | - |
119 | | -constexpr bool mongoSignedAddOverflow64(long long lhs, long long rhs, long long* sum) { |
120 | | - return __builtin_add_overflow(lhs, rhs, sum); |
121 | | -} |
122 | | - |
123 | | -constexpr bool mongoUnsignedAddOverflow64(unsigned long lhs, |
124 | | - unsigned long rhs, |
125 | | - unsigned long* sum) { |
126 | | - return __builtin_add_overflow(lhs, rhs, sum); |
127 | | -} |
128 | | - |
129 | | -constexpr bool mongoUnsignedAddOverflow64(unsigned long long lhs, |
130 | | - unsigned long long rhs, |
131 | | - unsigned long long* sum) { |
132 | | - return __builtin_add_overflow(lhs, rhs, sum); |
133 | | -} |
134 | | - |
135 | | -constexpr bool mongoSignedSubtractOverflow64(long lhs, long rhs, long* difference) { |
136 | | - return __builtin_sub_overflow(lhs, rhs, difference); |
137 | | -} |
138 | | - |
139 | | -constexpr bool mongoSignedSubtractOverflow64(long long lhs, long long rhs, long long* difference) { |
140 | | - return __builtin_sub_overflow(lhs, rhs, difference); |
141 | | -} |
142 | | - |
143 | | -constexpr bool mongoUnsignedSubtractOverflow64(unsigned long lhs, |
144 | | - unsigned long rhs, |
145 | | - unsigned long* sum) { |
146 | | - return __builtin_sub_overflow(lhs, rhs, sum); |
| 62 | + return __builtin_mul_overflow(a, b, r); |
| 63 | +#endif |
147 | 64 | } |
148 | 65 |
|
149 | | -constexpr bool mongoUnsignedSubtractOverflow64(unsigned long long lhs, |
150 | | - unsigned long long rhs, |
151 | | - unsigned long long* sum) { |
152 | | - return __builtin_sub_overflow(lhs, rhs, sum); |
| 66 | +template <typename T> |
| 67 | +constexpr bool add(stdx::type_identity_t<T> a, stdx::type_identity_t<T> b, T* r) { |
| 68 | +#ifdef _MSC_VER |
| 69 | + return !SafeAdd(a, b, *r); |
| 70 | +#else |
| 71 | + return __builtin_add_overflow(a, b, r); |
| 72 | +#endif |
153 | 73 | } |
154 | 74 |
|
| 75 | +template <typename T> |
| 76 | +constexpr bool sub(stdx::type_identity_t<T> a, stdx::type_identity_t<T> b, T* r) { |
| 77 | +#ifdef _MSC_VER |
| 78 | + return !SafeSubtract(a, b, *r); |
| 79 | +#else |
| 80 | + return __builtin_sub_overflow(a, b, r); |
155 | 81 | #endif |
| 82 | +} |
156 | 83 |
|
157 | | -} // namespace mongo |
| 84 | +} // namespace mongo::overflow |
0 commit comments