Line | Branch | Exec | Source |
---|---|---|---|
1 | #ifndef UTIL_ARITH_H | ||
2 | #define UTIL_ARITH_H | ||
3 | |||
4 | #include <stdbool.h> | ||
5 | #include <stddef.h> | ||
6 | #include <stdint.h> | ||
7 | #include "debug.h" | ||
8 | #include "macros.h" | ||
9 | |||
10 | // Calculate the maximum representable value for __typeof__(x), where x | ||
11 | // is an unsigned integer and sizeof(x) >= sizeof(int) | ||
12 | #define UNSIGNED_MAX_VALUE(x) (~((x) ^ (x))) | ||
13 | |||
14 | #if GNUC_AT_LEAST(5, 0) || HAS_BUILTIN(__builtin_mul_overflow) | ||
15 | #define CHECKED_ADD(a, b, res) return __builtin_add_overflow(a, b, res) | ||
16 | #define CHECKED_MUL(a, b, res) return __builtin_mul_overflow(a, b, res) | ||
17 | #elif __STDC_VERSION__ >= 202311L | ||
18 | #include <stdckdint.h> | ||
19 | #define CHECKED_ADD(a, b, res) return ckd_add(res, a, b) | ||
20 | #define CHECKED_MUL(a, b, res) return ckd_mul(res, a, b) | ||
21 | #else | ||
22 | #define CHECKED_ADD(a, b, res) \ | ||
23 | if (unlikely(b > UNSIGNED_MAX_VALUE(a) - a)) return true; else {*res = a + b; return false;} | ||
24 | #define CHECKED_MUL(a, b, res) \ | ||
25 | if (unlikely(a > 0 && b > UNSIGNED_MAX_VALUE(a) / a)) return true; else {*res = a * b; return false;} | ||
26 | #endif | ||
27 | |||
28 | 470 | static inline bool umax_multiply_overflows(uintmax_t a, uintmax_t b, uintmax_t *result) | |
29 | { | ||
30 | 470 | CHECKED_MUL(a, b, result); | |
31 | } | ||
32 | |||
33 | 14481 | static inline bool size_multiply_overflows(size_t a, size_t b, size_t *result) | |
34 | { | ||
35 | 14481 | CHECKED_MUL(a, b, result); | |
36 | } | ||
37 | |||
38 | 464 | static inline bool umax_add_overflows(uintmax_t a, uintmax_t b, uintmax_t *result) | |
39 | { | ||
40 | 464 | CHECKED_ADD(a, b, result); | |
41 | } | ||
42 | |||
43 | 225254 | static inline bool size_add_overflows(size_t a, size_t b, size_t *result) | |
44 | { | ||
45 | 225254 | CHECKED_ADD(a, b, result); | |
46 | } | ||
47 | |||
48 | // This is equivalent to `(x + 1) % modulus`, given the constraints | ||
49 | // imposed by BUG_ON(), but avoids expensive divisions by a non-constant | ||
50 | 65 | static inline size_t wrapping_increment(size_t x, size_t modulus) | |
51 | { | ||
52 | 65 | BUG_ON(modulus == 0); | |
53 | 65 | BUG_ON(x >= modulus); | |
54 |
2/2✓ Branch 0 (6→7) taken 49 times.
✓ Branch 1 (6→8) taken 16 times.
|
65 | return (x + 1 < modulus) ? x + 1 : 0; |
55 | } | ||
56 | |||
57 | // As above, but for decrementing `x` instead of incrementing it | ||
58 | 51 | static inline size_t wrapping_decrement(size_t x, size_t modulus) | |
59 | { | ||
60 | 51 | BUG_ON(modulus == 0); | |
61 | 51 | BUG_ON(x >= modulus); | |
62 |
2/2✓ Branch 0 (6→7) taken 37 times.
✓ Branch 1 (6→8) taken 14 times.
|
51 | return (x ? x : modulus) - 1; |
63 | } | ||
64 | |||
65 | 7 | static inline size_t saturating_increment(size_t x, size_t max) | |
66 | { | ||
67 | 7 | BUG_ON(x > max); | |
68 | 7 | return x + (x < max); | |
69 | } | ||
70 | |||
71 | 5 | static inline size_t saturating_decrement(size_t x) | |
72 | { | ||
73 | 5 | return x - (x > 0); | |
74 | } | ||
75 | |||
76 | 12 | static inline size_t saturating_subtract(size_t a, size_t b) | |
77 | { | ||
78 |
2/2✓ Branch 0 (2→3) taken 6 times.
✓ Branch 1 (2→4) taken 6 times.
|
12 | return (a > b) ? a - b : 0; |
79 | } | ||
80 | |||
81 | #endif | ||
82 |