GCC Code Coverage Report


libs/base/src/base/
File: range.h
Date: 2025-03-19 20:55:25
Lines:
38/39
97.4%
Functions:
12/12
100.0%
Branches:
17/42
40.5%

Line Branch Exec Source
1 #pragma once
2
3 #include <type_traits>
4
5 #include "base/angle.h"
6 #include "assert/assert.h"
7
8
9 namespace eu
10 {
11 /** \addtogroup math
12 * @{
13 */
14
15 /// A (inclusive) range between two values.
16 /// Zero range is allowed.
17 template <typename T>
18 struct R
19 {
20 T lower_bound;
21 T upper_bound;
22
23 /// Asserts if max is below min
24 32 constexpr R(T min, T max) : lower_bound(min), upper_bound(max)
25 {
26
1/10
✗ Branch 0 (2 → 3) not taken.
✓ Branch 1 (2 → 17) taken 32 times.
✗ Branch 2 (9 → 10) not taken.
✗ Branch 3 (9 → 20) not taken.
✗ Branch 4 (10 → 11) not taken.
✗ Branch 5 (10 → 18) not taken.
✗ Branch 6 (14 → 15) not taken.
✗ Branch 7 (14 → 16) not taken.
✗ Branch 8 (24 → 25) not taken.
✗ Branch 9 (24 → 26) not taken.
32 ASSERTX(lower_bound <= upper_bound, upper_bound, lower_bound);
27
0/8
✗ Branch 0 (5 → 6) not taken.
✗ Branch 1 (5 → 27) not taken.
✗ Branch 2 (6 → 7) not taken.
✗ Branch 3 (6 → 27) not taken.
✗ Branch 4 (27 → 28) not taken.
✗ Branch 5 (27 → 31) not taken.
✗ Branch 6 (29 → 30) not taken.
✗ Branch 7 (29 → 31) not taken.
32 }
28
29 [[nodiscard]] T
30 get_distance() const
31 {
32 return upper_bound - lower_bound;
33 }
34 };
35
36
37 /// Create a range from `min` to `max` (inclusive)
38 template <typename T>
39 30 R<T> make_range(T min, T max)
40 {
41
1/2
✓ Branch 0 (2 → 3) taken 30 times.
✗ Branch 1 (2 → 6) not taken.
30 return {min, max};
42 }
43
44 /// Create a range from zero (0) to `max` (inclusive)
45 template <typename T>
46 2 R<T> make_range(T max)
47 {
48
1/2
✓ Branch 0 (2 → 3) taken 2 times.
✗ Branch 1 (2 → 6) not taken.
2 return R<T>(0, max);
49 }
50
51 /// A range going from 0 to 1
52 constexpr R<float> r01 = { 0.0f, 1.0f};
53
54 // A range going from -1 to 1
55 constexpr R<float> r11 = { -1.0f, 1.0};
56
57 float from_01f(float lower_bound, float upper_bound, float value);
58
59 /// Converts a value in 0-1 range to a custom range
60 template <typename T>
61 6 T from_01(const R<T>& range, float value)
62 {
63 const float r = from_01f
64 12 (
65 6 static_cast<float>(range.lower_bound),
66 6 static_cast<float>(range.upper_bound),
67 value
68 );
69
70 if constexpr (std::is_unsigned<T>::value)
71 {
72 ASSERT(r >= 0.0f);
73 }
74
75 6 return static_cast<T>(r);
76 }
77
78 template <>
79 float from_01(const R<float>& range, float value);
80
81 /// Converts a value in a range to the 0-1 range
82 template <typename T>
83 4 float to01(const R<T>& range, T value)
84 {
85 4 return (value - range.lower_bound)
86 4 / (range.upper_bound - range.lower_bound);
87 }
88
89 // inclusive
90 template <typename T>
91 5 T get360_angular(const R<T>& range, float value)
92 {
93 5 const float half_difference
94 5 = (range.upper_bound - range.lower_bound) / 2.0f;
95 5 return range.lower_bound + half_difference
96
2/4
✓ Branch 0 (2 → 3) taken 5 times.
✗ Branch 1 (2 → 7) not taken.
✓ Branch 2 (3 → 4) taken 5 times.
✗ Branch 3 (3 → 7) not taken.
5 - half_difference * cos(An::from_percent_of_360(value));
97 }
98
99 /// Remaps a value from one range to another
100 template <typename T, typename F>
101 1 T remap_to(const R<F>& from, const R<T>& to, F value)
102 {
103 1 return from_01(to, to01(from, value));
104 }
105
106 /// Returns true if a value is withing a range
107 template <typename T>
108 4 bool is_within(const R<T>& range, T value)
109 {
110
4/4
✓ Branch 0 (2 → 3) taken 3 times.
✓ Branch 1 (2 → 5) taken 1 times.
✓ Branch 2 (3 → 4) taken 2 times.
✓ Branch 3 (3 → 5) taken 1 times.
4 return value >= range.lower_bound && value <= range.upper_bound;
111 }
112
113 /// Returns a value that is kept within the range.
114 /// i.e the value can't go lower than the lower bound or higher than the higher bound
115 /// @see wrap
116 template <typename T>
117 3 T keep_within(const R<T>& range, T value)
118 {
119
2/2
✓ Branch 0 (2 → 3) taken 1 times.
✓ Branch 1 (2 → 4) taken 2 times.
3 if(value > range.upper_bound)
120 {
121 1 return range.upper_bound;
122 }
123
2/2
✓ Branch 0 (4 → 5) taken 1 times.
✓ Branch 1 (4 → 6) taken 1 times.
2 if(value < range.lower_bound)
124 {
125 1 return range.lower_bound;
126 }
127
128 1 return value;
129 }
130
131 /// Returns a value that wraps around the range.
132 /// When the value go outside the range, the value is wrapped back to either the start if exited at the end or vice versa.
133 template <typename T>
134 6 T wrap(const R<T>& range, T value)
135 {
136 6 const T diff = range.upper_bound - range.lower_bound;
137
1/4
✗ Branch 0 (2 → 3) not taken.
✓ Branch 1 (2 → 9) taken 6 times.
✗ Branch 2 (6 → 7) not taken.
✗ Branch 3 (6 → 17) not taken.
6 ASSERT(diff > 0);
138 6 T wrapped = value - range.lower_bound;
139
1/2
✗ Branch 0 (11 → 10) not taken.
✓ Branch 1 (11 → 12) taken 6 times.
6 while(wrapped < 0)
140 {
141 wrapped += diff;
142 }
143
2/2
✓ Branch 0 (14 → 13) taken 59 times.
✓ Branch 1 (14 → 15) taken 6 times.
65 while(wrapped > diff)
144 {
145 59 wrapped -= diff;
146 }
147 6 return range.lower_bound + wrapped;
148 }
149
150 /** @}*/
151 }
152
153