Update to v106r77 release.

byuu says:

So this turned out to be a rather unproductive ten-hour rabbit hole, but
...

I reworked nall/primitives.hpp a lot. And because the changes are
massive, testing of this WIP for regressions is critically important. I
really can't stress that enough, we're almost certainly going to have
some hidden regressions here ...

We now have a nall/primitives/ subfolder that splits up the classes into
manageable components. The bit-field support is now shared between both
Natural and Integer. All of the assignment operator overloads are now
templated and take references instead of values. Things like the
GSU::Register class are non-copyable on account of the function<>
object inside of it, and previously only operator= would work with
classes like that.

The big change is nall/primitives/operators.hpp, which is a really
elaborate system to compute the minimum number of bits needed for any
operation, and to return a Natural<T> or Integer<T> when one or both of
the arguments are such a type.

Unfortunately, it doesn't really work yet ... Kirby's Dream Land 3
breaks if we include operators.hpp. Zelda 3 runs fine with this, but I
had to make a huge amount of core changes, including introducing a new
ternary(bool, lhs, rhs) function to nall/algorithm to get past
Natural<X> and Natural<Y> not being equivalent (is_integral types get a
special exemption to ternary ?: type equivalence, yet it's impossible to
simulate with our own classes, which is bullshit.) The horrifying part
is that ternary() will evaluate both lhs and rhs, unlike ?:

I converted some of the functions to test ? uint(x) : uint(y), and
others to ternary(test, x, y) ... I don't have a strong preference
either way yet.

But the part where things may have gotten broken is in the changes to
where ternary() was placed. Some cases like in the GBA PPU renderer, it
was rather unclear the order of evaluations, so I may have made a
mistake somewhere.

So again, please please test this if you can. Or even better, look over
the diff.

Longer-term, I'd really like the enable nall/primitives/operators.hpp,
but right now I'm not sure why Kirby's Dream Land 3 is breaking. Help
would be appreciated, but ... it's gonna be really complex and difficult
to debug, so I'm probably gonna be on my own here ... sigh.
This commit is contained in:
Tim Allen 2019-01-13 17:25:14 +11:00
parent c9f7c6c4be
commit bb1dd8c609
33 changed files with 583 additions and 335 deletions

View File

@ -30,7 +30,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
static const string Version = "106.76";
static const string Version = "106.77";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "https://byuu.org/";

View File

