1#ifndef AWS_COMMON_MATH_INL
2#define AWS_COMMON_MATH_INL
3
4/*
5 * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License").
8 * You may not use this file except in compliance with the License.
9 * A copy of the License is located at
10 *
11 * http://aws.amazon.com/apache2.0
12 *
13 * or in the "license" file accompanying this file. This file is distributed
14 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
15 * express or implied. See the License for the specific language governing
16 * permissions and limitations under the License.
17 */
18
19#include <aws/common/common.h>
20#include <aws/common/config.h>
21#include <aws/common/math.h>
22
23#include <limits.h>
24#include <stdlib.h>
25
26AWS_EXTERN_C_BEGIN
27
28#if defined(AWS_HAVE_GCC_OVERFLOW_MATH_EXTENSIONS) && (defined(__clang__) || !defined(__cplusplus))
29/*
30 * GCC and clang have these super convenient overflow checking builtins...
31 * but (in the case of GCC) they're only available when building C source.
32 * We'll fall back to one of the other inlinable variants (or a non-inlined version)
33 * if we are building this header on G++.
34 */
35# include <aws/common/math.gcc_overflow.inl>
36#elif defined(__x86_64__) && defined(AWS_HAVE_GCC_INLINE_ASM)
37# include <aws/common/math.gcc_x64_asm.inl>
38#elif defined(AWS_HAVE_MSVC_MULX)
39# include <aws/common/math.msvc.inl>
40#elif defined(CBMC)
41# include <aws/common/math.cbmc.inl>
42#else
43# ifndef AWS_HAVE_GCC_OVERFLOW_MATH_EXTENSIONS
44/* Fall back to the pure-C implementations */
45# include <aws/common/math.fallback.inl>
46# else
47/*
48 * We got here because we are building in C++ mode but we only support overflow extensions
49 * in C mode. Because the fallback is _slow_ (involving a division), we'd prefer to make a
50 * non-inline call to the fast C intrinsics.
51 */
52# endif /* AWS_HAVE_GCC_OVERFLOW_MATH_EXTENSIONS */
53#endif /* defined(AWS_HAVE_GCC_OVERFLOW_MATH_EXTENSIONS) && (defined(__clang__) || !defined(__cplusplus)) */
54
55#if _MSC_VER
56# pragma warning(push)
57# pragma warning(disable : 4127) /*Disable "conditional expression is constant" */
58#endif /* _MSC_VER */
59
60/**
61 * Multiplies a * b. If the result overflows, returns SIZE_MAX.
62 */
63AWS_STATIC_IMPL size_t aws_mul_size_saturating(size_t a, size_t b) {
64#if SIZE_BITS == 32
65 return (size_t)aws_mul_u32_saturating(a, b);
66#elif SIZE_BITS == 64
67 return (size_t)aws_mul_u64_saturating(a, b);
68#else
69# error "Target not supported"
70#endif
71}
72
73/**
74 * Multiplies a * b and returns the result in *r. If the result
75 * overflows, returns AWS_OP_ERR; otherwise returns AWS_OP_SUCCESS.
76 */
77AWS_STATIC_IMPL int aws_mul_size_checked(size_t a, size_t b, size_t *r) {
78#if SIZE_BITS == 32
79 return aws_mul_u32_checked(a, b, (uint32_t *)r);
80#elif SIZE_BITS == 64
81 return aws_mul_u64_checked(a, b, (uint64_t *)r);
82#else
83# error "Target not supported"
84#endif
85}
86
87/**
88 * Adds a + b. If the result overflows returns SIZE_MAX.
89 */
90AWS_STATIC_IMPL size_t aws_add_size_saturating(size_t a, size_t b) {
91#if SIZE_BITS == 32
92 return (size_t)aws_add_u32_saturating(a, b);
93#elif SIZE_BITS == 64
94 return (size_t)aws_add_u64_saturating(a, b);
95#else
96# error "Target not supported"
97#endif
98}
99
100/**
101 * Adds a + b and returns the result in *r. If the result
102 * overflows, returns AWS_OP_ERR; otherwise returns AWS_OP_SUCCESS.
103 */
104AWS_STATIC_IMPL int aws_add_size_checked(size_t a, size_t b, size_t *r) {
105#if SIZE_BITS == 32
106 return aws_add_u32_checked(a, b, (uint32_t *)r);
107#elif SIZE_BITS == 64
108 return aws_add_u64_checked(a, b, (uint64_t *)r);
109#else
110# error "Target not supported"
111#endif
112}
113
114/**
115 * Function to check if x is power of 2
116 */
117AWS_STATIC_IMPL bool aws_is_power_of_two(const size_t x) {
118 /* First x in the below expression is for the case when x is 0 */
119 return x && (!(x & (x - 1)));
120}
121
122/**
123 * Function to find the smallest result that is power of 2 >= n. Returns AWS_OP_ERR if this cannot
124 * be done without overflow
125 */
126AWS_STATIC_IMPL int aws_round_up_to_power_of_two(size_t n, size_t *result) {
127 if (n == 0) {
128 *result = 1;
129 return AWS_OP_SUCCESS;
130 }
131 if (n > SIZE_MAX_POWER_OF_TWO) {
132 return aws_raise_error(AWS_ERROR_OVERFLOW_DETECTED);
133 }
134
135 n--;
136 n |= n >> 1;
137 n |= n >> 2;
138 n |= n >> 4;
139 n |= n >> 8;
140 n |= n >> 16;
141#if SIZE_BITS == 64
142 n |= n >> 32;
143#endif
144 n++;
145 *result = n;
146 return AWS_OP_SUCCESS;
147}
148
149#if _MSC_VER
150# pragma warning(pop)
151#endif /* _MSC_VER */
152
153AWS_EXTERN_C_END
154
155#endif /* AWS_COMMON_MATH_INL */
156