Merge remote-tracking branch 'upstream/master'

This commit is contained in:
dP
2024-02-04 22:50:08 +05:30
1358 changed files with 138991 additions and 72904 deletions
+86 -42
View File
@@ -10,6 +10,8 @@
#ifndef MATH_FUNC_HPP
#define MATH_FUNC_HPP
#include "strong_typedef_type.hpp"
/**
* Returns the absolute value of (scalar) variable.
*
@@ -18,7 +20,7 @@
* @return The unsigned value
*/
template <typename T>
static inline T abs(const T a)
constexpr T abs(const T a)
{
return (a < (T)0) ? -a : a;
}
@@ -32,7 +34,7 @@ static inline T abs(const T a)
* @return The smallest multiple of n equal or greater than x
*/
template <typename T>
static inline T Align(const T x, uint n)
constexpr T Align(const T x, uint n)
{
assert((n & (n - 1)) == 0 && n != 0);
n--;
@@ -50,7 +52,7 @@ static inline T Align(const T x, uint n)
* @see Align()
*/
template <typename T>
static inline T *AlignPtr(T *x, uint n)
constexpr T *AlignPtr(T *x, uint n)
{
static_assert(sizeof(size_t) == sizeof(void *));
return reinterpret_cast<T *>(Align((size_t)x, n));
@@ -74,7 +76,7 @@ static inline T *AlignPtr(T *x, uint n)
* @see Clamp(int, int, int)
*/
template <typename T>
static inline T Clamp(const T a, const T min, const T max)
constexpr T Clamp(const T a, const T min, const T max)
{
assert(min <= max);
if (a <= min) return min;
@@ -97,7 +99,7 @@ static inline T Clamp(const T a, const T min, const T max)
* @returns A value between min and max which is closest to a.
*/
template <typename T>
static inline T SoftClamp(const T a, const T min, const T max)
constexpr T SoftClamp(const T a, const T min, const T max)
{
if (min > max) {
using U = std::make_unsigned_t<T>;
@@ -124,7 +126,7 @@ static inline T SoftClamp(const T a, const T min, const T max)
* @returns A value between min and max which is closest to a.
* @see ClampU(uint, uint, uint)
*/
static inline int Clamp(const int a, const int min, const int max)
constexpr int Clamp(const int a, const int min, const int max)
{
return Clamp<int>(a, min, max);
}
@@ -145,44 +147,80 @@ static inline int Clamp(const int a, const int min, const int max)
* @returns A value between min and max which is closest to a.
* @see Clamp(int, int, int)
*/
static inline uint ClampU(const uint a, const uint min, const uint max)
constexpr uint ClampU(const uint a, const uint min, const uint max)
{
return Clamp<uint>(a, min, max);
}
/**
* Reduce a signed 64-bit int to a signed 32-bit one
* Clamp the given value down to lie within the requested type.
*
* This function clamps a 64-bit integer to a 32-bit integer.
* If the 64-bit value is smaller than the smallest 32-bit integer
* value 0x80000000 this value is returned (the left one bit is the sign bit).
* If the 64-bit value is greater than the greatest 32-bit integer value 0x7FFFFFFF
* this value is returned. In all other cases the 64-bit value 'fits' in a
* 32-bits integer field and so the value is casted to int32 and returned.
* For example ClampTo<uint8_t> will return a value clamped to the range of 0
* to 255. Anything smaller will become 0, anything larger will become 255.
*
* @param a The 64-bit value to clamps
* @return The 64-bit value reduced to a 32-bit value
* @param a The 64-bit value to clamp.
* @return The 64-bit value reduced to a value within the given allowed range
* for the return type.
* @see Clamp(int, int, int)
*/
static inline int32 ClampToI32(const int64 a)
template <typename To, typename From, std::enable_if_t<std::is_integral<From>::value, int> = 0>
constexpr To ClampTo(From value)
{
return static_cast<int32>(Clamp<int64>(a, INT32_MIN, INT32_MAX));
static_assert(std::numeric_limits<To>::is_integer, "Do not clamp from non-integer values");
static_assert(std::numeric_limits<From>::is_integer, "Do not clamp to non-integer values");
if constexpr (sizeof(To) >= sizeof(From) && std::numeric_limits<To>::is_signed == std::numeric_limits<From>::is_signed) {
/* Same signedness and To type is larger or equal than From type, no clamping is required. */
return static_cast<To>(value);
}
if constexpr (sizeof(To) > sizeof(From) && std::numeric_limits<To>::is_signed) {
/* Signed destination and a larger To type, no clamping is required. */
return static_cast<To>(value);
}
/* Get the bigger of the two types based on essentially the number of bits. */
using BiggerType = typename std::conditional<sizeof(From) >= sizeof(To), From, To>::type;
if constexpr (std::numeric_limits<To>::is_signed) {
/* The output is a signed number. */
if constexpr (std::numeric_limits<From>::is_signed) {
/* Both input and output are signed. */
return static_cast<To>(std::clamp<BiggerType>(value,
std::numeric_limits<To>::lowest(), std::numeric_limits<To>::max()));
}
/* The input is unsigned, so skip the minimum check and use unsigned variant of the biggest type as intermediate type. */
using BiggerUnsignedType = typename std::make_unsigned<BiggerType>::type;
return static_cast<To>(std::min<BiggerUnsignedType>(std::numeric_limits<To>::max(), value));
}
/* The output is unsigned. */
if constexpr (std::numeric_limits<From>::is_signed) {
/* Input is signed; account for the negative numbers in the input. */
if constexpr (sizeof(To) >= sizeof(From)) {
/* If the output type is larger or equal to the input type, then only clamp the negative numbers. */
return static_cast<To>(std::max<From>(value, 0));
}
/* The output type is smaller than the input type. */
using BiggerSignedType = typename std::make_signed<BiggerType>::type;
return static_cast<To>(std::clamp<BiggerSignedType>(value,
std::numeric_limits<To>::lowest(), std::numeric_limits<To>::max()));
}
/* The input and output are unsigned, just clamp at the high side. */
return static_cast<To>(std::min<BiggerType>(value, std::numeric_limits<To>::max()));
}
/**
* Reduce an unsigned 64-bit int to an unsigned 16-bit one
*
* @param a The 64-bit value to clamp
* @return The 64-bit value reduced to a 16-bit value
* @see ClampU(uint, uint, uint)
* Specialization of ClampTo for #StrongType::Typedef.
*/
static inline uint16 ClampToU16(const uint64 a)
template <typename To, typename From, std::enable_if_t<std::is_base_of<StrongTypedefBase, From>::value, int> = 0>
constexpr To ClampTo(From value)
{
/* MSVC thinks, in its infinite wisdom, that int min(int, int) is a better
* match for min(uint64, uint) than uint64 min(uint64, uint64). As such we
* need to cast the UINT16_MAX to prevent MSVC from displaying its
* infinite loads of warnings. */
return static_cast<uint16>(std::min(a, static_cast<uint64>(UINT16_MAX)));
return ClampTo<To>(value.base());
}
/**
@@ -193,7 +231,7 @@ static inline uint16 ClampToU16(const uint64 a)
* @return The absolute difference between the given scalars
*/
template <typename T>
static inline T Delta(const T a, const T b)
constexpr T Delta(const T a, const T b)
{
return (a < b) ? b - a : a - b;
}
@@ -211,7 +249,7 @@ static inline T Delta(const T a, const T b)
* @return True if the value is in the interval, false else.
*/
template <typename T>
static inline bool IsInsideBS(const T x, const size_t base, const size_t size)
constexpr bool IsInsideBS(const T x, const size_t base, const size_t size)
{
return (size_t)(x - base) < size;
}
@@ -226,10 +264,14 @@ static inline bool IsInsideBS(const T x, const size_t base, const size_t size)
* @param max The maximum of the interval
* @see IsInsideBS()
*/
template <typename T>
static constexpr inline bool IsInsideMM(const T x, const size_t min, const size_t max) noexcept
template <typename T, std::enable_if_t<std::disjunction_v<std::is_convertible<T, size_t>, std::is_base_of<StrongTypedefBase, T>>, int> = 0>
constexpr bool IsInsideMM(const T x, const size_t min, const size_t max) noexcept
{
return (size_t)(x - min) < (max - min);
if constexpr (std::is_base_of_v<StrongTypedefBase, T>) {
return (size_t)(x.base() - min) < (max - min);
} else {
return (size_t)(x - min) < (max - min);
}
}
/**
@@ -238,7 +280,7 @@ static constexpr inline bool IsInsideMM(const T x, const size_t min, const size_
* @param b variable to swap with a
*/
template <typename T>
static inline void Swap(T &a, T &b)
constexpr void Swap(T &a, T &b)
{
T t = a;
a = b;
@@ -250,7 +292,7 @@ static inline void Swap(T &a, T &b)
* @param i value to convert, range 0..255
* @return value in range 0..100
*/
static inline uint ToPercent8(uint i)
constexpr uint ToPercent8(uint i)
{
assert(i < 256);
return i * 101 >> 8;
@@ -261,14 +303,12 @@ static inline uint ToPercent8(uint i)
* @param i value to convert, range 0..65535
* @return value in range 0..100
*/
static inline uint ToPercent16(uint i)
constexpr uint ToPercent16(uint i)
{
assert(i < 65536);
return i * 101 >> 16;
}
int LeastCommonMultiple(int a, int b);
int GreatestCommonDivisor(int a, int b);
int DivideApprox(int a, int b);
/**
@@ -277,7 +317,7 @@ int DivideApprox(int a, int b);
* @param b Denominator
* @return Quotient, rounded up
*/
static inline uint CeilDiv(uint a, uint b)
constexpr uint CeilDiv(uint a, uint b)
{
return (a + b - 1) / b;
}
@@ -288,7 +328,7 @@ static inline uint CeilDiv(uint a, uint b)
* @param b Denominator
* @return a rounded up to the nearest multiple of b.
*/
static inline uint Ceil(uint a, uint b)
constexpr uint Ceil(uint a, uint b)
{
return CeilDiv(a, b) * b;
}
@@ -299,7 +339,7 @@ static inline uint Ceil(uint a, uint b)
* @param b Denominator
* @return Quotient, rounded to nearest
*/
static inline int RoundDivSU(int a, uint b)
constexpr int RoundDivSU(int a, uint b)
{
if (a > 0) {
/* 0.5 is rounded to 1 */
@@ -310,6 +350,8 @@ static inline int RoundDivSU(int a, uint b)
}
}
/* CityMania code start */
// TODO: Not sure it's actually used by any code
/**
* Computes (a / b) rounded away from zero.
* @param a Numerator
@@ -351,6 +393,8 @@ static inline T DivTowardsPositiveInf(T a, T b)
return (a / b) + (a % b > 0 ? 1 : 0);
}
/* CityMania code end */
uint32 IntSqrt(uint32 num);
#endif /* MATH_FUNC_HPP */