Update to v098r08 release.

byuu says:

Changelog:
- nall/vector rewritten from scratch
- higan/audio uses nall/vector instead of raw pointers
- higan/sfc/coprocessor/sdd1 updated with new research information
- ruby/video/glx and ruby/video/glx2: fuck salt glXSwapIntervalEXT!

The big change here is definitely nall/vector. The Windows, OS X and Qt
ports won't compile until you change some first/last strings to
left/right, but GTK will compile.

I'd be really grateful if anyone could stress-test nall/vector. Pretty
much everything I do relies on this class. If we introduce a bug, the
worst case scenario is my entire SFC game dump database gets corrupted,
or the byuu.org server gets compromised. So it's really critical that we
test the hell out of this right now.

The S-DD1 changes mean you need to update your installation of icarus
again. Also, even though the Lunar FMV never really worked on the
accuracy core anyway (it didn't initialize the PPU properly), it really
won't work now that we emulate the hard-limit of 16MiB for S-DD1 games.
This commit is contained in:
Tim Allen 2016-05-02 19:57:04 +10:00
parent 7cdae5195a
commit 0955295475
68 changed files with 994 additions and 604 deletions

View File

@ -76,8 +76,8 @@ auto Audio::poll() -> void {
if(reverbDelay) {
reverbLeft.append(ileft);
reverbRight.append(iright);
ileft += reverbLeft.takeFirst() * reverbLevel;
iright += reverbRight.takeFirst() * reverbLevel;
ileft += reverbLeft.takeLeft() * reverbLevel;
iright += reverbRight.takeLeft() * reverbLevel;
}
interface->audioSample(sclamp<16>(ileft), sclamp<16>(iright));

View File

@ -36,7 +36,6 @@ private:
struct Stream {
Stream(uint channels, double inputFrequency);
~Stream();
auto reset() -> void;
auto setFrequency(double outputFrequency) -> void;
@ -56,21 +55,20 @@ private:
double outputFrequency = 0.0;
double cutoffFrequency = 0.0;
double* tap = nullptr;
uint taps = 0;
vector<double> taps;
uint decimationRate = 0;
uint decimationOffset = 0;
double** input = nullptr;
vector<vector<double>> input;
uint inputOffset = 0;
double resamplerFrequency = 0.0;
double resamplerFraction = 0.0;
double resamplerStep = 0.0;
double** queue = nullptr;
vector<vector<double>> queue;
double** output = nullptr;
vector<vector<double>> output;
uint outputs = 0;
uint outputReadOffset = 0;
uint outputWriteOffset = 0;

View File

@ -7,18 +7,11 @@
Stream::Stream(uint channels, double inputFrequency) : channels(channels), inputFrequency(inputFrequency) {
}
Stream::~Stream() {
reset();
}
auto Stream::reset() -> void {
if(tap) delete[] tap, tap = nullptr;
if(input) for(auto c : range(channels)) delete[] input[c];
delete[] input, input = nullptr;
if(queue) for(auto c : range(channels)) delete[] queue[c];
delete[] queue, queue = nullptr;
if(output) for(auto c : range(channels)) delete[] output[c];
delete[] output, output = nullptr;
taps.reset();
input.reset();
queue.reset();
output.reset();
}
auto Stream::setFrequency(double outputFrequency_) -> void {
@ -34,45 +27,43 @@ auto Stream::setFrequency(double outputFrequency_) -> void {
cutoffFrequency = outputFrequency / inputFrequency;
if(cutoffFrequency < 0.5) {
double transitionBandwidth = 0.008; //lower = higher quality; more taps (slower)
taps = (uint)ceil(4.0 / transitionBandwidth) | 1;
tap = new double[taps];
taps.resize((uint)ceil(4.0 / transitionBandwidth) | 1);
double sum = 0.0;
for(uint t : range(taps)) {
//sinc filter
double s = sinc(2.0 * cutoffFrequency * (t - (taps - 1) / 2.0));
double s = sinc(2.0 * cutoffFrequency * (t - (taps.size() - 1) / 2.0));
//blackman window
double b = 0.42 - 0.5 * cos(2.0 * pi * t / (taps - 1)) + 0.08 * cos(4.0 * pi * t / (taps - 1));
double b = 0.42 - 0.5 * cos(2.0 * pi * t / (taps.size() - 1)) + 0.08 * cos(4.0 * pi * t / (taps.size() - 1));
tap[t] = s * b;
sum += tap[t];
taps[t] = s * b;
sum += taps[t];
}
//normalize so that the sum of all coefficients is 1.0
for(auto t : range(taps)) tap[t] /= sum;
for(auto& tap : taps) tap /= sum;
} else {
taps = 1;
tap = new double[taps];
tap[0] = 1.0;
taps.resize(1);
taps[0] = 1.0;
}
decimationRate = max(1, (uint)floor(inputFrequency / outputFrequency));
decimationOffset = 0;
input = new double*[channels];
for(auto c : range(channels)) input[c] = new double[taps * 2]();
input.resize(channels);
for(auto c : range(channels)) input[c].resize(taps.size() * 2);
inputOffset = 0;
resamplerFrequency = inputFrequency / decimationRate;
resamplerFraction = 0.0;
resamplerStep = resamplerFrequency / outputFrequency;
queue = new double*[channels];
for(auto c : range(channels)) queue[c] = new double[4]();
queue.resize(channels);
for(auto c : range(channels)) queue[c].resize(4);
output = new double*[channels];
output.resize(channels);
outputs = inputFrequency * 0.02;
for(auto c : range(channels)) output[c] = new double[outputs]();
for(auto c : range(channels)) output[c].resize(outputs);
outputReadOffset = 0;
outputWriteOffset = 0;
}
@ -90,10 +81,10 @@ auto Stream::read(double* samples) -> void {
}
auto Stream::write(int16* samples) -> void {
inputOffset = !inputOffset ? taps - 1 : inputOffset - 1;
inputOffset = !inputOffset ? taps.size() - 1 : inputOffset - 1;
for(auto c : range(channels)) {
auto sample = (samples[c] + 32768.0) / 65535.0; //normalize
input[c][inputOffset] = input[c][inputOffset + taps] = sample;
input[c][inputOffset] = input[c][inputOffset + taps.size()] = sample;
}
if(++decimationOffset >= decimationRate) {
@ -101,7 +92,7 @@ auto Stream::write(int16* samples) -> void {
for(auto c : range(channels)) {
double sample = 0.0;
for(auto t : range(taps)) sample += input[c][inputOffset + t] * tap[t];
for(auto t : range(taps)) sample += input[c][inputOffset + t] * taps[t];
auto& q = queue[c];
q[0] = q[1];

View File

@ -8,7 +8,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
static const string Version = "098.07";
static const string Version = "098.08";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "http://byuu.org/";

View File

@ -376,7 +376,7 @@ auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers, bool bytes) -> str
if(bytes) {
b = " ";
while(bytesRead) {
b.append(hex(bytesRead.takeFirst(), 2L), " ");
b.append(hex(bytesRead.takeLeft(), 2L), " ");
}
b.rstrip();
}

View File

@ -3,7 +3,7 @@
//36 ss:
//3e ds:
auto V30MZ::opSegment(uint16 segment) {
if(prefixes.size() >= 7) prefixes.removeLast();
if(prefixes.size() >= 7) prefixes.removeRight();
prefixes.prepend(opcode);
state.prefix = true;
state.poll = false;
@ -12,7 +12,7 @@ auto V30MZ::opSegment(uint16 segment) {
//f2 repnz:
//f3 repz:
auto V30MZ::opRepeat(bool flag) {
if(prefixes.size() >= 7) prefixes.removeLast();
if(prefixes.size() >= 7) prefixes.removeRight();
prefixes.prepend(opcode);
wait(4);
state.prefix = true;
@ -21,7 +21,7 @@ auto V30MZ::opRepeat(bool flag) {
//f0 lock:
auto V30MZ::opLock() {
if(prefixes.size() >= 7) prefixes.removeLast();
if(prefixes.size() >= 7) prefixes.removeRight();
prefixes.prepend(opcode);
state.prefix = true;
state.poll = false;

View File

@ -358,11 +358,11 @@ auto Cartridge::parseMarkupSDD1(Markup::Node root) -> void {
}
for(auto node : root["rom"].find("map")) {
parseMarkupMap(node, {&SDD1::mcurom_read, &sdd1}, {&SDD1::mcurom_write, &sdd1});
parseMarkupMap(node, {&SDD1::mcuromRead, &sdd1}, {&SDD1::mcuromWrite, &sdd1});
}
for(auto node : root["ram"].find("map")) {
parseMarkupMap(node, {&SDD1::mcuram_read, &sdd1}, {&SDD1::mcuram_write, &sdd1});
parseMarkupMap(node, {&SDD1::mcuramRead, &sdd1}, {&SDD1::mcuramWrite, &sdd1});
}
}

View File

@ -8,20 +8,20 @@
//input manager
auto SDD1::Decomp::IM::init(uint offset_) -> void {
auto SDD1::Decompressor::IM::init(uint offset_) -> void {
offset = offset_;
bit_count = 4;
}
auto SDD1::Decomp::IM::get_codeword(uint8 code_length) -> uint8 {
auto SDD1::Decompressor::IM::get_codeword(uint8 code_length) -> uint8 {
uint8 codeword;
uint8 comp_count;
codeword = sdd1.mmc_read(offset) << bit_count;
codeword = sdd1.mmcRead(offset) << bit_count;
bit_count++;
if(codeword & 0x80) {
codeword |= sdd1.mmc_read(offset + 1) >> (9 - bit_count);
codeword |= sdd1.mmcRead(offset + 1) >> (9 - bit_count);
bit_count += code_length;
}
@ -35,7 +35,7 @@ auto SDD1::Decomp::IM::get_codeword(uint8 code_length) -> uint8 {
//golomb-code decoder
const uint8 SDD1::Decomp::GCD::run_count[] = {
const uint8 SDD1::Decompressor::GCD::run_count[] = {
0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00,
0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00,
0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01,
@ -70,7 +70,7 @@ const uint8 SDD1::Decomp::GCD::run_count[] = {
0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00,
};
auto SDD1::Decomp::GCD::get_run_count(uint8 code_number, uint8& mps_count, bool& lps_index) -> void {
auto SDD1::Decompressor::GCD::get_run_count(uint8 code_number, uint8& mps_count, bool& lps_index) -> void {
uint8 codeword = self.im.get_codeword(code_number);
if(codeword & 0x80) {
@ -83,12 +83,12 @@ auto SDD1::Decomp::GCD::get_run_count(uint8 code_number, uint8& mps_count, bool&
//bits generator
auto SDD1::Decomp::BG::init() -> void {
auto SDD1::Decompressor::BG::init() -> void {
mps_count = 0;
lps_index = 0;
}
auto SDD1::Decomp::BG::get_bit(bool& end_of_run) -> uint8 {
auto SDD1::Decompressor::BG::get_bit(bool& end_of_run) -> uint8 {
if(!(mps_count || lps_index)) self.gcd.get_run_count(code_number, mps_count, lps_index);
uint8 bit;
@ -106,7 +106,7 @@ auto SDD1::Decomp::BG::get_bit(bool& end_of_run) -> uint8 {
//probability estimation module
const SDD1::Decomp::PEM::State SDD1::Decomp::PEM::evolution_table[33] = {
const SDD1::Decompressor::PEM::State SDD1::Decompressor::PEM::evolution_table[33] = {
{0, 25, 25},
{0, 2, 1},
{0, 3, 1},
@ -142,18 +142,18 @@ const SDD1::Decomp::PEM::State SDD1::Decomp::PEM::evolution_table[33] = {
{7, 24, 22},
};
auto SDD1::Decomp::PEM::init() -> void {
auto SDD1::Decompressor::PEM::init() -> void {
for(auto n : range(32)) {
context_info[n].status = 0;
context_info[n].mps = 0;
}
}
auto SDD1::Decomp::PEM::get_bit(uint8 context) -> uint8 {
auto SDD1::Decompressor::PEM::get_bit(uint8 context) -> uint8 {
ContextInfo& info = context_info[context];
uint8 current_status = info.status;
uint8 current_mps = info.mps;
const State& s = SDD1::Decomp::PEM::evolution_table[current_status];
const State& s = SDD1::Decompressor::PEM::evolution_table[current_status];
uint8 bit;
bool end_of_run;
@ -182,9 +182,9 @@ auto SDD1::Decomp::PEM::get_bit(uint8 context) -> uint8 {
//context model
auto SDD1::Decomp::CM::init(uint offset) -> void {
bitplanes_info = sdd1.mmc_read(offset) & 0xc0;
context_bits_info = sdd1.mmc_read(offset) & 0x30;
auto SDD1::Decompressor::CM::init(uint offset) -> void {
bitplanes_info = sdd1.mmcRead(offset) & 0xc0;
context_bits_info = sdd1.mmcRead(offset) & 0x30;
bit_number = 0;
for(auto n : range(8)) previous_bitplane_bits[n] = 0;
switch(bitplanes_info) {
@ -194,7 +194,7 @@ auto SDD1::Decomp::CM::init(uint offset) -> void {
}
}
auto SDD1::Decomp::CM::get_bit() -> uint8 {
auto SDD1::Decompressor::CM::get_bit() -> uint8 {
switch(bitplanes_info) {
case 0x00:
current_bitplane ^= 0x01;
@ -230,12 +230,12 @@ auto SDD1::Decomp::CM::get_bit() -> uint8 {
//output logic
auto SDD1::Decomp::OL::init(uint offset) -> void {
bitplanes_info = sdd1.mmc_read(offset) & 0xc0;
auto SDD1::Decompressor::OL::init(uint offset) -> void {
bitplanes_info = sdd1.mmcRead(offset) & 0xc0;
r0 = 0x01;
}
auto SDD1::Decomp::OL::decompress() -> uint8 {
auto SDD1::Decompressor::OL::decompress() -> uint8 {
switch(bitplanes_info) {
case 0x00: case 0x40: case 0x80:
if(r0 == 0) {
@ -257,14 +257,14 @@ auto SDD1::Decomp::OL::decompress() -> uint8 {
//core
SDD1::Decomp::Decomp():
SDD1::Decompressor::Decompressor():
im(*this), gcd(*this),
bg0(*this, 0), bg1(*this, 1), bg2(*this, 2), bg3(*this, 3),
bg4(*this, 4), bg5(*this, 5), bg6(*this, 6), bg7(*this, 7),
pem(*this), cm(*this), ol(*this) {
}
auto SDD1::Decomp::init(uint offset) -> void {
auto SDD1::Decompressor::init(uint offset) -> void {
im.init(offset);
bg0.init();
bg1.init();
@ -279,6 +279,6 @@ auto SDD1::Decomp::init(uint offset) -> void {
ol.init(offset);
}
auto SDD1::Decomp::read() -> uint8 {
auto SDD1::Decompressor::read() -> uint8 {
return ol.decompress();
}

View File

@ -1,43 +1,43 @@
struct Decomp {
struct Decompressor {
struct IM { //input manager
IM(SDD1::Decomp& self) : self(self) {}
IM(SDD1::Decompressor& self) : self(self) {}
auto init(uint offset) -> void;
auto get_codeword(uint8 code_length) -> uint8;
private:
Decomp& self;
Decompressor& self;
uint offset;
uint bit_count;
};
struct GCD { //golomb-code decoder
GCD(SDD1::Decomp& self) : self(self) {}
GCD(SDD1::Decompressor& self) : self(self) {}
auto get_run_count(uint8 code_number, uint8& mps_count, bool& lps_index) -> void;
private:
Decomp& self;
Decompressor& self;
static const uint8 run_count[256];
};
struct BG { //bits generator
BG(SDD1::Decomp& self, uint8 code_number) : self(self), code_number(code_number) {}
BG(SDD1::Decompressor& self, uint8 code_number) : self(self), code_number(code_number) {}
auto init() -> void;
auto get_bit(bool& end_of_run) -> uint8;
private:
Decomp& self;
Decompressor& self;
const uint8 code_number;
uint8 mps_count;
bool lps_index;
};
struct PEM { //probability estimation module
PEM(SDD1::Decomp& self) : self(self) {}
PEM(SDD1::Decompressor& self) : self(self) {}
auto init() -> void;
auto get_bit(uint8 context) -> uint8;
private:
Decomp& self;
Decompressor& self;
struct State {
uint8 code_number;
uint8 next_if_mps;
@ -51,12 +51,12 @@ struct Decomp {
};
struct CM { //context model
CM(SDD1::Decomp& self) : self(self) {}
CM(SDD1::Decompressor& self) : self(self) {}
auto init(uint offset) -> void;
uint8 get_bit();
private:
Decomp& self;
Decompressor& self;
uint8 bitplanes_info;
uint8 context_bits_info;
uint8 bit_number;
@ -65,17 +65,17 @@ struct Decomp {
};
struct OL { //output logic
OL(SDD1::Decomp& self) : self(self) {}
OL(SDD1::Decompressor& self) : self(self) {}
auto init(uint offset) -> void;
auto decompress() -> uint8;
private:
Decomp& self;
Decompressor& self;
uint8 bitplanes_info;
uint8 r0, r1, r2;
};
Decomp();
Decompressor();
auto init(uint offset) -> void;
auto read() -> uint8;

View File

@ -4,7 +4,7 @@ namespace SuperFamicom {
SDD1 sdd1;
#include "decomp.cpp"
#include "decompressor.cpp"
#include "serialization.cpp"
auto SDD1::init() -> void {
@ -24,113 +24,106 @@ auto SDD1::power() -> void {
auto SDD1::reset() -> void {
//hook S-CPU DMA MMIO registers to gather information for struct dma[];
//buffer address and transfer size information for use in SDD1::mcu_read()
bus.map({&SDD1::dma_read, &sdd1}, {&SDD1::dma_write, &sdd1}, "00-3f,80-bf:4300-437f");
bus.map({&SDD1::dmaRead, &sdd1}, {&SDD1::dmaWrite, &sdd1}, "00-3f,80-bf:4300-437f");
sdd1_enable = 0x00;
xfer_enable = 0x00;
dma_ready = false;
mmc[0] = 0 << 20;
mmc[1] = 1 << 20;
mmc[2] = 2 << 20;
mmc[3] = 3 << 20;
r4800 = 0x00;
r4801 = 0x00;
r4804 = 0x00;
r4805 = 0x01;
r4806 = 0x02;
r4807 = 0x03;
for(auto n : range(8)) {
dma[n].addr = 0;
dma[n].size = 0;
}
dmaReady = false;
}
auto SDD1::read(uint24 addr, uint8 data) -> uint8 {
addr = 0x4800 | (addr & 7);
addr = 0x4800 | addr.bits(0,3);
switch(addr) {
case 0x4804: return mmc[0] >> 20;
case 0x4805: return mmc[1] >> 20;
case 0x4806: return mmc[2] >> 20;
case 0x4807: return mmc[3] >> 20;
case 0x4800: return r4800;
case 0x4801: return r4801;
case 0x4804: return r4804;
case 0x4805: return r4805;
case 0x4806: return r4806;
case 0x4807: return r4807;
}
return data;
//00-3f,80-bf:4802-4803,4808-480f falls through to ROM
return rom.read(addr);
}
auto SDD1::write(uint24 addr, uint8 data) -> void {
addr = 0x4800 | (addr & 7);
addr = 0x4800 | addr.bits(0,3);
switch(addr) {
case 0x4800: sdd1_enable = data; break;
case 0x4801: xfer_enable = data; break;
case 0x4804: mmc[0] = data << 20; break;
case 0x4805: mmc[1] = data << 20; break;
case 0x4806: mmc[2] = data << 20; break;
case 0x4807: mmc[3] = data << 20; break;
case 0x4800: r4800 = data; break;
case 0x4801: r4801 = data; break;
case 0x4804: r4804 = data & 0x8f; break;
case 0x4805: r4805 = data & 0x8f; break;
case 0x4806: r4806 = data & 0x8f; break;
case 0x4807: r4807 = data & 0x8f; break;
}
}
auto SDD1::dma_read(uint24 addr, uint8 data) -> uint8 {
auto SDD1::dmaRead(uint24 addr, uint8 data) -> uint8 {
return cpu.dmaPortRead(addr, data);
}
auto SDD1::dma_write(uint24 addr, uint8 data) -> void {
uint channel = (addr >> 4) & 7;
switch(addr & 15) {
case 2: dma[channel].addr = (dma[channel].addr & 0xffff00) + (data << 0); break;
case 3: dma[channel].addr = (dma[channel].addr & 0xff00ff) + (data << 8); break;
case 4: dma[channel].addr = (dma[channel].addr & 0x00ffff) + (data << 16); break;
case 5: dma[channel].size = (dma[channel].size & 0xff00) + (data << 0); break;
case 6: dma[channel].size = (dma[channel].size & 0x00ff) + (data << 8); break;
auto SDD1::dmaWrite(uint24 addr, uint8 data) -> void {
uint channel = addr.bits(4,6);
switch(addr.bits(0,3)) {
case 2: dma[channel].addr.byte(0) = data; break;
case 3: dma[channel].addr.byte(1) = data; break;
case 4: dma[channel].addr.byte(2) = data; break;
case 5: dma[channel].size.byte(0) = data; break;
case 6: dma[channel].size.byte(1) = data; break;
}
return cpu.dmaPortWrite(addr, data);
}
auto SDD1::mmc_read(uint24 addr) -> uint8 {
return rom.read(mmc[(addr >> 20) & 3] + (addr & 0x0fffff));
auto SDD1::mmcRead(uint24 addr) -> uint8 {
switch(addr.bits(20,21)) {
case 0: return rom.read(r4804.bits(0,3) << 20 | addr.bits(0,19)); //c0-cf:0000-ffff
case 1: return rom.read(r4805.bits(0,3) << 20 | addr.bits(0,19)); //d0-df:0000-ffff
case 2: return rom.read(r4806.bits(0,3) << 20 | addr.bits(0,19)); //e0-ef:0000-ffff
case 3: return rom.read(r4807.bits(0,3) << 20 | addr.bits(0,19)); //f0-ff:0000-ffff
}
unreachable;
}
//SDD1::mcu_read() is mapped to $c0-ff:0000-ffff
//the design is meant to be as close to the hardware design as possible, thus this code
//avoids adding S-DD1 hooks inside S-CPU::DMA emulation.
//
//the real S-DD1 cannot see $420b (DMA enable) writes, as they are not placed on the bus.
//however, $43x0-$43xf writes (DMAx channel settings) most likely do appear on the bus.
//the S-DD1 also requires fixed addresses for transfers, which wouldn't be necessary if
//it could see $420b writes (eg it would know when the transfer should begin.)
//
//the hardware needs a way to distinguish program code after $4801 writes from DMA
//decompression that follows soon after.
//
//the only plausible design for hardware would be for the S-DD1 to spy on DMAx settings,
//and begin spooling decompression on writes to $4801 that activate a channel. after that,
//it feeds decompressed data only when the ROM read address matches the DMA channel address.
//
//the actual S-DD1 transfer can occur on any channel, but it is most likely limited to
//one transfer per $420b write (for spooling purposes). however, this is not known for certain.
auto SDD1::mcurom_read(uint24 addr, uint8) -> uint8 {
//map address=00-3f,80-bf:8000-ffff
//map address=c0-ff:0000-ffff
auto SDD1::mcuromRead(uint24 addr, uint8 data) -> uint8 {
//map address=00-3f,80-bf:8000-ffff mask=0x808000 => 00-1f:0000-ffff
if(addr < 0x200000) {
if(!addr.bit(22)) {
if(!addr.bit(23) && addr.bit(21) && r4805.bit(7)) addr.bit(21) = 0; //20-3f:8000-ffff
if( addr.bit(23) && addr.bit(21) && r4807.bit(7)) addr.bit(21) = 0; //a0-bf:8000-ffff
addr = addr.bits(16,21) << 15 | addr.bits(0,14);
return rom.read(addr);
}
//map address=c0-ff:0000-ffff
if(sdd1_enable & xfer_enable) {
if(r4800 & r4801) {
//at least one channel has S-DD1 decompression enabled ...
for(auto n : range(8)) {
if(sdd1_enable & xfer_enable & (1 << n)) {
if(r4800.bit(n) && r4801.bit(n)) {
//S-DD1 always uses fixed transfer mode, so address will not change during transfer
if(addr == dma[n].addr) {
if(!dma_ready) {
if(!dmaReady) {
//prepare streaming decompression
decomp.init(addr);
dma_ready = true;
decompressor.init(addr);
dmaReady = true;
}
//fetch a decompressed byte; once finished, disable channel and invalidate buffer
uint8 data = decomp.read();
data = decompressor.read();
if(--dma[n].size == 0) {
dma_ready = false;
xfer_enable &= ~(1 << n);
dmaReady = false;
r4801.bit(n) = 0;
}
return data;
@ -140,20 +133,20 @@ auto SDD1::mcurom_read(uint24 addr, uint8) -> uint8 {
} //S-DD1 decompressor enabled
//S-DD1 decompression mode inactive; return ROM data
return mmc_read(addr);
return mmcRead(addr);
}
auto SDD1::mcurom_write(uint24 addr, uint8 data) -> void {
auto SDD1::mcuromWrite(uint24 addr, uint8 data) -> void {
}
//map address=00-3f,80-bf:6000-7fff mask=0xe000
//map address=70-7d:0000-7fff mask=0x8000
auto SDD1::mcuram_read(uint24 addr, uint8 data) -> uint8 {
return ram.read(addr & 0x1fff, data);
//map address=70-73:0000-ffff mask=0x8000
auto SDD1::mcuramRead(uint24 addr, uint8 data) -> uint8 {
return ram.read(addr.bits(0,12), data);
}
auto SDD1::mcuram_write(uint24 addr, uint8 data) -> void {
return ram.write(addr & 0x1fff, data);
auto SDD1::mcuramWrite(uint24 addr, uint8 data) -> void {
return ram.write(addr.bits(0,12), data);
}
}

View File

@ -8,16 +8,16 @@ struct SDD1 {
auto read(uint24 addr, uint8 data) -> uint8;
auto write(uint24 addr, uint8 data) -> void;
auto dma_read(uint24 addr, uint8 data) -> uint8;
auto dma_write(uint24 addr, uint8 data) -> void;
auto dmaRead(uint24 addr, uint8 data) -> uint8;
auto dmaWrite(uint24 addr, uint8 data) -> void;
auto mmc_read(uint24 addr) -> uint8;
auto mmcRead(uint24 addr) -> uint8;
auto mcurom_read(uint24 addr, uint8 data) -> uint8;
auto mcurom_write(uint24 addr, uint8 data) -> void;
auto mcuromRead(uint24 addr, uint8 data) -> uint8;
auto mcuromWrite(uint24 addr, uint8 data) -> void;
auto mcuram_read(uint24 addr, uint8 data) -> uint8;
auto mcuram_write(uint24 addr, uint8 data) -> void;
auto mcuramRead(uint24 addr, uint8 data) -> uint8;
auto mcuramWrite(uint24 addr, uint8 data) -> void;
auto serialize(serializer&) -> void;
@ -25,19 +25,22 @@ struct SDD1 {
MappedRAM ram;
private:
uint8 sdd1_enable; //channel bit-mask
uint8 xfer_enable; //channel bit-mask
bool dma_ready; //used to initialize decompression module
uint mmc[4]; //memory map controller ROM indices
uint8 r4800; //hard enable
uint8 r4801; //soft enable
uint8 r4804; //MMC bank 0
uint8 r4805; //MMC bank 1
uint8 r4806; //MMC bank 2
uint8 r4807; //MMC bank 3
struct {
uint addr; //$43x2-$43x4 -- DMA transfer address
uint16 size; //$43x5-$43x6 -- DMA transfer size
struct DMA {
uint24 addr; //$43x2-$43x4 -- DMA transfer address
uint16 size; //$43x5-$43x6 -- DMA transfer size
} dma[8];
bool dmaReady; //used to initialize decompression module
public:
#include "decomp.hpp"
Decomp decomp;
#include "decompressor.hpp"
Decompressor decompressor;
};
extern SDD1 sdd1;

View File

@ -1,13 +1,16 @@
auto SDD1::serialize(serializer& s) -> void {
s.array(ram.data(), ram.size());
s.integer(sdd1_enable);
s.integer(xfer_enable);
s.integer(dma_ready);
s.array(mmc);
s.integer(r4800);
s.integer(r4801);
s.integer(r4804);
s.integer(r4805);
s.integer(r4806);
s.integer(r4807);
for(auto n : range(8)) {
s.integer(dma[n].addr);
s.integer(dma[n].size);
}
s.integer(dmaReady);
}

View File

@ -83,7 +83,7 @@ auto S21FX::read(uint24 addr, uint8 data) -> uint8 {
if(addr == 0x21ff) {
if(linkBuffer.size() > 0) {
return linkBuffer.takeFirst();
return linkBuffer.takeLeft();
}
}
@ -123,7 +123,7 @@ auto S21FX::writable() -> bool {
auto S21FX::read() -> uint8 {
step(1);
if(snesBuffer.size() > 0) {
return snesBuffer.takeFirst();
return snesBuffer.takeLeft();
}
return 0x00;
}

View File

@ -60,8 +60,8 @@ Interface::Interface() {
device.input.append({n + 9, 0, {"Port ", p, " - ", "X" }});
device.input.append({n + 10, 0, {"Port ", p, " - ", "L" }});
device.input.append({n + 11, 0, {"Port ", p, " - ", "R" }});
device.order.append(n + 4, n + 5, n + 6, n + 7, n + 0, n + 8);
device.order.append(n + 1, n + 9, n + 10, n + 11, n + 2, n + 3);
device.order.append({n + 4, n + 5, n + 6, n + 7, n + 0, n + 8});
device.order.append({n + 1, n + 9, n + 10, n + 11, n + 2, n + 3});
}
this->device.append(device);
}
@ -100,12 +100,12 @@ Interface::Interface() {
device.input.append({1, 1, "Port 1 - Y-axis" });
device.input.append({2, 0, "Port 1 - Trigger"});
device.input.append({3, 0, "Port 1 - Start" });
device.order.append(0, 1, 2, 3);
device.order.append({0, 1, 2, 3});
device.input.append({4, 1, "Port 2 - X-axis" });
device.input.append({5, 1, "Port 2 - Y-axis" });
device.input.append({6, 0, "Port 2 - Trigger"});
device.input.append({7, 0, "Port 2 - Start" });
device.order.append(4, 5, 6, 7);
device.order.append({4, 5, 6, 7});
this->device.append(device);
}

View File

@ -147,21 +147,21 @@ InputManager::InputManager() {
for(auto& emulator : program->emulators) {
emulators.append(InputEmulator());
auto& inputEmulator = emulators.last();
auto& inputEmulator = emulators.right();
inputEmulator.name = emulator->information.name;
for(auto& port : emulator->port) {
inputEmulator.ports.append(InputPort());
auto& inputPort = inputEmulator.ports.last();
auto& inputPort = inputEmulator.ports.right();
inputPort.name = port.name;
for(auto& device : port.device) {
inputPort.devices.append(InputDevice());
auto& inputDevice = inputPort.devices.last();
auto& inputDevice = inputPort.devices.right();
inputDevice.name = device.name;
for(auto number : device.order) {
auto& input = device.input[number];
inputDevice.mappings.append(new InputMapping());
auto& inputMapping = inputDevice.mappings.last();
auto& inputMapping = inputDevice.mappings.right();
inputMapping->name = input.name;
inputMapping->link = &input;
input.guid = (uintptr)inputMapping;

View File

@ -52,7 +52,7 @@ Program::Program(lstring args) {
updateAudioDriver();
updateAudioEffects();
args.takeFirst(); //ignore program location in argument parsing
args.takeLeft(); //ignore program location in argument parsing
for(auto& argument : args) {
if(argument == "--fullscreen") {
presentation->toggleFullScreen();

View File

@ -48,7 +48,7 @@ auto mMenu::remove(sAction action) -> type& {
}
auto mMenu::reset() -> type& {
while(state.actions) remove(state.actions.last());
while(state.actions) remove(state.actions.right());
return *this;
}

View File

@ -41,7 +41,7 @@ auto mLayout::remove(sSizable sizable) -> type& {
}
auto mLayout::reset() -> type& {
while(state.sizables) remove(state.sizables.last());
while(state.sizables) remove(state.sizables.right());
return *this;
}

View File

@ -50,7 +50,7 @@ auto mMenuBar::remove(sMenu menu) -> type& {
}
auto mMenuBar::reset() -> type& {
while(state.menus) remove(state.menus.last());
while(state.menus) remove(state.menus.right());
return *this;
}

View File

@ -45,7 +45,7 @@ auto mPopupMenu::remove(sAction action) -> type& {
}
auto mPopupMenu::reset() -> type& {
while(state.actions) remove(state.actions.last());
while(state.actions) remove(state.actions.right());
return *this;
}

View File

@ -86,7 +86,7 @@ struct Group : sGroup {
template<typename T = Object> auto objects() const -> vector<T> {
vector<T> objects;
for(auto object : self().objects()) {
if(auto cast = object.cast<T>()) objects.append(cast);
if(auto casted = object.cast<T>()) objects.append(casted);
}
return objects;
}

View File

@ -77,7 +77,7 @@ auto mTabFrame::remove(sTabFrameItem item) -> type& {
}
auto mTabFrame::reset() -> type& {
while(state.items) remove(state.items.last());
while(state.items) remove(state.items.right());
return *this;
}

View File

@ -59,9 +59,9 @@ auto mTreeViewItem::icon() const -> image {
auto mTreeViewItem::item(const string& path) const -> TreeViewItem {
if(path.empty()) return {};
auto paths = path.split("/");
unsigned position = paths.takeFirst().natural();
unsigned position = paths.takeLeft().natural();
if(position >= itemCount()) return {};
if(paths.empty()) return state.items[position];
if(!paths) return state.items[position];
return state.items[position]->item(paths.merge("/"));
}

View File

@ -45,9 +45,9 @@ auto mTreeView::foregroundColor() const -> Color {
auto mTreeView::item(const string& path) const -> TreeViewItem {
if(path.empty()) return {};
auto paths = path.split("/");
unsigned position = paths.takeFirst().natural();
unsigned position = paths.takeLeft().natural();
if(position >= itemCount()) return {};
if(paths.empty()) return state.items[position];
if(!paths) return state.items[position];
return state.items[position]->item(paths.merge("/"));
}

View File

@ -35,7 +35,7 @@ auto BrowserDialogWindow::accept() -> void {
auto batched = view.batched();
if(state.action == "openFile" && batched) {
string name = batched.first()->cell(0)->text();
string name = batched.left()->cell(0)->text();
if(isFolder(name)) return setPath({state.path, name});
state.response.append(string{state.path, name});
}
@ -48,14 +48,14 @@ auto BrowserDialogWindow::accept() -> void {
}
if(state.action == "openFolder" && batched) {
string name = batched.first()->cell(0)->text();
string name = batched.left()->cell(0)->text();
if(!isMatch(name)) return setPath({state.path, name});
state.response.append(string{state.path, name, "/"});
}
if(state.action == "saveFile") {
string name = fileName.text();
if(!name && batched) name = batched.first()->cell(0)->text();
if(!name && batched) name = batched.left()->cell(0)->text();
if(!name || isFolder(name)) return;
if(file::exists({state.path, name})) {
if(MessageDialog("File already exists; overwrite it?").question() != "Yes") return;
@ -64,7 +64,7 @@ auto BrowserDialogWindow::accept() -> void {
}
if(state.action == "selectFolder" && batched) {
string name = batched.first()->cell(0)->text();
string name = batched.left()->cell(0)->text();
if(isFolder(name)) state.response.append(string{state.path, name, "/"});
}
@ -125,7 +125,7 @@ auto BrowserDialogWindow::run() -> lstring {
filterList.setVisible(state.action != "selectFolder").onChange([&] { setPath(state.path); });
for(auto& filter : state.filters) {
auto part = filter.split("|", 1L);
filterList.append(ComboButtonItem().setText(part.first()));
filterList.append(ComboButtonItem().setText(part.left()));
}
fileName.setVisible(state.action == "saveFile").onActivate([&] { accept(); });
acceptButton.onActivate([&] { accept(); });
@ -137,7 +137,7 @@ auto BrowserDialogWindow::run() -> lstring {
if(!state.filters) state.filters.append("All|*");
for(auto& filter : state.filters) {
auto part = filter.split("|", 1L);
filters.append(part.last().split(":"));
filters.append(part.right().split(":"));
}
setPath(state.path);
@ -201,7 +201,7 @@ BrowserDialog::BrowserDialog() {
auto BrowserDialog::openFile() -> string {
state.action = "openFile";
if(!state.title) state.title = "Open File";
if(auto result = _run()) return result.first();
if(auto result = _run()) return result.left();
return {};
}
@ -215,21 +215,21 @@ auto BrowserDialog::openFiles() -> lstring {
auto BrowserDialog::openFolder() -> string {
state.action = "openFolder";
if(!state.title) state.title = "Open Folder";
if(auto result = _run()) return result.first();
if(auto result = _run()) return result.left();
return {};
}
auto BrowserDialog::saveFile() -> string {
state.action = "saveFile";
if(!state.title) state.title = "Save File";
if(auto result = _run()) return result.first();
if(auto result = _run()) return result.left();
return {};
}
auto BrowserDialog::selectFolder() -> string {
state.action = "selectFolder";
if(!state.title) state.title = "Select Folder";
if(auto result = _run()) return result.first();
if(auto result = _run()) return result.left();
return {};
}

View File

@ -26,7 +26,7 @@ auto mHorizontalLayout::minimumSize() const -> Size {
} else {
width += child.width;
}
if(&child != &properties.last()) width += child.spacing;
if(&child != &properties.right()) width += child.spacing;
}
for(auto n : range(sizableCount())) {
@ -94,7 +94,7 @@ auto mHorizontalLayout::setGeometry(Geometry containerGeometry) -> type& {
for(auto& child : properties) {
if(child.width == Size::Maximum) maximumWidthCounter++;
if(child.width != Size::Maximum) minimumWidth += child.width;
if(&child != &properties.last()) minimumWidth += child.spacing;
if(&child != &properties.right()) minimumWidth += child.spacing;
}
for(auto& child : properties) {

View File

@ -35,7 +35,7 @@ auto mVerticalLayout::minimumSize() const -> Size {
} else {
height += child.height;
}
if(&child != &properties.last()) height += child.spacing;
if(&child != &properties.right()) height += child.spacing;
}
return {settings.margin * 2 + width, settings.margin * 2 + height};
@ -94,7 +94,7 @@ auto mVerticalLayout::setGeometry(Geometry containerGeometry) -> type& {
for(auto& child : properties) {
if(child.height == Size::Maximum) maximumHeightCounter++;
if(child.height != Size::Maximum) minimumHeight += child.height;
if(&child != &properties.last()) minimumHeight += child.spacing;
if(&child != &properties.right()) minimumHeight += child.spacing;
}
for(auto& child : properties) {

View File

@ -6,7 +6,7 @@ static auto Canvas_drop(GtkWidget* widget, GdkDragContext* context, signed x, si
GtkSelectionData* data, unsigned type, unsigned timestamp, pCanvas* p) -> void {
if(!p->state().droppable) return;
lstring paths = DropPaths(data);
if(paths.empty()) return;
if(!paths) return;
p->self().doDrop(paths);
}

View File

@ -83,7 +83,7 @@ auto pConsole::_keyPress(unsigned scancode, unsigned mask) -> bool {
gtk_text_buffer_insert(textBuffer, &end, string{"\n", state().prompt}, -1);
self().doActivate(s);
if(s) history.prepend(s);
if(history.size() > 128) history.removeLast();
if(history.size() > 128) history.removeRight();
historyOffset = 0;
_seekToEnd();
return true;

View File

@ -133,10 +133,10 @@ auto pTreeView::_doDataFunc(GtkTreeViewColumn* column, GtkCellRenderer* renderer
auto parts = string{path}.split(":");
g_free(path);
auto item = self().item(parts.takeFirst().natural());
auto item = self().item(parts.takeLeft().natural());
if(!item) return;
while(parts) {
item = item.item(parts.takeFirst().natural());
item = item.item(parts.takeLeft().natural());
if(!item) return;
}

View File

@ -6,7 +6,7 @@ static auto Viewport_dropEvent(GtkWidget* widget, GdkDragContext* context, signe
GtkSelectionData* data, unsigned type, unsigned timestamp, pViewport* p) -> void {
if(!p->state().droppable) return;
lstring paths = DropPaths(data);
if(paths.empty()) return;
if(!paths) return;
p->self().doDrop(paths);
}

View File

@ -82,7 +82,7 @@ static auto Window_drop(GtkWidget* widget, GdkDragContext* context, signed x, si
GtkSelectionData* data, unsigned type, unsigned timestamp, pWindow* p) -> void {
if(!p->state().droppable) return;
lstring paths = DropPaths(data);
if(paths.empty()) return;
if(!paths) return;
p->self().doDrop(paths);
}

View File

@ -7376,9 +7376,9 @@ cartridge sha256:b4626cf0c876a124b50f9421c48a7d762e9ed808ad336c799d543d60b484897
cartridge sha256:910a29f834199c63c22beddc749baba746da9922196a553255deade59f4fc127
:board region=ntsc
: sdd1
: map address=00-3f,80-bf:4800-4807
: map address=00-3f,80-bf:4800-480f
: rom name=program.rom size=0x400000
: map address=00-3f,80-bf:8000-ffff mask=0x808000
: map address=00-3f,80-bf:8000-ffff
: map address=c0-ff:0000-ffff
:
:information

View File

@ -30,7 +30,7 @@ GameBoyAdvanceCartridge::GameBoyAdvanceCartridge(const uint8_t* data, unsigned s
char text[16];
memcpy(text, data + n, id.size + 3);
text[id.size + 3] = 0;
list.appendOnce(text);
if(!list.find(text)) list.append(text);
}
}
}

View File

@ -253,15 +253,15 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t* data, uint size, boo
else if(has_sdd1) {
markup.append(
" sdd1\n"
" map address=00-3f,80-bf:4800-4807\n"
" map address=00-3f,80-bf:4800-480f\n"
" rom name=program.rom size=0x", hex(rom_size), "\n"
" map address=00-3f,80-bf:8000-ffff mask=0x808000\n"
" map address=00-3f,80-bf:8000-ffff\n"
" map address=c0-ff:0000-ffff\n"
);
if(ram_size > 0) markup.append(
" ram name=save.ram size=0x", hex(ram_size), "\n"
" map address=20-3f,a0-bf:6000-7fff mask=0xe000\n"
" map address=70-7d:0000-7fff mask=0x8000\n"
" map address=00-3f,80-bf:6000-7fff mask=0xe000\n"
" map address=70-73:0000-ffff mask=0x8000\n"
);
}

View File

@ -57,7 +57,7 @@ struct Node {
auto find(const string& path) -> maybe<Node&> {
auto p = path.split("/");
auto name = p.takeFirst();
auto name = p.takeLeft();
for(auto& child : children) {
if(child.name == name) {
if(p.size() == 0) return child;

134
nall/emulation/21fx.hpp Normal file
View File

@ -0,0 +1,134 @@
#pragma once
#include <nall/nall.hpp>
#include <nall/serial.hpp>
using namespace nall;
struct FX {
auto open(lstring& args) -> bool;
auto close() -> void;
auto readable() -> bool;
auto read() -> uint8_t;
auto writable() -> bool;
auto write(uint8_t data) -> void;
auto read(uint offset, uint length) -> vector<uint8_t>;
auto write(uint offset, const vector<uint8_t>& buffer) -> void;
auto execute(uint offset) -> void;
auto read(uint offset) -> uint8_t;
auto write(uint offset, uint8_t data) -> void;
serial device;
};
auto FX::open(lstring& args) -> bool {
//device name override support
string name;
for(uint n : range(args)) {
if(args[n].beginsWith("--device=")) {
name = args.take(n).ltrim("--device=", 1L);
break;
}
}
if(!device.open(name)) {
print("[21fx] error: unable to open hardware device\n");
return false;
}
//flush the device (to clear floating inputs)
while(true) {
while(readable()) read();
auto iplrom = read(0x2184, 122);
auto sha256 = Hash::SHA256(iplrom.data(), iplrom.size()).digest();
if(sha256 == "41b79712a4a2d16d39894ae1b38cde5c41dad22eadc560df631d39f13df1e4b9") break;
}
return true;
}
auto FX::close() -> void {
device.close();
}
auto FX::readable() -> bool {
return device.readable();
}
//1000ns delay avoids burning CPU core at 100%; does not slow down max transfer rate at all
auto FX::read() -> uint8_t {
while(!readable()) usleep(1000);
uint8_t buffer[1] = {0};
device.read(buffer, 1);
return buffer[0];
}
auto FX::writable() -> bool {
return device.writable();
}
auto FX::write(uint8_t data) -> void {
while(!writable()) usleep(1000);
uint8_t buffer[1] = {data};
device.write(buffer, 1);
}
//
auto FX::read(uint offset, uint length) -> vector<uint8_t> {
write(0x21);
write(0x66);
write(0x78);
write(offset >> 16);
write(offset >> 8);
write(offset >> 0);
write(0x01);
write(length >> 8);
write(length >> 0);
write(0x00);
vector<uint8_t> buffer;
while(length--) buffer.append(read());
return buffer;
}
auto FX::write(uint offset, const vector<uint8_t>& buffer) -> void {
auto length = buffer.size();
write(0x21);
write(0x66);
write(0x78);
write(offset >> 16);
write(offset >> 8);
write(offset >> 0);
write(0x01);
write(buffer.size() >> 8);
write(buffer.size() >> 0);
write(0x01);
for(auto data : buffer) write(data);
write(0x00);
}
auto FX::execute(uint offset) -> void {
write(0x21);
write(0x66);
write(0x78);
write(offset >> 16);
write(offset >> 8);
write(offset >> 0);
write(0x00);
}
//
auto FX::read(uint offset) -> uint8_t {
auto buffer = read(offset, 1);
return buffer[0];
}
auto FX::write(uint offset, uint8_t data) -> void {
vector<uint8_t> buffer = {data};
write(offset, buffer);
}

View File

@ -34,14 +34,14 @@ inline auto Base64(const uint8_t* data, unsigned size, const string& format = "M
case 1:
buffer |= data[i] >> 4;
result.last() = lookup[buffer];
result.right() = lookup[buffer];
buffer = (data[i] & 15) << 2;
result.append(lookup[buffer]);
break;
case 2:
buffer |= data[i] >> 6;
result.last() = lookup[buffer];
result.right() = lookup[buffer];
buffer = (data[i] & 63);
result.append(lookup[buffer]);
break;

View File

@ -2,38 +2,57 @@
#include <nall/range.hpp>
namespace nall {
struct string;
namespace Hash {
namespace nall { struct string; }
namespace nall { namespace Hash {
struct CRC16 {
CRC16() { reset(); }
CRC16(const void* values, unsigned size) : CRC16() { data(values, size); }
CRC16(const void* values, uint size) : CRC16() { data(values, size); }
CRC16(const vector<uint8_t>& values) : CRC16() { data(values); }
auto reset() -> void {
checksum = ~0;
}
auto data(uint8_t value) -> void {
for(auto n : range(8)) {
if((checksum & 1) ^ (value & 1)) checksum = (checksum >> 1) ^ 0x8408;
else checksum >>= 1;
value >>= 1;
}
checksum = (checksum >> 8) ^ table(checksum ^ value);
}
auto data(const void* values, unsigned size) -> void {
auto data(const void* values, uint size) -> void {
auto p = (const uint8_t*)values;
while(size--) data(*p++);
}
auto value() -> uint16_t {
auto data(const vector<uint8_t>& values) -> void {
for(auto value : values) data(value);
}
auto value() const -> uint16_t {
return ~checksum;
}
inline auto digest() -> string;
inline auto digest() const -> string;
private:
static auto table(uint8_t index) -> uint16_t {
static uint16_t table[256] = {0};
static bool initialized = false;
if(!initialized) {
initialized = true;
for(auto index : range(256)) {
uint16_t crc = index;
for(auto bit : range(8)) {
crc = (crc >> 1) ^ (crc & 1 ? 0x8408 : 0);
}
table[index] = crc;
}
}
return table[index];
}
uint16_t checksum;
};

View File

@ -2,80 +2,57 @@
#include <nall/range.hpp>
namespace nall {
struct string;
namespace Hash {
namespace nall { struct string; }
const uint32_t _crc32_table[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};
namespace nall { namespace Hash {
struct CRC32 {
CRC32() { reset(); }
CRC32(const void* values, unsigned size) : CRC32() { data(values, size); }
CRC32(const void* values, uint size) : CRC32() { data(values, size); }
CRC32(const vector<uint8_t>& values) : CRC32() { data(values); }
auto reset() -> void {
checksum = ~0;
}
auto data(uint8_t value) -> void {
checksum = ((checksum >> 8) & 0xffffff) ^ _crc32_table[(checksum ^ value) & 0xff];
checksum = (checksum >> 8) ^ table(checksum ^ value);
}
auto data(const void* values, unsigned size) -> void {
auto data(const void* values, uint size) -> void {
auto p = (const uint8_t*)values;
while(size--) data(*p++);
}
auto data(const vector<uint8_t>& values) -> void {
for(auto value : values) data(value);
}
auto value() const -> uint32_t {
return ~checksum;
}
inline auto digest() -> string;
inline auto digest() const -> string;
private:
static auto table(uint8_t index) -> uint32_t {
static uint32_t table[256] = {0};
static bool initialized = false;
if(!initialized) {
initialized = true;
for(auto index : range(256)) {
uint32_t crc = index;
for(auto bit : range(8)) {
crc = (crc >> 1) ^ (crc & 1 ? 0xedb8'8320 : 0);
}
table[index] = crc;
}
}
return table[index];
}
uint32_t checksum;
};

59
nall/hash/crc64.hpp Normal file
View File

@ -0,0 +1,59 @@
#pragma once
#include <nall/range.hpp>
namespace nall { struct string; }
namespace nall { namespace Hash {
struct CRC64 {
CRC64() { reset(); }
CRC64(const void* values, uint size) : CRC64() { data(values, size); }
CRC64(const vector<uint8_t>& values) : CRC64() { data(values); }
auto reset() -> void {
checksum = ~0;
}
auto data(uint8_t value) -> void {
checksum = (checksum >> 8) ^ table(checksum ^ value);
}
auto data(const void* values, uint size) -> void {
auto p = (const uint8_t*)values;
while(size--) data(*p++);
}
auto data(const vector<uint8_t>& values) -> void {
for(auto value : values) data(value);
}
auto value() const -> uint64_t {
return ~checksum;
}
inline auto digest() const -> string;
private:
static auto table(uint8_t index) -> uint64_t {
static uint64_t table[256] = {0};
static bool initialized = false;
if(!initialized) {
initialized = true;
for(auto index : range(256)) {
uint64_t crc = index;
for(auto bit : range(8)) {
crc = (crc >> 1) ^ (crc & 1 ? 0xc96c'5795'd787'0f42 : 0);
}
table[index] = crc;
}
}
return table[index];
}
uint64_t checksum;
};
}}

View File

@ -2,13 +2,14 @@
#include <nall/range.hpp>
namespace nall {
struct string;
namespace Hash {
namespace nall { struct string; }
namespace nall { namespace Hash {
struct SHA256 {
SHA256() { reset(); }
SHA256(const void* values, unsigned size) : SHA256() { data(values, size); }
SHA256(const void* values, uint size) : SHA256() { data(values, size); }
SHA256(const vector<uint8_t>& values) : SHA256() { data(values); }
auto reset() -> void {
for(auto n : input) n = 0;
@ -22,12 +23,16 @@ struct SHA256 {
length++;
}
auto data(const void* values, unsigned size) -> void {
auto data(const void* values, uint size) -> void {
length += size;
auto p = (const uint8_t*)values;
while(size--) byte(*p++);
}
auto data(const vector<uint8_t>& values) -> void {
for(auto value : values) data(value);
}
auto value() const -> vector<uint8_t> {
SHA256 self(*this);
self.finish();
@ -77,14 +82,14 @@ private:
return (x >> n) | (x << 32 - n);
}
auto square(unsigned n) -> uint32_t {
auto square(uint n) -> uint32_t {
static const uint32_t value[8] = {
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
};
return value[n];
}
auto cube(unsigned n) -> uint32_t {
auto cube(uint n) -> uint32_t {
static const uint32_t value[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,

View File

@ -20,7 +20,7 @@ struct Group : vector<Input> {
auto name() const -> string { return _name; }
auto input(unsigned id) -> Input& { return operator[](id); }
auto append(const string& name) -> void { vector::append({name}); }
auto append(const string& name) -> void { vector::append(Input{name}); }
auto find(const string& name) const -> maybe<unsigned> {
for(auto id : range(size())) {
@ -51,7 +51,7 @@ struct Device : vector<Group> {
auto id() const -> uint64_t { return _id; }
auto setID(uint64_t id) -> void { _id = id; }
auto group(unsigned id) -> Group& { return operator[](id); }
auto append(const string& name) -> void { vector::append({name}); }
auto append(const string& name) -> void { vector::append(Group{name}); }
auto find(const string& name) const -> maybe<unsigned> {
for(auto id : range(size())) {

View File

@ -70,7 +70,7 @@ auto Request::head(const function<bool (const uint8_t*, unsigned)>& callback) co
auto Request::setHead() -> bool {
lstring headers = _head.split("\n");
string request = headers.takeFirst().rtrim("\r", 1L);
string request = headers.takeLeft().rtrim("\r", 1L);
string requestHost;
if(request.iendsWith(" HTTP/1.0")) request.irtrim(" HTTP/1.0", 1L);
@ -146,7 +146,7 @@ auto Request::setBody() -> bool {
auto boundary = contentType.iltrim("multipart/form-data; boundary=", 1L).trim("\"", "\"", 1L);
auto blocks = _body.split({"--", boundary}, 1024L); //limit blocks to prevent memory exhaustion
for(auto& block : blocks) block.trim("\r\n", "\r\n", 1L);
if(blocks.size() < 2 || (blocks.takeFirst(), !blocks.takeLast().beginsWith("--"))) return false;
if(blocks.size() < 2 || (blocks.takeLeft(), !blocks.takeRight().beginsWith("--"))) return false;
for(auto& block : blocks) {
string name;
string filename;

View File

@ -88,7 +88,7 @@ auto Response::head(const function<bool (const uint8_t*, unsigned)>& callback) c
auto Response::setHead() -> bool {
lstring headers = _head.split("\n");
string response = headers.takeFirst().rtrim("\r");
string response = headers.takeLeft().rtrim("\r");
if(response.ibeginsWith("HTTP/1.0 ")) response.iltrim("HTTP/1.0 ", 1L);
else if(response.ibeginsWith("HTTP/1.1 ")) response.iltrim("HTTP/1.1 ", 1L);

View File

@ -1,3 +1,7 @@
#pragma once
#include <stdlib.h>
#include <nall/range.hpp>
#include <nall/stdint.hpp>
#include <nall/memory/memory.hpp>

View File

@ -64,6 +64,7 @@
#include <nall/encode/url.hpp>
#include <nall/hash/crc16.hpp>
#include <nall/hash/crc32.hpp>
#include <nall/hash/crc64.hpp>
#include <nall/hash/sha256.hpp>
#if defined(PLATFORM_WINDOWS)

View File

@ -39,12 +39,4 @@ inline auto rrange(int size) {
return range_t{size - 1, -1, -1};
}
template<typename T> inline auto range(const vector<T>& container) {
return range_t{0, (int)container.size(), 1};
}
template<typename T> inline auto rrange(const vector<T>& container) {
return range_t{(int)container.size() - 1, -1, -1};
}
}

View File

@ -16,17 +16,12 @@
namespace nall {
struct serial {
serial() {
port = -1;
port_open = false;
}
~serial() {
close();
}
auto readable() -> bool {
if(port_open == false) return false;
if(!opened) return false;
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(port, &fdset);
@ -40,12 +35,12 @@ struct serial {
//-1 on error, otherwise return bytes read
auto read(uint8_t* data, uint length) -> int {
if(port_open == false) return -1;
if(!opened) return -1;
return ::read(port, (void*)data, length);
}
auto writable() -> bool {
if(port_open == false) return false;
if(!opened) return false;
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(port, &fdset);
@ -59,14 +54,17 @@ struct serial {
//-1 on error, otherwise return bytes written
auto write(const uint8_t* data, uint length) -> int {
if(port_open == false) return -1;
if(!opened) return -1;
return ::write(port, (void*)data, length);
}
auto open(const string& portname, uint rate, bool flowcontrol) -> bool {
//rate==0: use flow control (synchronous mode)
//rate!=0: baud-rate (asynchronous mode)
auto open(string device, uint rate = 0) -> bool {
close();
port = ::open(portname, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
if(!device) device = "/dev/ttyU0"; //note: default device name is for FreeBSD 10+
port = ::open(device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
if(port == -1) return false;
if(ioctl(port, TIOCEXCL) == -1) { close(); return false; }
@ -75,7 +73,7 @@ struct serial {
termios attr = original_attr;
cfmakeraw(&attr);
cfsetspeed(&attr, rate);
cfsetspeed(&attr, rate ? rate : 57600); //rate value has no effect in synchronous mode
attr.c_lflag &=~ (ECHO | ECHONL | ISIG | ICANON | IEXTEN);
attr.c_iflag &=~ (BRKINT | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY);
@ -83,7 +81,7 @@ struct serial {
attr.c_oflag &=~ (OPOST);
attr.c_cflag &=~ (CSIZE | CSTOPB | PARENB | CLOCAL);
attr.c_cflag |= (CS8 | CREAD);
if(flowcontrol == false) {
if(rate) {
attr.c_cflag &= ~CRTSCTS;
} else {
attr.c_cflag |= CRTSCTS;
@ -91,15 +89,15 @@ struct serial {
attr.c_cc[VTIME] = attr.c_cc[VMIN] = 0;
if(tcsetattr(port, TCSANOW, &attr) == -1) { close(); return false; }
return port_open = true;
return opened = true;
}
auto close() -> void {
if(port != -1) {
tcdrain(port);
if(port_open == true) {
if(opened) {
tcsetattr(port, TCSANOW, &original_attr);
port_open = false;
opened = false;
}
::close(port);
port = -1;
@ -107,8 +105,8 @@ struct serial {
}
private:
int port;
bool port_open;
int port = -1;
bool opened = false;
termios original_attr;
};

View File

@ -22,6 +22,7 @@
#include <nall/vector.hpp>
#include <nall/hash/crc16.hpp>
#include <nall/hash/crc32.hpp>
#include <nall/hash/crc64.hpp>
#include <nall/hash/sha256.hpp>
#include <nall/string/base.hpp>

View File

@ -32,6 +32,7 @@ inline auto real(long double value) -> string;
//hash.hpp
inline auto crc16(rstring self) -> string;
inline auto crc32(rstring self) -> string;
inline auto crc64(rstring self) -> string;
inline auto sha256(rstring self) -> string;
//match.hpp

View File

@ -45,7 +45,7 @@ inline auto parse(Node*& node, const char*& s, uint depth) -> void {
while(whitespace(s[0])) s++;
if(!s[0]) return;
if(s[0] == '(' && node->link.empty()) {
if(s[0] == '(' && !node->link) {
parse(node, s += 1, 1);
if(*s++ != ')') throw "mismatched group";
}
@ -55,7 +55,7 @@ inline auto parse(Node*& node, const char*& s, uint depth) -> void {
node->literal = literal(s);
}
#define p() (node->literal.empty() && node->link.empty())
#define p() (!node->literal && !node->link)
while(true) {
while(whitespace(s[0])) s++;
if(!s[0]) return;

View File

@ -3,14 +3,18 @@
namespace nall {
namespace Hash {
auto CRC16::digest() -> string {
auto CRC16::digest() const -> string {
return hex(value(), 4L);
}
auto CRC32::digest() -> string {
auto CRC32::digest() const -> string {
return hex(value(), 8L);
}
auto CRC64::digest() const -> string {
return hex(value(), 16L);
}
auto SHA256::digest() const -> string {
string result;
for(auto n : value()) result.append(hex(n, 2L));
@ -26,6 +30,10 @@ auto crc32(rstring self) -> string {
return Hash::CRC32(self.data(), self.size()).digest();
}
auto crc64(rstring self) -> string {
return Hash::CRC64(self.data(), self.size()).digest();
}
auto sha256(rstring self) -> string {
return Hash::SHA256(self.data(), self.size()).digest();
}

View File

@ -16,7 +16,7 @@ auto lstring::operator!=(const lstring& source) const -> bool {
}
auto lstring::isort() -> lstring& {
nall::sort(pool, objectsize, [](const string& x, const string& y) {
sort([](const string& x, const string& y) {
return memory::icompare(x.data(), x.size(), y.data(), y.size()) < 0;
});
return *this;

View File

@ -119,13 +119,13 @@ auto ManagedNode::_create(const string& path) -> Node {
}
}
_children.append(new ManagedNode(name));
return _children.last()->_create(slice(path, *position + 1));
return _children.right()->_create(slice(path, *position + 1));
}
for(auto& node : _children) {
if(path == node->_name) return node;
}
_children.append(new ManagedNode(path));
return _children.last();
return _children.right();
}
}}

View File

@ -55,7 +55,7 @@ auto CML::parseDocument(const string& filedata, const string& pathname, uint dep
for(auto& block : filedata.split("\n\n")) {
lstring lines = block.rstrip().split("\n");
string name = lines.takeFirst();
string name = lines.takeLeft();
if(name.beginsWith("include ")) {
name.ltrim("include ", 1L);

View File

@ -85,7 +85,7 @@ auto DML::parseBlock(string& block, const string& pathname, uint depth) -> bool
if(state.sections++) state.output.append("</section>");
state.output.append("<section>");
}
auto content = lines.takeFirst().ltrim("# ", 1L).split(" => ", 1L);
auto content = lines.takeLeft().ltrim("# ", 1L).split(" => ", 1L);
auto data = markup(content[0]);
auto name = escape(content(1, crc32(data)));
state.output.append("<header id=\"", name, "\">", data);
@ -98,7 +98,7 @@ auto DML::parseBlock(string& block, const string& pathname, uint depth) -> bool
//header
else if(auto depth = count(block, '=')) {
auto content = slice(lines.takeFirst(), depth + 1).split(" => ", 1L);
auto content = slice(lines.takeLeft(), depth + 1).split(" => ", 1L);
auto data = markup(content[0]);
auto name = escape(content(1, crc32(data)));
if(depth <= 6) {

View File

@ -1,282 +1,109 @@
#pragma once
#include <algorithm>
#include <initializer_list>
#include <new>
#include <utility>
#include <nall/algorithm.hpp>
#include <nall/bit.hpp>
#include <nall/function.hpp>
#include <nall/maybe.hpp>
#include <nall/memory.hpp>
#include <nall/range.hpp>
#include <nall/sort.hpp>
#include <nall/utility.hpp>
#include <nall/traits.hpp>
namespace nall {
template<typename T> struct vector {
struct exception_out_of_bounds{};
template<typename T> struct vector_iterator;
template<typename T> struct vector_iterator_const;
explicit operator bool() const { return objectsize; }
auto data() -> T* { return pool + poolbase; }
auto data() const -> const T* { return pool + poolbase; }
auto empty() const -> bool { return objectsize == 0; }
auto size() const -> unsigned { return objectsize; }
auto capacity() const -> unsigned { return poolsize; }
auto release() -> T* {
T* result = pool + poolbase;
pool = nullptr;
poolbase = 0;
poolsize = 0;
objectsize = 0;
return result;
}
auto reset() -> void {
if(pool) {
for(unsigned n = 0; n < objectsize; n++) pool[poolbase + n].~T();
memory::free(pool);
}
pool = nullptr;
poolbase = 0;
poolsize = 0;
objectsize = 0;
}
auto reserve(unsigned size) -> void {
if(size <= poolsize) return;
size = bit::round(size); //amortize growth
T* copy = (T*)memory::allocate(size * sizeof(T));
for(unsigned n = 0; n < objectsize; n++) new(copy + n) T(move(pool[poolbase + n]));
free(pool);
pool = copy;
poolbase = 0;
poolsize = size;
}
auto resize(unsigned size, T value = T()) -> void {
T* copy = (T*)memory::allocate(size * sizeof(T));
for(unsigned n = 0; n < size && n < objectsize; n++) new(copy + n) T(move(pool[poolbase + n]));
for(unsigned n = objectsize; n < size; n++) new(copy + n) T(value);
reset();
pool = copy;
poolbase = 0;
poolsize = size;
objectsize = size;
}
auto reallocate(unsigned size, T value = T()) -> void {
reset();
resize(size, value);
}
template<typename... Args> auto prepend(const T& data, Args&&... args) -> void {
prepend(forward<Args>(args)...);
prepend(data);
}
auto prepend(const T& data) -> T& {
reserve(objectsize + 1);
if(poolbase == 0) {
unsigned available = poolsize - objectsize;
poolbase = max(1u, available >> 1);
for(signed n = objectsize - 1; n >= 0; n--) {
pool[poolbase + n] = move(pool[n]);
}
}
new(pool + --poolbase) T(data);
objectsize++;
return first();
}
template<typename... Args> auto append(const T& data, Args&&... args) -> void {
append(data);
append(forward<Args>(args)...);
}
auto append(const T& data) -> T& {
reserve(poolbase + objectsize + 1);
new(pool + poolbase + objectsize++) T(data);
return last();
}
auto appendOnce(const T& data) -> bool {
if(find(data)) return false;
return append(data), true;
}
auto insert(unsigned position, const T& data) -> void {
if(position == 0) {
prepend(data);
return;
}
append(data);
if(position == ~0u) return;
for(signed n = objectsize - 1; n > position; n--) {
pool[poolbase + n] = move(pool[poolbase + n - 1]);
}
pool[poolbase + position] = data;
}
auto remove(unsigned position = ~0u, unsigned length = 1) -> void {
if(position == ~0u) position = objectsize - 1;
if(position + length > objectsize) throw exception_out_of_bounds{};
if(position == 0) {
for(unsigned n = 0; n < length; n++) pool[poolbase + n].~T();
poolbase += length;
} else {
for(unsigned n = position; n < objectsize; n++) {
if(n + length < objectsize) {
pool[poolbase + n] = move(pool[poolbase + n + length]);
} else {
pool[poolbase + n].~T();
}
}
}
objectsize -= length;
}
auto removeFirst() -> void { return remove(0); }
auto removeLast() -> void { return remove(~0u); }
auto take(unsigned position = ~0u) -> T {
if(position == ~0u) position = objectsize - 1;
T object = pool[poolbase + position];
remove(position);
return object;
}
auto takeFirst() -> T { return take(0); }
auto takeLast() -> T { return take(~0u); }
auto reverse() -> void {
unsigned pivot = size() / 2;
for(unsigned l = 0, r = size() - 1; l < pivot; l++, r--) {
swap(pool[poolbase + l], pool[poolbase + r]);
}
}
auto sort(const function<bool (const T& lhs, const T& rhs)>& comparator = [](const T& lhs, const T& rhs) -> bool {
return lhs < rhs;
}) -> void {
nall::sort(pool + poolbase, objectsize, comparator);
}
auto find(const T& data) const -> maybe<unsigned> {
for(unsigned n = 0; n < objectsize; n++) if(pool[poolbase + n] == data) return n;
return nothing;
}
auto first() -> T& {
if(objectsize == 0) throw exception_out_of_bounds();
return pool[poolbase];
}
auto first() const -> const T& {
if(objectsize == 0) throw exception_out_of_bounds();
return pool[poolbase];
}
auto last() -> T& {
if(objectsize == 0) throw exception_out_of_bounds();
return pool[poolbase + objectsize - 1];
}
auto last() const -> const T& {
if(objectsize == 0) throw exception_out_of_bounds();
return pool[poolbase + objectsize - 1];
}
//access
inline auto operator[](unsigned position) -> T& {
if(position >= objectsize) throw exception_out_of_bounds();
return pool[poolbase + position];
}
inline auto operator[](unsigned position) const -> const T& {
if(position >= objectsize) throw exception_out_of_bounds();
return pool[poolbase + position];
}
inline auto operator()(unsigned position) -> T& {
if(position >= poolsize) reserve(position + 1);
while(position >= objectsize) append(T());
return pool[poolbase + position];
}
inline auto operator()(unsigned position, const T& data) const -> const T& {
if(position >= objectsize) return data;
return pool[poolbase + position];
}
//iteration
struct iterator {
iterator(vector& source, unsigned position) : source(source), position(position) {}
auto operator*() -> T& { return source.operator[](position); }
auto operator!=(const iterator& source) const -> bool { return position != source.position; }
auto operator++() -> iterator& { position++; return *this; }
private:
vector& source;
unsigned position;
};
auto begin() -> iterator { return iterator(*this, 0); }
auto end() -> iterator { return iterator(*this, size()); }
struct constIterator {
constIterator(const vector& source, unsigned position) : source(source), position(position) {}
auto operator*() const -> const T& { return source.operator[](position); }
auto operator!=(const constIterator& source) const -> bool { return position != source.position; }
auto operator++() -> constIterator& { position++; return *this; }
private:
const vector& source;
unsigned position;
};
auto begin() const -> const constIterator { return constIterator(*this, 0); }
auto end() const -> const constIterator { return constIterator(*this, size()); }
//copy
inline auto operator=(const vector& source) -> vector& {
if(this == &source) return *this;
reset();
reserve(source.size());
for(auto& data : source) append(data);
return *this;
}
//move
inline auto operator=(vector&& source) -> vector& {
if(this == &source) return *this;
reset();
pool = source.pool;
poolbase = source.poolbase;
poolsize = source.poolsize;
objectsize = source.objectsize;
source.pool = nullptr;
source.poolbase = 0;
source.poolsize = 0;
source.objectsize = 0;
return *this;
}
//construction and destruction
template<typename T>
struct vector {
//core.hpp
vector() = default;
vector(initializer_list<T> list) { for(auto& data : list) append(data); }
vector(const vector& source) { operator=(source); }
vector(vector&& source) { operator=(move(source)); }
~vector() { reset(); }
vector(const initializer_list<T>& values);
vector(const vector& source);
vector(vector&& source);
~vector();
protected:
T* pool = nullptr;
unsigned poolbase = 0;
unsigned poolsize = 0;
unsigned objectsize = 0;
explicit operator bool() const;
auto capacity() const -> uint;
auto size() const -> uint;
auto data() -> T*;
auto data() const -> const T*;
//assign.hpp
auto operator=(const vector& source) -> vector&;
auto operator=(vector&& source) -> vector&;
//memory.hpp
auto reset() -> void;
auto release() -> T*;
auto reserveLeft(uint capacity) -> bool;
auto reserveRight(uint capacity) -> bool;
auto reserve(uint capacity) -> bool { return reserveRight(capacity); }
auto resizeLeft(uint size, const T& value = T()) -> bool;
auto resizeRight(uint size, const T& value = T()) -> bool;
auto resize(uint size, const T& value = T()) -> bool { return resizeRight(size, value); }
//access.hpp
alwaysinline auto operator[](uint offset) -> T&;
alwaysinline auto operator[](uint offset) const -> const T&;
alwaysinline auto operator()(uint offset) -> T&;
alwaysinline auto operator()(uint offset, const T& value) const -> const T&;
alwaysinline auto left() -> T&;
alwaysinline auto left() const -> const T&;
alwaysinline auto right() -> T&;
alwaysinline auto right() const -> const T&;
//modify.hpp
auto prepend(const T& value) -> void;
auto prepend(T&& value) -> void;
auto prepend(const vector<T>& values) -> void;
auto prepend(vector<T>&& values) -> void;
auto append(const T& value) -> void;
auto append(T&& value) -> void;
auto append(const vector<T>& values) -> void;
auto append(vector<T>&& values) -> void;
auto insert(uint offset, const T& value) -> void;
auto removeLeft(uint length = 1) -> void;
auto removeRight(uint length = 1) -> void;
auto remove(uint offset, uint length = 1) -> void;
auto takeLeft() -> T;
auto takeRight() -> T;
auto take(uint offset) -> T;
//iterator.hpp
auto begin() { return vector_iterator<T>{*this, 0}; }
auto end() { return vector_iterator<T>{*this, size()}; }
auto begin() const { return vector_iterator_const<T>{*this, 0}; }
auto end() const { return vector_iterator_const<T>{*this, size()}; }
//utility.hpp
auto sort(const function<bool (const T& lhs, const T& rhs)>& comparator = {}) -> void;
auto find(const T& value) const -> maybe<uint>;
private:
T* _pool = nullptr; //pointer to first initialized element in pool
uint _size = 0; //number of initialized elements in pool
uint _left = 0; //number of allocated elements free on the left of pool
uint _right = 0; //number of allocated elements free on the right of pool
};
}
#include <nall/vector/core.hpp>
#include <nall/vector/assign.hpp>
#include <nall/vector/memory.hpp>
#include <nall/vector/access.hpp>
#include <nall/vector/modify.hpp>
#include <nall/vector/iterator.hpp>
#include <nall/vector/utility.hpp>

39
nall/vector/access.hpp Normal file
View File

@ -0,0 +1,39 @@
#pragma once
namespace nall {
template<typename T> auto vector<T>::operator[](uint offset) -> T& {
return _pool[offset];
}
template<typename T> auto vector<T>::operator[](uint offset) const -> const T& {
return _pool[offset];
}
template<typename T> auto vector<T>::operator()(uint offset) -> T& {
while(offset >= size()) append(T());
return _pool[offset];
}
template<typename T> auto vector<T>::operator()(uint offset, const T& value) const -> const T& {
if(offset >= size()) return value;
return _pool[offset];
}
template<typename T> auto vector<T>::left() -> T& {
return _pool[0];
}
template<typename T> auto vector<T>::left() const -> const T& {
return _pool[0];
}
template<typename T> auto vector<T>::right() -> T& {
return _pool[_size - 1];
}
template<typename T> auto vector<T>::right() const -> const T& {
return _pool[_size - 1];
}
}

28
nall/vector/assign.hpp Normal file
View File

@ -0,0 +1,28 @@
#pragma once
namespace nall {
template<typename T> auto vector<T>::operator=(const vector<T>& source) -> vector<T>& {
if(this == &source) return *this;
_pool = (T*)memory::allocate(sizeof(T) * source._size);
_size = source._size;
_left = 0;
_right = 0;
for(uint n : range(_size)) new(_pool + n) T(source._pool[n]);
return *this;
}
template<typename T> auto vector<T>::operator=(vector<T>&& source) -> vector<T>& {
if(this == &source) return *this;
_pool = source._pool;
_size = source._size;
_left = source._left;
_right = source._right;
source._pool = nullptr;
source._size = 0;
source._left = 0;
source._right = 0;
return *this;
}
}

42
nall/vector/core.hpp Normal file
View File

@ -0,0 +1,42 @@
#pragma once
namespace nall {
template<typename T> vector<T>::vector(const initializer_list<T>& values) {
reserveRight(values.size());
for(auto& value : values) append(value);
}
template<typename T> vector<T>::vector(const vector<T>& source) {
operator=(source);
}
template<typename T> vector<T>::vector(vector<T>&& source) {
operator=(move(source));
}
template<typename T> vector<T>::~vector() {
reset();
}
template<typename T> vector<T>::operator bool() const {
return _size;
}
template<typename T> auto vector<T>::capacity() const -> uint {
return _left + _size + _right;
}
template<typename T> auto vector<T>::size() const -> uint {
return _size;
}
template<typename T> auto vector<T>::data() -> T* {
return _pool;
}
template<typename T> auto vector<T>::data() const -> const T* {
return _pool;
}
}

37
nall/vector/iterator.hpp Normal file
View File

@ -0,0 +1,37 @@
#pragma once
namespace nall {
template<typename T>
struct vector_iterator {
vector_iterator(vector<T>& self, uint offset) : self(self), offset(offset) {}
auto operator*() -> T& { return self.operator[](offset); }
auto operator!=(const vector_iterator& source) const -> bool { return offset != source.offset; }
auto operator++() -> vector_iterator& { return offset++, *this; }
private:
vector<T>& self;
uint offset;
};
template<typename T>
struct vector_iterator_const {
vector_iterator_const(const vector<T>& self, uint offset) : self(self), offset(offset) {}
auto operator*() -> const T& { return self.operator[](offset); }
auto operator!=(const vector_iterator_const& source) const -> bool { return offset != source.offset; }
auto operator++() -> vector_iterator_const& { return offset++, *this; }
private:
const vector<T>& self;
uint offset;
};
template<typename T> inline auto range(const vector<T>& container) {
return range_t{0, (int)container.size(), 1};
}
template<typename T> inline auto rrange(const vector<T>& container) {
return range_t{(int)container.size() - 1, -1, -1};
}
}

90
nall/vector/memory.hpp Normal file
View File

@ -0,0 +1,90 @@
#pragma once
namespace nall {
template<typename T> auto vector<T>::reset() -> void {
if(!_pool) return;
for(uint n : range(_size)) _pool[n].~T();
memory::free(_pool - _left);
_pool = nullptr;
_size = 0;
_left = 0;
_right = 0;
}
template<typename T> auto vector<T>::release() -> T* {
auto pool = _pool;
_pool = nullptr;
_size = 0;
_left = 0;
_right = 0;
return pool;
}
template<typename T> auto vector<T>::reserveLeft(uint capacity) -> bool {
if(_size + _left >= capacity) return false;
uint left = bit::round(capacity);
auto pool = (T*)memory::allocate(sizeof(T) * (left + _right)) + left;
for(uint n : range(_size)) new(pool + n) T(move(_pool[n]));
memory::free(_pool - _left);
_pool = pool;
_left = left - _size;
return true;
}
template<typename T> auto vector<T>::reserveRight(uint capacity) -> bool {
if(_size + _right >= capacity) return false;
uint right = bit::round(capacity);
auto pool = (T*)memory::allocate(sizeof(T) * (_left + right)) + _left;
for(uint n : range(_size)) new(pool + n) T(move(_pool[n]));
memory::free(_pool - _left);
_pool = pool;
_right = right - _size;
return true;
}
template<typename T> auto vector<T>::resizeLeft(uint size, const T& value) -> bool {
if(size < _size) { //shrink
for(uint n : range(_size - size)) _pool[n].~T();
_pool += _size - size;
_left += _size - size;
_size = size;
return true;
}
if(size > _size) { //grow
reserveLeft(size);
_pool -= size - _size;
for(uint n : rrange(size - _size)) new(_pool + n) T(value);
_left -= size - _size;
_size = size;
return true;
}
return false;
}
template<typename T> auto vector<T>::resizeRight(uint size, const T& value) -> bool {
if(size < _size) { //shrink
for(uint n = size; n < _size; n++) _pool[n].~T();
_right += _size - size;
_size = size;
return true;
}
if(size > _size) { //grow
reserveRight(size);
for(uint n = _size; n < size; n++) new(_pool + n) T(value);
_right -= size - _size;
_size = size;
return true;
}
return false;
}
}

127
nall/vector/modify.hpp Normal file
View File

@ -0,0 +1,127 @@
#pragma once
namespace nall {
template<typename T> auto vector<T>::prepend(const T& value) -> void {
reserveLeft(size() + 1);
new(--_pool) T(value);
_left--;
_size++;
}
template<typename T> auto vector<T>::prepend(T&& value) -> void {
reserveLeft(size() + 1);
new(--_pool) T(move(value));
_left--;
_size++;
}
template<typename T> auto vector<T>::prepend(const vector<T>& values) -> void {
reserveLeft(size() + values.size());
_pool -= values.size();
for(uint n : range(values)) new(_pool + n) T(values[n]);
_left -= values.size();
_size += values.size();
}
template<typename T> auto vector<T>::prepend(vector<T>&& values) -> void {
reserveLeft(size() + values.size());
_pool -= values.size();
for(uint n : range(values)) new(_pool + n) T(move(values[n]));
_left -= values.size();
_size += values.size();
}
//
template<typename T> auto vector<T>::append(const T& value) -> void {
reserveRight(size() + 1);
new(_pool + _size) T(value);
_right--;
_size++;
}
template<typename T> auto vector<T>::append(T&& value) -> void {
reserveRight(size() + 1);
new(_pool + _size) T(move(value));
_right--;
_size++;
}
template<typename T> auto vector<T>::append(const vector<T>& values) -> void {
reserveRight(size() + values.size());
for(uint n : range(values)) new(_pool + _size + n) T(values[n]);
_right -= values.size();
_size += values.size();
}
template<typename T> auto vector<T>::append(vector<T>&& values) -> void {
reserveRight(size() + values.size());
for(uint n : range(values)) new(_pool + _size + n) T(move(values[n]));
_right -= values.size();
_size += values.size();
}
//
template<typename T> auto vector<T>::insert(uint offset, const T& value) -> void {
if(offset == 0) return prepend(value);
if(offset == size() - 1) return append(value);
reserveRight(size() + 1);
_size++;
for(int n = size() - 1; n > offset; n--) {
_pool[n] = move(_pool[n - 1]);
}
new(_pool + offset) T(value);
}
//
template<typename T> auto vector<T>::removeLeft(uint length) -> void {
if(length > size()) length = size();
resizeLeft(size() - length);
}
template<typename T> auto vector<T>::removeRight(uint length) -> void {
if(length > size()) length = size();
resizeRight(size() - length);
}
template<typename T> auto vector<T>::remove(uint offset, uint length) -> void {
if(offset == 0) return removeLeft(length);
if(offset == size() - 1) return removeRight(length);
for(uint n = offset; n < size(); n++) {
if(n + length < size()) {
_pool[n] = move(_pool[n + length]);
} else {
_pool[n].~T();
}
}
_size -= length;
}
//
template<typename T> auto vector<T>::takeLeft() -> T {
T value = move(_pool[0]);
removeLeft();
return value;
}
template<typename T> auto vector<T>::takeRight() -> T {
T value = move(_pool[size() - 1]);
removeRight();
return value;
}
template<typename T> auto vector<T>::take(uint offset) -> T {
if(offset == 0) return takeLeft();
if(offset == size() - 1) return takeRight();
T value = move(_pool[offset]);
remove(offset);
return value;
}
}

15
nall/vector/utility.hpp Normal file
View File

@ -0,0 +1,15 @@
#pragma once
namespace nall {
template<typename T> auto vector<T>::sort(const function<bool (const T& lhs, const T& rhs)>& comparator) -> void {
if(!comparator) return nall::sort(_pool, _size, [](const T& lhs, const T& rhs) { return lhs < rhs; });
nall::sort(_pool, _size, comparator);
}
template<typename T> auto vector<T>::find(const T& value) const -> maybe<uint> {
for(uint n : range(size())) if(_pool[n] == value) return n;
return nothing;
}
}

View File

@ -182,7 +182,6 @@ struct VideoGLX : Video, OpenGL {
//glXSwapInterval is used to toggle Vsync
//note that the ordering is very important! MESA declares SGI, but the SGI function does nothing
glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalEXT");
if(!glXSwapInterval) glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalMESA");
if(!glXSwapInterval) glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalSGI");

View File

@ -163,7 +163,6 @@ struct VideoGLX2 : Video {
glxcontext = glXCreateContext(display, vi, 0, GL_TRUE);
glXMakeCurrent(display, glxwindow = xwindow, glxcontext);
glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalEXT");
if(!glXSwapInterval) glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalMESA");
if(!glXSwapInterval) glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalSGI");

View File

@ -167,7 +167,7 @@ auto OpenGL::refresh() -> void {
render(sources[0].width, sources[0].height, outputWidth, outputHeight);
if(history.size() > 0) {
OpenGLTexture frame = history.takeLast();
OpenGLTexture frame = history.takeRight();
glBindTexture(GL_TEXTURE_2D, frame.texture);
if(width == frame.width && height == frame.height) {