51 return a >= T{0} ? a : -a;
78 MOCHI_CONCEPT(std::is_arithmetic_v<From>&& std::is_arithmetic_v<To>)>
80 return static_cast<To
>(a);
88 MOCHI_CONCEPT(std::is_pointer_v<From>&& std::is_pointer_v<To>)>
90 static_assert(
sizeof(To) ==
sizeof(From),
"Invalid cast. Types must be the same size.");
91 return reinterpret_cast<To
>(a);
99 MOCHI_CONCEPT(std::is_arithmetic_v<From>&& std::is_arithmetic_v<To>)>
101 static_assert(
sizeof(To) ==
sizeof(From),
"Invalid cast. Types must be the same size.");
103 memcpy(&b, &a,
sizeof(a));
111template <
typename A,
typename B,
typename C>
116template <
typename A,
typename B,
typename C>
121template <
typename A,
typename B,
typename C>
126template <
typename A,
typename B,
typename C>
135template <
typename T, MOCHI_CONCEPT(std::is_arithmetic_v<T>)>
137 if constexpr (std::is_integral_v<T>) {
140 return std::isfinite(a);
150 return (a <= b) ? a : b;
154template <
typename T,
typename... More>
156 return Min(a,
Min(b, c, args...));
161 return (a >= b) ? a : b;
165template <
typename T,
typename... More>
167 return Max(a,
Max(b, c, args...));
170template <
typename ValT,
typename MinT,
typename MaxT>
172 return Min(ValT(max),
Max(ValT(min), value));
175template <
typename ValT,
typename MinT,
typename MaxT,
bool kMinInclusive,
bool kMaxInclusive>
180 std::integral_constant<bool, kMinInclusive> = std::true_type{},
181 std::integral_constant<bool, kMaxInclusive> = std::false_type{}) {
183 if constexpr (kMinInclusive) {
184 test1 = (value >= min);
186 test1 = (value > min);
189 if constexpr (kMaxInclusive) {
190 test2 = (value <= max);
192 test2 = (value < max);
194 return static_cast<ValT
>(test1 && test2);
217template <
typename T, MOCHI_CONCEPT(std::is_arithmetic_v<T>)>
220 static_assert(!std::is_same_v<std::remove_cv_t<T>,
bool>,
"NearEqual not supported for bool");
221 return Abs(a - b) <= epsilon;
224template <
typename T, MOCHI_CONCEPT(std::is_arithmetic_v<T>)>
227 static_assert(!std::is_same_v<std::remove_cv_t<T>,
bool>,
"NearEqualRel not supported for bool");
228 auto scaledEpsilon = epsilon *
Max(
Abs(a),
Abs(b));
229 auto tolerance =
Max(epsilon, scaledEpsilon);
233template <
typename T, MOCHI_CONCEPT(std::is_arithmetic_v<T>)>
237 static_assert(!std::is_same_v<std::remove_cv_t<T>,
bool>,
"NearZero not supported for bool");
238 return Abs(a) <= epsilon;
249 return static_cast<int>(a.size());
253template <
typename T,
size_t N>
255 return static_cast<int>(N);
262template <
typename T,
typename Frac>
264 return T(a * (Frac{1} - t) + b * t);
275 return Lerp<T>(outA, outB, (value - inA) / (inB - inA));
285 return Lerp<T>(outA, outB,
Clamp<T>((value - inA) / (inB - inA), T{0}, T{1}));
292template <
typename B,
typename E>
294 return std::pow(base, exp);
323 std::is_integral_v<T> && !std::is_same_v<std::remove_cv_t<T>,
bool>,
324 "IsPowerOfTwo requires a non-bool integral type");
325 return (a > T(0)) && ((a & (a - T(1))) == T(0));
333 std::is_integral_v<T> && !std::is_same_v<std::remove_cv_t<T>,
bool>,
334 "NextPowerOfTwo requires a non-bool integral type");
335 [[maybe_unused]]
constexpr T kMaxPowerOfTwo = T(1) << (std::numeric_limits<T>::digits - 1);
337 a <= kMaxPowerOfTwo,
"Input exceeds the largest representable power of two.");
341 using UnsignedT = std::make_unsigned_t<T>;
343 std::numeric_limits<UnsignedT>::digits > 4 && std::numeric_limits<UnsignedT>::digits <= 64,
344 "Unsupported integral type");
345 auto result =
static_cast<UnsignedT
>(a - T(1));
346 result |= result >> 1;
347 result |= result >> 2;
348 result |= result >> 4;
349 if constexpr (std::numeric_limits<UnsignedT>::digits > 8) {
350 result |= result >> 8;
352 if constexpr (std::numeric_limits<UnsignedT>::digits > 16) {
353 result |= result >> 16;
355 if constexpr (std::numeric_limits<UnsignedT>::digits > 32) {
356 result |= result >> 32;
358 return static_cast<T
>(result + UnsignedT(1));
387 return std::floor(a);
397 return std::round(a);
403 std::is_integral_v<T> && !std::is_same_v<std::remove_cv_t<T>,
bool>,
"Unsupported type");
404 return ((numToRound + multiple - 1) / multiple) * multiple;
410 std::is_integral_v<T> && !std::is_same_v<std::remove_cv_t<T>,
bool>,
"Unsupported type");
411 return (numToRound / multiple) * multiple;
424 static_assert(std::is_arithmetic_v<T>,
"Unsupported type");
425 return condition ? a : b;
435 return Select(x >= T{}, T{1}, T{-1});
477 return std::atan2(y, x);
#define MOCHI_ASSERT_VERBOSE(condition_without_side_effects,...)
constexpr bool IsPowerOfTwo(T a)
constexpr T const & Min(T const &a, T const &b)
constexpr T RoundDown(T numToRound, T multiple)
constexpr auto Equal(T const &a, T const &b)
constexpr T NextPowerOfTwo(T a)
constexpr To StaticCast(From const &a)
constexpr T kDefaultNearEqualEpsilon
constexpr ValT Rect(ValT value, MinT min, MaxT max, std::integral_constant< bool, kMinInclusive >=std::true_type{}, std::integral_constant< bool, kMaxInclusive >=std::false_type{})
constexpr auto MulAdd(A a, B b, C c)
constexpr T ATan2(T y, T x)
constexpr T RoundUp(T numToRound, T multiple)
constexpr auto NotEqual(T const &a, T const &b)
constexpr auto MulSub(A a, B b, C c)
constexpr T Select(bool condition, T a, T b)
constexpr T SignedSqrt(T a)
constexpr auto NegMulAdd(A a, B b, C c)
constexpr T IntegralSqrt(T a)
constexpr ValT Clamp(ValT value, MinT min, MaxT max)
constexpr T SignedSqr(T a)
constexpr T RemapAndClamp(T value, T inA, T inB, T outA, T outB)
constexpr int isize(T const &a)
constexpr T Lerp(T a, T b, Frac t)
constexpr T const & Max(T const &a, T const &b)
constexpr T RcpApprox(T a)
bool NearEqual(TransformRT const &a, TransformRT const &b, real epsilon=kDefaultNearEqualEpsilon< real >)
constexpr auto NegMulSub(A a, B b, C c)
constexpr B Pow(B base, E exp)
constexpr auto NearEqualRel(T const &a, T const &b, T epsilon=kDefaultNearEqualEpsilon< T >)
bool IsFinite(TransformRT const &a)
constexpr T Remap(T value, T inA, T inB, T outA, T outB)
constexpr auto NearZero(T const &a, T epsilon=kDefaultNearEqualEpsilon< T >)