diff --git a/higan/audio/audio.cpp b/higan/audio/audio.cpp index 3b8c0f36..223b8ae9 100644 --- a/higan/audio/audio.cpp +++ b/higan/audio/audio.cpp @@ -76,8 +76,8 @@ auto Audio::poll() -> void { if(reverbDelay) { reverbLeft.append(ileft); reverbRight.append(iright); - ileft += reverbLeft.takeFirst() * reverbLevel; - iright += reverbRight.takeFirst() * reverbLevel; + ileft += reverbLeft.takeLeft() * reverbLevel; + iright += reverbRight.takeLeft() * reverbLevel; } interface->audioSample(sclamp<16>(ileft), sclamp<16>(iright)); diff --git a/higan/audio/audio.hpp b/higan/audio/audio.hpp index 93b0998a..ccb33d9b 100644 --- a/higan/audio/audio.hpp +++ b/higan/audio/audio.hpp @@ -36,7 +36,6 @@ private: struct Stream { Stream(uint channels, double inputFrequency); - ~Stream(); auto reset() -> void; auto setFrequency(double outputFrequency) -> void; @@ -56,21 +55,20 @@ private: double outputFrequency = 0.0; double cutoffFrequency = 0.0; - double* tap = nullptr; - uint taps = 0; + vector taps; uint decimationRate = 0; uint decimationOffset = 0; - double** input = nullptr; + vector> input; uint inputOffset = 0; double resamplerFrequency = 0.0; double resamplerFraction = 0.0; double resamplerStep = 0.0; - double** queue = nullptr; + vector> queue; - double** output = nullptr; + vector> output; uint outputs = 0; uint outputReadOffset = 0; uint outputWriteOffset = 0; diff --git a/higan/audio/stream.cpp b/higan/audio/stream.cpp index 7c477ae3..e5f20aed 100644 --- a/higan/audio/stream.cpp +++ b/higan/audio/stream.cpp @@ -7,18 +7,11 @@ Stream::Stream(uint channels, double inputFrequency) : channels(channels), inputFrequency(inputFrequency) { } -Stream::~Stream() { - reset(); -} - auto Stream::reset() -> void { - if(tap) delete[] tap, tap = nullptr; - if(input) for(auto c : range(channels)) delete[] input[c]; - delete[] input, input = nullptr; - if(queue) for(auto c : range(channels)) delete[] queue[c]; - delete[] queue, queue = nullptr; - if(output) for(auto c : range(channels)) delete[] output[c]; - delete[] output, output = nullptr; + taps.reset(); + input.reset(); + queue.reset(); + output.reset(); } auto Stream::setFrequency(double outputFrequency_) -> void { @@ -34,45 +27,43 @@ auto Stream::setFrequency(double outputFrequency_) -> void { cutoffFrequency = outputFrequency / inputFrequency; if(cutoffFrequency < 0.5) { double transitionBandwidth = 0.008; //lower = higher quality; more taps (slower) - taps = (uint)ceil(4.0 / transitionBandwidth) | 1; - tap = new double[taps]; + taps.resize((uint)ceil(4.0 / transitionBandwidth) | 1); double sum = 0.0; for(uint t : range(taps)) { //sinc filter - double s = sinc(2.0 * cutoffFrequency * (t - (taps - 1) / 2.0)); + double s = sinc(2.0 * cutoffFrequency * (t - (taps.size() - 1) / 2.0)); //blackman window - double b = 0.42 - 0.5 * cos(2.0 * pi * t / (taps - 1)) + 0.08 * cos(4.0 * pi * t / (taps - 1)); + double b = 0.42 - 0.5 * cos(2.0 * pi * t / (taps.size() - 1)) + 0.08 * cos(4.0 * pi * t / (taps.size() - 1)); - tap[t] = s * b; - sum += tap[t]; + taps[t] = s * b; + sum += taps[t]; } //normalize so that the sum of all coefficients is 1.0 - for(auto t : range(taps)) tap[t] /= sum; + for(auto& tap : taps) tap /= sum; } else { - taps = 1; - tap = new double[taps]; - tap[0] = 1.0; + taps.resize(1); + taps[0] = 1.0; } decimationRate = max(1, (uint)floor(inputFrequency / outputFrequency)); decimationOffset = 0; - input = new double*[channels]; - for(auto c : range(channels)) input[c] = new double[taps * 2](); + input.resize(channels); + for(auto c : range(channels)) input[c].resize(taps.size() * 2); inputOffset = 0; resamplerFrequency = inputFrequency / decimationRate; resamplerFraction = 0.0; resamplerStep = resamplerFrequency / outputFrequency; - queue = new double*[channels]; - for(auto c : range(channels)) queue[c] = new double[4](); + queue.resize(channels); + for(auto c : range(channels)) queue[c].resize(4); - output = new double*[channels]; + output.resize(channels); outputs = inputFrequency * 0.02; - for(auto c : range(channels)) output[c] = new double[outputs](); + for(auto c : range(channels)) output[c].resize(outputs); outputReadOffset = 0; outputWriteOffset = 0; } @@ -90,10 +81,10 @@ auto Stream::read(double* samples) -> void { } auto Stream::write(int16* samples) -> void { - inputOffset = !inputOffset ? taps - 1 : inputOffset - 1; + inputOffset = !inputOffset ? taps.size() - 1 : inputOffset - 1; for(auto c : range(channels)) { auto sample = (samples[c] + 32768.0) / 65535.0; //normalize - input[c][inputOffset] = input[c][inputOffset + taps] = sample; + input[c][inputOffset] = input[c][inputOffset + taps.size()] = sample; } if(++decimationOffset >= decimationRate) { @@ -101,7 +92,7 @@ auto Stream::write(int16* samples) -> void { for(auto c : range(channels)) { double sample = 0.0; - for(auto t : range(taps)) sample += input[c][inputOffset + t] * tap[t]; + for(auto t : range(taps)) sample += input[c][inputOffset + t] * taps[t]; auto& q = queue[c]; q[0] = q[1]; diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 7c2a6a8c..5e5eb6c4 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -8,7 +8,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "098.07"; + static const string Version = "098.08"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/processor/v30mz/disassembler.cpp b/higan/processor/v30mz/disassembler.cpp index a8a2bbe8..f356c709 100644 --- a/higan/processor/v30mz/disassembler.cpp +++ b/higan/processor/v30mz/disassembler.cpp @@ -376,7 +376,7 @@ auto V30MZ::disassemble(uint16 cs, uint16 ip, bool registers, bool bytes) -> str if(bytes) { b = " "; while(bytesRead) { - b.append(hex(bytesRead.takeFirst(), 2L), " "); + b.append(hex(bytesRead.takeLeft(), 2L), " "); } b.rstrip(); } diff --git a/higan/processor/v30mz/instructions-misc.cpp b/higan/processor/v30mz/instructions-misc.cpp index 043a99a6..ef3e7745 100644 --- a/higan/processor/v30mz/instructions-misc.cpp +++ b/higan/processor/v30mz/instructions-misc.cpp @@ -3,7 +3,7 @@ //36 ss: //3e ds: auto V30MZ::opSegment(uint16 segment) { - if(prefixes.size() >= 7) prefixes.removeLast(); + if(prefixes.size() >= 7) prefixes.removeRight(); prefixes.prepend(opcode); state.prefix = true; state.poll = false; @@ -12,7 +12,7 @@ auto V30MZ::opSegment(uint16 segment) { //f2 repnz: //f3 repz: auto V30MZ::opRepeat(bool flag) { - if(prefixes.size() >= 7) prefixes.removeLast(); + if(prefixes.size() >= 7) prefixes.removeRight(); prefixes.prepend(opcode); wait(4); state.prefix = true; @@ -21,7 +21,7 @@ auto V30MZ::opRepeat(bool flag) { //f0 lock: auto V30MZ::opLock() { - if(prefixes.size() >= 7) prefixes.removeLast(); + if(prefixes.size() >= 7) prefixes.removeRight(); prefixes.prepend(opcode); state.prefix = true; state.poll = false; diff --git a/higan/sfc/cartridge/markup.cpp b/higan/sfc/cartridge/markup.cpp index 28945113..728d43b6 100644 --- a/higan/sfc/cartridge/markup.cpp +++ b/higan/sfc/cartridge/markup.cpp @@ -358,11 +358,11 @@ auto Cartridge::parseMarkupSDD1(Markup::Node root) -> void { } for(auto node : root["rom"].find("map")) { - parseMarkupMap(node, {&SDD1::mcurom_read, &sdd1}, {&SDD1::mcurom_write, &sdd1}); + parseMarkupMap(node, {&SDD1::mcuromRead, &sdd1}, {&SDD1::mcuromWrite, &sdd1}); } for(auto node : root["ram"].find("map")) { - parseMarkupMap(node, {&SDD1::mcuram_read, &sdd1}, {&SDD1::mcuram_write, &sdd1}); + parseMarkupMap(node, {&SDD1::mcuramRead, &sdd1}, {&SDD1::mcuramWrite, &sdd1}); } } diff --git a/higan/sfc/coprocessor/sdd1/decomp.cpp b/higan/sfc/coprocessor/sdd1/decompressor.cpp similarity index 83% rename from higan/sfc/coprocessor/sdd1/decomp.cpp rename to higan/sfc/coprocessor/sdd1/decompressor.cpp index c4548076..de147e67 100644 --- a/higan/sfc/coprocessor/sdd1/decomp.cpp +++ b/higan/sfc/coprocessor/sdd1/decompressor.cpp @@ -8,20 +8,20 @@ //input manager -auto SDD1::Decomp::IM::init(uint offset_) -> void { +auto SDD1::Decompressor::IM::init(uint offset_) -> void { offset = offset_; bit_count = 4; } -auto SDD1::Decomp::IM::get_codeword(uint8 code_length) -> uint8 { +auto SDD1::Decompressor::IM::get_codeword(uint8 code_length) -> uint8 { uint8 codeword; uint8 comp_count; - codeword = sdd1.mmc_read(offset) << bit_count; + codeword = sdd1.mmcRead(offset) << bit_count; bit_count++; if(codeword & 0x80) { - codeword |= sdd1.mmc_read(offset + 1) >> (9 - bit_count); + codeword |= sdd1.mmcRead(offset + 1) >> (9 - bit_count); bit_count += code_length; } @@ -35,7 +35,7 @@ auto SDD1::Decomp::IM::get_codeword(uint8 code_length) -> uint8 { //golomb-code decoder -const uint8 SDD1::Decomp::GCD::run_count[] = { +const uint8 SDD1::Decompressor::GCD::run_count[] = { 0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00, 0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00, 0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01, @@ -70,7 +70,7 @@ const uint8 SDD1::Decomp::GCD::run_count[] = { 0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00, }; -auto SDD1::Decomp::GCD::get_run_count(uint8 code_number, uint8& mps_count, bool& lps_index) -> void { +auto SDD1::Decompressor::GCD::get_run_count(uint8 code_number, uint8& mps_count, bool& lps_index) -> void { uint8 codeword = self.im.get_codeword(code_number); if(codeword & 0x80) { @@ -83,12 +83,12 @@ auto SDD1::Decomp::GCD::get_run_count(uint8 code_number, uint8& mps_count, bool& //bits generator -auto SDD1::Decomp::BG::init() -> void { +auto SDD1::Decompressor::BG::init() -> void { mps_count = 0; lps_index = 0; } -auto SDD1::Decomp::BG::get_bit(bool& end_of_run) -> uint8 { +auto SDD1::Decompressor::BG::get_bit(bool& end_of_run) -> uint8 { if(!(mps_count || lps_index)) self.gcd.get_run_count(code_number, mps_count, lps_index); uint8 bit; @@ -106,7 +106,7 @@ auto SDD1::Decomp::BG::get_bit(bool& end_of_run) -> uint8 { //probability estimation module -const SDD1::Decomp::PEM::State SDD1::Decomp::PEM::evolution_table[33] = { +const SDD1::Decompressor::PEM::State SDD1::Decompressor::PEM::evolution_table[33] = { {0, 25, 25}, {0, 2, 1}, {0, 3, 1}, @@ -142,18 +142,18 @@ const SDD1::Decomp::PEM::State SDD1::Decomp::PEM::evolution_table[33] = { {7, 24, 22}, }; -auto SDD1::Decomp::PEM::init() -> void { +auto SDD1::Decompressor::PEM::init() -> void { for(auto n : range(32)) { context_info[n].status = 0; context_info[n].mps = 0; } } -auto SDD1::Decomp::PEM::get_bit(uint8 context) -> uint8 { +auto SDD1::Decompressor::PEM::get_bit(uint8 context) -> uint8 { ContextInfo& info = context_info[context]; uint8 current_status = info.status; uint8 current_mps = info.mps; - const State& s = SDD1::Decomp::PEM::evolution_table[current_status]; + const State& s = SDD1::Decompressor::PEM::evolution_table[current_status]; uint8 bit; bool end_of_run; @@ -182,9 +182,9 @@ auto SDD1::Decomp::PEM::get_bit(uint8 context) -> uint8 { //context model -auto SDD1::Decomp::CM::init(uint offset) -> void { - bitplanes_info = sdd1.mmc_read(offset) & 0xc0; - context_bits_info = sdd1.mmc_read(offset) & 0x30; +auto SDD1::Decompressor::CM::init(uint offset) -> void { + bitplanes_info = sdd1.mmcRead(offset) & 0xc0; + context_bits_info = sdd1.mmcRead(offset) & 0x30; bit_number = 0; for(auto n : range(8)) previous_bitplane_bits[n] = 0; switch(bitplanes_info) { @@ -194,7 +194,7 @@ auto SDD1::Decomp::CM::init(uint offset) -> void { } } -auto SDD1::Decomp::CM::get_bit() -> uint8 { +auto SDD1::Decompressor::CM::get_bit() -> uint8 { switch(bitplanes_info) { case 0x00: current_bitplane ^= 0x01; @@ -230,12 +230,12 @@ auto SDD1::Decomp::CM::get_bit() -> uint8 { //output logic -auto SDD1::Decomp::OL::init(uint offset) -> void { - bitplanes_info = sdd1.mmc_read(offset) & 0xc0; +auto SDD1::Decompressor::OL::init(uint offset) -> void { + bitplanes_info = sdd1.mmcRead(offset) & 0xc0; r0 = 0x01; } -auto SDD1::Decomp::OL::decompress() -> uint8 { +auto SDD1::Decompressor::OL::decompress() -> uint8 { switch(bitplanes_info) { case 0x00: case 0x40: case 0x80: if(r0 == 0) { @@ -257,14 +257,14 @@ auto SDD1::Decomp::OL::decompress() -> uint8 { //core -SDD1::Decomp::Decomp(): +SDD1::Decompressor::Decompressor(): im(*this), gcd(*this), bg0(*this, 0), bg1(*this, 1), bg2(*this, 2), bg3(*this, 3), bg4(*this, 4), bg5(*this, 5), bg6(*this, 6), bg7(*this, 7), pem(*this), cm(*this), ol(*this) { } -auto SDD1::Decomp::init(uint offset) -> void { +auto SDD1::Decompressor::init(uint offset) -> void { im.init(offset); bg0.init(); bg1.init(); @@ -279,6 +279,6 @@ auto SDD1::Decomp::init(uint offset) -> void { ol.init(offset); } -auto SDD1::Decomp::read() -> uint8 { +auto SDD1::Decompressor::read() -> uint8 { return ol.decompress(); } diff --git a/higan/sfc/coprocessor/sdd1/decomp.hpp b/higan/sfc/coprocessor/sdd1/decompressor.hpp similarity index 73% rename from higan/sfc/coprocessor/sdd1/decomp.hpp rename to higan/sfc/coprocessor/sdd1/decompressor.hpp index e8bc8be2..a6331b86 100644 --- a/higan/sfc/coprocessor/sdd1/decomp.hpp +++ b/higan/sfc/coprocessor/sdd1/decompressor.hpp @@ -1,43 +1,43 @@ -struct Decomp { +struct Decompressor { struct IM { //input manager - IM(SDD1::Decomp& self) : self(self) {} + IM(SDD1::Decompressor& self) : self(self) {} auto init(uint offset) -> void; auto get_codeword(uint8 code_length) -> uint8; private: - Decomp& self; + Decompressor& self; uint offset; uint bit_count; }; struct GCD { //golomb-code decoder - GCD(SDD1::Decomp& self) : self(self) {} + GCD(SDD1::Decompressor& self) : self(self) {} auto get_run_count(uint8 code_number, uint8& mps_count, bool& lps_index) -> void; private: - Decomp& self; + Decompressor& self; static const uint8 run_count[256]; }; struct BG { //bits generator - BG(SDD1::Decomp& self, uint8 code_number) : self(self), code_number(code_number) {} + BG(SDD1::Decompressor& self, uint8 code_number) : self(self), code_number(code_number) {} auto init() -> void; auto get_bit(bool& end_of_run) -> uint8; private: - Decomp& self; + Decompressor& self; const uint8 code_number; uint8 mps_count; bool lps_index; }; struct PEM { //probability estimation module - PEM(SDD1::Decomp& self) : self(self) {} + PEM(SDD1::Decompressor& self) : self(self) {} auto init() -> void; auto get_bit(uint8 context) -> uint8; private: - Decomp& self; + Decompressor& self; struct State { uint8 code_number; uint8 next_if_mps; @@ -51,12 +51,12 @@ struct Decomp { }; struct CM { //context model - CM(SDD1::Decomp& self) : self(self) {} + CM(SDD1::Decompressor& self) : self(self) {} auto init(uint offset) -> void; uint8 get_bit(); private: - Decomp& self; + Decompressor& self; uint8 bitplanes_info; uint8 context_bits_info; uint8 bit_number; @@ -65,17 +65,17 @@ struct Decomp { }; struct OL { //output logic - OL(SDD1::Decomp& self) : self(self) {} + OL(SDD1::Decompressor& self) : self(self) {} auto init(uint offset) -> void; auto decompress() -> uint8; private: - Decomp& self; + Decompressor& self; uint8 bitplanes_info; uint8 r0, r1, r2; }; - Decomp(); + Decompressor(); auto init(uint offset) -> void; auto read() -> uint8; diff --git a/higan/sfc/coprocessor/sdd1/sdd1.cpp b/higan/sfc/coprocessor/sdd1/sdd1.cpp index de01bd4f..44cd432f 100644 --- a/higan/sfc/coprocessor/sdd1/sdd1.cpp +++ b/higan/sfc/coprocessor/sdd1/sdd1.cpp @@ -4,7 +4,7 @@ namespace SuperFamicom { SDD1 sdd1; -#include "decomp.cpp" +#include "decompressor.cpp" #include "serialization.cpp" auto SDD1::init() -> void { @@ -24,113 +24,106 @@ auto SDD1::power() -> void { auto SDD1::reset() -> void { //hook S-CPU DMA MMIO registers to gather information for struct dma[]; //buffer address and transfer size information for use in SDD1::mcu_read() - bus.map({&SDD1::dma_read, &sdd1}, {&SDD1::dma_write, &sdd1}, "00-3f,80-bf:4300-437f"); + bus.map({&SDD1::dmaRead, &sdd1}, {&SDD1::dmaWrite, &sdd1}, "00-3f,80-bf:4300-437f"); - sdd1_enable = 0x00; - xfer_enable = 0x00; - dma_ready = false; - - mmc[0] = 0 << 20; - mmc[1] = 1 << 20; - mmc[2] = 2 << 20; - mmc[3] = 3 << 20; + r4800 = 0x00; + r4801 = 0x00; + r4804 = 0x00; + r4805 = 0x01; + r4806 = 0x02; + r4807 = 0x03; for(auto n : range(8)) { dma[n].addr = 0; dma[n].size = 0; } + dmaReady = false; } auto SDD1::read(uint24 addr, uint8 data) -> uint8 { - addr = 0x4800 | (addr & 7); + addr = 0x4800 | addr.bits(0,3); switch(addr) { - case 0x4804: return mmc[0] >> 20; - case 0x4805: return mmc[1] >> 20; - case 0x4806: return mmc[2] >> 20; - case 0x4807: return mmc[3] >> 20; + case 0x4800: return r4800; + case 0x4801: return r4801; + case 0x4804: return r4804; + case 0x4805: return r4805; + case 0x4806: return r4806; + case 0x4807: return r4807; } - return data; + //00-3f,80-bf:4802-4803,4808-480f falls through to ROM + return rom.read(addr); } auto SDD1::write(uint24 addr, uint8 data) -> void { - addr = 0x4800 | (addr & 7); + addr = 0x4800 | addr.bits(0,3); switch(addr) { - case 0x4800: sdd1_enable = data; break; - case 0x4801: xfer_enable = data; break; - - case 0x4804: mmc[0] = data << 20; break; - case 0x4805: mmc[1] = data << 20; break; - case 0x4806: mmc[2] = data << 20; break; - case 0x4807: mmc[3] = data << 20; break; + case 0x4800: r4800 = data; break; + case 0x4801: r4801 = data; break; + case 0x4804: r4804 = data & 0x8f; break; + case 0x4805: r4805 = data & 0x8f; break; + case 0x4806: r4806 = data & 0x8f; break; + case 0x4807: r4807 = data & 0x8f; break; } } -auto SDD1::dma_read(uint24 addr, uint8 data) -> uint8 { +auto SDD1::dmaRead(uint24 addr, uint8 data) -> uint8 { return cpu.dmaPortRead(addr, data); } -auto SDD1::dma_write(uint24 addr, uint8 data) -> void { - uint channel = (addr >> 4) & 7; - switch(addr & 15) { - case 2: dma[channel].addr = (dma[channel].addr & 0xffff00) + (data << 0); break; - case 3: dma[channel].addr = (dma[channel].addr & 0xff00ff) + (data << 8); break; - case 4: dma[channel].addr = (dma[channel].addr & 0x00ffff) + (data << 16); break; - - case 5: dma[channel].size = (dma[channel].size & 0xff00) + (data << 0); break; - case 6: dma[channel].size = (dma[channel].size & 0x00ff) + (data << 8); break; +auto SDD1::dmaWrite(uint24 addr, uint8 data) -> void { + uint channel = addr.bits(4,6); + switch(addr.bits(0,3)) { + case 2: dma[channel].addr.byte(0) = data; break; + case 3: dma[channel].addr.byte(1) = data; break; + case 4: dma[channel].addr.byte(2) = data; break; + case 5: dma[channel].size.byte(0) = data; break; + case 6: dma[channel].size.byte(1) = data; break; } return cpu.dmaPortWrite(addr, data); } -auto SDD1::mmc_read(uint24 addr) -> uint8 { - return rom.read(mmc[(addr >> 20) & 3] + (addr & 0x0fffff)); +auto SDD1::mmcRead(uint24 addr) -> uint8 { + switch(addr.bits(20,21)) { + case 0: return rom.read(r4804.bits(0,3) << 20 | addr.bits(0,19)); //c0-cf:0000-ffff + case 1: return rom.read(r4805.bits(0,3) << 20 | addr.bits(0,19)); //d0-df:0000-ffff + case 2: return rom.read(r4806.bits(0,3) << 20 | addr.bits(0,19)); //e0-ef:0000-ffff + case 3: return rom.read(r4807.bits(0,3) << 20 | addr.bits(0,19)); //f0-ff:0000-ffff + } + unreachable; } -//SDD1::mcu_read() is mapped to $c0-ff:0000-ffff -//the design is meant to be as close to the hardware design as possible, thus this code -//avoids adding S-DD1 hooks inside S-CPU::DMA emulation. -// -//the real S-DD1 cannot see $420b (DMA enable) writes, as they are not placed on the bus. -//however, $43x0-$43xf writes (DMAx channel settings) most likely do appear on the bus. -//the S-DD1 also requires fixed addresses for transfers, which wouldn't be necessary if -//it could see $420b writes (eg it would know when the transfer should begin.) -// -//the hardware needs a way to distinguish program code after $4801 writes from DMA -//decompression that follows soon after. -// -//the only plausible design for hardware would be for the S-DD1 to spy on DMAx settings, -//and begin spooling decompression on writes to $4801 that activate a channel. after that, -//it feeds decompressed data only when the ROM read address matches the DMA channel address. -// -//the actual S-DD1 transfer can occur on any channel, but it is most likely limited to -//one transfer per $420b write (for spooling purposes). however, this is not known for certain. -auto SDD1::mcurom_read(uint24 addr, uint8) -> uint8 { +//map address=00-3f,80-bf:8000-ffff +//map address=c0-ff:0000-ffff +auto SDD1::mcuromRead(uint24 addr, uint8 data) -> uint8 { //map address=00-3f,80-bf:8000-ffff mask=0x808000 => 00-1f:0000-ffff - if(addr < 0x200000) { + if(!addr.bit(22)) { + if(!addr.bit(23) && addr.bit(21) && r4805.bit(7)) addr.bit(21) = 0; //20-3f:8000-ffff + if( addr.bit(23) && addr.bit(21) && r4807.bit(7)) addr.bit(21) = 0; //a0-bf:8000-ffff + addr = addr.bits(16,21) << 15 | addr.bits(0,14); return rom.read(addr); } //map address=c0-ff:0000-ffff - if(sdd1_enable & xfer_enable) { + if(r4800 & r4801) { //at least one channel has S-DD1 decompression enabled ... for(auto n : range(8)) { - if(sdd1_enable & xfer_enable & (1 << n)) { + if(r4800.bit(n) && r4801.bit(n)) { //S-DD1 always uses fixed transfer mode, so address will not change during transfer if(addr == dma[n].addr) { - if(!dma_ready) { + if(!dmaReady) { //prepare streaming decompression - decomp.init(addr); - dma_ready = true; + decompressor.init(addr); + dmaReady = true; } //fetch a decompressed byte; once finished, disable channel and invalidate buffer - uint8 data = decomp.read(); + data = decompressor.read(); if(--dma[n].size == 0) { - dma_ready = false; - xfer_enable &= ~(1 << n); + dmaReady = false; + r4801.bit(n) = 0; } return data; @@ -140,20 +133,20 @@ auto SDD1::mcurom_read(uint24 addr, uint8) -> uint8 { } //S-DD1 decompressor enabled //S-DD1 decompression mode inactive; return ROM data - return mmc_read(addr); + return mmcRead(addr); } -auto SDD1::mcurom_write(uint24 addr, uint8 data) -> void { +auto SDD1::mcuromWrite(uint24 addr, uint8 data) -> void { } //map address=00-3f,80-bf:6000-7fff mask=0xe000 -//map address=70-7d:0000-7fff mask=0x8000 -auto SDD1::mcuram_read(uint24 addr, uint8 data) -> uint8 { - return ram.read(addr & 0x1fff, data); +//map address=70-73:0000-ffff mask=0x8000 +auto SDD1::mcuramRead(uint24 addr, uint8 data) -> uint8 { + return ram.read(addr.bits(0,12), data); } -auto SDD1::mcuram_write(uint24 addr, uint8 data) -> void { - return ram.write(addr & 0x1fff, data); +auto SDD1::mcuramWrite(uint24 addr, uint8 data) -> void { + return ram.write(addr.bits(0,12), data); } } diff --git a/higan/sfc/coprocessor/sdd1/sdd1.hpp b/higan/sfc/coprocessor/sdd1/sdd1.hpp index 2013cce6..6a578ce9 100644 --- a/higan/sfc/coprocessor/sdd1/sdd1.hpp +++ b/higan/sfc/coprocessor/sdd1/sdd1.hpp @@ -8,16 +8,16 @@ struct SDD1 { auto read(uint24 addr, uint8 data) -> uint8; auto write(uint24 addr, uint8 data) -> void; - auto dma_read(uint24 addr, uint8 data) -> uint8; - auto dma_write(uint24 addr, uint8 data) -> void; + auto dmaRead(uint24 addr, uint8 data) -> uint8; + auto dmaWrite(uint24 addr, uint8 data) -> void; - auto mmc_read(uint24 addr) -> uint8; + auto mmcRead(uint24 addr) -> uint8; - auto mcurom_read(uint24 addr, uint8 data) -> uint8; - auto mcurom_write(uint24 addr, uint8 data) -> void; + auto mcuromRead(uint24 addr, uint8 data) -> uint8; + auto mcuromWrite(uint24 addr, uint8 data) -> void; - auto mcuram_read(uint24 addr, uint8 data) -> uint8; - auto mcuram_write(uint24 addr, uint8 data) -> void; + auto mcuramRead(uint24 addr, uint8 data) -> uint8; + auto mcuramWrite(uint24 addr, uint8 data) -> void; auto serialize(serializer&) -> void; @@ -25,19 +25,22 @@ struct SDD1 { MappedRAM ram; private: - uint8 sdd1_enable; //channel bit-mask - uint8 xfer_enable; //channel bit-mask - bool dma_ready; //used to initialize decompression module - uint mmc[4]; //memory map controller ROM indices + uint8 r4800; //hard enable + uint8 r4801; //soft enable + uint8 r4804; //MMC bank 0 + uint8 r4805; //MMC bank 1 + uint8 r4806; //MMC bank 2 + uint8 r4807; //MMC bank 3 - struct { - uint addr; //$43x2-$43x4 -- DMA transfer address - uint16 size; //$43x5-$43x6 -- DMA transfer size + struct DMA { + uint24 addr; //$43x2-$43x4 -- DMA transfer address + uint16 size; //$43x5-$43x6 -- DMA transfer size } dma[8]; + bool dmaReady; //used to initialize decompression module public: - #include "decomp.hpp" - Decomp decomp; + #include "decompressor.hpp" + Decompressor decompressor; }; extern SDD1 sdd1; diff --git a/higan/sfc/coprocessor/sdd1/serialization.cpp b/higan/sfc/coprocessor/sdd1/serialization.cpp index d008e762..618b5dcf 100644 --- a/higan/sfc/coprocessor/sdd1/serialization.cpp +++ b/higan/sfc/coprocessor/sdd1/serialization.cpp @@ -1,13 +1,16 @@ auto SDD1::serialize(serializer& s) -> void { s.array(ram.data(), ram.size()); - s.integer(sdd1_enable); - s.integer(xfer_enable); - s.integer(dma_ready); - s.array(mmc); + s.integer(r4800); + s.integer(r4801); + s.integer(r4804); + s.integer(r4805); + s.integer(r4806); + s.integer(r4807); for(auto n : range(8)) { s.integer(dma[n].addr); s.integer(dma[n].size); } + s.integer(dmaReady); } diff --git a/higan/sfc/expansion/21fx/21fx.cpp b/higan/sfc/expansion/21fx/21fx.cpp index 2e624e8b..405b7854 100644 --- a/higan/sfc/expansion/21fx/21fx.cpp +++ b/higan/sfc/expansion/21fx/21fx.cpp @@ -83,7 +83,7 @@ auto S21FX::read(uint24 addr, uint8 data) -> uint8 { if(addr == 0x21ff) { if(linkBuffer.size() > 0) { - return linkBuffer.takeFirst(); + return linkBuffer.takeLeft(); } } @@ -123,7 +123,7 @@ auto S21FX::writable() -> bool { auto S21FX::read() -> uint8 { step(1); if(snesBuffer.size() > 0) { - return snesBuffer.takeFirst(); + return snesBuffer.takeLeft(); } return 0x00; } diff --git a/higan/sfc/interface/interface.cpp b/higan/sfc/interface/interface.cpp index a8c0e9ae..2fa4d912 100644 --- a/higan/sfc/interface/interface.cpp +++ b/higan/sfc/interface/interface.cpp @@ -60,8 +60,8 @@ Interface::Interface() { device.input.append({n + 9, 0, {"Port ", p, " - ", "X" }}); device.input.append({n + 10, 0, {"Port ", p, " - ", "L" }}); device.input.append({n + 11, 0, {"Port ", p, " - ", "R" }}); - device.order.append(n + 4, n + 5, n + 6, n + 7, n + 0, n + 8); - device.order.append(n + 1, n + 9, n + 10, n + 11, n + 2, n + 3); + device.order.append({n + 4, n + 5, n + 6, n + 7, n + 0, n + 8}); + device.order.append({n + 1, n + 9, n + 10, n + 11, n + 2, n + 3}); } this->device.append(device); } @@ -100,12 +100,12 @@ Interface::Interface() { device.input.append({1, 1, "Port 1 - Y-axis" }); device.input.append({2, 0, "Port 1 - Trigger"}); device.input.append({3, 0, "Port 1 - Start" }); - device.order.append(0, 1, 2, 3); + device.order.append({0, 1, 2, 3}); device.input.append({4, 1, "Port 2 - X-axis" }); device.input.append({5, 1, "Port 2 - Y-axis" }); device.input.append({6, 0, "Port 2 - Trigger"}); device.input.append({7, 0, "Port 2 - Start" }); - device.order.append(4, 5, 6, 7); + device.order.append({4, 5, 6, 7}); this->device.append(device); } diff --git a/higan/target-tomoko/input/input.cpp b/higan/target-tomoko/input/input.cpp index d8db41c0..c939c0f1 100644 --- a/higan/target-tomoko/input/input.cpp +++ b/higan/target-tomoko/input/input.cpp @@ -147,21 +147,21 @@ InputManager::InputManager() { for(auto& emulator : program->emulators) { emulators.append(InputEmulator()); - auto& inputEmulator = emulators.last(); + auto& inputEmulator = emulators.right(); inputEmulator.name = emulator->information.name; for(auto& port : emulator->port) { inputEmulator.ports.append(InputPort()); - auto& inputPort = inputEmulator.ports.last(); + auto& inputPort = inputEmulator.ports.right(); inputPort.name = port.name; for(auto& device : port.device) { inputPort.devices.append(InputDevice()); - auto& inputDevice = inputPort.devices.last(); + auto& inputDevice = inputPort.devices.right(); inputDevice.name = device.name; for(auto number : device.order) { auto& input = device.input[number]; inputDevice.mappings.append(new InputMapping()); - auto& inputMapping = inputDevice.mappings.last(); + auto& inputMapping = inputDevice.mappings.right(); inputMapping->name = input.name; inputMapping->link = &input; input.guid = (uintptr)inputMapping; diff --git a/higan/target-tomoko/program/program.cpp b/higan/target-tomoko/program/program.cpp index 68f247a4..85d63154 100644 --- a/higan/target-tomoko/program/program.cpp +++ b/higan/target-tomoko/program/program.cpp @@ -52,7 +52,7 @@ Program::Program(lstring args) { updateAudioDriver(); updateAudioEffects(); - args.takeFirst(); //ignore program location in argument parsing + args.takeLeft(); //ignore program location in argument parsing for(auto& argument : args) { if(argument == "--fullscreen") { presentation->toggleFullScreen(); diff --git a/hiro/core/action/menu.cpp b/hiro/core/action/menu.cpp index 45bea2eb..37678cdd 100644 --- a/hiro/core/action/menu.cpp +++ b/hiro/core/action/menu.cpp @@ -48,7 +48,7 @@ auto mMenu::remove(sAction action) -> type& { } auto mMenu::reset() -> type& { - while(state.actions) remove(state.actions.last()); + while(state.actions) remove(state.actions.right()); return *this; } diff --git a/hiro/core/layout.cpp b/hiro/core/layout.cpp index cf4a94e8..bb0518d0 100644 --- a/hiro/core/layout.cpp +++ b/hiro/core/layout.cpp @@ -41,7 +41,7 @@ auto mLayout::remove(sSizable sizable) -> type& { } auto mLayout::reset() -> type& { - while(state.sizables) remove(state.sizables.last()); + while(state.sizables) remove(state.sizables.right()); return *this; } diff --git a/hiro/core/menu-bar.cpp b/hiro/core/menu-bar.cpp index 329f0826..280814be 100644 --- a/hiro/core/menu-bar.cpp +++ b/hiro/core/menu-bar.cpp @@ -50,7 +50,7 @@ auto mMenuBar::remove(sMenu menu) -> type& { } auto mMenuBar::reset() -> type& { - while(state.menus) remove(state.menus.last()); + while(state.menus) remove(state.menus.right()); return *this; } diff --git a/hiro/core/popup-menu.cpp b/hiro/core/popup-menu.cpp index f064df7c..f2a38798 100644 --- a/hiro/core/popup-menu.cpp +++ b/hiro/core/popup-menu.cpp @@ -45,7 +45,7 @@ auto mPopupMenu::remove(sAction action) -> type& { } auto mPopupMenu::reset() -> type& { - while(state.actions) remove(state.actions.last()); + while(state.actions) remove(state.actions.right()); return *this; } diff --git a/hiro/core/shared.hpp b/hiro/core/shared.hpp index 947e091c..03762527 100644 --- a/hiro/core/shared.hpp +++ b/hiro/core/shared.hpp @@ -86,7 +86,7 @@ struct Group : sGroup { template auto objects() const -> vector { vector objects; for(auto object : self().objects()) { - if(auto cast = object.cast()) objects.append(cast); + if(auto casted = object.cast()) objects.append(casted); } return objects; } diff --git a/hiro/core/widget/tab-frame.cpp b/hiro/core/widget/tab-frame.cpp index 1ac78bf5..58bbec78 100644 --- a/hiro/core/widget/tab-frame.cpp +++ b/hiro/core/widget/tab-frame.cpp @@ -77,7 +77,7 @@ auto mTabFrame::remove(sTabFrameItem item) -> type& { } auto mTabFrame::reset() -> type& { - while(state.items) remove(state.items.last()); + while(state.items) remove(state.items.right()); return *this; } diff --git a/hiro/core/widget/tree-view-item.cpp b/hiro/core/widget/tree-view-item.cpp index 75724a01..58b879ee 100644 --- a/hiro/core/widget/tree-view-item.cpp +++ b/hiro/core/widget/tree-view-item.cpp @@ -59,9 +59,9 @@ auto mTreeViewItem::icon() const -> image { auto mTreeViewItem::item(const string& path) const -> TreeViewItem { if(path.empty()) return {}; auto paths = path.split("/"); - unsigned position = paths.takeFirst().natural(); + unsigned position = paths.takeLeft().natural(); if(position >= itemCount()) return {}; - if(paths.empty()) return state.items[position]; + if(!paths) return state.items[position]; return state.items[position]->item(paths.merge("/")); } diff --git a/hiro/core/widget/tree-view.cpp b/hiro/core/widget/tree-view.cpp index a62d211a..8ef17c49 100644 --- a/hiro/core/widget/tree-view.cpp +++ b/hiro/core/widget/tree-view.cpp @@ -45,9 +45,9 @@ auto mTreeView::foregroundColor() const -> Color { auto mTreeView::item(const string& path) const -> TreeViewItem { if(path.empty()) return {}; auto paths = path.split("/"); - unsigned position = paths.takeFirst().natural(); + unsigned position = paths.takeLeft().natural(); if(position >= itemCount()) return {}; - if(paths.empty()) return state.items[position]; + if(!paths) return state.items[position]; return state.items[position]->item(paths.merge("/")); } diff --git a/hiro/extension/browser-dialog.cpp b/hiro/extension/browser-dialog.cpp index 56a784a8..57aa22ae 100644 --- a/hiro/extension/browser-dialog.cpp +++ b/hiro/extension/browser-dialog.cpp @@ -35,7 +35,7 @@ auto BrowserDialogWindow::accept() -> void { auto batched = view.batched(); if(state.action == "openFile" && batched) { - string name = batched.first()->cell(0)->text(); + string name = batched.left()->cell(0)->text(); if(isFolder(name)) return setPath({state.path, name}); state.response.append(string{state.path, name}); } @@ -48,14 +48,14 @@ auto BrowserDialogWindow::accept() -> void { } if(state.action == "openFolder" && batched) { - string name = batched.first()->cell(0)->text(); + string name = batched.left()->cell(0)->text(); if(!isMatch(name)) return setPath({state.path, name}); state.response.append(string{state.path, name, "/"}); } if(state.action == "saveFile") { string name = fileName.text(); - if(!name && batched) name = batched.first()->cell(0)->text(); + if(!name && batched) name = batched.left()->cell(0)->text(); if(!name || isFolder(name)) return; if(file::exists({state.path, name})) { if(MessageDialog("File already exists; overwrite it?").question() != "Yes") return; @@ -64,7 +64,7 @@ auto BrowserDialogWindow::accept() -> void { } if(state.action == "selectFolder" && batched) { - string name = batched.first()->cell(0)->text(); + string name = batched.left()->cell(0)->text(); if(isFolder(name)) state.response.append(string{state.path, name, "/"}); } @@ -125,7 +125,7 @@ auto BrowserDialogWindow::run() -> lstring { filterList.setVisible(state.action != "selectFolder").onChange([&] { setPath(state.path); }); for(auto& filter : state.filters) { auto part = filter.split("|", 1L); - filterList.append(ComboButtonItem().setText(part.first())); + filterList.append(ComboButtonItem().setText(part.left())); } fileName.setVisible(state.action == "saveFile").onActivate([&] { accept(); }); acceptButton.onActivate([&] { accept(); }); @@ -137,7 +137,7 @@ auto BrowserDialogWindow::run() -> lstring { if(!state.filters) state.filters.append("All|*"); for(auto& filter : state.filters) { auto part = filter.split("|", 1L); - filters.append(part.last().split(":")); + filters.append(part.right().split(":")); } setPath(state.path); @@ -201,7 +201,7 @@ BrowserDialog::BrowserDialog() { auto BrowserDialog::openFile() -> string { state.action = "openFile"; if(!state.title) state.title = "Open File"; - if(auto result = _run()) return result.first(); + if(auto result = _run()) return result.left(); return {}; } @@ -215,21 +215,21 @@ auto BrowserDialog::openFiles() -> lstring { auto BrowserDialog::openFolder() -> string { state.action = "openFolder"; if(!state.title) state.title = "Open Folder"; - if(auto result = _run()) return result.first(); + if(auto result = _run()) return result.left(); return {}; } auto BrowserDialog::saveFile() -> string { state.action = "saveFile"; if(!state.title) state.title = "Save File"; - if(auto result = _run()) return result.first(); + if(auto result = _run()) return result.left(); return {}; } auto BrowserDialog::selectFolder() -> string { state.action = "selectFolder"; if(!state.title) state.title = "Select Folder"; - if(auto result = _run()) return result.first(); + if(auto result = _run()) return result.left(); return {}; } diff --git a/hiro/extension/horizontal-layout.cpp b/hiro/extension/horizontal-layout.cpp index c120c177..c17f8429 100644 --- a/hiro/extension/horizontal-layout.cpp +++ b/hiro/extension/horizontal-layout.cpp @@ -26,7 +26,7 @@ auto mHorizontalLayout::minimumSize() const -> Size { } else { width += child.width; } - if(&child != &properties.last()) width += child.spacing; + if(&child != &properties.right()) width += child.spacing; } for(auto n : range(sizableCount())) { @@ -94,7 +94,7 @@ auto mHorizontalLayout::setGeometry(Geometry containerGeometry) -> type& { for(auto& child : properties) { if(child.width == Size::Maximum) maximumWidthCounter++; if(child.width != Size::Maximum) minimumWidth += child.width; - if(&child != &properties.last()) minimumWidth += child.spacing; + if(&child != &properties.right()) minimumWidth += child.spacing; } for(auto& child : properties) { diff --git a/hiro/extension/vertical-layout.cpp b/hiro/extension/vertical-layout.cpp index d5a2867a..601fe582 100644 --- a/hiro/extension/vertical-layout.cpp +++ b/hiro/extension/vertical-layout.cpp @@ -35,7 +35,7 @@ auto mVerticalLayout::minimumSize() const -> Size { } else { height += child.height; } - if(&child != &properties.last()) height += child.spacing; + if(&child != &properties.right()) height += child.spacing; } return {settings.margin * 2 + width, settings.margin * 2 + height}; @@ -94,7 +94,7 @@ auto mVerticalLayout::setGeometry(Geometry containerGeometry) -> type& { for(auto& child : properties) { if(child.height == Size::Maximum) maximumHeightCounter++; if(child.height != Size::Maximum) minimumHeight += child.height; - if(&child != &properties.last()) minimumHeight += child.spacing; + if(&child != &properties.right()) minimumHeight += child.spacing; } for(auto& child : properties) { diff --git a/hiro/gtk/widget/canvas.cpp b/hiro/gtk/widget/canvas.cpp index ca9fc7ae..4bf2fe50 100644 --- a/hiro/gtk/widget/canvas.cpp +++ b/hiro/gtk/widget/canvas.cpp @@ -6,7 +6,7 @@ static auto Canvas_drop(GtkWidget* widget, GdkDragContext* context, signed x, si GtkSelectionData* data, unsigned type, unsigned timestamp, pCanvas* p) -> void { if(!p->state().droppable) return; lstring paths = DropPaths(data); - if(paths.empty()) return; + if(!paths) return; p->self().doDrop(paths); } diff --git a/hiro/gtk/widget/console.cpp b/hiro/gtk/widget/console.cpp index 2a687bf0..954f0f13 100644 --- a/hiro/gtk/widget/console.cpp +++ b/hiro/gtk/widget/console.cpp @@ -83,7 +83,7 @@ auto pConsole::_keyPress(unsigned scancode, unsigned mask) -> bool { gtk_text_buffer_insert(textBuffer, &end, string{"\n", state().prompt}, -1); self().doActivate(s); if(s) history.prepend(s); - if(history.size() > 128) history.removeLast(); + if(history.size() > 128) history.removeRight(); historyOffset = 0; _seekToEnd(); return true; diff --git a/hiro/gtk/widget/tree-view.cpp b/hiro/gtk/widget/tree-view.cpp index 44e2fa52..1411b8fc 100644 --- a/hiro/gtk/widget/tree-view.cpp +++ b/hiro/gtk/widget/tree-view.cpp @@ -133,10 +133,10 @@ auto pTreeView::_doDataFunc(GtkTreeViewColumn* column, GtkCellRenderer* renderer auto parts = string{path}.split(":"); g_free(path); - auto item = self().item(parts.takeFirst().natural()); + auto item = self().item(parts.takeLeft().natural()); if(!item) return; while(parts) { - item = item.item(parts.takeFirst().natural()); + item = item.item(parts.takeLeft().natural()); if(!item) return; } diff --git a/hiro/gtk/widget/viewport.cpp b/hiro/gtk/widget/viewport.cpp index 8d52e909..d9c224dc 100644 --- a/hiro/gtk/widget/viewport.cpp +++ b/hiro/gtk/widget/viewport.cpp @@ -6,7 +6,7 @@ static auto Viewport_dropEvent(GtkWidget* widget, GdkDragContext* context, signe GtkSelectionData* data, unsigned type, unsigned timestamp, pViewport* p) -> void { if(!p->state().droppable) return; lstring paths = DropPaths(data); - if(paths.empty()) return; + if(!paths) return; p->self().doDrop(paths); } diff --git a/hiro/gtk/window.cpp b/hiro/gtk/window.cpp index ef816ba6..5f45d005 100644 --- a/hiro/gtk/window.cpp +++ b/hiro/gtk/window.cpp @@ -82,7 +82,7 @@ static auto Window_drop(GtkWidget* widget, GdkDragContext* context, signed x, si GtkSelectionData* data, unsigned type, unsigned timestamp, pWindow* p) -> void { if(!p->state().droppable) return; lstring paths = DropPaths(data); - if(paths.empty()) return; + if(!paths) return; p->self().doDrop(paths); } diff --git a/icarus/Database/Super Famicom.bml b/icarus/Database/Super Famicom.bml index f0439a32..7f63ba81 100644 --- a/icarus/Database/Super Famicom.bml +++ b/icarus/Database/Super Famicom.bml @@ -7376,9 +7376,9 @@ cartridge sha256:b4626cf0c876a124b50f9421c48a7d762e9ed808ad336c799d543d60b484897 cartridge sha256:910a29f834199c63c22beddc749baba746da9922196a553255deade59f4fc127 :board region=ntsc : sdd1 - : map address=00-3f,80-bf:4800-4807 + : map address=00-3f,80-bf:4800-480f : rom name=program.rom size=0x400000 - : map address=00-3f,80-bf:8000-ffff mask=0x808000 + : map address=00-3f,80-bf:8000-ffff : map address=c0-ff:0000-ffff : :information diff --git a/icarus/heuristics/game-boy-advance.cpp b/icarus/heuristics/game-boy-advance.cpp index 2363a2bc..53f08de5 100644 --- a/icarus/heuristics/game-boy-advance.cpp +++ b/icarus/heuristics/game-boy-advance.cpp @@ -30,7 +30,7 @@ GameBoyAdvanceCartridge::GameBoyAdvanceCartridge(const uint8_t* data, unsigned s char text[16]; memcpy(text, data + n, id.size + 3); text[id.size + 3] = 0; - list.appendOnce(text); + if(!list.find(text)) list.append(text); } } } diff --git a/icarus/heuristics/super-famicom.cpp b/icarus/heuristics/super-famicom.cpp index a9d5ed44..83536d4b 100644 --- a/icarus/heuristics/super-famicom.cpp +++ b/icarus/heuristics/super-famicom.cpp @@ -253,15 +253,15 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t* data, uint size, boo else if(has_sdd1) { markup.append( " sdd1\n" - " map address=00-3f,80-bf:4800-4807\n" + " map address=00-3f,80-bf:4800-480f\n" " rom name=program.rom size=0x", hex(rom_size), "\n" - " map address=00-3f,80-bf:8000-ffff mask=0x808000\n" + " map address=00-3f,80-bf:8000-ffff\n" " map address=c0-ff:0000-ffff\n" ); if(ram_size > 0) markup.append( " ram name=save.ram size=0x", hex(ram_size), "\n" - " map address=20-3f,a0-bf:6000-7fff mask=0xe000\n" - " map address=70-7d:0000-7fff mask=0x8000\n" + " map address=00-3f,80-bf:6000-7fff mask=0xe000\n" + " map address=70-73:0000-ffff mask=0x8000\n" ); } diff --git a/nall/config.hpp b/nall/config.hpp index 3201cfe9..3ceffb8d 100644 --- a/nall/config.hpp +++ b/nall/config.hpp @@ -57,7 +57,7 @@ struct Node { auto find(const string& path) -> maybe { auto p = path.split("/"); - auto name = p.takeFirst(); + auto name = p.takeLeft(); for(auto& child : children) { if(child.name == name) { if(p.size() == 0) return child; diff --git a/nall/emulation/21fx.hpp b/nall/emulation/21fx.hpp new file mode 100644 index 00000000..a43b22b2 --- /dev/null +++ b/nall/emulation/21fx.hpp @@ -0,0 +1,134 @@ +#pragma once + +#include +#include +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; + auto write(uint offset, const vector& 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 { + 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 buffer; + while(length--) buffer.append(read()); + return buffer; +} + +auto FX::write(uint offset, const vector& 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 buffer = {data}; + write(offset, buffer); +} diff --git a/nall/encode/base64.hpp b/nall/encode/base64.hpp index 46fa5f5f..cba70c78 100644 --- a/nall/encode/base64.hpp +++ b/nall/encode/base64.hpp @@ -34,14 +34,14 @@ inline auto Base64(const uint8_t* data, unsigned size, const string& format = "M case 1: buffer |= data[i] >> 4; - result.last() = lookup[buffer]; + result.right() = lookup[buffer]; buffer = (data[i] & 15) << 2; result.append(lookup[buffer]); break; case 2: buffer |= data[i] >> 6; - result.last() = lookup[buffer]; + result.right() = lookup[buffer]; buffer = (data[i] & 63); result.append(lookup[buffer]); break; diff --git a/nall/hash/crc16.hpp b/nall/hash/crc16.hpp index 63d3c47e..6430dbd7 100644 --- a/nall/hash/crc16.hpp +++ b/nall/hash/crc16.hpp @@ -2,38 +2,57 @@ #include -namespace nall { -struct string; -namespace Hash { +namespace nall { struct string; } + +namespace nall { namespace Hash { struct CRC16 { CRC16() { reset(); } - CRC16(const void* values, unsigned size) : CRC16() { data(values, size); } + CRC16(const void* values, uint size) : CRC16() { data(values, size); } + CRC16(const vector& values) : CRC16() { data(values); } auto reset() -> void { checksum = ~0; } auto data(uint8_t value) -> void { - for(auto n : range(8)) { - if((checksum & 1) ^ (value & 1)) checksum = (checksum >> 1) ^ 0x8408; - else checksum >>= 1; - value >>= 1; - } + checksum = (checksum >> 8) ^ table(checksum ^ value); } - auto data(const void* values, unsigned size) -> void { + auto data(const void* values, uint size) -> void { auto p = (const uint8_t*)values; while(size--) data(*p++); } - auto value() -> uint16_t { + auto data(const vector& values) -> void { + for(auto value : values) data(value); + } + + auto value() const -> uint16_t { return ~checksum; } - inline auto digest() -> string; + inline auto digest() const -> string; private: + static auto table(uint8_t index) -> uint16_t { + static uint16_t table[256] = {0}; + static bool initialized = false; + + if(!initialized) { + initialized = true; + for(auto index : range(256)) { + uint16_t crc = index; + for(auto bit : range(8)) { + crc = (crc >> 1) ^ (crc & 1 ? 0x8408 : 0); + } + table[index] = crc; + } + } + + return table[index]; + } + uint16_t checksum; }; diff --git a/nall/hash/crc32.hpp b/nall/hash/crc32.hpp index 73ded1ae..d34bcd6f 100644 --- a/nall/hash/crc32.hpp +++ b/nall/hash/crc32.hpp @@ -2,80 +2,57 @@ #include -namespace nall { -struct string; -namespace Hash { +namespace nall { struct string; } -const uint32_t _crc32_table[256] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, - 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, - 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, - 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, - 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, - 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, - 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, - 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, - 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, - 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, - 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, - 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, - 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, - 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, - 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, - 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, - 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, - 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, - 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, - 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, - 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, -}; +namespace nall { namespace Hash { struct CRC32 { CRC32() { reset(); } - CRC32(const void* values, unsigned size) : CRC32() { data(values, size); } + CRC32(const void* values, uint size) : CRC32() { data(values, size); } + CRC32(const vector& values) : CRC32() { data(values); } auto reset() -> void { checksum = ~0; } auto data(uint8_t value) -> void { - checksum = ((checksum >> 8) & 0xffffff) ^ _crc32_table[(checksum ^ value) & 0xff]; + checksum = (checksum >> 8) ^ table(checksum ^ value); } - auto data(const void* values, unsigned size) -> void { + auto data(const void* values, uint size) -> void { auto p = (const uint8_t*)values; while(size--) data(*p++); } + auto data(const vector& values) -> void { + for(auto value : values) data(value); + } + auto value() const -> uint32_t { return ~checksum; } - inline auto digest() -> string; + inline auto digest() const -> string; private: + static auto table(uint8_t index) -> uint32_t { + static uint32_t table[256] = {0}; + static bool initialized = false; + + if(!initialized) { + initialized = true; + for(auto index : range(256)) { + uint32_t crc = index; + for(auto bit : range(8)) { + crc = (crc >> 1) ^ (crc & 1 ? 0xedb8'8320 : 0); + } + table[index] = crc; + } + } + + return table[index]; + } + uint32_t checksum; }; diff --git a/nall/hash/crc64.hpp b/nall/hash/crc64.hpp new file mode 100644 index 00000000..d838cb7a --- /dev/null +++ b/nall/hash/crc64.hpp @@ -0,0 +1,59 @@ +#pragma once + +#include + +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& 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& 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; +}; + +}} diff --git a/nall/hash/sha256.hpp b/nall/hash/sha256.hpp index 0e71f727..9365e189 100644 --- a/nall/hash/sha256.hpp +++ b/nall/hash/sha256.hpp @@ -2,13 +2,14 @@ #include -namespace nall { -struct string; -namespace Hash { +namespace nall { struct string; } + +namespace nall { namespace Hash { struct SHA256 { SHA256() { reset(); } - SHA256(const void* values, unsigned size) : SHA256() { data(values, size); } + SHA256(const void* values, uint size) : SHA256() { data(values, size); } + SHA256(const vector& values) : SHA256() { data(values); } auto reset() -> void { for(auto n : input) n = 0; @@ -22,12 +23,16 @@ struct SHA256 { length++; } - auto data(const void* values, unsigned size) -> void { + auto data(const void* values, uint size) -> void { length += size; auto p = (const uint8_t*)values; while(size--) byte(*p++); } + auto data(const vector& values) -> void { + for(auto value : values) data(value); + } + auto value() const -> vector { SHA256 self(*this); self.finish(); @@ -77,14 +82,14 @@ private: return (x >> n) | (x << 32 - n); } - auto square(unsigned n) -> uint32_t { + auto square(uint n) -> uint32_t { static const uint32_t value[8] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, }; return value[n]; } - auto cube(unsigned n) -> uint32_t { + auto cube(uint n) -> uint32_t { static const uint32_t value[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, diff --git a/nall/hid.hpp b/nall/hid.hpp index fbbe06c3..678e4834 100644 --- a/nall/hid.hpp +++ b/nall/hid.hpp @@ -20,7 +20,7 @@ struct Group : vector { auto name() const -> string { return _name; } auto input(unsigned id) -> Input& { return operator[](id); } - auto append(const string& name) -> void { vector::append({name}); } + auto append(const string& name) -> void { vector::append(Input{name}); } auto find(const string& name) const -> maybe { for(auto id : range(size())) { @@ -51,7 +51,7 @@ struct Device : vector { auto id() const -> uint64_t { return _id; } auto setID(uint64_t id) -> void { _id = id; } auto group(unsigned id) -> Group& { return operator[](id); } - auto append(const string& name) -> void { vector::append({name}); } + auto append(const string& name) -> void { vector::append(Group{name}); } auto find(const string& name) const -> maybe { for(auto id : range(size())) { diff --git a/nall/http/request.hpp b/nall/http/request.hpp index a9afe8d9..9a6ec087 100644 --- a/nall/http/request.hpp +++ b/nall/http/request.hpp @@ -70,7 +70,7 @@ auto Request::head(const function& callback) co auto Request::setHead() -> bool { lstring headers = _head.split("\n"); - string request = headers.takeFirst().rtrim("\r", 1L); + string request = headers.takeLeft().rtrim("\r", 1L); string requestHost; if(request.iendsWith(" HTTP/1.0")) request.irtrim(" HTTP/1.0", 1L); @@ -146,7 +146,7 @@ auto Request::setBody() -> bool { auto boundary = contentType.iltrim("multipart/form-data; boundary=", 1L).trim("\"", "\"", 1L); auto blocks = _body.split({"--", boundary}, 1024L); //limit blocks to prevent memory exhaustion for(auto& block : blocks) block.trim("\r\n", "\r\n", 1L); - if(blocks.size() < 2 || (blocks.takeFirst(), !blocks.takeLast().beginsWith("--"))) return false; + if(blocks.size() < 2 || (blocks.takeLeft(), !blocks.takeRight().beginsWith("--"))) return false; for(auto& block : blocks) { string name; string filename; diff --git a/nall/http/response.hpp b/nall/http/response.hpp index 9b00f998..c8174257 100644 --- a/nall/http/response.hpp +++ b/nall/http/response.hpp @@ -88,7 +88,7 @@ auto Response::head(const function& callback) c auto Response::setHead() -> bool { lstring headers = _head.split("\n"); - string response = headers.takeFirst().rtrim("\r"); + string response = headers.takeLeft().rtrim("\r"); if(response.ibeginsWith("HTTP/1.0 ")) response.iltrim("HTTP/1.0 ", 1L); else if(response.ibeginsWith("HTTP/1.1 ")) response.iltrim("HTTP/1.1 ", 1L); diff --git a/nall/memory.hpp b/nall/memory.hpp index 7331dd22..3e997183 100644 --- a/nall/memory.hpp +++ b/nall/memory.hpp @@ -1,3 +1,7 @@ #pragma once +#include + +#include +#include #include diff --git a/nall/nall.hpp b/nall/nall.hpp index fe5ea45b..aa79a941 100644 --- a/nall/nall.hpp +++ b/nall/nall.hpp @@ -64,6 +64,7 @@ #include #include #include +#include #include #if defined(PLATFORM_WINDOWS) diff --git a/nall/range.hpp b/nall/range.hpp index f29a838d..a64fd3e5 100644 --- a/nall/range.hpp +++ b/nall/range.hpp @@ -39,12 +39,4 @@ inline auto rrange(int size) { return range_t{size - 1, -1, -1}; } -template inline auto range(const vector& container) { - return range_t{0, (int)container.size(), 1}; -} - -template inline auto rrange(const vector& container) { - return range_t{(int)container.size() - 1, -1, -1}; -} - } diff --git a/nall/serial.hpp b/nall/serial.hpp index 4d580dc9..671e8ffe 100644 --- a/nall/serial.hpp +++ b/nall/serial.hpp @@ -16,17 +16,12 @@ namespace nall { struct serial { - serial() { - port = -1; - port_open = false; - } - ~serial() { close(); } auto readable() -> bool { - if(port_open == false) return false; + if(!opened) return false; fd_set fdset; FD_ZERO(&fdset); FD_SET(port, &fdset); @@ -40,12 +35,12 @@ struct serial { //-1 on error, otherwise return bytes read auto read(uint8_t* data, uint length) -> int { - if(port_open == false) return -1; + if(!opened) return -1; return ::read(port, (void*)data, length); } auto writable() -> bool { - if(port_open == false) return false; + if(!opened) return false; fd_set fdset; FD_ZERO(&fdset); FD_SET(port, &fdset); @@ -59,14 +54,17 @@ struct serial { //-1 on error, otherwise return bytes written auto write(const uint8_t* data, uint length) -> int { - if(port_open == false) return -1; + if(!opened) return -1; return ::write(port, (void*)data, length); } - auto open(const string& portname, uint rate, bool flowcontrol) -> bool { + //rate==0: use flow control (synchronous mode) + //rate!=0: baud-rate (asynchronous mode) + auto open(string device, uint rate = 0) -> bool { close(); - port = ::open(portname, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK); + if(!device) device = "/dev/ttyU0"; //note: default device name is for FreeBSD 10+ + port = ::open(device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK); if(port == -1) return false; if(ioctl(port, TIOCEXCL) == -1) { close(); return false; } @@ -75,7 +73,7 @@ struct serial { termios attr = original_attr; cfmakeraw(&attr); - cfsetspeed(&attr, rate); + cfsetspeed(&attr, rate ? rate : 57600); //rate value has no effect in synchronous mode attr.c_lflag &=~ (ECHO | ECHONL | ISIG | ICANON | IEXTEN); attr.c_iflag &=~ (BRKINT | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY); @@ -83,7 +81,7 @@ struct serial { attr.c_oflag &=~ (OPOST); attr.c_cflag &=~ (CSIZE | CSTOPB | PARENB | CLOCAL); attr.c_cflag |= (CS8 | CREAD); - if(flowcontrol == false) { + if(rate) { attr.c_cflag &= ~CRTSCTS; } else { attr.c_cflag |= CRTSCTS; @@ -91,15 +89,15 @@ struct serial { attr.c_cc[VTIME] = attr.c_cc[VMIN] = 0; if(tcsetattr(port, TCSANOW, &attr) == -1) { close(); return false; } - return port_open = true; + return opened = true; } auto close() -> void { if(port != -1) { tcdrain(port); - if(port_open == true) { + if(opened) { tcsetattr(port, TCSANOW, &original_attr); - port_open = false; + opened = false; } ::close(port); port = -1; @@ -107,8 +105,8 @@ struct serial { } private: - int port; - bool port_open; + int port = -1; + bool opened = false; termios original_attr; }; diff --git a/nall/string.hpp b/nall/string.hpp index a774fdc2..b38ba8fe 100644 --- a/nall/string.hpp +++ b/nall/string.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include diff --git a/nall/string/base.hpp b/nall/string/base.hpp index e72c7026..d638f035 100644 --- a/nall/string/base.hpp +++ b/nall/string/base.hpp @@ -32,6 +32,7 @@ inline auto real(long double value) -> string; //hash.hpp inline auto crc16(rstring self) -> string; inline auto crc32(rstring self) -> string; +inline auto crc64(rstring self) -> string; inline auto sha256(rstring self) -> string; //match.hpp diff --git a/nall/string/eval/parser.hpp b/nall/string/eval/parser.hpp index 1cae0d97..5e8ebe52 100644 --- a/nall/string/eval/parser.hpp +++ b/nall/string/eval/parser.hpp @@ -45,7 +45,7 @@ inline auto parse(Node*& node, const char*& s, uint depth) -> void { while(whitespace(s[0])) s++; if(!s[0]) return; - if(s[0] == '(' && node->link.empty()) { + if(s[0] == '(' && !node->link) { parse(node, s += 1, 1); if(*s++ != ')') throw "mismatched group"; } @@ -55,7 +55,7 @@ inline auto parse(Node*& node, const char*& s, uint depth) -> void { node->literal = literal(s); } - #define p() (node->literal.empty() && node->link.empty()) + #define p() (!node->literal && !node->link) while(true) { while(whitespace(s[0])) s++; if(!s[0]) return; diff --git a/nall/string/hash.hpp b/nall/string/hash.hpp index 11371a3d..04be44ff 100644 --- a/nall/string/hash.hpp +++ b/nall/string/hash.hpp @@ -3,14 +3,18 @@ namespace nall { namespace Hash { - auto CRC16::digest() -> string { + auto CRC16::digest() const -> string { return hex(value(), 4L); } - auto CRC32::digest() -> string { + auto CRC32::digest() const -> string { return hex(value(), 8L); } + auto CRC64::digest() const -> string { + return hex(value(), 16L); + } + auto SHA256::digest() const -> string { string result; for(auto n : value()) result.append(hex(n, 2L)); @@ -26,6 +30,10 @@ auto crc32(rstring self) -> string { return Hash::CRC32(self.data(), self.size()).digest(); } +auto crc64(rstring self) -> string { + return Hash::CRC64(self.data(), self.size()).digest(); +} + auto sha256(rstring self) -> string { return Hash::SHA256(self.data(), self.size()).digest(); } diff --git a/nall/string/list.hpp b/nall/string/list.hpp index cbdc3754..e448acb7 100644 --- a/nall/string/list.hpp +++ b/nall/string/list.hpp @@ -16,7 +16,7 @@ auto lstring::operator!=(const lstring& source) const -> bool { } auto lstring::isort() -> lstring& { - nall::sort(pool, objectsize, [](const string& x, const string& y) { + sort([](const string& x, const string& y) { return memory::icompare(x.data(), x.size(), y.data(), y.size()) < 0; }); return *this; diff --git a/nall/string/markup/find.hpp b/nall/string/markup/find.hpp index 9767bfdb..91dedc17 100644 --- a/nall/string/markup/find.hpp +++ b/nall/string/markup/find.hpp @@ -119,13 +119,13 @@ auto ManagedNode::_create(const string& path) -> Node { } } _children.append(new ManagedNode(name)); - return _children.last()->_create(slice(path, *position + 1)); + return _children.right()->_create(slice(path, *position + 1)); } for(auto& node : _children) { if(path == node->_name) return node; } _children.append(new ManagedNode(path)); - return _children.last(); + return _children.right(); } }} diff --git a/nall/string/transform/cml.hpp b/nall/string/transform/cml.hpp index 0b99669c..d00e1fdb 100644 --- a/nall/string/transform/cml.hpp +++ b/nall/string/transform/cml.hpp @@ -55,7 +55,7 @@ auto CML::parseDocument(const string& filedata, const string& pathname, uint dep for(auto& block : filedata.split("\n\n")) { lstring lines = block.rstrip().split("\n"); - string name = lines.takeFirst(); + string name = lines.takeLeft(); if(name.beginsWith("include ")) { name.ltrim("include ", 1L); diff --git a/nall/string/transform/dml.hpp b/nall/string/transform/dml.hpp index 9c6f915e..5a603e11 100644 --- a/nall/string/transform/dml.hpp +++ b/nall/string/transform/dml.hpp @@ -85,7 +85,7 @@ auto DML::parseBlock(string& block, const string& pathname, uint depth) -> bool if(state.sections++) state.output.append(""); state.output.append("
"); } - auto content = lines.takeFirst().ltrim("# ", 1L).split(" => ", 1L); + auto content = lines.takeLeft().ltrim("# ", 1L).split(" => ", 1L); auto data = markup(content[0]); auto name = escape(content(1, crc32(data))); state.output.append("
", data); @@ -98,7 +98,7 @@ auto DML::parseBlock(string& block, const string& pathname, uint depth) -> bool //header else if(auto depth = count(block, '=')) { - auto content = slice(lines.takeFirst(), depth + 1).split(" => ", 1L); + auto content = slice(lines.takeLeft(), depth + 1).split(" => ", 1L); auto data = markup(content[0]); auto name = escape(content(1, crc32(data))); if(depth <= 6) { diff --git a/nall/vector.hpp b/nall/vector.hpp index 73c7d36a..0bdde14c 100644 --- a/nall/vector.hpp +++ b/nall/vector.hpp @@ -1,282 +1,109 @@ #pragma once -#include -#include #include -#include -#include + #include +#include #include #include +#include #include -#include +#include namespace nall { -template struct vector { - struct exception_out_of_bounds{}; +template struct vector_iterator; +template struct vector_iterator_const; - explicit operator bool() const { return objectsize; } - auto data() -> T* { return pool + poolbase; } - auto data() const -> const T* { return pool + poolbase; } - - auto empty() const -> bool { return objectsize == 0; } - auto size() const -> unsigned { return objectsize; } - auto capacity() const -> unsigned { return poolsize; } - - auto release() -> T* { - T* result = pool + poolbase; - pool = nullptr; - poolbase = 0; - poolsize = 0; - objectsize = 0; - return result; - } - - auto reset() -> void { - if(pool) { - for(unsigned n = 0; n < objectsize; n++) pool[poolbase + n].~T(); - memory::free(pool); - } - pool = nullptr; - poolbase = 0; - poolsize = 0; - objectsize = 0; - } - - auto reserve(unsigned size) -> void { - if(size <= poolsize) return; - size = bit::round(size); //amortize growth - - T* copy = (T*)memory::allocate(size * sizeof(T)); - for(unsigned n = 0; n < objectsize; n++) new(copy + n) T(move(pool[poolbase + n])); - free(pool); - pool = copy; - poolbase = 0; - poolsize = size; - } - - auto resize(unsigned size, T value = T()) -> void { - T* copy = (T*)memory::allocate(size * sizeof(T)); - for(unsigned n = 0; n < size && n < objectsize; n++) new(copy + n) T(move(pool[poolbase + n])); - for(unsigned n = objectsize; n < size; n++) new(copy + n) T(value); - reset(); - pool = copy; - poolbase = 0; - poolsize = size; - objectsize = size; - } - - auto reallocate(unsigned size, T value = T()) -> void { - reset(); - resize(size, value); - } - - template auto prepend(const T& data, Args&&... args) -> void { - prepend(forward(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 auto append(const T& data, Args&&... args) -> void { - append(data); - append(forward(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& 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 { - for(unsigned n = 0; n < objectsize; n++) if(pool[poolbase + n] == data) return n; - return nothing; - } - - auto first() -> T& { - if(objectsize == 0) throw exception_out_of_bounds(); - return pool[poolbase]; - } - - auto first() const -> const T& { - if(objectsize == 0) throw exception_out_of_bounds(); - return pool[poolbase]; - } - - auto last() -> T& { - if(objectsize == 0) throw exception_out_of_bounds(); - return pool[poolbase + objectsize - 1]; - } - - auto last() const -> const T& { - if(objectsize == 0) throw exception_out_of_bounds(); - return pool[poolbase + objectsize - 1]; - } - - //access - inline auto operator[](unsigned position) -> T& { - if(position >= objectsize) throw exception_out_of_bounds(); - return pool[poolbase + position]; - } - - inline auto operator[](unsigned position) const -> const T& { - if(position >= objectsize) throw exception_out_of_bounds(); - return pool[poolbase + position]; - } - - inline auto operator()(unsigned position) -> T& { - if(position >= poolsize) reserve(position + 1); - while(position >= objectsize) append(T()); - return pool[poolbase + position]; - } - - inline auto operator()(unsigned position, const T& data) const -> const T& { - if(position >= objectsize) return data; - return pool[poolbase + position]; - } - - //iteration - struct iterator { - iterator(vector& source, unsigned position) : source(source), position(position) {} - auto operator*() -> T& { return source.operator[](position); } - auto operator!=(const iterator& source) const -> bool { return position != source.position; } - auto operator++() -> iterator& { position++; return *this; } - - private: - vector& source; - unsigned position; - }; - - auto begin() -> iterator { return iterator(*this, 0); } - auto end() -> iterator { return iterator(*this, size()); } - - struct constIterator { - constIterator(const vector& source, unsigned position) : source(source), position(position) {} - auto operator*() const -> const T& { return source.operator[](position); } - auto operator!=(const constIterator& source) const -> bool { return position != source.position; } - auto operator++() -> constIterator& { position++; return *this; } - - private: - const vector& source; - unsigned position; - }; - - auto begin() const -> const constIterator { return constIterator(*this, 0); } - auto end() const -> const constIterator { return constIterator(*this, size()); } - - //copy - inline auto operator=(const vector& source) -> vector& { - if(this == &source) return *this; - reset(); - reserve(source.size()); - for(auto& data : source) append(data); - return *this; - } - - //move - inline auto operator=(vector&& source) -> vector& { - if(this == &source) return *this; - reset(); - pool = source.pool; - poolbase = source.poolbase; - poolsize = source.poolsize; - objectsize = source.objectsize; - source.pool = nullptr; - source.poolbase = 0; - source.poolsize = 0; - source.objectsize = 0; - return *this; - } - - //construction and destruction +template +struct vector { + //core.hpp vector() = default; - vector(initializer_list list) { for(auto& data : list) append(data); } - vector(const vector& source) { operator=(source); } - vector(vector&& source) { operator=(move(source)); } - ~vector() { reset(); } + vector(const initializer_list& values); + vector(const vector& source); + vector(vector&& source); + ~vector(); -protected: - T* pool = nullptr; - unsigned poolbase = 0; - unsigned poolsize = 0; - unsigned objectsize = 0; + explicit operator bool() const; + auto capacity() const -> uint; + auto size() const -> uint; + auto data() -> T*; + auto data() const -> const T*; + + //assign.hpp + auto operator=(const vector& source) -> vector&; + auto operator=(vector&& source) -> vector&; + + //memory.hpp + auto reset() -> void; + auto release() -> T*; + + auto reserveLeft(uint capacity) -> bool; + auto reserveRight(uint capacity) -> bool; + auto reserve(uint capacity) -> bool { return reserveRight(capacity); } + + auto resizeLeft(uint size, const T& value = T()) -> bool; + auto resizeRight(uint size, const T& value = T()) -> bool; + auto resize(uint size, const T& value = T()) -> bool { return resizeRight(size, value); } + + //access.hpp + alwaysinline auto operator[](uint offset) -> T&; + alwaysinline auto operator[](uint offset) const -> const T&; + + alwaysinline auto operator()(uint offset) -> T&; + alwaysinline auto operator()(uint offset, const T& value) const -> const T&; + + alwaysinline auto left() -> T&; + alwaysinline auto left() const -> const T&; + + alwaysinline auto right() -> T&; + alwaysinline auto right() const -> const T&; + + //modify.hpp + auto prepend(const T& value) -> void; + auto prepend(T&& value) -> void; + auto prepend(const vector& values) -> void; + auto prepend(vector&& values) -> void; + + auto append(const T& value) -> void; + auto append(T&& value) -> void; + auto append(const vector& values) -> void; + auto append(vector&& 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{*this, 0}; } + auto end() { return vector_iterator{*this, size()}; } + + auto begin() const { return vector_iterator_const{*this, 0}; } + auto end() const { return vector_iterator_const{*this, size()}; } + + //utility.hpp + auto sort(const function& comparator = {}) -> void; + auto find(const T& value) const -> maybe; + +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 +#include +#include +#include +#include +#include +#include diff --git a/nall/vector/access.hpp b/nall/vector/access.hpp new file mode 100644 index 00000000..4867c1b8 --- /dev/null +++ b/nall/vector/access.hpp @@ -0,0 +1,39 @@ +#pragma once + +namespace nall { + +template auto vector::operator[](uint offset) -> T& { + return _pool[offset]; +} + +template auto vector::operator[](uint offset) const -> const T& { + return _pool[offset]; +} + +template auto vector::operator()(uint offset) -> T& { + while(offset >= size()) append(T()); + return _pool[offset]; +} + +template auto vector::operator()(uint offset, const T& value) const -> const T& { + if(offset >= size()) return value; + return _pool[offset]; +} + +template auto vector::left() -> T& { + return _pool[0]; +} + +template auto vector::left() const -> const T& { + return _pool[0]; +} + +template auto vector::right() -> T& { + return _pool[_size - 1]; +} + +template auto vector::right() const -> const T& { + return _pool[_size - 1]; +} + +} diff --git a/nall/vector/assign.hpp b/nall/vector/assign.hpp new file mode 100644 index 00000000..d13eca58 --- /dev/null +++ b/nall/vector/assign.hpp @@ -0,0 +1,28 @@ +#pragma once + +namespace nall { + +template auto vector::operator=(const vector& source) -> vector& { + 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 auto vector::operator=(vector&& source) -> vector& { + 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; +} + +} diff --git a/nall/vector/core.hpp b/nall/vector/core.hpp new file mode 100644 index 00000000..0073b89a --- /dev/null +++ b/nall/vector/core.hpp @@ -0,0 +1,42 @@ +#pragma once + +namespace nall { + +template vector::vector(const initializer_list& values) { + reserveRight(values.size()); + for(auto& value : values) append(value); +} + +template vector::vector(const vector& source) { + operator=(source); +} + +template vector::vector(vector&& source) { + operator=(move(source)); +} + +template vector::~vector() { + reset(); +} + +template vector::operator bool() const { + return _size; +} + +template auto vector::capacity() const -> uint { + return _left + _size + _right; +} + +template auto vector::size() const -> uint { + return _size; +} + +template auto vector::data() -> T* { + return _pool; +} + +template auto vector::data() const -> const T* { + return _pool; +} + +} diff --git a/nall/vector/iterator.hpp b/nall/vector/iterator.hpp new file mode 100644 index 00000000..641a1c5f --- /dev/null +++ b/nall/vector/iterator.hpp @@ -0,0 +1,37 @@ +#pragma once + +namespace nall { + +template +struct vector_iterator { + vector_iterator(vector& 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& self; + uint offset; +}; + +template +struct vector_iterator_const { + vector_iterator_const(const vector& 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& self; + uint offset; +}; + +template inline auto range(const vector& container) { + return range_t{0, (int)container.size(), 1}; +} + +template inline auto rrange(const vector& container) { + return range_t{(int)container.size() - 1, -1, -1}; +} + +} diff --git a/nall/vector/memory.hpp b/nall/vector/memory.hpp new file mode 100644 index 00000000..fe4ca118 --- /dev/null +++ b/nall/vector/memory.hpp @@ -0,0 +1,90 @@ +#pragma once + +namespace nall { + +template auto vector::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 auto vector::release() -> T* { + auto pool = _pool; + _pool = nullptr; + _size = 0; + _left = 0; + _right = 0; + return pool; +} + +template auto vector::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 auto vector::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 auto vector::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 auto vector::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; +} + +} diff --git a/nall/vector/modify.hpp b/nall/vector/modify.hpp new file mode 100644 index 00000000..402429b4 --- /dev/null +++ b/nall/vector/modify.hpp @@ -0,0 +1,127 @@ +#pragma once + +namespace nall { + +template auto vector::prepend(const T& value) -> void { + reserveLeft(size() + 1); + new(--_pool) T(value); + _left--; + _size++; +} + +template auto vector::prepend(T&& value) -> void { + reserveLeft(size() + 1); + new(--_pool) T(move(value)); + _left--; + _size++; +} + +template auto vector::prepend(const vector& 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 auto vector::prepend(vector&& 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 auto vector::append(const T& value) -> void { + reserveRight(size() + 1); + new(_pool + _size) T(value); + _right--; + _size++; +} + +template auto vector::append(T&& value) -> void { + reserveRight(size() + 1); + new(_pool + _size) T(move(value)); + _right--; + _size++; +} + +template auto vector::append(const vector& 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 auto vector::append(vector&& 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 auto vector::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 auto vector::removeLeft(uint length) -> void { + if(length > size()) length = size(); + resizeLeft(size() - length); +} + +template auto vector::removeRight(uint length) -> void { + if(length > size()) length = size(); + resizeRight(size() - length); +} + +template auto vector::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 auto vector::takeLeft() -> T { + T value = move(_pool[0]); + removeLeft(); + return value; +} + +template auto vector::takeRight() -> T { + T value = move(_pool[size() - 1]); + removeRight(); + return value; +} + +template auto vector::take(uint offset) -> T { + if(offset == 0) return takeLeft(); + if(offset == size() - 1) return takeRight(); + + T value = move(_pool[offset]); + remove(offset); + return value; +} + +} diff --git a/nall/vector/utility.hpp b/nall/vector/utility.hpp new file mode 100644 index 00000000..e58948e9 --- /dev/null +++ b/nall/vector/utility.hpp @@ -0,0 +1,15 @@ +#pragma once + +namespace nall { + +template auto vector::sort(const function& comparator) -> void { + if(!comparator) return nall::sort(_pool, _size, [](const T& lhs, const T& rhs) { return lhs < rhs; }); + nall::sort(_pool, _size, comparator); +} + +template auto vector::find(const T& value) const -> maybe { + for(uint n : range(size())) if(_pool[n] == value) return n; + return nothing; +} + +} diff --git a/ruby/video/glx.cpp b/ruby/video/glx.cpp index 81530c1f..b462c056 100644 --- a/ruby/video/glx.cpp +++ b/ruby/video/glx.cpp @@ -182,7 +182,6 @@ struct VideoGLX : Video, OpenGL { //glXSwapInterval is used to toggle Vsync //note that the ordering is very important! MESA declares SGI, but the SGI function does nothing - glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalEXT"); if(!glXSwapInterval) glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalMESA"); if(!glXSwapInterval) glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalSGI"); diff --git a/ruby/video/glx2.cpp b/ruby/video/glx2.cpp index 71b6c18b..afe8d282 100644 --- a/ruby/video/glx2.cpp +++ b/ruby/video/glx2.cpp @@ -163,7 +163,6 @@ struct VideoGLX2 : Video { glxcontext = glXCreateContext(display, vi, 0, GL_TRUE); glXMakeCurrent(display, glxwindow = xwindow, glxcontext); - glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalEXT"); if(!glXSwapInterval) glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalMESA"); if(!glXSwapInterval) glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalSGI"); diff --git a/ruby/video/opengl/main.hpp b/ruby/video/opengl/main.hpp index 3c4f6d1b..6791d5f1 100644 --- a/ruby/video/opengl/main.hpp +++ b/ruby/video/opengl/main.hpp @@ -167,7 +167,7 @@ auto OpenGL::refresh() -> void { render(sources[0].width, sources[0].height, outputWidth, outputHeight); if(history.size() > 0) { - OpenGLTexture frame = history.takeLast(); + OpenGLTexture frame = history.takeRight(); glBindTexture(GL_TEXTURE_2D, frame.texture); if(width == frame.width && height == frame.height) {