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