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
16AWS_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
56AWS_STATIC_IMPL uint64_t aws_sub_u64_saturating(uint64_t a, uint64_t b) {
57    return a <= b ? 0 : a - b;
58}
59
60AWS_STATIC_IMPL int aws_sub_u64_checked(uint64_t a, uint64_t b, uint64_t *r) {
61    if (a < b) {
62        return aws_raise_error(AWS_ERROR_OVERFLOW_DETECTED);
63    }
64
65    *r = a - b;
66    return AWS_OP_SUCCESS;
67}
68
69AWS_STATIC_IMPL uint32_t aws_sub_u32_saturating(uint32_t a, uint32_t b) {
70    return a <= b ? 0 : a - b;
71}
72
73AWS_STATIC_IMPL int aws_sub_u32_checked(uint32_t a, uint32_t b, uint32_t *r) {
74    if (a < b) {
75        return aws_raise_error(AWS_ERROR_OVERFLOW_DETECTED);
76    }
77
78    *r = a - b;
79    return AWS_OP_SUCCESS;
80}
81
82/**
83 * Multiplies a * b. If the result overflows, returns SIZE_MAX.
84 */
85AWS_STATIC_IMPL size_t aws_mul_size_saturating(size_t a, size_t b) {
86#if SIZE_BITS == 32
87    return (size_t)aws_mul_u32_saturating(a, b);
88#elif SIZE_BITS == 64
89    return (size_t)aws_mul_u64_saturating(a, b);
90#else
91#    error "Target not supported"
92#endif
93}
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 */
99AWS_STATIC_IMPL int aws_mul_size_checked(size_t a, size_t b, size_t *r) {
100#if SIZE_BITS == 32
101    return aws_mul_u32_checked(a, b, (uint32_t *)r);
102#elif SIZE_BITS == 64
103    return aws_mul_u64_checked(a, b, (uint64_t *)r);
104#else
105#    error "Target not supported"
106#endif
107}
108
109/**
110 * Adds a + b.  If the result overflows returns SIZE_MAX.
111 */
112AWS_STATIC_IMPL size_t aws_add_size_saturating(size_t a, size_t b) {
113#if SIZE_BITS == 32
114    return (size_t)aws_add_u32_saturating(a, b);
115#elif SIZE_BITS == 64
116    return (size_t)aws_add_u64_saturating(a, b);
117#else
118#    error "Target not supported"
119#endif
120}
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 */
126AWS_STATIC_IMPL int aws_add_size_checked(size_t a, size_t b, size_t *r) {
127#if SIZE_BITS == 32
128    return aws_add_u32_checked(a, b, (uint32_t *)r);
129#elif SIZE_BITS == 64
130    return aws_add_u64_checked(a, b, (uint64_t *)r);
131#else
132#    error "Target not supported"
133#endif
134}
135
136AWS_STATIC_IMPL size_t aws_sub_size_saturating(size_t a, size_t b) {
137#if SIZE_BITS == 32
138    return (size_t)aws_sub_u32_saturating(a, b);
139#elif SIZE_BITS == 64
140    return (size_t)aws_sub_u64_saturating(a, b);
141#else
142#    error "Target not supported"
143#endif
144}
145
146AWS_STATIC_IMPL int aws_sub_size_checked(size_t a, size_t b, size_t *r) {
147#if SIZE_BITS == 32
148    return aws_sub_u32_checked(a, b, (uint32_t *)r);
149#elif SIZE_BITS == 64
150    return aws_sub_u64_checked(a, b, (uint64_t *)r);
151#else
152#    error "Target not supported"
153#endif
154}
155
156/**
157 * Function to check if x is power of 2
158 */
159AWS_STATIC_IMPL bool aws_is_power_of_two(const size_t x) {
160    /* First x in the below expression is for the case when x is 0 */
161    return x && (!(x & (x - 1)));
162}
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 */
168AWS_STATIC_IMPL int aws_round_up_to_power_of_two(size_t n, size_t *result) {
169    if (n == 0) {
170        *result = 1;
171        return AWS_OP_SUCCESS;
172    }
173    if (n > SIZE_MAX_POWER_OF_TWO) {
174        return aws_raise_error(AWS_ERROR_OVERFLOW_DETECTED);
175    }
176
177    n--;
178    n |= n >> 1;
179    n |= n >> 2;
180    n |= n >> 4;
181    n |= n >> 8;
182    n |= n >> 16;
183#if SIZE_BITS == 64
184    n |= n >> 32;
185#endif
186    n++;
187    *result = n;
188    return AWS_OP_SUCCESS;
189}
190
191#if _MSC_VER
192#    pragma warning(pop)
193#endif /* _MSC_VER */
194
195AWS_STATIC_IMPL uint8_t aws_min_u8(uint8_t a, uint8_t b) {
196    return a < b ? a : b;
197}
198
199AWS_STATIC_IMPL uint8_t aws_max_u8(uint8_t a, uint8_t b) {
200    return a > b ? a : b;
201}
202
203AWS_STATIC_IMPL int8_t aws_min_i8(int8_t a, int8_t b) {
204    return a < b ? a : b;
205}
206
207AWS_STATIC_IMPL int8_t aws_max_i8(int8_t a, int8_t b) {
208    return a > b ? a : b;
209}
210
211AWS_STATIC_IMPL uint16_t aws_min_u16(uint16_t a, uint16_t b) {
212    return a < b ? a : b;
213}
214
215AWS_STATIC_IMPL uint16_t aws_max_u16(uint16_t a, uint16_t b) {
216    return a > b ? a : b;
217}
218
219AWS_STATIC_IMPL int16_t aws_min_i16(int16_t a, int16_t b) {
220    return a < b ? a : b;
221}
222
223AWS_STATIC_IMPL int16_t aws_max_i16(int16_t a, int16_t b) {
224    return a > b ? a : b;
225}
226
227AWS_STATIC_IMPL uint32_t aws_min_u32(uint32_t a, uint32_t b) {
228    return a < b ? a : b;
229}
230
231AWS_STATIC_IMPL uint32_t aws_max_u32(uint32_t a, uint32_t b) {
232    return a > b ? a : b;
233}
234
235AWS_STATIC_IMPL int32_t aws_min_i32(int32_t a, int32_t b) {
236    return a < b ? a : b;
237}
238
239AWS_STATIC_IMPL int32_t aws_max_i32(int32_t a, int32_t b) {
240    return a > b ? a : b;
241}
242
243AWS_STATIC_IMPL uint64_t aws_min_u64(uint64_t a, uint64_t b) {
244    return a < b ? a : b;
245}
246
247AWS_STATIC_IMPL uint64_t aws_max_u64(uint64_t a, uint64_t b) {
248    return a > b ? a : b;
249}
250
251AWS_STATIC_IMPL int64_t aws_min_i64(int64_t a, int64_t b) {
252    return a < b ? a : b;
253}
254
255AWS_STATIC_IMPL int64_t aws_max_i64(int64_t a, int64_t b) {
256    return a > b ? a : b;
257}
258
259AWS_STATIC_IMPL size_t aws_min_size(size_t a, size_t b) {
260    return a < b ? a : b;
261}
262
263AWS_STATIC_IMPL size_t aws_max_size(size_t a, size_t b) {
264    return a > b ? a : b;
265}
266
267AWS_STATIC_IMPL int aws_min_int(int a, int b) {
268    return a < b ? a : b;
269}
270
271AWS_STATIC_IMPL int aws_max_int(int a, int b) {
272    return a > b ? a : b;
273}
274
275AWS_STATIC_IMPL float aws_min_float(float a, float b) {
276    return a < b ? a : b;
277}
278
279AWS_STATIC_IMPL float aws_max_float(float a, float b) {
280    return a > b ? a : b;
281}
282
283AWS_STATIC_IMPL double aws_min_double(double a, double b) {
284    return a < b ? a : b;
285}
286
287AWS_STATIC_IMPL double aws_max_double(double a, double b) {
288    return a > b ? a : b;
289}
290
291AWS_EXTERN_C_END
292
293#endif /* AWS_COMMON_MATH_INL */
294