@ -33,7 +33,7 @@ auto Interface::color(uint32 n) -> uint64 {
double brightness = 1.0;
double gamma = settings.colorEmulation ? 1.8 : 2.2;
int color = (n & 0x0f), level = color < 0xe ? (n >> 4) & 3 : 1;
int color = (n & 0x0f), level = color < 0xe ? int(n >> 4 & 3) : 1;
static const double black = 0.518, white = 1.962, attenuation = 0.746;
static const double levels[8] = {

View File

@ -104,7 +104,7 @@ auto PPU::Background::affine(uint x, uint y) -> void {
}
uint screenSize = 16 << io.screenSize;
uint screenWrap = (1 << (io.affineWrap ? 7 + io.screenSize : 20)) - 1;
uint screenWrap = (1 << ternary(io.affineWrap, 7 + io.screenSize, 20)) - 1;
uint cx = (fx >> 8) & screenWrap;
uint cy = (fy >> 8) & screenWrap;
@ -148,7 +148,7 @@ auto PPU::Background::bitmap(uint x, uint y) -> void {
uint height = io.mode == 5 ? 128 : 160;
uint mode = depth ? Half : Byte;
uint baseAddress = io.mode == 3 ? 0 : 0xa000 * io.frame;
uint baseAddress = ternary(io.mode == 3, 0, 0xa000 * io.frame);
uint px = fx >> 8;
uint py = fy >> 8;

View File

@ -8,12 +8,12 @@ auto PPU::Objects::scanline(uint y) -> void {
if(object.affine == 0 && object.affineSize == 1) continue; //hidden
if(py >= object.height << object.affineSize) continue; //offscreen
uint rowSize = io.mapping == 0 ? 32 >> object.colors : object.width >> 3;
uint rowSize = ternary(io.mapping == 0, 32 >> object.colors, object.width >> 3);
uint baseAddress = object.character << 5;
if(object.mosaic && io.mosaicHeight) {
int mosaicY = (y / (1 + io.mosaicHeight)) * (1 + io.mosaicHeight);
py = object.y >= 160 || mosaicY - object.y >= 0 ? mosaicY - object.y : 0;
py = object.y >= 160 || mosaicY - object.y >= 0 ? uint(mosaicY - object.y) : 0;
}
int16 pa = ppu.objectParam[object.affineParam].pa;

View File

@ -70,7 +70,7 @@ auto VDP::Background::run(uint x, uint y) -> void {
uint16 tileData = vdp.vram.read(tileAddress);
uint4 color = tileData >> (((pixelX & 3) ^ 3) << 2);
output.color = color ? tileAttributes.bits(13,14) << 4 | color : 0;
output.color = ternary(color, tileAttributes.bits(13,14) << 4 | color, 0);
output.priority = tileAttributes.bit(15);
}

View File

@ -27,7 +27,7 @@ auto YM2612::Channel::Operator::trigger(bool state) -> void {
}
auto YM2612::Channel::Operator::runEnvelope() -> void {
uint sustain = envelope.sustainLevel < 15 ? envelope.sustainLevel << 5 : 0x3f0;
uint sustain = ternary(envelope.sustainLevel < 15, envelope.sustainLevel << 5, 0x3f0);
if(ym2612.envelope.clock & (1 << envelope.divider) - 1) return;
uint value = ym2612.envelope.clock >> envelope.divider;
@ -121,7 +121,7 @@ auto YM2612::Channel::Operator::updatePhase() -> void {
phase.delta = pitch.value + (pm >> 10 - msb) << 6 >> 7 - octave.value;
phase.delta = (!detune.bit(2) ? phase.delta + tuning : phase.delta - tuning) & 0x1ffff;
phase.delta = (multiple ? phase.delta * multiple : phase.delta >> 1) & 0xfffff;
phase.delta = ternary(multiple, phase.delta * multiple, phase.delta >> 1) & 0xfffff;
}
auto YM2612::Channel::Operator::updateLevel() -> void {

View File

@ -64,7 +64,7 @@ auto YM2612::sample() -> void {
auto wave = [&](uint n, uint modulation) -> int {
int x = (modulation >> 1) + (op[n].phase.value >> 10);
int y = sine[x & 0x3ff] + op[n].outputLevel;
return y < 0x2000 ? pow2[y & 0x1ff] << 2 >> (y >> 9) : 0;
return ternary(y < 0x2000, pow2[y & 0x1ff] << 2 >> (y >> 9), 0);
};
int feedback = modMask & op[0].output + op[0].prior >> 9 - channel.feedback;

View File

@ -13,8 +13,8 @@ auto ARM7TDMI::ADD(uint32 source, uint32 modify, bool carry) -> uint32 {
auto ARM7TDMI::ASR(uint32 source, uint8 shift) -> uint32 {
carry = cpsr().c;
if(shift == 0) return source;
carry = shift > 32 ? source & 1 << 31 : source & 1 << shift - 1;
source = shift > 31 ? (int32)source >> 31 : (int32)source >> shift;
carry = ternary(shift > 32, source & 1 << 31, source & 1 << shift - 1);
source = ternary(shift > 31, (int32)source >> 31, (int32)source >> shift);
return source;
}
@ -30,16 +30,16 @@ auto ARM7TDMI::BIT(uint32 result) -> uint32 {
auto ARM7TDMI::LSL(uint32 source, uint8 shift) -> uint32 {
carry = cpsr().c;
if(shift == 0) return source;
carry = shift > 32 ? 0 : source & 1 << 32 - shift;
source = shift > 31 ? 0 : source << shift;
carry = ternary(shift > 32, 0, source & 1 << 32 - shift);
source = ternary(shift > 31, 0, source << shift);
return source;
}
auto ARM7TDMI::LSR(uint32 source, uint8 shift) -> uint32 {
carry = cpsr().c;
if(shift == 0) return source;
carry = shift > 32 ? 0 : source & 1 << shift - 1;
source = shift > 31 ? 0 : source >> shift;
carry = ternary(shift > 32, 0, source & 1 << shift - 1);
source = ternary(shift > 31, 0, source >> shift);
return source;
}

View File

@ -95,7 +95,7 @@ auto ARM7TDMI::armInstructionDataRegisterShift
case 0: rm = LSL(rm, rs < 33 ? rs : (uint8)33); break;
case 1: rm = LSR(rm, rs < 33 ? rs : (uint8)33); break;
case 2: rm = ASR(rm, rs < 32 ? rs : (uint8)32); break;
case 3: if(rs) rm = ROR(rm, rs & 31 ? rs & 31 : 32); break;
case 3: if(rs) rm = ROR(rm, rs & 31 ? uint(rs & 31) : 32); break;
}
armALU(mode, d, n, rm);

View File

@ -221,7 +221,7 @@ auto GSU::instructionAND_BIC(uint n) -> void {
//$80-8f(alt3) umult #N
auto GSU::instructionMULT_UMULT(uint n) -> void {
if(!regs.sfr.alt2) n = regs.r[n];
regs.dr() = (!regs.sfr.alt1 ? ((int8)regs.sr() * (int8)n) : ((uint8)regs.sr() * (uint8)n));
regs.dr() = (!regs.sfr.alt1 ? uint16((int8)regs.sr() * (int8)n) : uint16((uint8)regs.sr() * (uint8)n));
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();

View File

@ -63,14 +63,14 @@ struct M68K {
//registers.cpp
struct DataRegister {
explicit DataRegister(uint number_) : number(number_) {}
explicit DataRegister(uint64 number_) : number(number_) {}
uint3 number;
};
template<uint Size = Long> auto read(DataRegister reg) -> uint32;
template<uint Size = Long> auto write(DataRegister reg, uint32 data) -> void;
struct AddressRegister {
explicit AddressRegister(uint number_) : number(number_) {}
explicit AddressRegister(uint64 number_) : number(number_) {}
uint3 number;
};
template<uint Size = Long> auto read(AddressRegister reg) -> uint32;

View File

@ -570,7 +570,7 @@ auto SPC700::instructionTestSetBitsAbsolute(bool set) -> void {
ZF = (A - data) == 0;
NF = (A - data) & 0x80;
read(address);
write(address, set ? data | A : data & ~A);
write(address, ternary(set, data | A, data & ~A));
}
auto SPC700::instructionTransfer(uint8& from, uint8& to) -> void {

View File

@ -21,10 +21,12 @@ template<> auto TLCS900H::parity<uint32>(uint32 data) const -> bool {
template<typename T> auto TLCS900H::algorithmAdd(T target, T source, uint1 carry) -> T {
T result = target + source + carry;
CF = result < target || result == target && carry;
T carries = target ^ source ^ result;
T overflow = (target ^ result) & (source ^ result);
CF = T(carries ^ overflow).negative();
NF = 0;
VF = T((target ^ result) & (source ^ result)).negative();
HF = T(target ^ source ^ result).bit(4);
VF = overflow.negative();
HF = carries.bit(4);
if constexpr(T::bits() == 32) HF = Undefined;
ZF = result.zero();
SF = result.negative();
@ -79,10 +81,12 @@ template<typename T> auto TLCS900H::algorithmOr(T target, T source) -> T {
template<typename T> auto TLCS900H::algorithmSubtract(T target, T source, uint1 carry) -> T {
T result = target - source - carry;
CF = result > target || result == target && carry;
T carries = target ^ source ^ result;
T overflow = (target ^ result) & (source ^ target);
CF = T(carries ^ overflow).negative();
NF = 1;
VF = T((target ^ source) & (target ^ result)).negative();
HF = T(target ^ source ^ result).bit(4);
VF = overflow.negative();
HF = carries.bit(4);
if constexpr(T::bits() == 32) HF = Undefined;
ZF = result.zero();
SF = result.negative();

View File

@ -32,13 +32,13 @@ auto WDC65816::fetch() -> uint8 {
}
auto WDC65816::pull() -> uint8 {
EF ? lo(S)++ : S++;
EF ? (void)lo(S)++ : (void)S++;
return read(S);
}
auto WDC65816::push(uint8 data) -> void {
write(S, data);
EF ? lo(S)-- : S--;
EF ? (void)lo(S)-- : (void)S--;
}
auto WDC65816::pullN() -> uint8 {

View File

@ -437,7 +437,7 @@ auto SA1::writeIOSA1(uint24 address, uint8 data) -> void {
} else {
int16 dividend = mmio.ma;
uint16 divisor = mmio.mb;
uint16 remainder = dividend >= 0 ? dividend % divisor : (dividend % divisor + divisor) % divisor;
uint16 remainder = dividend >= 0 ? uint16(dividend % divisor) : uint16((dividend % divisor + divisor) % divisor);
uint16 quotient = (dividend - remainder) / divisor;
mmio.mr = remainder << 16 | quotient;
}

View File

@ -18,7 +18,7 @@ auto SPC7110::dcuBeginTransfer() -> void {
decompressor->initialize(dcuMode, dcuAddress);
decompressor->decode();
uint seek = r480b & 2 ? r4805 | r4806 << 8 : 0;
uint seek = ternary(r480b & 2, r4805 | r4806 << 8, 0);
while(seek--) decompressor->decode();
r480c |= 0x80;

View File

@ -26,7 +26,7 @@ auto PPU::Line::renderBackground(PPU::IO::Background& self, uint source) -> void
uint hmask = (width << self.tileSize << self.screenSize.bit(0)) - 1;
uint vmask = (width << self.tileSize << self.screenSize.bit(1)) - 1;
uint y = this->y - (self.mosaicEnable ? this->y % (1 + io.mosaicSize) : 0);
uint y = this->y - ternary(self.mosaicEnable, this->y % (1 + io.mosaicSize), 0);
if(hires) {
hscroll <<= 1;
if(io.interlace) y = y << 1 | ppu.field();

View File

@ -1,5 +1,5 @@
auto PPU::Line::renderMode7(PPU::IO::Background& self, uint source) -> void {
int Y = this->y - (self.mosaicEnable ? this->y % (1 + io.mosaicSize) : 0);
int Y = this->y - ternary(self.mosaicEnable, this->y % (1 + io.mosaicSize), 0);
int y = !io.mode7.vflip ? Y : 255 - Y;
int a = (int16)io.mode7.a;

View File

@ -129,7 +129,7 @@ auto PPU::oamAddressReset() -> void {
}
auto PPU::oamSetFirstObject() -> void {
io.obj.first = !io.oamPriority ? 0 : io.oamAddress >> 2;
io.obj.first = !io.oamPriority ? 0 : uint(io.oamAddress >> 2);
}
auto PPU::readObject(uint10 address) -> uint8 {

View File

@ -165,7 +165,7 @@ auto PPU::Background::run(bool screen) -> void {
uint8 color = getTileColor();
Pixel pixel;
pixel.priority = priority;
pixel.palette = color ? paletteIndex + color : 0;
pixel.palette = color ? uint(paletteIndex + color) : 0;
pixel.tile = tile;
if(x == 0) {

View File

@ -6,7 +6,7 @@ auto PPU::Object::addressReset() -> void {
}
auto PPU::Object::setFirstSprite() -> void {
io.firstSprite = !ppu.io.oamPriority ? 0 : ppu.io.oamAddress >> 2;
io.firstSprite = !ppu.io.oamPriority ? 0 : uint(ppu.io.oamAddress >> 2);
}
auto PPU::Object::frame() -> void {

View File

@ -8,7 +8,7 @@
namespace nall { namespace {
template<typename T, typename U> auto min(const T& t, const U& u) -> T {
return t < u ? t : u;
return t < u ? t : (T)u;
}
template<typename T, typename U, typename... P> auto min(const T& t, const U& u, P&&... p) -> T {
@ -16,11 +16,15 @@ template<typename T, typename U, typename... P> auto min(const T& t, const U& u,
}
template<typename T, typename U> auto max(const T& t, const U& u) -> T {
return t > u ? t : u;
return t > u ? t : (T)u;
}
template<typename T, typename U, typename... P> auto max(const T& t, const U& u, P&&... p) -> T {
return t > u ? max(t, forward<P>(p)...) : max(u, forward<P>(p)...);
}
template<typename T, typename U> auto ternary(bool test, const T& lhs, const U& rhs) -> T {
return test ? lhs : (T)rhs;
}
}}

View File

@ -1,5 +1,7 @@
#pragma once
#include <nall/primitives.hpp>
namespace nall {
template<typename Type, uint Bit> struct BooleanBitField {
@ -55,7 +57,7 @@ template<typename Type, uint Lo, uint Hi> struct NaturalBitField {
inline operator utype() const { return get(); }
inline auto& operator=(const NaturalBitField& value) { return set(value.data); }
template<typename T> inline auto& operator=(const T& value) { return set(value << lo); }
template<typename T> inline auto& operator=(T value) { return set(value << lo); }
inline auto operator++(int) { utype value = get(); set(data + (1 << lo)); return value; }
inline auto operator--(int) { utype value = get(); set(data - (1 << lo)); return value; }

View File

@ -4,300 +4,20 @@
#include <nall/traits.hpp>
namespace nall {
struct Boolean;
template<uint Bits> struct Natural;
template<uint Bits> struct Integer;
struct Boolean {
inline Boolean() : data(false) {}
template<typename T> inline Boolean(const T& value) : data(value) {}
inline operator bool() const { return data; }
template<typename T> inline auto& operator=(const T& value) { data = value; return *this; }
inline auto flip() { return data ^= 1; }
inline auto raise() { return data == 0 ? data = 1, true : false; }
inline auto lower() { return data == 1 ? data = 0, true : false; }
inline auto flip(bool value) { return data != value ? (data = value, true) : false; }
inline auto raise(bool value) { return !data && value ? (data = value, true) : (data = value, false); }
inline auto lower(bool value) { return data && !value ? (data = value, true) : (data = value, false); }
inline auto serialize(serializer& s) { s(data); }
private:
bool data;
};
template<uint Bits> struct Natural {
using type =
typename conditional<Bits <= 8, uint8_t,
typename conditional<Bits <= 16, uint16_t,
typename conditional<Bits <= 32, uint32_t,
typename conditional<Bits <= 64, uint64_t,
void>::type>::type>::type>::type;
enum : type { Mask = ~0ull >> (64 - Bits) };
static inline constexpr auto bits() -> uint { return Bits; }
inline Natural() : data(0) {}
template<typename T> inline Natural(const T& value) { set(value); }
inline operator type() const { return data; }
template<typename T> inline auto& operator=(const T& value) { set(value); return *this; }
inline auto operator++(int) { type value = data; set(data + 1); return value; }
inline auto operator--(int) { type value = data; set(data - 1); return value; }
inline auto& operator++() { set(data + 1); return *this; }
inline auto& operator--() { set(data - 1); return *this; }
inline auto& operator &=(const type value) { set(data & value); return *this; }
inline auto& operator |=(const type value) { set(data | value); return *this; }
inline auto& operator ^=(const type value) { set(data ^ value); return *this; }
inline auto& operator<<=(const type value) { set(data << value); return *this; }
inline auto& operator>>=(const type value) { set(data >> value); return *this; }
inline auto& operator +=(const type value) { set(data + value); return *this; }
inline auto& operator -=(const type value) { set(data - value); return *this; }
inline auto& operator *=(const type value) { set(data * value); return *this; }
inline auto& operator /=(const type value) { set(data / value); return *this; }
inline auto& operator %=(const type value) { set(data % value); return *this; }
inline auto serialize(serializer& s) { s(data); }
struct Reference {
inline Reference(Natural& source, uint lo, uint hi) : source(source), Lo(lo), Hi(hi) {}
inline auto& operator=(Reference& source) { return set(source.get()); }
inline auto get() const -> type {
const type RangeBits = Hi - Lo + 1;
const type RangeMask = (((1ull << RangeBits) - 1) << Lo) & Mask;
return (source & RangeMask) >> Lo;
}
inline auto& set(const type value) {
const type RangeBits = Hi - Lo + 1;
const type RangeMask = (((1ull << RangeBits) - 1) << Lo) & Mask;
source = (source & ~RangeMask) | ((value << Lo) & RangeMask);
return *this;
}
inline operator type() const { return get(); }
inline auto& operator =(const type value) { return set( value); }
inline auto& operator &=(const type value) { return set(get() & value); }
inline auto& operator |=(const type value) { return set(get() | value); }
inline auto& operator ^=(const type value) { return set(get() ^ value); }
inline auto& operator<<=(const type value) { return set(get() << value); }
inline auto& operator>>=(const type value) { return set(get() >> value); }
inline auto& operator +=(const type value) { return set(get() + value); }
inline auto& operator -=(const type value) { return set(get() - value); }
inline auto& operator *=(const type value) { return set(get() * value); }
inline auto& operator /=(const type value) { return set(get() / value); }
inline auto& operator %=(const type value) { return set(get() % value); }
inline auto operator++(int) { auto value = get(); set(value + 1); return value; }
inline auto operator--(int) { auto value = get(); set(value - 1); return value; }
inline auto& operator++() { return set(get() + 1); }
inline auto& operator--() { return set(get() - 1); }
private:
Natural& source;
const type Lo;
const type Hi;
};
inline auto zero() const -> bool { return data == 0; }
inline auto positive() const -> bool { return (data >> bits() - 1) == 0; }
inline auto negative() const -> bool { return (data >> bits() - 1) == 1; }
inline auto bits(uint lo, uint hi) -> Reference { return {*this, lo < hi ? lo : hi, hi > lo ? hi : lo}; }
inline auto bit(uint index) -> Reference { return {*this, index, index}; }
inline auto byte(uint index) -> Reference { return {*this, index * 8 + 0, index * 8 + 7}; }
inline auto bits(uint lo, uint hi) const -> const Reference { return {(Natural&)*this, lo < hi ? lo : hi, hi > lo ? hi : lo}; }
inline auto bit(uint index) const -> const Reference { return {(Natural&)*this, index, index}; }
inline auto byte(uint index) const -> const Reference { return {(Natural&)*this, index * 8 + 0, index * 8 + 7}; }
inline auto clamp(uint bits) -> uintmax {
const uintmax b = 1ull << (bits - 1);
const uintmax m = b * 2 - 1;
return data < m ? data : m;
}
inline auto clip(uint bits) -> uintmax {
const uintmax b = 1ull << (bits - 1);
const uintmax m = b * 2 - 1;
return data & m;
}
inline auto integer() const -> Integer<Bits>;
private:
auto set(type value) -> void {
data = value & Mask;
}
type data;
};
template<uint Bits> struct Integer {
using type =
typename conditional<Bits <= 8, int8_t,
typename conditional<Bits <= 16, int16_t,
typename conditional<Bits <= 32, int32_t,
typename conditional<Bits <= 64, int64_t,
void>::type>::type>::type>::type;
using utype = typename Natural<Bits>::type;
enum : utype { Mask = ~0ull >> (64 - Bits), Sign = 1ull << (Bits - 1) };
static inline constexpr auto bits() -> uint { return Bits; }
inline Integer() : data(0) {}
template<typename T> inline Integer(const T& value) { set(value); }
inline operator type() const { return data; }
template<typename T> inline auto& operator=(const T& value) { set(value); return *this; }
inline auto operator++(int) { type value = data; set(data + 1); return value; }
inline auto operator--(int) { type value = data; set(data - 1); return value; }
inline auto& operator++() { set(data + 1); return *this; }
inline auto& operator--() { set(data - 1); return *this; }
inline auto& operator &=(const type value) { set(data & value); return *this; }
inline auto& operator |=(const type value) { set(data | value); return *this; }
inline auto& operator ^=(const type value) { set(data ^ value); return *this; }
inline auto& operator<<=(const type value) { set(data << value); return *this; }
inline auto& operator>>=(const type value) { set(data >> value); return *this; }
inline auto& operator +=(const type value) { set(data + value); return *this; }
inline auto& operator -=(const type value) { set(data - value); return *this; }
inline auto& operator *=(const type value) { set(data * value); return *this; }
inline auto& operator /=(const type value) { set(data / value); return *this; }
inline auto& operator %=(const type value) { set(data % value); return *this; }
inline auto serialize(serializer& s) { s(data); }
struct Reference {
inline Reference(Integer& source, uint lo, uint hi) : source(source), Lo(lo), Hi(hi) {}
inline auto& operator=(const Reference& source) { return set(source.get()); }
inline auto get() const -> utype {
const type RangeBits = Hi - Lo + 1;
const type RangeMask = (((1ull << RangeBits) - 1) << Lo) & Mask;
return ((utype)source & RangeMask) >> Lo;
}
inline auto& set(const utype value) {
const type RangeBits = Hi - Lo + 1;
const type RangeMask = (((1ull << RangeBits) - 1) << Lo) & Mask;
source = ((utype)source & ~RangeMask) | ((value << Lo) & RangeMask);
return *this;
}
inline operator utype() const { return get(); }
inline auto& operator =(const utype value) { return set( value); }
inline auto& operator &=(const utype value) { return set(get() & value); }
inline auto& operator |=(const utype value) { return set(get() | value); }
inline auto& operator ^=(const utype value) { return set(get() ^ value); }
inline auto& operator<<=(const utype value) { return set(get() << value); }
inline auto& operator>>=(const utype value) { return set(get() >> value); }
inline auto& operator +=(const utype value) { return set(get() + value); }
inline auto& operator -=(const utype value) { return set(get() - value); }
inline auto& operator *=(const utype value) { return set(get() * value); }
inline auto& operator /=(const utype value) { return set(get() / value); }
inline auto& operator %=(const utype value) { return set(get() % value); }
inline auto operator++(int) { auto value = get(); set(value + 1); return value; }
inline auto operator--(int) { auto value = get(); set(value - 1); return value; }
inline auto& operator++() { return set(get() + 1); }
inline auto& operator--() { return set(get() - 1); }
private:
Integer& source;
const uint Lo;
const uint Hi;
};
inline auto zero() const -> bool { return data == 0; }
inline auto positive() const -> bool { return data >= 0; }
inline auto negative() const -> bool { return data < 0; }
inline auto bits(uint lo, uint hi) -> Reference { return {*this, lo < hi ? lo : hi, hi > lo ? hi : lo}; }
inline auto bit(uint index) -> Reference { return {*this, index, index}; }
inline auto byte(uint index) -> Reference { return {*this, index * 8 + 0, index * 8 + 7}; }
inline auto bits(uint lo, uint hi) const -> const Reference { return {(Integer&)*this, lo < hi ? lo : hi, hi > lo ? hi : lo}; }
inline auto bit(uint index) const -> const Reference { return {(Integer&)*this, index, index}; }
inline auto byte(uint index) const -> const Reference { return {(Integer&)*this, index * 8 + 0, index * 8 + 7}; }
inline auto clamp(uint bits) -> intmax {
const intmax b = 1ull << (bits - 1);
const intmax m = b - 1;
return data > m ? m : data < -b ? -b : data;
}
inline auto clip(uint bits) -> intmax {
const uintmax b = 1ull << (bits - 1);
const uintmax m = b * 2 - 1;
return ((data & m) ^ b) - b;
}
inline auto natural() const -> Natural<Bits>;
private:
auto set(type value) -> void {
data = ((value & Mask) ^ Sign) - Sign;
}
type data;
};
//cast an unsigned type to a signed type with the same number of bits
template<uint Bits> auto Natural<Bits>::integer() const -> Integer<Bits> {
return Integer<Bits>(*this);
struct Boolean;
template<int Precision> struct Natural;
template<int Precision> struct Integer;
}
//cast a signed type to an unsigned type with the same number of bits
template<uint Bits> auto Integer<Bits>::natural() const -> Natural<Bits> {
return Natural<Bits>(*this);
}
template<uint Bits> struct Real {
using type =
typename conditional<Bits == 32, float32_t,
typename conditional<Bits == 64, float64_t,
void>::type>::type;
static inline constexpr auto bits() -> uint { return Bits; }
inline Real() : data(0.0) {}
template<typename T> inline Real(const T& value) : data((type)value) {}
inline operator type() const { return data; }
template<typename T> inline auto& operator=(const T& value) { data = (type)value; return *this; }
inline auto operator++(int) { type value = data; ++data; return value; }
inline auto operator--(int) { type value = data; --data; return value; }
inline auto& operator++() { data++; return *this; }
inline auto& operator--() { data--; return *this; }
inline auto& operator+=(const type value) { data = data + value; return *this; }
inline auto& operator-=(const type value) { data = data - value; return *this; }
inline auto& operator*=(const type value) { data = data * value; return *this; }
inline auto& operator/=(const type value) { data = data / value; return *this; }
inline auto& operator%=(const type value) { data = data % value; return *this; }
inline auto serialize(serializer& s) { s(data); }
private:
type data;
};
using boolean = nall::Boolean;
using natural = nall::Natural<sizeof(uint) * 8>;
using integer = nall::Integer<sizeof(int) * 8>;
using real = nall::Real<sizeof(double) * 8>;
#include <nall/primitives/bit-range.hpp>
#include <nall/primitives/boolean.hpp>
#include <nall/primitives/natural.hpp>
#include <nall/primitives/integer.hpp>
#include <nall/primitives/real.hpp>
#include <nall/primitives/types.hpp>
//#include <nall/primitives/operators.hpp>
namespace nall {
template<int Bits> auto Natural<Bits>::integer() const -> Integer<Bits> { return Integer<Bits>(*this); }
template<int Bits> auto Integer<Bits>::natural() const -> Natural<Bits> { return Natural<Bits>(*this); }
}

View File

@ -0,0 +1,58 @@
#pragma once
namespace nall {
template<int RequestedPrecision> struct BitRange {
enum : uint { Precision = RequestedPrecision < 1 ? 1 : RequestedPrecision > 64 ? 64 : RequestedPrecision };
static inline constexpr auto bits() -> uint { return Precision; }
using type =
typename conditional<bits() <= 8, uint8_t,
typename conditional<bits() <= 16, uint16_t,
typename conditional<bits() <= 32, uint32_t,
typename conditional<bits() <= 64, uint64_t,
void>::type>::type>::type>::type;
static inline constexpr auto mask() -> type { return ~0ull >> 64 - bits(); }
inline BitRange(type& source, uint low, uint high)
: source(source), lo(low < high ? low : high), hi(high > low ? high : low) {}
inline auto& operator=(BitRange& source) { return set(source.get()); }
inline auto operator++(int) { auto value = get(); set(value + 1); return value; }
inline auto operator--(int) { auto value = get(); set(value - 1); return value; }
inline auto& operator++() { return set(get() + 1); }
inline auto& operator--() { return set(get() - 1); }
inline operator uint64_t() const { return get(); }
template<typename T> inline auto& operator =(const T& value) { return set( value); }
template<typename T> inline auto& operator *=(const T& value) { return set(get() * value); }
template<typename T> inline auto& operator /=(const T& value) { return set(get() / value); }
template<typename T> inline auto& operator %=(const T& value) { return set(get() % value); }
template<typename T> inline auto& operator +=(const T& value) { return set(get() + value); }
template<typename T> inline auto& operator -=(const T& value) { return set(get() - value); }
template<typename T> inline auto& operator<<=(const T& value) { return set(get() << value); }
template<typename T> inline auto& operator>>=(const T& value) { return set(get() >> value); }
template<typename T> inline auto& operator &=(const T& value) { return set(get() & value); }
template<typename T> inline auto& operator ^=(const T& value) { return set(get() ^ value); }
template<typename T> inline auto& operator |=(const T& value) { return set(get() | value); }
private:
inline auto get() const -> uint64_t {
const type rangeBits = hi - lo + 1;
const type rangeMask = (1ull << rangeBits) - 1 << lo & mask();
return (source & rangeMask) >> lo;
}
inline auto& set(const type& value) {
const type rangeBits = hi - lo + 1;
const type rangeMask = (1ull << rangeBits) - 1 << lo & mask();
source = source & ~rangeMask | value << lo & rangeMask;
return *this;
}
type& source;
const uint lo;
const uint hi;
};
}

View File

@ -0,0 +1,29 @@
#pragma once
namespace nall {
struct Boolean {
static inline constexpr auto bits() -> uint { return 1; }
using type = bool;
inline Boolean() : data(false) {}
template<typename T> inline Boolean(const T& value) : data(value) {}
inline operator bool() const { return data; }
template<typename T> inline auto& operator=(const T& value) { data = value; return *this; }
inline auto flip() { return data ^= 1; }
inline auto raise() { return data == 0 ? data = 1, true : false; }
inline auto lower() { return data == 1 ? data = 0, true : false; }
inline auto flip(bool value) { return data != value ? (data = value, true) : false; }
inline auto raise(bool value) { return !data && value ? (data = value, true) : (data = value, false); }
inline auto lower(bool value) { return data && !value ? (data = value, true) : (data = value, false); }
inline auto serialize(serializer& s) { s(data); }
private:
type data;
};
}

View File

@ -0,0 +1,87 @@
#pragma once
namespace nall {
template<int RequestedPrecision> struct Integer {
enum : uint { Precision = RequestedPrecision < 1 ? 1 : RequestedPrecision > 64 ? 64 : RequestedPrecision };
static inline constexpr auto bits() -> uint { return Precision; }
using type =
typename conditional<bits() <= 8, int8_t,
typename conditional<bits() <= 16, int16_t,
typename conditional<bits() <= 32, int32_t,
typename conditional<bits() <= 64, int64_t,
void>::type>::type>::type>::type;
using utype = typename Natural<RequestedPrecision>::type;
static inline constexpr auto mask() -> utype { return ~0ull >> 64 - bits(); }
static inline constexpr auto sign() -> utype { return 1ull << Precision - 1; }
inline Integer() : data(0) {}
template<typename T> inline Integer(const T& value) { data = mask(value); }
explicit inline operator bool() const { return (bool)data; }
inline operator type() const { return data; }
inline auto operator++(int) { auto value = *this; data = mask(data + 1); return value; }
inline auto operator--(int) { auto value = *this; data = mask(data - 1); return value; }
inline auto& operator++() { data = mask(data + 1); return *this; }
inline auto& operator--() { data = mask(data - 1); return *this; }
inline auto operator!() const { return Integer{!data}; }
inline auto operator~() const { return Integer{~data}; }
inline auto operator+() const { return Integer{+data}; }
inline auto operator-() const { return Integer{-data}; }
#define lhs data
#define rhs value
template<typename T> inline auto& operator =(const T& value) { lhs = mask( rhs); return *this; }
template<typename T> inline auto& operator *=(const T& value) { lhs = mask(lhs * rhs); return *this; }
template<typename T> inline auto& operator /=(const T& value) { lhs = mask(lhs / rhs); return *this; }
template<typename T> inline auto& operator %=(const T& value) { lhs = mask(lhs % rhs); return *this; }
template<typename T> inline auto& operator +=(const T& value) { lhs = mask(lhs + rhs); return *this; }
template<typename T> inline auto& operator -=(const T& value) { lhs = mask(lhs - rhs); return *this; }
template<typename T> inline auto& operator<<=(const T& value) { lhs = mask(lhs << rhs); return *this; }
template<typename T> inline auto& operator>>=(const T& value) { lhs = mask(lhs >> rhs); return *this; }
template<typename T> inline auto& operator &=(const T& value) { lhs = mask(lhs & rhs); return *this; }
template<typename T> inline auto& operator ^=(const T& value) { lhs = mask(lhs ^ rhs); return *this; }
template<typename T> inline auto& operator |=(const T& value) { lhs = mask(lhs | rhs); return *this; }
#undef lhs
#undef rfs
inline auto serialize(serializer& s) { s(data); }
inline auto zero() const -> bool { return data == 0; }
inline auto positive() const -> bool { return data >= 0; }
inline auto negative() const -> bool { return data < 0; }
inline auto bits(uint lo, uint hi) -> BitRange<RequestedPrecision> { return {(utype&)data, lo, hi}; }
inline auto bit(uint index) -> BitRange<RequestedPrecision> { return {(utype&)data, index, index}; }
inline auto byte(uint index) -> BitRange<RequestedPrecision> { return {(utype&)data, index * 8 + 0, index * 8 + 7}; }
inline auto bits(uint lo, uint hi) const -> const BitRange<RequestedPrecision> { return {(utype&)*this, lo, lo}; }
inline auto bit(uint index) const -> const BitRange<RequestedPrecision> { return {(utype&)*this, index, index}; }
inline auto byte(uint index) const -> const BitRange<RequestedPrecision> { return {(utype&)*this, index * 8 + 0, index * 8 + 7}; }
inline auto clamp(uint bits) -> intmax {
const intmax b = 1ull << (bits - 1);
const intmax m = b - 1;
return data > m ? m : data < -b ? -b : data;
}
inline auto clip(uint bits) -> intmax {
const uintmax b = 1ull << (bits - 1);
const uintmax m = b * 2 - 1;
return ((data & m) ^ b) - b;
}
inline auto natural() const -> Natural<RequestedPrecision>;
private:
auto mask(type value) const -> type {
return (value & mask() ^ sign()) - sign();
}
type data;
};
}

View File

@ -0,0 +1,85 @@
#pragma once
namespace nall {
template<int RequestedPrecision> struct Natural {
enum : uint { Precision = RequestedPrecision < 1 ? 1 : RequestedPrecision > 64 ? 64 : RequestedPrecision };
static inline constexpr auto bits() -> uint { return Precision; }
using type =
typename conditional<bits() <= 8, uint8_t,
typename conditional<bits() <= 16, uint16_t,
typename conditional<bits() <= 32, uint32_t,
typename conditional<bits() <= 64, uint64_t,
void>::type>::type>::type>::type;
static inline constexpr auto mask() -> type { return ~0ull >> 64 - bits(); }
inline Natural() : data(0) {}
template<typename T> inline Natural(const T& value) { data = mask(value); }
explicit inline operator bool() const { return (bool)data; }
inline operator type() const { return data; }
inline auto operator++(int) { auto value = *this; data = mask(data + 1); return value; }
inline auto operator--(int) { auto value = *this; data = mask(data - 1); return value; }
inline auto& operator++() { data = mask(data + 1); return *this; }
inline auto& operator--() { data = mask(data - 1); return *this; }
inline auto operator!() const { return Natural{!data}; }
inline auto operator~() const { return Natural{~data}; }
inline auto operator+() const { return Natural{+data}; }
inline auto operator-() const { return Natural{-data}; }
#define lhs data
#define rhs value
template<typename T> inline auto& operator =(const T& value) { lhs = mask( rhs); return *this; }
template<typename T> inline auto& operator *=(const T& value) { lhs = mask(lhs * rhs); return *this; }
template<typename T> inline auto& operator /=(const T& value) { lhs = mask(lhs / rhs); return *this; }
template<typename T> inline auto& operator %=(const T& value) { lhs = mask(lhs % rhs); return *this; }
template<typename T> inline auto& operator +=(const T& value) { lhs = mask(lhs + rhs); return *this; }
template<typename T> inline auto& operator -=(const T& value) { lhs = mask(lhs - rhs); return *this; }
template<typename T> inline auto& operator<<=(const T& value) { lhs = mask(lhs << rhs); return *this; }
template<typename T> inline auto& operator>>=(const T& value) { lhs = mask(lhs >> rhs); return *this; }
template<typename T> inline auto& operator &=(const T& value) { lhs = mask(lhs & rhs); return *this; }
template<typename T> inline auto& operator ^=(const T& value) { lhs = mask(lhs ^ rhs); return *this; }
template<typename T> inline auto& operator |=(const T& value) { lhs = mask(lhs | rhs); return *this; }
#undef lhs
#undef rhs
inline auto serialize(serializer& s) { s(data); }
inline auto zero() const -> bool { return data == 0; }
inline auto positive() const -> bool { return data >> bits() - 1 == 0; }
inline auto negative() const -> bool { return data >> bits() - 1 == 1; }
inline auto bits(uint lo, uint hi) -> BitRange<RequestedPrecision> { return {(type&)data, lo, hi}; }
inline auto bit(uint index) -> BitRange<RequestedPrecision> { return {(type&)data, index, index}; }
inline auto byte(uint index) -> BitRange<RequestedPrecision> { return {(type&)data, index * 8 + 0, index * 8 + 7}; }
inline auto bits(uint lo, uint hi) const -> const BitRange<RequestedPrecision> { return {(type&)data, lo, hi}; }
inline auto bit(uint index) const -> const BitRange<RequestedPrecision> { return {(type&)data, index, index}; }
inline auto byte(uint index) const -> const BitRange<RequestedPrecision> { return {(type&)data, index * 8 + 0, index * 8 + 7}; }
inline auto clamp(uint bits) -> uintmax {
const uintmax b = 1ull << (bits - 1);
const uintmax m = b * 2 - 1;
return data < m ? data : m;
}
inline auto clip(uint bits) -> uintmax {
const uintmax b = 1ull << (bits - 1);
const uintmax m = b * 2 - 1;
return data & m;
}
inline auto integer() const -> Integer<RequestedPrecision>;
private:
inline auto mask(type value) const -> type {
return value & mask();
}
type data;
};
}

View File

@ -0,0 +1,174 @@
#pragma once
namespace nall {
//attempt to keep Natural / Integer types when performing a math operation against another Natural / Integer or primitive type
//try not to lose any data through truncation (eg Natural<32> + Natural<32> -> Natural<64>)
//complex SFINAE is needed to prevent the creation of ambiguous operator overloads
#define Type PrimitiveType
#define Compatible PrimitiveCompatible
#define CastExpand PrimitiveCastExpand
#define CastShrink PrimitiveCastShrink
#define CastDouble PrimitiveCastDouble
#define CastLarger PrimitiveCastLarger
#define CastLesser PrimitiveCastLesser
template<typename T> struct Type {
using type = T;
static inline constexpr uint bits = 8 * sizeof(T);
};
template<> struct Type<Boolean> {
using type = typename Boolean::type;
static inline constexpr uint bits = Boolean::bits();
};
template<int Precision> struct Type<Natural<Precision>> {
using type = typename Natural<Precision>::type;
static inline constexpr uint bits = Natural<Precision>::bits();
};
template<int Precision> struct Type<Integer<Precision>> {
using type = typename Integer<Precision>::type;
static inline constexpr uint bits = Integer<Precision>::bits();
};
template<int Precision> struct Type<Real<Precision>> {
using type = typename Real<Precision>::type;
static inline constexpr uint bits = Real<Precision>::bits();
};
//compatible: SFINAE operator enable
template<typename LHS, typename RHS, typename = void> struct Compatible { static const bool value = false; };
template<int LHS, typename RHS> struct Compatible<Natural<LHS>, RHS, enable_if_t<is_integral_v<RHS>>> { static const bool value = true; };
template<typename LHS, int RHS> struct Compatible<LHS, Natural<RHS>, enable_if_t<is_integral_v<LHS>>> { static const bool value = true; };
template<int LHS, int RHS> struct Compatible<Natural<LHS>, Natural<RHS>> { static const bool value = true; };
template<int LHS, typename RHS> struct Compatible<Integer<LHS>, RHS, enable_if_t<is_integral_v<RHS>>> { static const bool value = true; };
template<typename LHS, int RHS> struct Compatible<LHS, Integer<RHS>, enable_if_t<is_integral_v<LHS>>> { static const bool value = true; };
template<int LHS, int RHS> struct Compatible<Integer<LHS>, Integer<RHS>> { static const bool value = true; };
//expand: LHS+RHS bits
template<typename LHS, typename RHS, typename = void> struct CastExpand { using type = void; };
template<int LHS, typename RHS> struct CastExpand<Natural<LHS>, RHS, enable_if_t<is_integral_v<RHS>>> { using type = Natural<LHS + Type<RHS>::bits>; };
template<typename LHS, int RHS> struct CastExpand<LHS, Natural<RHS>, enable_if_t<is_integral_v<LHS>>> { using type = Natural<Type<LHS>::bits + RHS>; };
template<int LHS, int RHS> struct CastExpand<Natural<LHS>, Natural<RHS>> { using type = Natural<LHS + RHS>; };
template<int LHS, typename RHS> struct CastExpand<Integer<LHS>, RHS, enable_if_t<is_integral_v<RHS>>> { using type = Integer<LHS + Type<RHS>::bits>; };
template<typename LHS, int RHS> struct CastExpand<LHS, Integer<RHS>, enable_if_t<is_integral_v<LHS>>> { using type = Integer<Type<LHS>::bits + RHS>; };
template<int LHS, int RHS> struct CastExpand<Integer<LHS>, Integer<RHS>> { using type = Integer<LHS + RHS>; };
//shrink: LHS-RHS bits
template<typename LHS, typename RHS, typename = void> struct CastShrink { using type = void; };
template<int LHS, typename RHS> struct CastShrink<Natural<LHS>, RHS, enable_if_t<is_integral_v<RHS>>> { using type = Natural<LHS - Type<RHS>::bits>; };
template<typename LHS, int RHS> struct CastShrink<LHS, Natural<RHS>, enable_if_t<is_integral_v<LHS>>> { using type = Natural<Type<LHS>::bits - RHS>; };
template<int LHS, int RHS> struct CastShrink<Natural<LHS>, Natural<RHS>> { using type = Natural<LHS - RHS>; };
template<int LHS, typename RHS> struct CastShrink<Integer<LHS>, RHS, enable_if_t<is_integral_v<RHS>>> { using type = Integer<LHS - Type<RHS>::bits>; };
template<typename LHS, int RHS> struct CastShrink<LHS, Integer<RHS>, enable_if_t<is_integral_v<LHS>>> { using type = Integer<Type<LHS>::bits - RHS>; };
template<int LHS, int RHS> struct CastShrink<Integer<LHS>, Integer<RHS>> { using type = Integer<LHS - RHS>; };
//double: 1+max(LHS,RHS) bits
template<typename LHS, typename RHS, typename = void> struct CastDouble { using type = void; };
template<int LHS, typename RHS> struct CastDouble<Natural<LHS>, RHS, enable_if_t<is_integral_v<RHS>>> { using type = Natural<1 + (LHS >= Type<RHS>::bits ? LHS : Type<RHS>::bits)>; };
template<typename LHS, int RHS> struct CastDouble<LHS, Natural<RHS>, enable_if_t<is_integral_v<LHS>>> { using type = Natural<1 + (Type<LHS>::bits >= RHS ? Type<LHS>::bits : RHS)>; };
template<int LHS, int RHS> struct CastDouble<Natural<LHS>, Natural<RHS>> { using type = Natural<1 + (LHS >= RHS ? LHS : RHS)>; };
template<int LHS, typename RHS> struct CastDouble<Integer<LHS>, RHS, enable_if_t<is_integral_v<RHS>>> { using type = Integer<1 + (LHS >= Type<RHS>::bits ? LHS : Type<RHS>::bits)>; };
template<typename LHS, int RHS> struct CastDouble<LHS, Integer<RHS>, enable_if_t<is_integral_v<LHS>>> { using type = Integer<1 + (Type<LHS>::bits >= RHS ? Type<LHS>::bits : RHS)>; };
template<int LHS, int RHS> struct CastDouble<Integer<LHS>, Integer<RHS>> { using type = Integer<1 + (LHS >= RHS ? LHS : RHS)>; };
//larger: max(LHS,RHS) bits
template<typename LHS, typename RHS, typename = void> struct CastLarger { using type = void; };
template<int LHS, typename RHS> struct CastLarger<Natural<LHS>, RHS, enable_if_t<is_integral_v<RHS>>> { using type = Natural<LHS >= Type<RHS>::bits ? LHS : Type<RHS>::bits>; };
template<typename LHS, int RHS> struct CastLarger<LHS, Natural<RHS>, enable_if_t<is_integral_v<LHS>>> { using type = Natural<Type<LHS>::bits >= RHS ? Type<LHS>::bits : RHS>; };
template<int LHS, int RHS> struct CastLarger<Natural<LHS>, Natural<RHS>> { using type = Natural<LHS >= RHS ? LHS : RHS>; };
template<int LHS, typename RHS> struct CastLarger<Integer<LHS>, RHS, enable_if_t<is_integral_v<RHS>>> { using type = Integer<LHS >= Type<RHS>::bits ? LHS : Type<RHS>::bits>; };
template<typename LHS, int RHS> struct CastLarger<LHS, Integer<RHS>, enable_if_t<is_integral_v<LHS>>> { using type = Integer<Type<LHS>::bits >= RHS ? Type<LHS>::bits : RHS>; };
template<int LHS, int RHS> struct CastLarger<Integer<LHS>, Integer<RHS>> { using type = Integer<LHS >= RHS ? LHS : RHS>; };
//lesser: min(LHS,RHS) bits
template<typename LHS, typename RHS, typename = void> struct CastLesser { using type = void; };
template<int LHS, typename RHS> struct CastLesser<Natural<LHS>, RHS, enable_if_t<is_integral_v<RHS>>> { using type = Natural<LHS <= Type<RHS>::bits ? LHS : Type<RHS>::bits>; };
template<typename LHS, int RHS> struct CastLesser<LHS, Natural<RHS>, enable_if_t<is_integral_v<LHS>>> { using type = Natural<Type<LHS>::bits <= RHS ? Type<LHS>::bits : RHS>; };
template<int LHS, int RHS> struct CastLesser<Natural<LHS>, Natural<RHS>> { using type = Natural<LHS <= RHS ? LHS : RHS>; };
template<int LHS, typename RHS> struct CastLesser<Integer<LHS>, RHS, enable_if_t<is_integral_v<RHS>>> { using type = Integer<LHS <= Type<RHS>::bits ? LHS : Type<RHS>::bits>; };
template<typename LHS, int RHS> struct CastLesser<LHS, Integer<RHS>, enable_if_t<is_integral_v<LHS>>> { using type = Integer<Type<LHS>::bits <= RHS ? Type<LHS>::bits : RHS>; };
template<int LHS, int RHS> struct CastLesser<Integer<LHS>, Integer<RHS>> { using type = Integer<LHS <= RHS ? LHS : RHS>; };
#define TP template<typename LHS, typename RHS, typename = enable_if_t<Compatible<LHS, RHS>::value>>
#define Source typename Type<LHS>::type
#define Expand typename CastExpand<LHS, RHS>::type
#define Shrink typename CastShrink<LHS, RHS>::type
#define Double typename CastDouble<LHS, RHS>::type
#define Larger typename CastLarger<LHS, RHS>::type
#define Lesser typename CastLesser<LHS, RHS>::type
#define TLE typename Type<typename CastExpand<LHS, RHS>::type>::type
#define TLN typename Type<LHS>::type
#define TRN typename Type<RHS>::type
#if 1
TP inline auto operator *(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs * (TRN)rhs}; }
TP inline auto operator /(const LHS& lhs, const RHS& rhs) -> Source { return {(TLN)lhs / (TRN)rhs}; }
TP inline auto operator %(const LHS& lhs, const RHS& rhs) -> Source { return {(TLN)lhs % (TRN)rhs}; }
TP inline auto operator +(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs + (TRN)rhs}; }
TP inline auto operator -(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs - (TRN)rhs}; }
TP inline auto operator<<(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs << (TRN)rhs}; }
TP inline auto operator>>(const LHS& lhs, const RHS& rhs) -> Source { return {(TLN)lhs >> (TRN)rhs}; }
TP inline auto operator &(const LHS& lhs, const RHS& rhs) -> Lesser { return {(TLN)lhs & (TRN)rhs}; }
TP inline auto operator ^(const LHS& lhs, const RHS& rhs) -> Larger { return {(TLN)lhs ^ (TRN)rhs}; }
TP inline auto operator |(const LHS& lhs, const RHS& rhs) -> Larger { return {(TLN)lhs | (TRN)rhs}; }
#endif
#if 0
TP inline auto operator *(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs * (TRN)rhs}; }
TP inline auto operator /(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs / (TRN)rhs}; }
TP inline auto operator %(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs % (TRN)rhs}; }
TP inline auto operator +(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs + (TRN)rhs}; }
TP inline auto operator -(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs - (TRN)rhs}; }
TP inline auto operator<<(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs << (TRN)rhs}; }
TP inline auto operator>>(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs >> (TRN)rhs}; }
TP inline auto operator &(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs & (TRN)rhs}; }
TP inline auto operator ^(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs ^ (TRN)rhs}; }
TP inline auto operator |(const LHS& lhs, const RHS& rhs) -> Expand { return {(TLE)lhs | (TRN)rhs}; }
#endif
#undef TP
#undef Source
#undef Expand
#undef Shrink
#undef Double
#undef Larger
#undef Lesser
#undef TLE
#undef TLN
#undef TRN
#undef Type
#undef Compatible
#undef CastExpand
#undef CastShrink
#undef CastDouble
#undef CastLarger
#undef CastLesser
}

38
nall/primitives/real.hpp Normal file
View File

@ -0,0 +1,38 @@
#pragma once
namespace nall {
template<int RequestedPrecision> struct Real {
enum : uint { Precision = RequestedPrecision <= 32 ? 32 : 64 };
static inline constexpr auto bits() -> uint { return Precision; }
using type =
typename conditional<bits() == 32, float32_t,
typename conditional<bits() == 64, float64_t,
void>::type>::type;
inline Real() : data(0.0) {}
template<typename T> inline Real(const T& value) : data((type)value) {}
explicit operator bool() const { return (bool)data; }
inline operator type() const { return data; }
inline auto operator++(int) { auto value = *this; ++data; return value; }
inline auto operator--(int) { auto value = *this; --data; return value; }
inline auto& operator++() { data++; return *this; }
inline auto& operator--() { data--; return *this; }
template<typename T> inline auto& operator =(const T& value) { data = value; return *this; }
template<typename T> inline auto& operator+=(const T& value) { data = data + value; return *this; }
template<typename T> inline auto& operator-=(const T& value) { data = data - value; return *this; }
template<typename T> inline auto& operator*=(const T& value) { data = data * value; return *this; }
template<typename T> inline auto& operator/=(const T& value) { data = data / value; return *this; }
template<typename T> inline auto& operator%=(const T& value) { data = data % value; return *this; }
inline auto serialize(serializer& s) { s(data); }
private:
type data;
};
}

45
nall/primitives/types.hpp Normal file
View File

@ -0,0 +1,45 @@
#pragma once
namespace nall {
using boolean = Boolean;
using natural = Natural<64>;
using integer = Integer<64>;
using real = Real<64>;
using natural1 = Natural< 1>; using natural2 = Natural< 2>; using natural3 = Natural< 3>; using natural4 = Natural< 4>;
using natural5 = Natural< 5>; using natural6 = Natural< 6>; using natural7 = Natural< 7>; using natural8 = Natural< 8>;
using natural9 = Natural< 9>; using natural10 = Natural<10>; using natural11 = Natural<11>; using natural12 = Natural<12>;
using natural13 = Natural<13>; using natural14 = Natural<14>; using natural15 = Natural<15>; using natural16 = Natural<16>;
using natural17 = Natural<17>; using natural18 = Natural<18>; using natural19 = Natural<19>; using natural20 = Natural<20>;
using natural21 = Natural<21>; using natural22 = Natural<22>; using natural23 = Natural<23>; using natural24 = Natural<24>;
using natural25 = Natural<25>; using natural26 = Natural<26>; using natural27 = Natural<27>; using natural28 = Natural<28>;
using natural29 = Natural<29>; using natural30 = Natural<30>; using natural31 = Natural<31>; using natural32 = Natural<32>;
using natural33 = Natural<33>; using natural34 = Natural<34>; using natural35 = Natural<35>; using natural36 = Natural<36>;
using natural37 = Natural<37>; using natural38 = Natural<38>; using natural39 = Natural<39>; using natural40 = Natural<40>;
using natural41 = Natural<41>; using natural42 = Natural<42>; using natural43 = Natural<43>; using natural44 = Natural<44>;
using natural45 = Natural<45>; using natural46 = Natural<46>; using natural47 = Natural<47>; using natural48 = Natural<48>;
using natural49 = Natural<49>; using natural50 = Natural<50>; using natural51 = Natural<51>; using natural52 = Natural<52>;
using natural53 = Natural<53>; using natural54 = Natural<54>; using natural55 = Natural<55>; using natural56 = Natural<56>;
using natural57 = Natural<57>; using natural58 = Natural<58>; using natural59 = Natural<59>; using natural60 = Natural<60>;
using natural61 = Natural<61>; using natural62 = Natural<62>; using natural63 = Natural<63>; using natural64 = Natural<64>;
using integer1 = Integer< 1>; using integer2 = Integer< 2>; using integer3 = Integer< 3>; using integer4 = Integer< 4>;
using integer5 = Integer< 5>; using integer6 = Integer< 6>; using integer7 = Integer< 7>; using integer8 = Integer< 8>;
using integer9 = Integer< 9>; using integer10 = Integer<10>; using integer11 = Integer<11>; using integer12 = Integer<12>;
using integer13 = Integer<13>; using integer14 = Integer<14>; using integer15 = Integer<15>; using integer16 = Integer<16>;
using integer17 = Integer<17>; using integer18 = Integer<18>; using integer19 = Integer<19>; using integer20 = Integer<20>;
using integer21 = Integer<21>; using integer22 = Integer<22>; using integer23 = Integer<23>; using integer24 = Integer<24>;
using integer25 = Integer<25>; using integer26 = Integer<26>; using integer27 = Integer<27>; using integer28 = Integer<28>;
using integer29 = Integer<29>; using integer30 = Integer<30>; using integer31 = Integer<31>; using integer32 = Integer<32>;
using integer33 = Integer<33>; using integer34 = Integer<34>; using integer35 = Integer<35>; using integer36 = Integer<36>;
using integer37 = Integer<37>; using integer38 = Integer<38>; using integer39 = Integer<39>; using integer40 = Integer<40>;
using integer41 = Integer<41>; using integer42 = Integer<42>; using integer43 = Integer<43>; using integer44 = Integer<44>;
using integer45 = Integer<45>; using integer46 = Integer<46>; using integer47 = Integer<47>; using integer48 = Integer<48>;
using integer49 = Integer<49>; using integer50 = Integer<50>; using integer51 = Integer<51>; using integer52 = Integer<52>;
using integer53 = Integer<53>; using integer54 = Integer<54>; using integer55 = Integer<55>; using integer56 = Integer<56>;
using integer57 = Integer<57>; using integer58 = Integer<58>; using integer59 = Integer<59>; using integer60 = Integer<60>;
using integer61 = Integer<61>; using integer62 = Integer<62>; using integer63 = Integer<63>; using integer64 = Integer<64>;
using real32 = Real<32>;
using real64 = Real<64>;
}

View File

@ -76,7 +76,7 @@ template<> struct stringify<int128_t> {
};
#endif
template<uint Bits> struct stringify<Integer<Bits>> {
template<int Bits> struct stringify<Integer<Bits>> {
stringify(Integer<Bits> source) { fromInteger(_data, source); }
auto data() const -> const char* { return _data; }
auto size() const -> uint { return strlen(_data); }
@ -129,7 +129,7 @@ template<> struct stringify<uint128_t> {
};
#endif
template<uint Bits> struct stringify<Natural<Bits>> {
template<int Bits> struct stringify<Natural<Bits>> {
stringify(Natural<Bits> source) { fromNatural(_data, source); }
auto data() const -> const char* { return _data; }
auto size() const -> uint { return strlen(_data); }

View File

@ -14,12 +14,14 @@ namespace nall {
using std::enable_if;
using std::enable_if_t;
using std::false_type;
using std::is_floating_point;
using std::forward;
using std::initializer_list;
using std::is_array;
using std::is_base_of;
using std::is_function;
using std::is_integral;
using std::is_integral_v;
using std::is_same;
using std::is_signed;
using std::is_unsigned;