forked from ares-emulator/ares
-
Notifications
You must be signed in to change notification settings - Fork 0
/
natural.hpp
344 lines (290 loc) · 15.8 KB
/
natural.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
#include <stdexcept>
#define ConcatenateType(Size) u##Size
#define DeclareType(Size) ConcatenateType(Size)
#define Pair DeclareType(PairBits)
#define Type DeclareType(TypeBits)
#define Half DeclareType(HalfBits)
//pick the larger of two types to prevent unnecessary data clamping
#define Cast (typename conditional<sizeof(Pair) >= sizeof(T), Pair, T>::type)
namespace nall {
//namespace Arithmetic {
struct Pair {
Pair() = default;
explicit constexpr Pair(const Pair& source) : hi(source.hi), lo(source.lo) {}
template<typename Hi, typename Lo> constexpr Pair(const Hi& hi, const Lo& lo) : hi(hi), lo(lo) {}
template<typename T> Pair(const T& source) { _set(*this, source); }
explicit operator bool() const { return hi | lo; }
template<typename T> operator T() const { T value; _get(*this, value); return value; }
auto operator+() const -> Pair { return *this; }
auto operator-() const -> Pair { return Pair(0) - *this; }
auto operator~() const -> Pair { return {~hi, ~lo}; }
auto operator!() const -> bool { return !(hi || lo); }
auto operator++() -> Pair& { lo++; hi += lo == 0; return *this; }
auto operator--() -> Pair& { hi -= lo == 0; lo--; return *this; }
auto operator++(s32) -> Pair { Pair r = *this; lo++; hi += lo == 0; return r; }
auto operator--(s32) -> Pair { Pair r = *this; hi -= lo == 0; lo--; return r; }
auto operator* (const Pair& rhs) const -> Pair { return mul(*this, rhs); }
auto operator/ (const Pair& rhs) const -> Pair { Pair q, r; div(*this, rhs, q, r); return q; }
auto operator% (const Pair& rhs) const -> Pair { Pair q, r; div(*this, rhs, q, r); return r; }
auto operator+ (const Pair& rhs) const -> Pair { return {hi + rhs.hi + (lo + rhs.lo < lo), lo + rhs.lo}; }
auto operator- (const Pair& rhs) const -> Pair { return {hi - rhs.hi - (lo - rhs.lo > lo), lo - rhs.lo}; }
auto operator<<(const Pair& rhs) const -> Pair { return shl(*this, rhs); }
auto operator>>(const Pair& rhs) const -> Pair { return shr(*this, rhs); }
auto operator& (const Pair& rhs) const -> Pair { return {hi & rhs.hi, lo & rhs.lo}; }
auto operator| (const Pair& rhs) const -> Pair { return {hi | rhs.hi, lo | rhs.lo}; }
auto operator^ (const Pair& rhs) const -> Pair { return {hi ^ rhs.hi, lo ^ rhs.lo}; }
auto operator==(const Pair& rhs) const -> bool { return hi == rhs.hi && lo == rhs.lo; }
auto operator!=(const Pair& rhs) const -> bool { return hi != rhs.hi || lo != rhs.lo; }
auto operator>=(const Pair& rhs) const -> bool { return hi > rhs.hi || (hi == rhs.hi && lo >= rhs.lo); }
auto operator<=(const Pair& rhs) const -> bool { return hi < rhs.hi || (hi == rhs.hi && lo <= rhs.lo); }
auto operator> (const Pair& rhs) const -> bool { return hi > rhs.hi || (hi == rhs.hi && lo > rhs.lo); }
auto operator< (const Pair& rhs) const -> bool { return hi < rhs.hi || (hi == rhs.hi && lo < rhs.lo); }
template<typename T> auto& operator*= (const T& rhs) { return *this = *this * Pair(rhs); }
template<typename T> auto& operator/= (const T& rhs) { return *this = *this / Pair(rhs); }
template<typename T> auto& operator%= (const T& rhs) { return *this = *this % Pair(rhs); }
template<typename T> auto& operator+= (const T& rhs) { return *this = *this + Pair(rhs); }
template<typename T> auto& operator-= (const T& rhs) { return *this = *this - Pair(rhs); }
template<typename T> auto& operator<<=(const T& rhs) { return *this = *this << Pair(rhs); }
template<typename T> auto& operator>>=(const T& rhs) { return *this = *this >> Pair(rhs); }
template<typename T> auto& operator&= (const T& rhs) { return *this = *this & Pair(rhs); }
template<typename T> auto& operator|= (const T& rhs) { return *this = *this | Pair(rhs); }
template<typename T> auto& operator^= (const T& rhs) { return *this = *this ^ Pair(rhs); }
template<typename T> auto operator* (const T& rhs) const { return Cast(*this) * Cast(rhs); }
template<typename T> auto operator/ (const T& rhs) const { return Cast(*this) / Cast(rhs); }
template<typename T> auto operator% (const T& rhs) const { return Cast(*this) % Cast(rhs); }
template<typename T> auto operator+ (const T& rhs) const { return Cast(*this) + Cast(rhs); }
template<typename T> auto operator- (const T& rhs) const { return Cast(*this) - Cast(rhs); }
template<typename T> auto operator<<(const T& rhs) const { return Cast(*this) << Cast(rhs); }
template<typename T> auto operator>>(const T& rhs) const { return Cast(*this) >> Cast(rhs); }
template<typename T> auto operator& (const T& rhs) const { return Cast(*this) & Cast(rhs); }
template<typename T> auto operator| (const T& rhs) const { return Cast(*this) | Cast(rhs); }
template<typename T> auto operator^ (const T& rhs) const { return Cast(*this) ^ Cast(rhs); }
template<typename T> auto operator==(const T& rhs) const -> bool { return Cast(*this) == Cast(rhs); }
template<typename T> auto operator!=(const T& rhs) const -> bool { return Cast(*this) != Cast(rhs); }
template<typename T> auto operator>=(const T& rhs) const -> bool { return Cast(*this) >= Cast(rhs); }
template<typename T> auto operator<=(const T& rhs) const -> bool { return Cast(*this) <= Cast(rhs); }
template<typename T> auto operator> (const T& rhs) const -> bool { return Cast(*this) > Cast(rhs); }
template<typename T> auto operator< (const T& rhs) const -> bool { return Cast(*this) < Cast(rhs); }
private:
Type lo;
Type hi;
friend auto upper(const Pair&) -> Type;
friend auto lower(const Pair&) -> Type;
friend auto bits(Pair) -> u32;
friend auto square(const Pair&) -> Pair;
friend auto square(const Pair&, Pair&, Pair&) -> void;
friend auto mul(const Pair&, const Pair&) -> Pair;
friend auto mul(const Pair&, const Pair&, Pair&, Pair&) -> void;
friend auto div(const Pair&, const Pair&, Pair&, Pair&) -> void;
template<typename T> friend auto shl(const Pair&, const T&) -> Pair;
template<typename T> friend auto shr(const Pair&, const T&) -> Pair;
};
template<> struct ArithmeticNatural<PairBits> {
using type = Pair;
};
#define ConcatenateUDL(Size) _u##Size
#define DeclareUDL(Size) ConcatenateUDL(Size)
alwaysinline auto operator"" DeclareUDL(PairBits)(const char* s) -> Pair {
Pair p = 0;
if(s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
s += 2;
while(*s) {
auto c = *s++;
if(c == '\'');
else if(c >= '0' && c <= '9') p = (p << 4) + (c - '0');
else if(c >= 'a' && c <= 'f') p = (p << 4) + (c - 'a' + 10);
else if(c >= 'A' && c <= 'F') p = (p << 4) + (c - 'A' + 10);
else break;
}
} else {
while(*s) {
auto c = *s++;
if(c == '\'');
else if(c >= '0' && c <= '9') p = (p << 3) + (p << 1) + (c - '0');
else break;
}
}
return p;
}
#undef ConcatenateUDL
#undef DeclareUDL
template<typename T> alwaysinline auto _set(Pair& lhs, const T& rhs) -> enable_if_t<(sizeof(Pair) == sizeof(T))> {
lhs = rhs;
}
template<typename T> alwaysinline auto _set(Pair& lhs, const T& rhs) -> enable_if_t<(sizeof(Pair) > sizeof(T))> {
lhs = {0, rhs};
}
template<typename T> alwaysinline auto _set(Pair& lhs, const T& rhs) -> enable_if_t<(sizeof(Pair) < sizeof(T))> {
lhs = {lower(rhs) >> TypeBits, lower(rhs)};
}
template<typename T> alwaysinline auto _get(const Pair& lhs, T& rhs) -> enable_if_t<(sizeof(T) == sizeof(Pair))> {
rhs = lhs;
}
template<typename T> alwaysinline auto _get(const Pair& lhs, T& rhs) -> enable_if_t<(sizeof(T) > sizeof(Pair))> {
rhs = {0, lhs};
}
template<typename T> alwaysinline auto _get(const Pair& lhs, T& rhs) -> enable_if_t<(sizeof(T) < sizeof(Pair))> {
rhs = lower(lhs);
}
alwaysinline auto upper(const Pair& value) -> Type { return value.hi; }
alwaysinline auto lower(const Pair& value) -> Type { return value.lo; }
alwaysinline auto bits(Pair value) -> u32 {
if(value.hi) {
u32 bits = TypeBits;
while(value.hi) value.hi >>= 1, bits++;
return bits;
} else {
u32 bits = 0;
while(value.lo) value.lo >>= 1, bits++;
return bits;
}
}
//Bits * Bits => Bits
inline auto square(const Pair& lhs) -> Pair {
static const Type Mask = (Type(0) - 1) >> HalfBits;
Type a = lhs.hi >> HalfBits, b = lhs.hi & Mask, c = lhs.lo >> HalfBits, d = lhs.lo & Mask;
Type dd = square(d), dc = d * c, db = d * b, da = d * a;
Type cc = square(c), cb = c * b;
Pair r0 = Pair(dd);
Pair r1 = Pair(dc) + Pair(dc) + Pair(r0 >> HalfBits);
Pair r2 = Pair(db) + Pair(cc) + Pair(db) + Pair(r1 >> HalfBits);
Pair r3 = Pair(da) + Pair(cb) + Pair(cb) + Pair(da) + Pair(r2 >> HalfBits);
return {(r3.lo & Mask) << HalfBits | (r2.lo & Mask), (r1.lo & Mask) << HalfBits | (r0.lo & Mask)};
}
//Bits * Bits => 2 * Bits
inline auto square(const Pair& lhs, Pair& hi, Pair& lo) -> void {
static const Type Mask = (Type(0) - 1) >> HalfBits;
Type a = lhs.hi >> HalfBits, b = lhs.hi & Mask, c = lhs.lo >> HalfBits, d = lhs.lo & Mask;
Type dd = square(d), dc = d * c, db = d * b, da = d * a;
Type cc = square(c), cb = c * b, ca = c * a;
Type bb = square(b), ba = b * a;
Type aa = square(a);
Pair r0 = Pair(dd);
Pair r1 = Pair(dc) + Pair(dc) + Pair(r0 >> HalfBits);
Pair r2 = Pair(db) + Pair(cc) + Pair(db) + Pair(r1 >> HalfBits);
Pair r3 = Pair(da) + Pair(cb) + Pair(cb) + Pair(da) + Pair(r2 >> HalfBits);
Pair r4 = Pair(ca) + Pair(bb) + Pair(ca) + Pair(r3 >> HalfBits);
Pair r5 = Pair(ba) + Pair(ba) + Pair(r4 >> HalfBits);
Pair r6 = Pair(aa) + Pair(r5 >> HalfBits);
Pair r7 = Pair(r6 >> HalfBits);
hi = {(r7.lo & Mask) << HalfBits | (r6.lo & Mask), (r5.lo & Mask) << HalfBits | (r4.lo & Mask)};
lo = {(r3.lo & Mask) << HalfBits | (r2.lo & Mask), (r1.lo & Mask) << HalfBits | (r0.lo & Mask)};
}
//Bits * Bits => Bits
alwaysinline auto mul(const Pair& lhs, const Pair& rhs) -> Pair {
static const Type Mask = (Type(0) - 1) >> HalfBits;
Type a = lhs.hi >> HalfBits, b = lhs.hi & Mask, c = lhs.lo >> HalfBits, d = lhs.lo & Mask;
Type e = rhs.hi >> HalfBits, f = rhs.hi & Mask, g = rhs.lo >> HalfBits, h = rhs.lo & Mask;
Pair r0 = Pair(d * h);
Pair r1 = Pair(c * h) + Pair(d * g) + Pair(r0 >> HalfBits);
Pair r2 = Pair(b * h) + Pair(c * g) + Pair(d * f) + Pair(r1 >> HalfBits);
Pair r3 = Pair(a * h) + Pair(b * g) + Pair(c * f) + Pair(d * e) + Pair(r2 >> HalfBits);
return {(r3.lo & Mask) << HalfBits | (r2.lo & Mask), (r1.lo & Mask) << HalfBits | (r0.lo & Mask)};
}
//Bits * Bits => 2 * Bits
alwaysinline auto mul(const Pair& lhs, const Pair& rhs, Pair& hi, Pair& lo) -> void {
static const Type Mask = (Type(0) - 1) >> HalfBits;
Type a = lhs.hi >> HalfBits, b = lhs.hi & Mask, c = lhs.lo >> HalfBits, d = lhs.lo & Mask;
Type e = rhs.hi >> HalfBits, f = rhs.hi & Mask, g = rhs.lo >> HalfBits, h = rhs.lo & Mask;
Pair r0 = Pair(d * h);
Pair r1 = Pair(c * h) + Pair(d * g) + Pair(r0 >> HalfBits);
Pair r2 = Pair(b * h) + Pair(c * g) + Pair(d * f) + Pair(r1 >> HalfBits);
Pair r3 = Pair(a * h) + Pair(b * g) + Pair(c * f) + Pair(d * e) + Pair(r2 >> HalfBits);
Pair r4 = Pair(a * g) + Pair(b * f) + Pair(c * e) + Pair(r3 >> HalfBits);
Pair r5 = Pair(a * f) + Pair(b * e) + Pair(r4 >> HalfBits);
Pair r6 = Pair(a * e) + Pair(r5 >> HalfBits);
Pair r7 = Pair(r6 >> HalfBits);
hi = {(r7.lo & Mask) << HalfBits | (r6.lo & Mask), (r5.lo & Mask) << HalfBits | (r4.lo & Mask)};
lo = {(r3.lo & Mask) << HalfBits | (r2.lo & Mask), (r1.lo & Mask) << HalfBits | (r0.lo & Mask)};
}
alwaysinline auto div(const Pair& lhs, const Pair& rhs, Pair& quotient, Pair& remainder) -> void {
if(!rhs) throw std::runtime_error("division by zero");
quotient = 0, remainder = lhs;
if(!lhs || lhs < rhs) return;
auto count = bits(lhs) - bits(rhs);
Pair x = rhs << count;
Pair y = Pair(1) << count;
if(x > remainder) x >>= 1, y >>= 1;
while(remainder >= rhs) {
if(remainder >= x) remainder -= x, quotient |= y;
x >>= 1, y >>= 1;
}
}
template<typename T> alwaysinline auto shl(const Pair& lhs, const T& rhs) -> Pair {
if(!rhs) return lhs;
auto shift = (u32)rhs;
if(shift < TypeBits) {
return {lhs.hi << shift | lhs.lo >> (TypeBits - shift), lhs.lo << shift};
} else {
return {lhs.lo << (shift - TypeBits), 0};
}
}
template<typename T> alwaysinline auto shr(const Pair& lhs, const T& rhs) -> Pair {
if(!rhs) return lhs;
auto shift = (u32)rhs;
if(shift < TypeBits) {
return {lhs.hi >> shift, lhs.hi << (TypeBits - shift) | lhs.lo >> shift};
} else {
return {0, lhs.hi >> (shift - TypeBits)};
}
}
template<typename T> alwaysinline auto rol(const Pair& lhs, const T& rhs) -> Pair {
return lhs << rhs | lhs >> (PairBits - rhs);
}
template<typename T> alwaysinline auto ror(const Pair& lhs, const T& rhs) -> Pair {
return lhs >> rhs | lhs << (PairBits - rhs);
}
#define EI enable_if_t<is_integral<T>::value>
template<typename T, EI> auto& operator*= (T& lhs, const Pair& rhs) { return lhs = lhs * T(rhs); }
template<typename T, EI> auto& operator/= (T& lhs, const Pair& rhs) { return lhs = lhs / T(rhs); }
template<typename T, EI> auto& operator%= (T& lhs, const Pair& rhs) { return lhs = lhs % T(rhs); }
template<typename T, EI> auto& operator+= (T& lhs, const Pair& rhs) { return lhs = lhs + T(rhs); }
template<typename T, EI> auto& operator-= (T& lhs, const Pair& rhs) { return lhs = lhs - T(rhs); }
template<typename T, EI> auto& operator<<=(T& lhs, const Pair& rhs) { return lhs = lhs << T(rhs); }
template<typename T, EI> auto& operator>>=(T& lhs, const Pair& rhs) { return lhs = lhs >> T(rhs); }
template<typename T, EI> auto& operator&= (T& lhs, const Pair& rhs) { return lhs = lhs & T(rhs); }
template<typename T, EI> auto& operator|= (T& lhs, const Pair& rhs) { return lhs = lhs | T(rhs); }
template<typename T, EI> auto& operator^= (T& lhs, const Pair& rhs) { return lhs = lhs ^ T(rhs); }
template<typename T, EI> auto operator* (const T& lhs, const Pair& rhs) { return Cast(lhs) * Cast(rhs); }
template<typename T, EI> auto operator/ (const T& lhs, const Pair& rhs) { return Cast(lhs) / Cast(rhs); }
template<typename T, EI> auto operator% (const T& lhs, const Pair& rhs) { return Cast(lhs) % Cast(rhs); }
template<typename T, EI> auto operator+ (const T& lhs, const Pair& rhs) { return Cast(lhs) + Cast(rhs); }
template<typename T, EI> auto operator- (const T& lhs, const Pair& rhs) { return Cast(lhs) - Cast(rhs); }
template<typename T, EI> auto operator<<(const T& lhs, const Pair& rhs) { return Cast(lhs) << Cast(rhs); }
template<typename T, EI> auto operator>>(const T& lhs, const Pair& rhs) { return Cast(lhs) >> Cast(rhs); }
template<typename T, EI> auto operator& (const T& lhs, const Pair& rhs) { return Cast(lhs) & Cast(rhs); }
template<typename T, EI> auto operator| (const T& lhs, const Pair& rhs) { return Cast(lhs) | Cast(rhs); }
template<typename T, EI> auto operator^ (const T& lhs, const Pair& rhs) { return Cast(lhs) ^ Cast(rhs); }
template<typename T, EI> auto operator==(const T& lhs, const Pair& rhs) { return Cast(lhs) == Cast(rhs); }
template<typename T, EI> auto operator!=(const T& lhs, const Pair& rhs) { return Cast(lhs) != Cast(rhs); }
template<typename T, EI> auto operator>=(const T& lhs, const Pair& rhs) { return Cast(lhs) >= Cast(rhs); }
template<typename T, EI> auto operator<=(const T& lhs, const Pair& rhs) { return Cast(lhs) <= Cast(rhs); }
template<typename T, EI> auto operator> (const T& lhs, const Pair& rhs) { return Cast(lhs) > Cast(rhs); }
template<typename T, EI> auto operator< (const T& lhs, const Pair& rhs) { return Cast(lhs) < Cast(rhs); }
#undef EI
template<> struct stringify<Pair> {
stringify(Pair source) {
char _output[1 + sizeof(Pair) * 3];
auto p = (char*)&_output;
do {
Pair quotient, remainder;
div(source, 10, quotient, remainder);
*p++ = remainder + '0';
source = quotient;
} while(source);
_size = p - _output;
*p = 0;
for(s32 x = _size - 1, y = 0; x >= 0 && y < _size; x--, y++) _data[x] = _output[y];
}
auto data() const -> const char* { return _data; }
auto size() const -> u32 { return _size; }
char _data[1 + sizeof(Pair) * 3];
u32 _size;
};
}
#undef ConcatenateType
#undef DeclareType
#undef Pair
#undef Type
#undef Half
#undef Cast