OpenTTD Source 20260218-master-g2123fca5ea
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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
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
218template <typename To>
219constexpr To ClampTo(ConvertibleThroughBase auto value)
220{
221 return ClampTo<To>(value.base());
222}
223
231template <typename T>
232constexpr T Delta(const T a, const T b)
233{
234 return (a < b) ? b - a : a - b;
235}
236
249template <typename T>
250constexpr bool IsInsideBS(const T x, const size_t base, const size_t size)
251{
252 return static_cast<size_t>(x - base) < size;
253}
254
266constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
267{
268 return static_cast<size_t>(x - min) < (max - min);
269}
270
272constexpr bool IsInsideMM(const ConvertibleThroughBase auto x, const size_t min, const size_t max) noexcept { return IsInsideMM(x.base(), min, max); }
273
275template <typename enum_type, std::enable_if_t<std::is_enum_v<enum_type>, bool> = true>
276constexpr bool IsInsideMM(enum_type x, enum_type min, enum_type max) noexcept
277{
279}
280
286constexpr uint ToPercent8(uint i)
287{
288 assert(i < 256);
289 return i * 101 >> 8;
290}
291
297constexpr uint ToPercent16(uint i)
298{
299 assert(i < 65536);
300 return i * 101 >> 16;
301}
302
303int DivideApprox(int a, int b);
304
311constexpr uint CeilDiv(uint a, uint b)
312{
313 return (a + b - 1) / b;
314}
315
322constexpr uint Ceil(uint a, uint b)
323{
324 return CeilDiv(a, b) * b;
325}
326
333constexpr int RoundDivSU(int a, uint b)
334{
335 if (a > 0) {
336 /* 0.5 is rounded to 1 */
337 return (a + static_cast<int>(b) / 2) / static_cast<int>(b);
338 } else {
339 /* -0.5 is rounded to 0 */
340 return (a - (static_cast<int>(b) - 1) / 2) / static_cast<int>(b);
341 }
342}
343
349constexpr uint64_t PowerOfTen(int power)
350{
351 assert(power >= 0 && power <= 20 /* digits in uint64_t */);
352 uint64_t result = 1;
353 for (int i = 0; i < power; i++) result *= 10;
354 return result;
355}
356
357uint32_t IntSqrt(uint32_t num);
358
359#endif /* MATH_FUNC_HPP */
A type is considered 'convertible through base()' when it has a 'base()' function that returns someth...
Concept for unifying the convert through 'base()' behaviour of several 'strong' types.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23).
Definition enum_type.hpp:21
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.
constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
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.