ReXGlue SDK
Loading...
Searching...
No Matches
math.h
Go to the documentation of this file.
1
12
13#pragma once
14
15#include <algorithm>
16#include <bit>
17#include <cmath>
18#include <cstdint>
19#include <cstring>
20#include <limits>
21#include <numeric>
22#include <type_traits>
23#include <utility>
24
25#include <rex/assert.h>
26#include <rex/platform.h>
27#include <rex/types.h>
28
29namespace rex {
30
31template <typename T, size_t N>
32constexpr size_t CountOf(T (&)[N]) noexcept {
33 return std::extent<T[N]>::value;
34}
35
41template <typename T>
42constexpr T RoundUpPow2(T value, T alignment) {
43 return (value + alignment - 1) & ~(alignment - 1);
44}
45
51template <typename T, typename V>
52constexpr T RoundUp(T value, V multiple) {
53 return (value + multiple - 1) / multiple * multiple;
54}
55
62template <typename T, typename V>
63constexpr T RoundUpNonZero(T value, V multiple) {
64 if (!value) {
65 return multiple;
66 }
67 return RoundUp(value, multiple);
68}
69
76template <typename T>
77T clamp_float(T value, T min_value, T max_value) {
78 f32 clamped_to_min = std::isgreater(value, min_value) ? value : min_value;
79 return std::isless(clamped_to_min, max_value) ? clamped_to_min : max_value;
80}
81
83template <typename T>
84T saturate(T value) {
85 return clamp_float(value, static_cast<T>(0.0f), static_cast<T>(1.0f));
86}
87
94template <typename T>
95constexpr void reduce_fraction(T& numerator, T& denominator) {
96 auto gcd = std::gcd(numerator, denominator);
97 numerator /= gcd;
98 denominator /= gcd;
99}
100
106template <typename T>
107constexpr void reduce_fraction(std::pair<T, T>& fraction) {
108 reduce_fraction<T>(fraction.first, fraction.second);
109}
110
118constexpr u64 mul_div(u64 value, u64 numerator, u64 denominator) {
119 REX_ASSERT(denominator != 0);
120 constexpr u64 kMax = std::numeric_limits<u64>::max();
121 constexpr u64 kHalfMask = 0xFFFFFFFF;
122 if (denominator == 0) {
123 return kMax;
124 }
125 const unsigned __int128 product = static_cast<unsigned __int128>(value) * numerator;
126 u64 high = static_cast<u64>(product >> 64);
127 u64 low = static_cast<u64>(product);
128 if (high >= denominator) {
129 return kMax;
130 }
131 if (high == 0) {
132 return low / denominator;
133 }
134
135 const int shift = std::countl_zero(denominator);
136 denominator <<= shift;
137 high = (high << shift) | (shift == 0 ? 0 : low >> (64 - shift));
138 low <<= shift;
139 const u64 divisor_high = denominator >> 32;
140 const u64 divisor_low = denominator & kHalfMask;
141
142 const auto divide_step = [&](u64 dividend, u64 next_half) {
143 u64 quotient = dividend / divisor_high;
144 u64 remainder = dividend % divisor_high;
145 while ((quotient >> 32) != 0 || quotient * divisor_low > ((remainder << 32) | next_half)) {
146 --quotient;
147 remainder += divisor_high;
148 if ((remainder >> 32) != 0) {
149 break;
150 }
151 }
152 return quotient;
153 };
154
155 const u64 low_high = low >> 32;
156 const u64 quotient_high = divide_step(high, low_high);
157 const u64 partial = ((high << 32) | low_high) - quotient_high * denominator;
158 const u64 quotient_low = divide_step(partial, low & kHalfMask);
159 return (quotient_high << 32) | quotient_low;
160}
161
167template <typename T>
168inline T SatAdd(T a, T b) {
169 using TU = std::make_unsigned<T>::type;
170 TU result = static_cast<TU>(a) + static_cast<TU>(b);
171 if (std::is_unsigned<T>::value) {
172 result |= static_cast<TU>(-static_cast<std::make_signed<T>::type>(result < static_cast<TU>(a)));
173 } else {
174 TU overflowed = (static_cast<TU>(a) >> (sizeof(T) * 8 - 1)) + std::numeric_limits<T>::max();
175 if (static_cast<T>((overflowed ^ static_cast<TU>(b)) | ~(static_cast<TU>(b) ^ result)) >= 0) {
176 result = overflowed;
177 }
178 }
179 return static_cast<T>(result);
180}
181
187template <typename T>
188inline T SatSub(T a, T b) {
189 using TU = std::make_unsigned<T>::type;
190 TU result = static_cast<TU>(a) - static_cast<TU>(b);
191 if (std::is_unsigned<T>::value) {
192 result &=
193 static_cast<TU>(-static_cast<std::make_signed<T>::type>(result <= static_cast<TU>(a)));
194 } else {
195 TU overflowed = (static_cast<TU>(a) >> (sizeof(T) * 8 - 1)) + std::numeric_limits<T>::max();
196 if (static_cast<T>((overflowed ^ static_cast<TU>(b)) & (overflowed ^ result)) < 0) {
197 result = overflowed;
198 }
199 }
200 return static_cast<T>(result);
201}
202
204struct Vec2 {
205 f32 x = 0;
206 f32 y = 0;
207
208 constexpr bool operator==(const Vec2& other) const = default;
209};
210
211} // namespace rex
#define REX_ASSERT(cond,...)
Definition assert.h:84
Definition app.h:36
constexpr u64 mul_div(u64 value, u64 numerator, u64 denominator)
Definition math.h:118
constexpr T RoundUp(T value, V multiple)
Definition math.h:52
T SatSub(T a, T b)
Definition math.h:188
T saturate(T value)
Definition math.h:84
constexpr T RoundUpPow2(T value, T alignment)
Definition math.h:42
constexpr T RoundUpNonZero(T value, V multiple)
Definition math.h:63
T SatAdd(T a, T b)
Definition math.h:168
T clamp_float(T value, T min_value, T max_value)
Definition math.h:77
constexpr void reduce_fraction(T &numerator, T &denominator)
Definition math.h:95
Platform flags, packing macros and export markers.
Definition math.h:204
Integer types, byte order wrappers and size literals.