OpenTTD Source 20241224-master-gf74b0cf984
math_func.hpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10#ifndef MATH_FUNC_HPP
11#define MATH_FUNC_HPP
12
14
22template <typename T>
23constexpr T abs(const T a)
24{
25 return (a < static_cast<T>(0)) ? -a : a;
26}
27
36template <typename T>
37constexpr T Align(const T x, uint n)
38{
39 assert((n & (n - 1)) == 0 && n != 0);
40 n--;
41 return static_cast<T>((x + n) & ~static_cast<T>(n));
42}
43
54template <typename T>
55constexpr T *AlignPtr(T *x, uint n)
56{
57 static_assert(sizeof(uintptr_t) == sizeof(void *));
58 return reinterpret_cast<T *>(Align(reinterpret_cast<uintptr_t>(x), n));
59}
60
78template <typename T>
79constexpr T Clamp(const T a, const T min, const T max)
80{
81 assert(min <= max);
82 if (a <= min) return min;
83 if (a >= max) return max;
84 return a;
85}
86
101template <typename T>
102constexpr T SoftClamp(const T a, const T min, const T max)
103{
104 if (min > max) {
105 using U = std::make_unsigned_t<T>;
106 return min - (U(min) - max) / 2;
107 }
108 if (a <= min) return min;
109 if (a >= max) return max;
110 return a;
111}
112
129constexpr int Clamp(const int a, const int min, const int max)
130{
131 return Clamp<int>(a, min, max);
132}
133
150constexpr uint ClampU(const uint a, const uint min, const uint max)
151{
152 return Clamp<uint>(a, min, max);
153}
154
166template <typename To, typename From, std::enable_if_t<std::is_integral<From>::value, int> = 0>
167constexpr To ClampTo(From value)
168{
169 static_assert(std::numeric_limits<To>::is_integer, "Do not clamp from non-integer values");
170 static_assert(std::numeric_limits<From>::is_integer, "Do not clamp to non-integer values");
171
172 if constexpr (sizeof(To) >= sizeof(From) && std::numeric_limits<To>::is_signed == std::numeric_limits<From>::is_signed) {
173 /* Same signedness and To type is larger or equal than From type, no clamping is required. */
174 return static_cast<To>(value);
175 }
176
177 if constexpr (sizeof(To) > sizeof(From) && std::numeric_limits<To>::is_signed) {
178 /* Signed destination and a larger To type, no clamping is required. */
179 return static_cast<To>(value);
180 }
181
182 /* Get the bigger of the two types based on essentially the number of bits. */
183 using BiggerType = typename std::conditional<sizeof(From) >= sizeof(To), From, To>::type;
184
185 if constexpr (std::numeric_limits<To>::is_signed) {
186 /* The output is a signed number. */
187 if constexpr (std::numeric_limits<From>::is_signed) {
188 /* Both input and output are signed. */
189 return static_cast<To>(std::clamp<BiggerType>(value,
190 std::numeric_limits<To>::lowest(), std::numeric_limits<To>::max()));
191 }
192
193 /* The input is unsigned, so skip the minimum check and use unsigned variant of the biggest type as intermediate type. */
194 using BiggerUnsignedType = typename std::make_unsigned<BiggerType>::type;
195 return static_cast<To>(std::min<BiggerUnsignedType>(std::numeric_limits<To>::max(), value));
196 }
197
198 /* The output is unsigned. */
199
200 if constexpr (std::numeric_limits<From>::is_signed) {
201 /* Input is signed; account for the negative numbers in the input. */
202 if constexpr (sizeof(To) >= sizeof(From)) {
203 /* If the output type is larger or equal to the input type, then only clamp the negative numbers. */
204 return static_cast<To>(std::max<From>(value, 0));
205 }
206
207 /* The output type is smaller than the input type. */
208 using BiggerSignedType = typename std::make_signed<BiggerType>::type;
209 return static_cast<To>(std::clamp<BiggerSignedType>(value,
210 std::numeric_limits<To>::lowest(), std::numeric_limits<To>::max()));
211 }
212
213 /* The input and output are unsigned, just clamp at the high side. */
214 return static_cast<To>(std::min<BiggerType>(value, std::numeric_limits<To>::max()));
215}
216
220template <typename To, typename From, std::enable_if_t<std::is_base_of<StrongTypedefBase, From>::value, int> = 0>
221constexpr To ClampTo(From value)
222{
223 return ClampTo<To>(value.base());
224}
225
233template <typename T>
234constexpr T Delta(const T a, const T b)
235{
236 return (a < b) ? b - a : a - b;
237}
238
251template <typename T>
252constexpr bool IsInsideBS(const T x, const size_t base, const size_t size)
253{
254 return static_cast<size_t>(x - base) < size;
255}
256
267template <typename T, std::enable_if_t<std::disjunction_v<std::is_convertible<T, size_t>, std::is_base_of<StrongTypedefBase, T>>, int> = 0>
268constexpr bool IsInsideMM(const T x, const size_t min, const size_t max) noexcept
269{
270 if constexpr (std::is_base_of_v<StrongTypedefBase, T>) {
271 return static_cast<size_t>(x.base() - min) < (max - min);
272 } else {
273 return static_cast<size_t>(x - min) < (max - min);
274 }
275}
276
282template <typename T>
283constexpr void Swap(T &a, T &b)
284{
285 T t = a;
286 a = b;
287 b = t;
288}
289
295constexpr uint ToPercent8(uint i)
296{
297 assert(i < 256);
298 return i * 101 >> 8;
299}
300
306constexpr uint ToPercent16(uint i)
307{
308 assert(i < 65536);
309 return i * 101 >> 16;
310}
311
312int DivideApprox(int a, int b);
313
320constexpr uint CeilDiv(uint a, uint b)
321{
322 return (a + b - 1) / b;
323}
324
331constexpr uint Ceil(uint a, uint b)
332{
333 return CeilDiv(a, b) * b;
334}
335
342constexpr int RoundDivSU(int a, uint b)
343{
344 if (a > 0) {
345 /* 0.5 is rounded to 1 */
346 return (a + static_cast<int>(b) / 2) / static_cast<int>(b);
347 } else {
348 /* -0.5 is rounded to 0 */
349 return (a - (static_cast<int>(b) - 1) / 2) / static_cast<int>(b);
350 }
351}
352
358constexpr uint64_t PowerOfTen(int power)
359{
360 assert(power >= 0 && power <= 20 /* digits in uint64_t */);
361 uint64_t result = 1;
362 for (int i = 0; i < power; i++) result *= 10;
363 return result;
364}
365
366uint32_t IntSqrt(uint32_t num);
367
368#endif /* MATH_FUNC_HPP */
constexpr bool IsInsideBS(const T x, const size_t base, const size_t size)
Checks if a value is between a window started at some base point.
int DivideApprox(int a, int b)
Deterministic approximate division.
Definition math_func.cpp:22
constexpr uint ToPercent16(uint i)
Converts a "fract" value 0..65535 to "percent" value 0..100.
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition math_func.hpp:23
constexpr T * AlignPtr(T *x, uint n)
Return the smallest multiple of n equal or greater than x Applies to pointers only.
Definition math_func.hpp:55
constexpr uint64_t PowerOfTen(int power)
Computes ten to the given power.
constexpr T Align(const T x, uint n)
Return the smallest multiple of n equal or greater than x.
Definition math_func.hpp:37
uint32_t IntSqrt(uint32_t num)
Compute the integer square root.
Definition math_func.cpp:42
constexpr int RoundDivSU(int a, uint b)
Computes round(a / b) for signed a and unsigned b.
constexpr T SoftClamp(const T a, const T min, const T max)
Clamp a value between an interval.
constexpr uint CeilDiv(uint a, uint b)
Computes ceil(a / b) for non-negative a and b.
constexpr T Delta(const T a, const T b)
Returns the (absolute) difference between two (scalar) variables.
constexpr uint ToPercent8(uint i)
Converts a "fract" value 0..255 to "percent" value 0..100.
constexpr uint Ceil(uint a, uint b)
Computes ceil(a / b) * b for non-negative a and b.
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
constexpr uint ClampU(const uint a, const uint min, const uint max)
Clamp an unsigned integer between an interval.
constexpr To ClampTo(From value)
Clamp the given value down to lie within the requested type.
constexpr bool IsInsideMM(const T x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
constexpr void Swap(T &a, T &b)
Type safe swap operation.
Type (helpers) for making a strong typedef that is a distinct type.