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) { if(reverbDelay) {
reverbLeft.append(ileft); reverbLeft.append(ileft);
reverbRight.append(iright); reverbRight.append(iright);
ileft += reverbLeft.takeFirst() * reverbLevel; ileft += reverbLeft.takeLeft() * reverbLevel;
iright += reverbRight.takeFirst() * reverbLevel; iright += reverbRight.takeLeft() * reverbLevel;
} }
interface->audioSample(sclamp<16>(ileft), sclamp<16>(iright)); interface->audioSample(sclamp<16>(ileft), sclamp<16>(iright));

View File

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

View File

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

View File

@ -8,7 +8,7 @@ using namespace nall;
namespace Emulator { namespace Emulator {
static const string Name = "higan"; 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 Author = "byuu";
static const string License = "GPLv3"; static const string License = "GPLv3";
static const string Website = "http://byuu.org/"; 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) { if(bytes) {
b = " "; b = " ";
while(bytesRead) { while(bytesRead) {
b.append(hex(bytesRead.takeFirst(), 2L), " "); b.append(hex(bytesRead.takeLeft(), 2L), " ");
} }
b.rstrip(); b.rstrip();
} }

View File

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

View File

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

View File

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

View File

@ -4,7 +4,7 @@ namespace SuperFamicom {
SDD1 sdd1; SDD1 sdd1;
#include "decomp.cpp" #include "decompressor.cpp"
#include "serialization.cpp" #include "serialization.cpp"
auto SDD1::init() -> void { auto SDD1::init() -> void {
@ -24,113 +24,106 @@ auto SDD1::power() -> void {
auto SDD1::reset() -> void { auto SDD1::reset() -> void {
//hook S-CPU DMA MMIO registers to gather information for struct dma[]; //hook S-CPU DMA MMIO registers to gather information for struct dma[];
//buffer address and transfer size information for use in SDD1::mcu_read() //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; r4800 = 0x00;
xfer_enable = 0x00; r4801 = 0x00;
dma_ready = false; r4804 = 0x00;
r4805 = 0x01;
mmc[0] = 0 << 20; r4806 = 0x02;
mmc[1] = 1 << 20; r4807 = 0x03;
mmc[2] = 2 << 20;
mmc[3] = 3 << 20;
for(auto n : range(8)) { for(auto n : range(8)) {
dma[n].addr = 0; dma[n].addr = 0;
dma[n].size = 0; dma[n].size = 0;
} }
dmaReady = false;
} }
auto SDD1::read(uint24 addr, uint8 data) -> uint8 { auto SDD1::read(uint24 addr, uint8 data) -> uint8 {
addr = 0x4800 | (addr & 7); addr = 0x4800 | addr.bits(0,3);
switch(addr) { switch(addr) {
case 0x4804: return mmc[0] >> 20; case 0x4800: return r4800;
case 0x4805: return mmc[1] >> 20; case 0x4801: return r4801;
case 0x4806: return mmc[2] >> 20; case 0x4804: return r4804;
case 0x4807: return mmc[3] >> 20; 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 { auto SDD1::write(uint24 addr, uint8 data) -> void {
addr = 0x4800 | (addr & 7); addr = 0x4800 | addr.bits(0,3);
switch(addr) { switch(addr) {
case 0x4800: sdd1_enable = data; break; case 0x4800: r4800 = data; break;
case 0x4801: xfer_enable = data; break; case 0x4801: r4801 = data; break;
case 0x4804: r4804 = data & 0x8f; break;
case 0x4804: mmc[0] = data << 20; break; case 0x4805: r4805 = data & 0x8f; break;
case 0x4805: mmc[1] = data << 20; break; case 0x4806: r4806 = data & 0x8f; break;
case 0x4806: mmc[2] = data << 20; break; case 0x4807: r4807 = data & 0x8f; break;
case 0x4807: mmc[3] = data << 20; break;
} }
} }
auto SDD1::dma_read(uint24 addr, uint8 data) -> uint8 { auto SDD1::dmaRead(uint24 addr, uint8 data) -> uint8 {
return cpu.dmaPortRead(addr, data); return cpu.dmaPortRead(addr, data);
} }
auto SDD1::dma_write(uint24 addr, uint8 data) -> void { auto SDD1::dmaWrite(uint24 addr, uint8 data) -> void {
uint channel = (addr >> 4) & 7; uint channel = addr.bits(4,6);
switch(addr & 15) { switch(addr.bits(0,3)) {
case 2: dma[channel].addr = (dma[channel].addr & 0xffff00) + (data << 0); break; case 2: dma[channel].addr.byte(0) = data; break;
case 3: dma[channel].addr = (dma[channel].addr & 0xff00ff) + (data << 8); break; case 3: dma[channel].addr.byte(1) = data; break;
case 4: dma[channel].addr = (dma[channel].addr & 0x00ffff) + (data << 16); break; case 4: dma[channel].addr.byte(2) = data; break;
case 5: dma[channel].size.byte(0) = data; break;
case 5: dma[channel].size = (dma[channel].size & 0xff00) + (data << 0); break; case 6: dma[channel].size.byte(1) = data; break;
case 6: dma[channel].size = (dma[channel].size & 0x00ff) + (data << 8); break;
} }
return cpu.dmaPortWrite(addr, data); return cpu.dmaPortWrite(addr, data);
} }
auto SDD1::mmc_read(uint24 addr) -> uint8 { auto SDD1::mmcRead(uint24 addr) -> uint8 {
return rom.read(mmc[(addr >> 20) & 3] + (addr & 0x0fffff)); 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 //map address=00-3f,80-bf:8000-ffff
//the design is meant to be as close to the hardware design as possible, thus this code //map address=c0-ff:0000-ffff
//avoids adding S-DD1 hooks inside S-CPU::DMA emulation. auto SDD1::mcuromRead(uint24 addr, uint8 data) -> uint8 {
//
//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 mask=0x808000 => 00-1f:0000-ffff //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); return rom.read(addr);
} }
//map address=c0-ff:0000-ffff //map address=c0-ff:0000-ffff
if(sdd1_enable & xfer_enable) { if(r4800 & r4801) {
//at least one channel has S-DD1 decompression enabled ... //at least one channel has S-DD1 decompression enabled ...
for(auto n : range(8)) { 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 //S-DD1 always uses fixed transfer mode, so address will not change during transfer
if(addr == dma[n].addr) { if(addr == dma[n].addr) {
if(!dma_ready) { if(!dmaReady) {
//prepare streaming decompression //prepare streaming decompression
decomp.init(addr); decompressor.init(addr);
dma_ready = true; dmaReady = true;
} }
//fetch a decompressed byte; once finished, disable channel and invalidate buffer //fetch a decompressed byte; once finished, disable channel and invalidate buffer
uint8 data = decomp.read(); data = decompressor.read();
if(--dma[n].size == 0) { if(--dma[n].size == 0) {
dma_ready = false; dmaReady = false;
xfer_enable &= ~(1 << n); r4801.bit(n) = 0;
} }
return data; return data;
@ -140,20 +133,20 @@ auto SDD1::mcurom_read(uint24 addr, uint8) -> uint8 {
} //S-DD1 decompressor enabled } //S-DD1 decompressor enabled
//S-DD1 decompression mode inactive; return ROM data //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=00-3f,80-bf:6000-7fff mask=0xe000
//map address=70-7d:0000-7fff mask=0x8000 //map address=70-73:0000-ffff mask=0x8000
auto SDD1::mcuram_read(uint24 addr, uint8 data) -> uint8 { auto SDD1::mcuramRead(uint24 addr, uint8 data) -> uint8 {
return ram.read(addr & 0x1fff, data); return ram.read(addr.bits(0,12), data);
} }
auto SDD1::mcuram_write(uint24 addr, uint8 data) -> void { auto SDD1::mcuramWrite(uint24 addr, uint8 data) -> void {
return ram.write(addr & 0x1fff, data); return ram.write(addr.bits(0,12), data);
} }
} }

View File

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

View File

@ -1,13 +1,16 @@
auto SDD1::serialize(serializer& s) -> void { auto SDD1::serialize(serializer& s) -> void {
s.array(ram.data(), ram.size()); s.array(ram.data(), ram.size());
s.integer(sdd1_enable); s.integer(r4800);
s.integer(xfer_enable); s.integer(r4801);
s.integer(dma_ready); s.integer(r4804);
s.array(mmc); s.integer(r4805);
s.integer(r4806);
s.integer(r4807);
for(auto n : range(8)) { for(auto n : range(8)) {
s.integer(dma[n].addr); s.integer(dma[n].addr);
s.integer(dma[n].size); 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(addr == 0x21ff) {
if(linkBuffer.size() > 0) { if(linkBuffer.size() > 0) {
return linkBuffer.takeFirst(); return linkBuffer.takeLeft();
} }
} }
@ -123,7 +123,7 @@ auto S21FX::writable() -> bool {
auto S21FX::read() -> uint8 { auto S21FX::read() -> uint8 {
step(1); step(1);
if(snesBuffer.size() > 0) { if(snesBuffer.size() > 0) {
return snesBuffer.takeFirst(); return snesBuffer.takeLeft();
} }
return 0x00; return 0x00;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -86,7 +86,7 @@ struct Group : sGroup {
template<typename T = Object> auto objects() const -> vector<T> { template<typename T = Object> auto objects() const -> vector<T> {
vector<T> objects; vector<T> objects;
for(auto object : self().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; return objects;
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -35,7 +35,7 @@ auto mVerticalLayout::minimumSize() const -> Size {
} else { } else {
height += child.height; 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}; return {settings.margin * 2 + width, settings.margin * 2 + height};
@ -94,7 +94,7 @@ auto mVerticalLayout::setGeometry(Geometry containerGeometry) -> type& {
for(auto& child : properties) { for(auto& child : properties) {
if(child.height == Size::Maximum) maximumHeightCounter++; if(child.height == Size::Maximum) maximumHeightCounter++;
if(child.height != Size::Maximum) minimumHeight += child.height; 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) { 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 { GtkSelectionData* data, unsigned type, unsigned timestamp, pCanvas* p) -> void {
if(!p->state().droppable) return; if(!p->state().droppable) return;
lstring paths = DropPaths(data); lstring paths = DropPaths(data);
if(paths.empty()) return; if(!paths) return;
p->self().doDrop(paths); 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); gtk_text_buffer_insert(textBuffer, &end, string{"\n", state().prompt}, -1);
self().doActivate(s); self().doActivate(s);
if(s) history.prepend(s); if(s) history.prepend(s);
if(history.size() > 128) history.removeLast(); if(history.size() > 128) history.removeRight();
historyOffset = 0; historyOffset = 0;
_seekToEnd(); _seekToEnd();
return true; return true;

View File

@ -133,10 +133,10 @@ auto pTreeView::_doDataFunc(GtkTreeViewColumn* column, GtkCellRenderer* renderer
auto parts = string{path}.split(":"); auto parts = string{path}.split(":");
g_free(path); g_free(path);
auto item = self().item(parts.takeFirst().natural()); auto item = self().item(parts.takeLeft().natural());
if(!item) return; if(!item) return;
while(parts) { while(parts) {
item = item.item(parts.takeFirst().natural()); item = item.item(parts.takeLeft().natural());
if(!item) return; 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 { GtkSelectionData* data, unsigned type, unsigned timestamp, pViewport* p) -> void {
if(!p->state().droppable) return; if(!p->state().droppable) return;
lstring paths = DropPaths(data); lstring paths = DropPaths(data);
if(paths.empty()) return; if(!paths) return;
p->self().doDrop(paths); 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 { GtkSelectionData* data, unsigned type, unsigned timestamp, pWindow* p) -> void {
if(!p->state().droppable) return; if(!p->state().droppable) return;
lstring paths = DropPaths(data); lstring paths = DropPaths(data);
if(paths.empty()) return; if(!paths) return;
p->self().doDrop(paths); p->self().doDrop(paths);
} }

View File

@ -7376,9 +7376,9 @@ cartridge sha256:b4626cf0c876a124b50f9421c48a7d762e9ed808ad336c799d543d60b484897
cartridge sha256:910a29f834199c63c22beddc749baba746da9922196a553255deade59f4fc127 cartridge sha256:910a29f834199c63c22beddc749baba746da9922196a553255deade59f4fc127
:board region=ntsc :board region=ntsc
: sdd1 : sdd1
: map address=00-3f,80-bf:4800-4807 : map address=00-3f,80-bf:4800-480f
: rom name=program.rom size=0x400000 : 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 : map address=c0-ff:0000-ffff
: :
:information :information

View File

@ -30,7 +30,7 @@ GameBoyAdvanceCartridge::GameBoyAdvanceCartridge(const uint8_t* data, unsigned s
char text[16]; char text[16];
memcpy(text, data + n, id.size + 3); memcpy(text, data + n, id.size + 3);
text[id.size + 3] = 0; 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) { else if(has_sdd1) {
markup.append( markup.append(
" sdd1\n" " 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" " 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" " map address=c0-ff:0000-ffff\n"
); );
if(ram_size > 0) markup.append( if(ram_size > 0) markup.append(
" ram name=save.ram size=0x", hex(ram_size), "\n" " ram name=save.ram size=0x", hex(ram_size), "\n"
" map address=20-3f,a0-bf:6000-7fff mask=0xe000\n" " map address=00-3f,80-bf:6000-7fff mask=0xe000\n"
" map address=70-7d:0000-7fff mask=0x8000\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 find(const string& path) -> maybe<Node&> {
auto p = path.split("/"); auto p = path.split("/");
auto name = p.takeFirst(); auto name = p.takeLeft();
for(auto& child : children) { for(auto& child : children) {
if(child.name == name) { if(child.name == name) {
if(p.size() == 0) return child; 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: case 1:
buffer |= data[i] >> 4; buffer |= data[i] >> 4;
result.last() = lookup[buffer]; result.right() = lookup[buffer];
buffer = (data[i] & 15) << 2; buffer = (data[i] & 15) << 2;
result.append(lookup[buffer]); result.append(lookup[buffer]);
break; break;
case 2: case 2:
buffer |= data[i] >> 6; buffer |= data[i] >> 6;
result.last() = lookup[buffer]; result.right() = lookup[buffer];
buffer = (data[i] & 63); buffer = (data[i] & 63);
result.append(lookup[buffer]); result.append(lookup[buffer]);
break; break;

View File

@ -2,38 +2,57 @@
#include <nall/range.hpp> #include <nall/range.hpp>
namespace nall { namespace nall { struct string; }
struct string;
namespace Hash { namespace nall { namespace Hash {
struct CRC16 { struct CRC16 {
CRC16() { reset(); } 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 { auto reset() -> void {
checksum = ~0; checksum = ~0;
} }
auto data(uint8_t value) -> void { auto data(uint8_t value) -> void {
for(auto n : range(8)) { checksum = (checksum >> 8) ^ table(checksum ^ value);
if((checksum & 1) ^ (value & 1)) checksum = (checksum >> 1) ^ 0x8408;
else checksum >>= 1;
value >>= 1;
}
} }
auto data(const void* values, unsigned size) -> void { auto data(const void* values, uint size) -> void {
auto p = (const uint8_t*)values; auto p = (const uint8_t*)values;
while(size--) data(*p++); 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; return ~checksum;
} }
inline auto digest() -> string; inline auto digest() const -> string;
private: 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; uint16_t checksum;
}; };

View File

@ -2,80 +2,57 @@
#include <nall/range.hpp> #include <nall/range.hpp>
namespace nall { namespace nall { struct string; }
struct string;
namespace Hash {
const uint32_t _crc32_table[256] = { namespace nall { namespace Hash {
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,
};
struct CRC32 { struct CRC32 {
CRC32() { reset(); } 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 { auto reset() -> void {
checksum = ~0; checksum = ~0;
} }
auto data(uint8_t value) -> void { 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; auto p = (const uint8_t*)values;
while(size--) data(*p++); while(size--) data(*p++);
} }
auto data(const vector<uint8_t>& values) -> void {
for(auto value : values) data(value);
}
auto value() const -> uint32_t { auto value() const -> uint32_t {
return ~checksum; return ~checksum;
} }
inline auto digest() -> string; inline auto digest() const -> string;
private: 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; 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> #include <nall/range.hpp>
namespace nall { namespace nall { struct string; }
struct string;
namespace Hash { namespace nall { namespace Hash {
struct SHA256 { struct SHA256 {
SHA256() { reset(); } 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 { auto reset() -> void {
for(auto n : input) n = 0; for(auto n : input) n = 0;
@ -22,12 +23,16 @@ struct SHA256 {
length++; length++;
} }
auto data(const void* values, unsigned size) -> void { auto data(const void* values, uint size) -> void {
length += size; length += size;
auto p = (const uint8_t*)values; auto p = (const uint8_t*)values;
while(size--) byte(*p++); while(size--) byte(*p++);
} }
auto data(const vector<uint8_t>& values) -> void {
for(auto value : values) data(value);
}
auto value() const -> vector<uint8_t> { auto value() const -> vector<uint8_t> {
SHA256 self(*this); SHA256 self(*this);
self.finish(); self.finish();
@ -77,14 +82,14 @@ private:
return (x >> n) | (x << 32 - n); return (x >> n) | (x << 32 - n);
} }
auto square(unsigned n) -> uint32_t { auto square(uint n) -> uint32_t {
static const uint32_t value[8] = { static const uint32_t value[8] = {
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
}; };
return value[n]; return value[n];
} }
auto cube(unsigned n) -> uint32_t { auto cube(uint n) -> uint32_t {
static const uint32_t value[64] = { static const uint32_t value[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 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 name() const -> string { return _name; }
auto input(unsigned id) -> Input& { return operator[](id); } 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> { auto find(const string& name) const -> maybe<unsigned> {
for(auto id : range(size())) { for(auto id : range(size())) {
@ -51,7 +51,7 @@ struct Device : vector<Group> {
auto id() const -> uint64_t { return _id; } auto id() const -> uint64_t { return _id; }
auto setID(uint64_t id) -> void { _id = id; } auto setID(uint64_t id) -> void { _id = id; }
auto group(unsigned id) -> Group& { return operator[](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> { auto find(const string& name) const -> maybe<unsigned> {
for(auto id : range(size())) { 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 { auto Request::setHead() -> bool {
lstring headers = _head.split("\n"); lstring headers = _head.split("\n");
string request = headers.takeFirst().rtrim("\r", 1L); string request = headers.takeLeft().rtrim("\r", 1L);
string requestHost; string requestHost;
if(request.iendsWith(" HTTP/1.0")) request.irtrim(" HTTP/1.0", 1L); 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 boundary = contentType.iltrim("multipart/form-data; boundary=", 1L).trim("\"", "\"", 1L);
auto blocks = _body.split({"--", boundary}, 1024L); //limit blocks to prevent memory exhaustion auto blocks = _body.split({"--", boundary}, 1024L); //limit blocks to prevent memory exhaustion
for(auto& block : blocks) block.trim("\r\n", "\r\n", 1L); 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) { for(auto& block : blocks) {
string name; string name;
string filename; string filename;

View File

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

View File

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

View File

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

View File

@ -39,12 +39,4 @@ inline auto rrange(int size) {
return range_t{size - 1, -1, -1}; 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 { namespace nall {
struct serial { struct serial {
serial() {
port = -1;
port_open = false;
}
~serial() { ~serial() {
close(); close();
} }
auto readable() -> bool { auto readable() -> bool {
if(port_open == false) return false; if(!opened) return false;
fd_set fdset; fd_set fdset;
FD_ZERO(&fdset); FD_ZERO(&fdset);
FD_SET(port, &fdset); FD_SET(port, &fdset);
@ -40,12 +35,12 @@ struct serial {
//-1 on error, otherwise return bytes read //-1 on error, otherwise return bytes read
auto read(uint8_t* data, uint length) -> int { auto read(uint8_t* data, uint length) -> int {
if(port_open == false) return -1; if(!opened) return -1;
return ::read(port, (void*)data, length); return ::read(port, (void*)data, length);
} }
auto writable() -> bool { auto writable() -> bool {
if(port_open == false) return false; if(!opened) return false;
fd_set fdset; fd_set fdset;
FD_ZERO(&fdset); FD_ZERO(&fdset);
FD_SET(port, &fdset); FD_SET(port, &fdset);
@ -59,14 +54,17 @@ struct serial {
//-1 on error, otherwise return bytes written //-1 on error, otherwise return bytes written
auto write(const uint8_t* data, uint length) -> int { 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); 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(); 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(port == -1) return false;
if(ioctl(port, TIOCEXCL) == -1) { close(); return false; } if(ioctl(port, TIOCEXCL) == -1) { close(); return false; }
@ -75,7 +73,7 @@ struct serial {
termios attr = original_attr; termios attr = original_attr;
cfmakeraw(&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_lflag &=~ (ECHO | ECHONL | ISIG | ICANON | IEXTEN);
attr.c_iflag &=~ (BRKINT | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY); 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_oflag &=~ (OPOST);
attr.c_cflag &=~ (CSIZE | CSTOPB | PARENB | CLOCAL); attr.c_cflag &=~ (CSIZE | CSTOPB | PARENB | CLOCAL);
attr.c_cflag |= (CS8 | CREAD); attr.c_cflag |= (CS8 | CREAD);
if(flowcontrol == false) { if(rate) {
attr.c_cflag &= ~CRTSCTS; attr.c_cflag &= ~CRTSCTS;
} else { } else {
attr.c_cflag |= CRTSCTS; attr.c_cflag |= CRTSCTS;
@ -91,15 +89,15 @@ struct serial {
attr.c_cc[VTIME] = attr.c_cc[VMIN] = 0; attr.c_cc[VTIME] = attr.c_cc[VMIN] = 0;
if(tcsetattr(port, TCSANOW, &attr) == -1) { close(); return false; } if(tcsetattr(port, TCSANOW, &attr) == -1) { close(); return false; }
return port_open = true; return opened = true;
} }
auto close() -> void { auto close() -> void {
if(port != -1) { if(port != -1) {
tcdrain(port); tcdrain(port);
if(port_open == true) { if(opened) {
tcsetattr(port, TCSANOW, &original_attr); tcsetattr(port, TCSANOW, &original_attr);
port_open = false; opened = false;
} }
::close(port); ::close(port);
port = -1; port = -1;
@ -107,8 +105,8 @@ struct serial {
} }
private: private:
int port; int port = -1;
bool port_open; bool opened = false;
termios original_attr; termios original_attr;
}; };

View File

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

View File

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

View File

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

View File

@ -3,14 +3,18 @@
namespace nall { namespace nall {
namespace Hash { namespace Hash {
auto CRC16::digest() -> string { auto CRC16::digest() const -> string {
return hex(value(), 4L); return hex(value(), 4L);
} }
auto CRC32::digest() -> string { auto CRC32::digest() const -> string {
return hex(value(), 8L); return hex(value(), 8L);
} }
auto CRC64::digest() const -> string {
return hex(value(), 16L);
}
auto SHA256::digest() const -> string { auto SHA256::digest() const -> string {
string result; string result;
for(auto n : value()) result.append(hex(n, 2L)); 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(); 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 { auto sha256(rstring self) -> string {
return Hash::SHA256(self.data(), self.size()).digest(); 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& { 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 memory::icompare(x.data(), x.size(), y.data(), y.size()) < 0;
}); });
return *this; return *this;

View File

@ -119,13 +119,13 @@ auto ManagedNode::_create(const string& path) -> Node {
} }
} }
_children.append(new ManagedNode(name)); _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) { for(auto& node : _children) {
if(path == node->_name) return node; if(path == node->_name) return node;
} }
_children.append(new ManagedNode(path)); _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")) { for(auto& block : filedata.split("\n\n")) {
lstring lines = block.rstrip().split("\n"); lstring lines = block.rstrip().split("\n");
string name = lines.takeFirst(); string name = lines.takeLeft();
if(name.beginsWith("include ")) { if(name.beginsWith("include ")) {
name.ltrim("include ", 1L); 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>"); if(state.sections++) state.output.append("</section>");
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 data = markup(content[0]);
auto name = escape(content(1, crc32(data))); auto name = escape(content(1, crc32(data)));
state.output.append("<header id=\"", name, "\">", data); state.output.append("<header id=\"", name, "\">", data);
@ -98,7 +98,7 @@ auto DML::parseBlock(string& block, const string& pathname, uint depth) -> bool
//header //header
else if(auto depth = count(block, '=')) { 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 data = markup(content[0]);
auto name = escape(content(1, crc32(data))); auto name = escape(content(1, crc32(data)));
if(depth <= 6) { if(depth <= 6) {

View File

@ -1,282 +1,109 @@
#pragma once #pragma once
#include <algorithm>
#include <initializer_list>
#include <new> #include <new>
#include <utility>
#include <nall/algorithm.hpp>
#include <nall/bit.hpp> #include <nall/bit.hpp>
#include <nall/function.hpp>
#include <nall/maybe.hpp> #include <nall/maybe.hpp>
#include <nall/memory.hpp> #include <nall/memory.hpp>
#include <nall/range.hpp>
#include <nall/sort.hpp> #include <nall/sort.hpp>
#include <nall/utility.hpp> #include <nall/traits.hpp>
namespace nall { namespace nall {
template<typename T> struct vector { template<typename T> struct vector_iterator;
struct exception_out_of_bounds{}; template<typename T> struct vector_iterator_const;
explicit operator bool() const { return objectsize; } template<typename T>
auto data() -> T* { return pool + poolbase; } struct vector {
auto data() const -> const T* { return pool + poolbase; } //core.hpp
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
vector() = default; vector() = default;
vector(initializer_list<T> list) { for(auto& data : list) append(data); } vector(const initializer_list<T>& values);
vector(const vector& source) { operator=(source); } vector(const vector& source);
vector(vector&& source) { operator=(move(source)); } vector(vector&& source);
~vector() { reset(); } ~vector();
protected: explicit operator bool() const;
T* pool = nullptr; auto capacity() const -> uint;
unsigned poolbase = 0; auto size() const -> uint;
unsigned poolsize = 0; auto data() -> T*;
unsigned objectsize = 0; 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 //glXSwapInterval is used to toggle Vsync
//note that the ordering is very important! MESA declares SGI, but the SGI function does nothing //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("glXSwapIntervalMESA");
if(!glXSwapInterval) glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalSGI"); if(!glXSwapInterval) glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalSGI");

View File

@ -163,7 +163,6 @@ struct VideoGLX2 : Video {
glxcontext = glXCreateContext(display, vi, 0, GL_TRUE); glxcontext = glXCreateContext(display, vi, 0, GL_TRUE);
glXMakeCurrent(display, glxwindow = xwindow, glxcontext); glXMakeCurrent(display, glxwindow = xwindow, glxcontext);
glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalEXT");
if(!glXSwapInterval) glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalMESA"); if(!glXSwapInterval) glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalMESA");
if(!glXSwapInterval) glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalSGI"); 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); render(sources[0].width, sources[0].height, outputWidth, outputHeight);
if(history.size() > 0) { if(history.size() > 0) {
OpenGLTexture frame = history.takeLast(); OpenGLTexture frame = history.takeRight();
glBindTexture(GL_TEXTURE_2D, frame.texture); glBindTexture(GL_TEXTURE_2D, frame.texture);
if(width == frame.width && height == frame.height) { if(width == frame.width && height == frame.height) {