bsnes/nall/arithmetic/natural.hpp
Tim Allen f3e67da937 Update to v101r19 release.
byuu says:

Changelog:

-   added \~130 new PAL games to icarus (courtesy of Smarthuman
    and aquaman)
-   added all three Korean-localized games to icarus
-   sfc: removed SuperDisc emulation (it was going nowhere)
-   sfc: fixed MSU1 regression where the play/repeat flags were not
    being cleared on track select
-   nall: cryptography support added; will be used to sign future
    databases (validation will always be optional)
-   minor shims to fix compilation issues due to nall changes

The real magic is that we now have 25-30% of the PAL SNES library in
icarus!

Signing will be tricky. Obviously if I put the public key inside the
higan archive, then all anyone has to do is change that public key for
their own releases. And if you download from my site (which is now over
HTTPS), then you don't need the signing to verify integrity. I may just
put the public key on my site on my site and leave it at that, we'll
see.
2016-10-28 08:16:58 +11:00

354 lines
16 KiB
C++

#define ConcatenateType(Size) uint##Size##_t
#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 {~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--; }
auto operator++(int) -> Pair { Pair r = *this; lo++; hi += lo == 0; return r; }
auto operator--(int) -> 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); }
explicit Pair(const vector<uint8_t>& value) : hi(0), lo(0) {
for(auto n : rrange(value)) {
operator<<=(8);
operator|=(value[n]);
}
}
private:
Type lo;
Type hi;
friend auto upper(const Pair&) -> Type;
friend auto lower(const Pair&) -> Type;
friend auto bits(Pair) -> uint;
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;
};
#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) -> uint {
if(value.hi) {
uint bits = TypeBits;
while(value.hi) value.hi >>= 1, bits++;
return bits;
} else {
uint 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 = (uint)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 = (uint)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++ = '0' + remainder;
source = quotient;
} while(source);
_size = p - _output;
*p = 0;
for(int 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 -> uint { return _size; }
char _data[1 + sizeof(Pair) * 3];
uint _size;
};
inline auto to_vector(Pair value) -> vector<uint8_t> {
vector<uint8_t> result;
result.resize(PairBits / 8);
for(auto& byte : result) {
byte = value;
value >>= 8;
}
return result;
}
}
#undef ConcatenateType
#undef DeclareType
#undef Pair
#undef Type
#undef Half
#undef Cast