dte test coverage


Directory: ./
File: src/util/arith.h
Date: 2025-06-04 06:50:24
Exec Total Coverage
Lines: 23 23 100.0%
Functions: 9 9 100.0%
Branches: 6 6 100.0%

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