Line data Source code
1 : #ifndef AWS_COMMON_MATH_INL
2 : #define AWS_COMMON_MATH_INL
3 :
4 : /**
5 : * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
6 : * SPDX-License-Identifier: Apache-2.0.
7 : */
8 :
9 : #include <aws/common/common.h>
10 : #include <aws/common/config.h>
11 : #include <aws/common/math.h>
12 :
13 : #include <limits.h>
14 : #include <stdlib.h>
15 :
16 : AWS_EXTERN_C_BEGIN
17 :
18 : #if defined(AWS_HAVE_GCC_OVERFLOW_MATH_EXTENSIONS) && (defined(__clang__) || !defined(__cplusplus))
19 : /*
20 : * GCC and clang have these super convenient overflow checking builtins...
21 : * but (in the case of GCC) they're only available when building C source.
22 : * We'll fall back to one of the other inlinable variants (or a non-inlined version)
23 : * if we are building this header on G++.
24 : */
25 : # include <aws/common/math.gcc_overflow.inl>
26 : #elif defined(__x86_64__) && defined(AWS_HAVE_GCC_INLINE_ASM)
27 : # include <aws/common/math.gcc_x64_asm.inl>
28 : #elif defined(__aarch64__) && defined(AWS_HAVE_GCC_INLINE_ASM)
29 : # include <aws/common/math.gcc_arm64_asm.inl>
30 : #elif defined(AWS_HAVE_MSVC_MULX)
31 : # include <aws/common/math.msvc.inl>
32 : #elif defined(CBMC)
33 : # include <aws/common/math.cbmc.inl>
34 : #else
35 : # ifndef AWS_HAVE_GCC_OVERFLOW_MATH_EXTENSIONS
36 : /* Fall back to the pure-C implementations */
37 : # include <aws/common/math.fallback.inl>
38 : # else
39 : /*
40 : * We got here because we are building in C++ mode but we only support overflow extensions
41 : * in C mode. Because the fallback is _slow_ (involving a division), we'd prefer to make a
42 : * non-inline call to the fast C intrinsics.
43 : */
44 : # endif /* AWS_HAVE_GCC_OVERFLOW_MATH_EXTENSIONS */
45 : #endif /* defined(AWS_HAVE_GCC_OVERFLOW_MATH_EXTENSIONS) && (defined(__clang__) || !defined(__cplusplus)) */
46 :
47 : #if defined(__clang__) || defined(__GNUC__)
48 : # include <aws/common/math.gcc_builtin.inl>
49 : #endif
50 :
51 : #if _MSC_VER
52 : # pragma warning(push)
53 : # pragma warning(disable : 4127) /*Disable "conditional expression is constant" */
54 : #endif /* _MSC_VER */
55 :
56 0 : AWS_STATIC_IMPL uint64_t aws_sub_u64_saturating(uint64_t a, uint64_t b) {
57 0 : return a <= b ? 0 : a - b;
58 0 : }
59 :
60 0 : AWS_STATIC_IMPL int aws_sub_u64_checked(uint64_t a, uint64_t b, uint64_t *r) {
61 0 : if (a < b) {
62 0 : return aws_raise_error(AWS_ERROR_OVERFLOW_DETECTED);
63 0 : }
64 0 :
65 0 : *r = a - b;
66 0 : return AWS_OP_SUCCESS;
67 0 : }
68 :
69 0 : AWS_STATIC_IMPL uint32_t aws_sub_u32_saturating(uint32_t a, uint32_t b) {
70 0 : return a <= b ? 0 : a - b;
71 0 : }
72 :
73 0 : AWS_STATIC_IMPL int aws_sub_u32_checked(uint32_t a, uint32_t b, uint32_t *r) {
74 0 : if (a < b) {
75 0 : return aws_raise_error(AWS_ERROR_OVERFLOW_DETECTED);
76 0 : }
77 0 :
78 0 : *r = a - b;
79 0 : return AWS_OP_SUCCESS;
80 0 : }
81 :
82 : /**
83 : * Multiplies a * b. If the result overflows, returns SIZE_MAX.
84 : */
85 0 : AWS_STATIC_IMPL size_t aws_mul_size_saturating(size_t a, size_t b) {
86 0 : #if SIZE_BITS == 32
87 0 : return (size_t)aws_mul_u32_saturating(a, b);
88 0 : #elif SIZE_BITS == 64
89 0 : return (size_t)aws_mul_u64_saturating(a, b);
90 0 : #else
91 0 : # error "Target not supported"
92 0 : #endif
93 0 : }
94 :
95 : /**
96 : * Multiplies a * b and returns the result in *r. If the result
97 : * overflows, returns AWS_OP_ERR; otherwise returns AWS_OP_SUCCESS.
98 : */
99 8326111 : AWS_STATIC_IMPL int aws_mul_size_checked(size_t a, size_t b, size_t *r) {
100 0 : #if SIZE_BITS == 32
101 0 : return aws_mul_u32_checked(a, b, (uint32_t *)r);
102 0 : #elif SIZE_BITS == 64
103 0 : return aws_mul_u64_checked(a, b, (uint64_t *)r);
104 0 : #else
105 0 : # error "Target not supported"
106 0 : #endif
107 0 : }
108 :
109 : /**
110 : * Adds a + b. If the result overflows returns SIZE_MAX.
111 : */
112 81166 : AWS_STATIC_IMPL size_t aws_add_size_saturating(size_t a, size_t b) {
113 0 : #if SIZE_BITS == 32
114 0 : return (size_t)aws_add_u32_saturating(a, b);
115 0 : #elif SIZE_BITS == 64
116 0 : return (size_t)aws_add_u64_saturating(a, b);
117 0 : #else
118 0 : # error "Target not supported"
119 0 : #endif
120 0 : }
121 :
122 : /**
123 : * Adds a + b and returns the result in *r. If the result
124 : * overflows, returns AWS_OP_ERR; otherwise returns AWS_OP_SUCCESS.
125 : */
126 2951679 : AWS_STATIC_IMPL int aws_add_size_checked(size_t a, size_t b, size_t *r) {
127 0 : #if SIZE_BITS == 32
128 0 : return aws_add_u32_checked(a, b, (uint32_t *)r);
129 0 : #elif SIZE_BITS == 64
130 0 : return aws_add_u64_checked(a, b, (uint64_t *)r);
131 0 : #else
132 0 : # error "Target not supported"
133 0 : #endif
134 0 : }
135 :
136 0 : AWS_STATIC_IMPL size_t aws_sub_size_saturating(size_t a, size_t b) {
137 0 : #if SIZE_BITS == 32
138 0 : return (size_t)aws_sub_u32_saturating(a, b);
139 0 : #elif SIZE_BITS == 64
140 0 : return (size_t)aws_sub_u64_saturating(a, b);
141 0 : #else
142 0 : # error "Target not supported"
143 0 : #endif
144 0 : }
145 :
146 0 : AWS_STATIC_IMPL int aws_sub_size_checked(size_t a, size_t b, size_t *r) {
147 0 : #if SIZE_BITS == 32
148 0 : return aws_sub_u32_checked(a, b, (uint32_t *)r);
149 0 : #elif SIZE_BITS == 64
150 0 : return aws_sub_u64_checked(a, b, (uint64_t *)r);
151 0 : #else
152 0 : # error "Target not supported"
153 0 : #endif
154 0 : }
155 :
156 : /**
157 : * Function to check if x is power of 2
158 : */
159 2473707 : AWS_STATIC_IMPL bool aws_is_power_of_two(const size_t x) {
160 2473707 : /* First x in the below expression is for the case when x is 0 */
161 2473707 : return x && (!(x & (x - 1)));
162 2473707 : }
163 :
164 : /**
165 : * Function to find the smallest result that is power of 2 >= n. Returns AWS_OP_ERR if this cannot
166 : * be done without overflow
167 : */
168 2332051 : AWS_STATIC_IMPL int aws_round_up_to_power_of_two(size_t n, size_t *result) {
169 2332051 : if (n == 0) {
170 892826 : *result = 1;
171 892826 : return AWS_OP_SUCCESS;
172 892826 : }
173 1439225 : if (n > SIZE_MAX_POWER_OF_TWO) {
174 0 : return aws_raise_error(AWS_ERROR_OVERFLOW_DETECTED);
175 0 : }
176 1439225 :
177 1439225 : n--;
178 1439225 : n |= n >> 1;
179 1439225 : n |= n >> 2;
180 1439225 : n |= n >> 4;
181 1439225 : n |= n >> 8;
182 1439225 : n |= n >> 16;
183 1439225 : #if SIZE_BITS == 64
184 1439225 : n |= n >> 32;
185 1439225 : #endif
186 1439225 : n++;
187 1439225 : *result = n;
188 1439225 : return AWS_OP_SUCCESS;
189 1439225 : }
190 :
191 : #if _MSC_VER
192 : # pragma warning(pop)
193 : #endif /* _MSC_VER */
194 :
195 0 : AWS_STATIC_IMPL uint8_t aws_min_u8(uint8_t a, uint8_t b) {
196 0 : return a < b ? a : b;
197 0 : }
198 :
199 0 : AWS_STATIC_IMPL uint8_t aws_max_u8(uint8_t a, uint8_t b) {
200 0 : return a > b ? a : b;
201 0 : }
202 :
203 0 : AWS_STATIC_IMPL int8_t aws_min_i8(int8_t a, int8_t b) {
204 0 : return a < b ? a : b;
205 0 : }
206 :
207 0 : AWS_STATIC_IMPL int8_t aws_max_i8(int8_t a, int8_t b) {
208 0 : return a > b ? a : b;
209 0 : }
210 :
211 0 : AWS_STATIC_IMPL uint16_t aws_min_u16(uint16_t a, uint16_t b) {
212 0 : return a < b ? a : b;
213 0 : }
214 :
215 0 : AWS_STATIC_IMPL uint16_t aws_max_u16(uint16_t a, uint16_t b) {
216 0 : return a > b ? a : b;
217 0 : }
218 :
219 0 : AWS_STATIC_IMPL int16_t aws_min_i16(int16_t a, int16_t b) {
220 0 : return a < b ? a : b;
221 0 : }
222 :
223 0 : AWS_STATIC_IMPL int16_t aws_max_i16(int16_t a, int16_t b) {
224 0 : return a > b ? a : b;
225 0 : }
226 :
227 0 : AWS_STATIC_IMPL uint32_t aws_min_u32(uint32_t a, uint32_t b) {
228 0 : return a < b ? a : b;
229 0 : }
230 :
231 0 : AWS_STATIC_IMPL uint32_t aws_max_u32(uint32_t a, uint32_t b) {
232 0 : return a > b ? a : b;
233 0 : }
234 :
235 0 : AWS_STATIC_IMPL int32_t aws_min_i32(int32_t a, int32_t b) {
236 0 : return a < b ? a : b;
237 0 : }
238 :
239 0 : AWS_STATIC_IMPL int32_t aws_max_i32(int32_t a, int32_t b) {
240 0 : return a > b ? a : b;
241 0 : }
242 :
243 0 : AWS_STATIC_IMPL uint64_t aws_min_u64(uint64_t a, uint64_t b) {
244 0 : return a < b ? a : b;
245 0 : }
246 :
247 0 : AWS_STATIC_IMPL uint64_t aws_max_u64(uint64_t a, uint64_t b) {
248 0 : return a > b ? a : b;
249 0 : }
250 :
251 0 : AWS_STATIC_IMPL int64_t aws_min_i64(int64_t a, int64_t b) {
252 0 : return a < b ? a : b;
253 0 : }
254 :
255 0 : AWS_STATIC_IMPL int64_t aws_max_i64(int64_t a, int64_t b) {
256 0 : return a > b ? a : b;
257 0 : }
258 :
259 0 : AWS_STATIC_IMPL size_t aws_min_size(size_t a, size_t b) {
260 0 : return a < b ? a : b;
261 0 : }
262 :
263 0 : AWS_STATIC_IMPL size_t aws_max_size(size_t a, size_t b) {
264 0 : return a > b ? a : b;
265 0 : }
266 :
267 0 : AWS_STATIC_IMPL int aws_min_int(int a, int b) {
268 0 : return a < b ? a : b;
269 0 : }
270 :
271 0 : AWS_STATIC_IMPL int aws_max_int(int a, int b) {
272 0 : return a > b ? a : b;
273 0 : }
274 :
275 0 : AWS_STATIC_IMPL float aws_min_float(float a, float b) {
276 0 : return a < b ? a : b;
277 0 : }
278 :
279 0 : AWS_STATIC_IMPL float aws_max_float(float a, float b) {
280 0 : return a > b ? a : b;
281 0 : }
282 :
283 0 : AWS_STATIC_IMPL double aws_min_double(double a, double b) {
284 0 : return a < b ? a : b;
285 0 : }
286 :
287 0 : AWS_STATIC_IMPL double aws_max_double(double a, double b) {
288 0 : return a > b ? a : b;
289 0 : }
290 :
291 : AWS_EXTERN_C_END
292 :
293 : #endif /* AWS_COMMON_MATH_INL */
|