From 095529547576de0267d62685d60043758dd91aa4 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Mon, 2 May 2016 19:57:04 +1000 Subject: [PATCH] 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. --- higan/audio/audio.cpp | 4 +- higan/audio/audio.hpp | 10 +- higan/audio/stream.cpp | 51 +-- higan/emulator/emulator.hpp | 2 +- higan/processor/v30mz/disassembler.cpp | 2 +- higan/processor/v30mz/instructions-misc.cpp | 6 +- higan/sfc/cartridge/markup.cpp | 4 +- .../sdd1/{decomp.cpp => decompressor.cpp} | 44 +-- .../sdd1/{decomp.hpp => decompressor.hpp} | 28 +- higan/sfc/coprocessor/sdd1/sdd1.cpp | 135 ++++--- higan/sfc/coprocessor/sdd1/sdd1.hpp | 35 +- higan/sfc/coprocessor/sdd1/serialization.cpp | 11 +- higan/sfc/expansion/21fx/21fx.cpp | 4 +- higan/sfc/interface/interface.cpp | 8 +- higan/target-tomoko/input/input.cpp | 8 +- higan/target-tomoko/program/program.cpp | 2 +- hiro/core/action/menu.cpp | 2 +- hiro/core/layout.cpp | 2 +- hiro/core/menu-bar.cpp | 2 +- hiro/core/popup-menu.cpp | 2 +- hiro/core/shared.hpp | 2 +- hiro/core/widget/tab-frame.cpp | 2 +- hiro/core/widget/tree-view-item.cpp | 4 +- hiro/core/widget/tree-view.cpp | 4 +- hiro/extension/browser-dialog.cpp | 20 +- hiro/extension/horizontal-layout.cpp | 4 +- hiro/extension/vertical-layout.cpp | 4 +- hiro/gtk/widget/canvas.cpp | 2 +- hiro/gtk/widget/console.cpp | 2 +- hiro/gtk/widget/tree-view.cpp | 4 +- hiro/gtk/widget/viewport.cpp | 2 +- hiro/gtk/window.cpp | 2 +- icarus/Database/Super Famicom.bml | 4 +- icarus/heuristics/game-boy-advance.cpp | 2 +- icarus/heuristics/super-famicom.cpp | 8 +- nall/config.hpp | 2 +- nall/emulation/21fx.hpp | 134 +++++++ nall/encode/base64.hpp | 4 +- nall/hash/crc16.hpp | 43 ++- nall/hash/crc32.hpp | 81 ++-- nall/hash/crc64.hpp | 59 +++ nall/hash/sha256.hpp | 19 +- nall/hid.hpp | 4 +- nall/http/request.hpp | 4 +- nall/http/response.hpp | 2 +- nall/memory.hpp | 4 + nall/nall.hpp | 1 + nall/range.hpp | 8 - nall/serial.hpp | 34 +- nall/string.hpp | 1 + nall/string/base.hpp | 1 + nall/string/eval/parser.hpp | 4 +- nall/string/hash.hpp | 12 +- nall/string/list.hpp | 2 +- nall/string/markup/find.hpp | 4 +- nall/string/transform/cml.hpp | 2 +- nall/string/transform/dml.hpp | 4 +- nall/vector.hpp | 359 +++++------------- nall/vector/access.hpp | 39 ++ nall/vector/assign.hpp | 28 ++ nall/vector/core.hpp | 42 ++ nall/vector/iterator.hpp | 37 ++ nall/vector/memory.hpp | 90 +++++ nall/vector/modify.hpp | 127 +++++++ nall/vector/utility.hpp | 15 + ruby/video/glx.cpp | 1 - ruby/video/glx2.cpp | 1 - ruby/video/opengl/main.hpp | 2 +- 68 files changed, 994 insertions(+), 604 deletions(-) rename higan/sfc/coprocessor/sdd1/{decomp.cpp => decompressor.cpp} (83%) rename higan/sfc/coprocessor/sdd1/{decomp.hpp => decompressor.hpp} (73%) create mode 100644 nall/emulation/21fx.hpp create mode 100644 nall/hash/crc64.hpp create mode 100644 nall/vector/access.hpp create mode 100644 nall/vector/assign.hpp create mode 100644 nall/vector/core.hpp create mode 100644 nall/vector/iterator.hpp create mode 100644 nall/vector/memory.hpp create mode 100644 nall/vector/modify.hpp create mode 100644 nall/vector/utility.hpp 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) {