From 092cac9073c35e9a5603a477e34cb44fd5cf5f2e Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Tue, 14 Jul 2015 19:32:43 +1000 Subject: [PATCH] Update to v094r37 release. byuu says: Changelog: - synchronizes lots of nall changes - changes displayed program title from tomoko to higan(*) - browser dialog sort is case-insensitive - .sys folders look at user-selected library path; no longer hard-coded Tried to get rid of the file modes from the Windows browser dialog, but it was being a bitch so I left it on for now. - The storage locations and binary still use tomoko. I'm not really sure what to do here. The idea is there may be more than one "higan" UI in the future, but I don't want people to go around calling the entire program by the UI name. For official Windows releases, I can rename the binaries to "higan-{profile}.exe", and by putting the config files with the binary, they won't ever see the tomoko folder. Linux is of course trickier. Note: Windows users will need to edit hiro/components.hpp and comment out these lines: #define Hiro_Console #define Hiro_IconView #define Hiro_SourceView #define Hiro_TreeView I forgot to do that, and too lazy to upload another WIP. --- emulator/emulator.hpp | 2 +- hiro/components.hpp | 8 +- hiro/extension/browser-dialog.cpp | 10 +- hiro/gtk/browser-window.cpp | 2 +- hiro/gtk/font.cpp | 2 +- hiro/gtk/widget/hex-edit.cpp | 4 +- hiro/qt/font.cpp | 2 +- hiro/windows/browser-window.cpp | 2 +- hiro/windows/font.cpp | 2 +- hiro/windows/widget/hex-edit.cpp | 4 +- nall/atoi.hpp | 20 +- nall/beat/archive.hpp | 185 +++++++------ nall/beat/base.hpp | 92 ------- nall/beat/file.hpp | 26 ++ nall/beat/multi.hpp | 4 +- nall/bit.hpp | 24 +- nall/bitvector.hpp | 71 +++-- nall/bmp.hpp | 8 +- nall/config.hpp | 30 +-- nall/database/odbc.hpp | 274 ++++++++++++++++++++ nall/database/sqlite3.hpp | 173 +++++++----- nall/directory.hpp | 44 ++-- nall/dl.hpp | 46 ++-- nall/file.hpp | 11 + nall/filemap.hpp | 42 +-- nall/function.hpp | 96 +++---- nall/group.hpp | 66 ----- nall/hashset.hpp | 39 ++- nall/http/request.hpp | 37 +-- nall/http/response.hpp | 6 +- nall/http/server.hpp | 134 ++++++++-- nall/interpolation.hpp | 12 +- nall/map.hpp | 46 ++-- nall/matrix.hpp | 4 +- nall/method.hpp | 12 +- nall/mosaic/context.hpp | 16 +- nall/nall.hpp | 1 - nall/odbc.hpp | 153 ----------- nall/posix/shared-memory.hpp | 4 +- nall/priority-queue.hpp | 41 ++- nall/property.hpp | 24 +- nall/random.hpp | 14 +- nall/range.hpp | 20 +- nall/serial.hpp | 30 +-- nall/serializer.hpp | 36 +-- nall/set.hpp | 68 ++--- nall/smtp.hpp | 86 +++--- nall/sort.hpp | 4 +- nall/string/atoi.hpp | 4 + nall/string/base.hpp | 111 ++++---- nall/string/datetime.hpp | 12 +- nall/string/eval/evaluator.hpp | 2 +- nall/string/format.hpp | 18 +- nall/string/hash.hpp | 6 +- nall/string/markup/bml.hpp | 4 +- nall/string/markup/find.hpp | 18 +- nall/string/replace.hpp | 16 +- nall/string/split.hpp | 22 +- nall/string/transform/cml.hpp | 50 ++-- nall/string/transform/dml.hpp | 194 +++++++------- nall/string/trim.hpp | 110 ++++---- nall/string/utility.hpp | 3 +- nall/utility.hpp | 4 +- nall/varint.hpp | 139 +++++----- nall/vector.hpp | 109 ++++---- nall/windows/detour.hpp | 2 +- processor/arm/disassembler.cpp | 70 ++--- processor/hg51b/instructions.cpp | 2 +- processor/lr35902/disassembler.cpp | 96 +++---- processor/r6502/disassembler.cpp | 28 +- processor/spc700/disassembler.cpp | 22 +- ruby/video/opengl/main.hpp | 4 +- ruby/video/opengl/program.hpp | 6 +- sfc/alt/smp/core/generate.cpp | 10 +- sfc/cartridge/markup.cpp | 2 +- sfc/chip/event/event.cpp | 14 +- sfc/controller/usart/usart.cpp | 2 +- sfc/memory/memory.cpp | 6 +- target-tomoko/presentation/presentation.cpp | 2 +- target-tomoko/program/media.cpp | 10 +- target-tomoko/program/state.cpp | 2 +- 81 files changed, 1670 insertions(+), 1467 deletions(-) delete mode 100644 nall/beat/base.hpp create mode 100644 nall/beat/file.hpp create mode 100644 nall/database/odbc.hpp delete mode 100644 nall/group.hpp delete mode 100644 nall/odbc.hpp diff --git a/emulator/emulator.hpp b/emulator/emulator.hpp index 4697c77e..1349f888 100644 --- a/emulator/emulator.hpp +++ b/emulator/emulator.hpp @@ -8,7 +8,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "094.36"; + static const string Version = "094.37"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/hiro/components.hpp b/hiro/components.hpp index 6c03415d..e1a5a18d 100644 --- a/hiro/components.hpp +++ b/hiro/components.hpp @@ -50,22 +50,22 @@ #define Hiro_CheckButton #define Hiro_CheckLabel #define Hiro_ComboButton -//#define Hiro_Console +#define Hiro_Console #define Hiro_Frame #define Hiro_HexEdit #define Hiro_HorizontalScroller #define Hiro_HorizontalSlider -//#define Hiro_IconView +#define Hiro_IconView #define Hiro_Label #define Hiro_LineEdit #define Hiro_ListView #define Hiro_ProgressBar #define Hiro_RadioButton #define Hiro_RadioLabel -//#define Hiro_SourceView +#define Hiro_SourceView #define Hiro_TabFrame #define Hiro_TextEdit -//#define Hiro_TreeView +#define Hiro_TreeView #define Hiro_VerticalScroller #define Hiro_VerticalSlider #define Hiro_Viewport diff --git a/hiro/extension/browser-dialog.cpp b/hiro/extension/browser-dialog.cpp index 1673b7a7..b283493e 100644 --- a/hiro/extension/browser-dialog.cpp +++ b/hiro/extension/browser-dialog.cpp @@ -124,7 +124,7 @@ auto BrowserDialogWindow::run() -> lstring { view.setBatchable(state.action == "openFiles").onActivate([&] { activate(); }).onChange([&] { change(); }); filterList.setVisible(state.action != "selectFolder").onChange([&] { setPath(state.path); }); for(auto& filter : state.filters) { - auto part = filter.split<1>("|"); + auto part = filter.split("|", 1L); filterList.append(ComboButtonItem().setText(part.first())); } fileName.setVisible(state.action == "saveFile").onActivate([&] { accept(); }); @@ -136,7 +136,7 @@ auto BrowserDialogWindow::run() -> lstring { if(!state.filters) state.filters.append("All|*"); for(auto& filter : state.filters) { - auto part = filter.split<1>("|"); + auto part = filter.split("|", 1L); filters.append(part.last().split(":")); } @@ -165,7 +165,7 @@ auto BrowserDialogWindow::setPath(string path) -> void { view.append(ListViewColumn().setExpandable()); view.append(ListViewColumn().setForegroundColor({192, 128, 128})); - auto contents = directory::contents(path); + auto contents = directory::icontents(path); bool folderMode = state.action == "openFolder"; for(auto content : contents) { @@ -175,7 +175,7 @@ auto BrowserDialogWindow::setPath(string path) -> void { view.append(ListViewItem() .append(ListViewCell().setText(content).setIcon(Icon::Emblem::Folder)) - .append(ListViewCell().setText(octal<3>(storage::mode({path, content}) & 0777))) + .append(ListViewCell().setText(octal(storage::mode({path, content}) & 0777, 3L))) ); } @@ -186,7 +186,7 @@ auto BrowserDialogWindow::setPath(string path) -> void { view.append(ListViewItem() .append(ListViewCell().setText(content).setIcon(folderMode ? Icon::Action::Open : Icon::Emblem::File)) - .append(ListViewCell().setText(octal<3>(storage::mode({path, content}) & 0777))) + .append(ListViewCell().setText(octal(storage::mode({path, content}) & 0777, 3L))) ); } diff --git a/hiro/gtk/browser-window.cpp b/hiro/gtk/browser-window.cpp index 9fed6d08..1cffbfd4 100644 --- a/hiro/gtk/browser-window.cpp +++ b/hiro/gtk/browser-window.cpp @@ -6,7 +6,7 @@ static void BrowserWindow_addFilters(GtkWidget* dialog, lstring filters) { for(auto& filter : filters) { GtkFileFilter* gtkFilter = gtk_file_filter_new(); gtk_file_filter_set_name(gtkFilter, filter); - lstring patterns = filter.split<1>("(")(1).rtrim(")").split(",").strip(); + lstring patterns = filter.split("(", 1L)(1).rtrim(")", 1L).split(",").strip(); for(auto& pattern : patterns) gtk_file_filter_add_pattern(gtkFilter, pattern); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), gtkFilter); } diff --git a/hiro/gtk/font.cpp b/hiro/gtk/font.cpp index f5e09190..5addb5c6 100644 --- a/hiro/gtk/font.cpp +++ b/hiro/gtk/font.cpp @@ -27,7 +27,7 @@ auto pFont::size(string font, string text) -> Size { } auto pFont::create(string description) -> PangoFontDescription* { - lstring part = description.split<2>(",").strip(); + lstring part = description.split(",", 2L).strip(); string family = "Sans"; unsigned size = 8u; diff --git a/hiro/gtk/widget/hex-edit.cpp b/hiro/gtk/widget/hex-edit.cpp index 49e1d75e..fe128353 100644 --- a/hiro/gtk/widget/hex-edit.cpp +++ b/hiro/gtk/widget/hex-edit.cpp @@ -122,7 +122,7 @@ auto pHexEdit::update() -> void { string output; unsigned offset = state().offset; for(auto row : range(state().rows)) { - output.append(hex<8>(offset)); + output.append(hex(offset, 8L)); output.append(" "); string hexdata; @@ -130,7 +130,7 @@ auto pHexEdit::update() -> void { for(auto column : range(state().columns)) { if(offset < state().length) { uint8_t data = self().doRead(offset++); - hexdata.append(hex<2>(data)); + hexdata.append(hex(data, 2L)); hexdata.append(" "); ansidata.append(data >= 0x20 && data <= 0x7e ? (char)data : '.'); } else { diff --git a/hiro/qt/font.cpp b/hiro/qt/font.cpp index 58542f67..ab964054 100644 --- a/hiro/qt/font.cpp +++ b/hiro/qt/font.cpp @@ -23,7 +23,7 @@ Size pFont::size(string font, string text) { } QFont pFont::create(string description) { - lstring part = description.split<2>(",").strip(); + lstring part = description.split(",", 2L).strip(); string family = "Sans"; unsigned size = 8u; diff --git a/hiro/windows/browser-window.cpp b/hiro/windows/browser-window.cpp index eef3f47e..c439c935 100644 --- a/hiro/windows/browser-window.cpp +++ b/hiro/windows/browser-window.cpp @@ -21,7 +21,7 @@ static auto BrowserWindow_fileDialog(bool save, BrowserWindow::State& state) -> for(auto& filter : state.filters) { lstring part = filter.split("("); if(part.size() != 2) continue; - part[1].rtrim(")"); + part[1].rtrim(")", 1L); part[1].replace(" ", ""); part[1].transform(",", ";"); filters.append(filter, "\t", part[1], "\t"); diff --git a/hiro/windows/font.cpp b/hiro/windows/font.cpp index f76baa79..80d240be 100644 --- a/hiro/windows/font.cpp +++ b/hiro/windows/font.cpp @@ -28,7 +28,7 @@ auto pFont::size(const string& font, const string& text) -> Size { } auto pFont::create(const string& description) -> HFONT { - lstring part = description.split<2>(",").strip(); + lstring part = description.split(",", 2L).strip(); string family = "Tahoma"; unsigned size = 8u; diff --git a/hiro/windows/widget/hex-edit.cpp b/hiro/windows/widget/hex-edit.cpp index 6a8f7880..c241675a 100644 --- a/hiro/windows/widget/hex-edit.cpp +++ b/hiro/windows/widget/hex-edit.cpp @@ -122,7 +122,7 @@ auto pHexEdit::update() -> void { string output; unsigned offset = state().offset; for(auto row : range(state().rows)) { - output.append(hex<8>(offset)); + output.append(hex(offset, 8L)); output.append(" "); string hexdata; @@ -130,7 +130,7 @@ auto pHexEdit::update() -> void { for(auto column : range(state().columns)) { if(offset < state().length) { uint8_t data = self().doRead(offset++); - hexdata.append(hex<2>(data)); + hexdata.append(hex(data, 2L)); hexdata.append(" "); ansidata.append(data >= 0x20 && data <= 0x7e ? (char)data : '.'); } else { diff --git a/nall/atoi.hpp b/nall/atoi.hpp index 86f05f32..5141e296 100644 --- a/nall/atoi.hpp +++ b/nall/atoi.hpp @@ -5,7 +5,7 @@ namespace nall { -constexpr inline uintmax_t binary_(const char* s, uintmax_t sum = 0) { +constexpr inline auto binary_(const char* s, uintmax_t sum = 0) -> uintmax_t { return ( *s == '0' || *s == '1' ? binary_(s + 1, (sum << 1) | *s - '0') : *s == '\'' ? binary_(s + 1, sum) : @@ -13,7 +13,7 @@ constexpr inline uintmax_t binary_(const char* s, uintmax_t sum = 0) { ); } -constexpr inline uintmax_t octal_(const char* s, uintmax_t sum = 0) { +constexpr inline auto octal_(const char* s, uintmax_t sum = 0) -> uintmax_t { return ( *s >= '0' && *s <= '7' ? octal_(s + 1, (sum << 3) | *s - '0') : *s == '\'' ? octal_(s + 1, sum) : @@ -21,7 +21,7 @@ constexpr inline uintmax_t octal_(const char* s, uintmax_t sum = 0) { ); } -constexpr inline uintmax_t decimal_(const char* s, uintmax_t sum = 0) { +constexpr inline auto decimal_(const char* s, uintmax_t sum = 0) -> uintmax_t { return ( *s >= '0' && *s <= '9' ? decimal_(s + 1, (sum * 10) + *s - '0') : *s == '\'' ? decimal_(s + 1, sum) : @@ -29,7 +29,7 @@ constexpr inline uintmax_t decimal_(const char* s, uintmax_t sum = 0) { ); } -constexpr inline uintmax_t hex_(const char* s, uintmax_t sum = 0) { +constexpr inline auto hex_(const char* s, uintmax_t sum = 0) -> uintmax_t { return ( *s >= 'A' && *s <= 'F' ? hex_(s + 1, (sum << 4) | *s - 'A' + 10) : *s >= 'a' && *s <= 'f' ? hex_(s + 1, (sum << 4) | *s - 'a' + 10) : @@ -41,7 +41,7 @@ constexpr inline uintmax_t hex_(const char* s, uintmax_t sum = 0) { // -constexpr inline uintmax_t binary(const char* s) { +constexpr inline auto binary(const char* s) -> uintmax_t { return ( *s == '0' && *(s + 1) == 'B' ? binary_(s + 2) : *s == '0' && *(s + 1) == 'b' ? binary_(s + 2) : @@ -50,7 +50,7 @@ constexpr inline uintmax_t binary(const char* s) { ); } -constexpr inline uintmax_t octal(const char* s) { +constexpr inline auto octal(const char* s) -> uintmax_t { return ( *s == '0' && *(s + 1) == 'O' ? octal_(s + 2) : *s == '0' && *(s + 1) == 'o' ? octal_(s + 2) : @@ -58,7 +58,7 @@ constexpr inline uintmax_t octal(const char* s) { ); } -constexpr inline intmax_t integer(const char* s) { +constexpr inline auto integer(const char* s) -> intmax_t { return ( *s == '+' ? +decimal_(s + 1) : *s == '-' ? -decimal_(s + 1) : @@ -66,13 +66,13 @@ constexpr inline intmax_t integer(const char* s) { ); } -constexpr inline uintmax_t decimal(const char* s) { +constexpr inline auto decimal(const char* s) -> uintmax_t { return ( decimal_(s) ); } -constexpr inline uintmax_t hex(const char* s) { +constexpr inline auto hex(const char* s) -> uintmax_t { return ( *s == '0' && *(s + 1) == 'X' ? hex_(s + 2) : *s == '0' && *(s + 1) == 'x' ? hex_(s + 2) : @@ -81,7 +81,7 @@ constexpr inline uintmax_t hex(const char* s) { ); } -inline double real(const char* s) { +inline auto real(const char* s) -> double { return atof(s); } diff --git a/nall/beat/archive.hpp b/nall/beat/archive.hpp index f3fce618..c5a8f652 100644 --- a/nall/beat/archive.hpp +++ b/nall/beat/archive.hpp @@ -1,84 +1,123 @@ #ifndef NALL_BEAT_ARCHIVE_HPP #define NALL_BEAT_ARCHIVE_HPP -#include +#include -namespace nall { +namespace nall { namespace Beat { -struct beatArchive : beatBase { - bool create(const string& beatname, string pathname, const string& metadata = "") { - if(fp.open(beatname, file::mode::write) == false) return false; - if(pathname.endsWith("/") == false) pathname.append("/"); +struct Archive { + static auto create(const string& beatname, const string& pathname, const string& metadata = "") -> bool; + static auto unpack(const string& beatname, const string& pathname) -> bool; + static auto extract(const string& beatname, const string& pathname) -> vector; - checksum.reset(); - writeString("BPA1"); - writeNumber(metadata.length()); - writeString(metadata); - - lstring list; - ls(list, pathname, pathname); - for(auto &name : list) { - if(name.endsWith("/")) { - name.rtrim("/"); - writeNumber(0 | ((name.length() - 1) << 1)); - writeString(name); - } else { - file stream; - if(stream.open({pathname, name}, file::mode::read) == false) return false; - writeNumber(1 | ((name.length() - 1) << 1)); - writeString(name); - unsigned size = stream.size(); - writeNumber(size); - Hash::CRC32 checksum; - while(size--) { - uint8_t data = stream.read(); - write(data); - checksum.data(data); - } - writeChecksum(checksum.value()); - } - } - - writeChecksum(checksum.value()); - fp.close(); - return true; - } - - bool unpack(const string& beatname, string pathname) { - if(fp.open(beatname, file::mode::read) == false) return false; - if(pathname.endsWith("/") == false) pathname.append("/"); - - checksum.reset(); - if(readString(4) != "BPA1") return false; - unsigned length = readNumber(); - while(length--) read(); - - directory::create(pathname); - while(fp.offset() < fp.size() - 4) { - unsigned data = readNumber(); - string name = readString((data >> 1) + 1); - if(name.find("\\") || name.find("../")) return false; //block path exploits - - if((data & 1) == 0) { - directory::create({pathname, name}); - } else { - file stream; - if(stream.open({pathname, name}, file::mode::write) == false) return false; - unsigned size = readNumber(); - Hash::CRC32 checksum; - while(size--) { - uint8_t data = read(); - stream.write(data); - checksum.data(data); - } - if(readChecksum(checksum.value()) == false) return false; - } - } - - return readChecksum(checksum.value()); - } +private: + static auto scan(lstring& result, const string& basename, const string& pathname) -> void; }; +auto Archive::create(const string& beatname, const string& pathname, const string& metadata) -> bool { + if(!beatname.endsWith(".bpa") || !pathname.endsWith("/")) return false; //protect against reversed arguments + + File beat{beatname, file::mode::write}; + if(!beat) return false; //file not writable? + + beat.writes("BPA1"); + beat.writevu(metadata.size()); + beat.writes(metadata); + + lstring contents; + scan(contents, pathname, pathname); + + for(auto& name : contents) { + if(name.endsWith("/")) { + name.rtrim("/"); + beat.writevu(0 | ((name.length() - 1) << 1)); + beat.writes(name); + } else { + File input{{pathname, name}, file::mode::read}; + if(!input) return false; + + beat.writevu(1 | ((name.length() - 1) << 1)); + beat.writes(name); + auto size = input.size(); + beat.writevu(size); + while(size--) beat.write(input.read()); + beat.writel(input.checksum.value(), 4); + } + } + + beat.writel(beat.checksum.value(), 4); + return true; } +auto Archive::unpack(const string& beatname, const string& pathname) -> bool { + if(!beatname.endsWith(".bpa") || !pathname.endsWith("/")) return false; //protect against reversed arguments + + File beat{beatname, file::mode::read}; + if(!beat) return false; //file not readable? + + if(beat.reads(4) != "BPA1") return false; + auto size = beat.readvu(); + while(size--) beat.read(); + + directory::create(pathname); + while(beat.offset() < beat.size() - 4) { + auto data = beat.readvu(); + auto name = beat.reads((data >> 1) + 1); + if(name.find("\\") || name.find("../")) return false; //block path exploits + + if((data & 1) == 0) { + directory::create({pathname, name}); + } else { + File output{{pathname, name}, file::mode::write}; + if(!output) return false; + + auto size = beat.readvu(); + while(size--) output.write(beat.read()); + if(beat.readl(4) != output.checksum.value()) return false; + } + } + + uint32_t checksum = beat.checksum.value(); + return beat.readl(4) == checksum; +} + +auto Archive::extract(const string& beatname, const string& filename) -> vector { + File beat{beatname, file::mode::read}; + if(!beat) return {}; //file not readable? + + if(beat.reads(4) != "BPA1") return {}; + auto size = beat.readvu(); + beat.seek(beat.offset() + size); + + while(beat.offset() < beat.size() - 4) { + auto data = beat.readvu(); + auto name = beat.reads((data >> 1) + 1); + if((data & 1) == 0) continue; + auto size = beat.readvu(); + if(name != filename) { + beat.seek(beat.offset() + size + 4); + continue; + } + + vector result; + result.resize(size); + beat.checksum.reset(); + for(auto n : range(size)) result[n] = beat.read(); + uint32_t checksum = beat.checksum.value(); + if(beat.readl(4) != checksum) return {}; + return result; + } + + return {}; +} + +auto Archive::scan(lstring& result, const string& basename, const string& pathname) -> void { + for(auto& name : directory::contents(pathname)) { + result.append(string{pathname, name}.ltrim(basename, 1L)); + if(name.endsWith("/")) scan(result, basename, {pathname, name}); + } +} + +}} + #endif diff --git a/nall/beat/base.hpp b/nall/beat/base.hpp deleted file mode 100644 index 7d021d52..00000000 --- a/nall/beat/base.hpp +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef NALL_BEAT_BASE_HPP -#define NALL_BEAT_BASE_HPP - -namespace nall { - -struct beatBase { -protected: - file fp; - Hash::CRC32 checksum; - - void ls(lstring& list, const string& path, const string& basepath) { - lstring paths = directory::folders(path); - for(auto& pathname : paths) { - list.append(string{path, pathname}.ltrim(basepath)); - ls(list, {path, pathname}, basepath); - } - - lstring files = directory::files(path); - for(auto& filename : files) { - list.append(string{path, filename}.ltrim(basepath)); - } - } - - void write(uint8_t data) { - fp.write(data); - checksum.data(data); - } - - void writeNumber(uint64_t data) { - while(true) { - uint64_t x = data & 0x7f; - data >>= 7; - if(data == 0) return write(0x80 | x); - write(x); - data--; - } - } - - void writeString(const string& text) { - unsigned length = text.length(); - for(unsigned n = 0; n < length; n++) write(text[n]); - } - - void writeChecksum(uint32_t checksum) { - write(checksum >> 0); - write(checksum >> 8); - write(checksum >> 16); - write(checksum >> 24); - } - - uint8_t read() { - uint8_t data = fp.read(); - checksum.data(data); - return data; - } - - uint64_t readNumber() { - uint64_t data = 0, shift = 1; - while(true) { - uint8_t x = read(); - data += (x & 0x7f) * shift; - if(x & 0x80) break; - shift <<= 7; - data += shift; - } - return data; - } - - string readString(unsigned length) { - string text; - text.resize(length + 1); - char* p = text.pointer(); - while(length--) { - *p = fp.read(); - checksum.data(*p++); - } - return text; - } - - bool readChecksum(uint32_t source) { - uint32_t checksum = 0; - checksum |= read() << 0; - checksum |= read() << 8; - checksum |= read() << 16; - checksum |= read() << 24; - return checksum == source; - } -}; - -} - -#endif diff --git a/nall/beat/file.hpp b/nall/beat/file.hpp new file mode 100644 index 00000000..37593900 --- /dev/null +++ b/nall/beat/file.hpp @@ -0,0 +1,26 @@ +#ifndef NALL_BEAT_FILE_HPP +#define NALL_BEAT_FILE_HPP + +namespace nall { namespace Beat { + +struct File : file { + using file::file; + auto read() -> uint8_t override; + auto write(uint8_t) -> void override; + Hash::CRC32 checksum; +}; + +auto File::read() -> uint8_t { + uint8_t data = file::read(); + checksum.data(data); + return data; +} + +auto File::write(uint8_t data) -> void { + checksum.data(data); + return file::write(data); +} + +}} + +#endif diff --git a/nall/beat/multi.hpp b/nall/beat/multi.hpp index 6d9428d6..a9e15796 100644 --- a/nall/beat/multi.hpp +++ b/nall/beat/multi.hpp @@ -160,13 +160,13 @@ protected: void ls(lstring& list, const string& path, const string& basepath) { lstring paths = directory::folders(path); for(auto& pathname : paths) { - list.append(string{path, pathname}.ltrim(basepath)); + list.append(string{path, pathname}.ltrim(basepath, 1L)); ls(list, {path, pathname}, basepath); } lstring files = directory::files(path); for(auto& filename : files) { - list.append(string{path, filename}.ltrim(basepath)); + list.append(string{path, filename}.ltrim(basepath, 1L)); } } diff --git a/nall/bit.hpp b/nall/bit.hpp index c1cb15ee..818313e4 100644 --- a/nall/bit.hpp +++ b/nall/bit.hpp @@ -5,28 +5,28 @@ namespace nall { -template inline uintmax_t uclamp(const uintmax_t x) { +template inline auto uclamp(const uintmax_t x) -> uintmax_t { enum : uintmax_t { b = 1ull << (bits - 1), y = b * 2 - 1 }; return y + ((x - y) & -(x < y)); //min(x, y); } -template inline uintmax_t uclip(const uintmax_t x) { +template inline auto uclip(const uintmax_t x) -> uintmax_t { enum : uintmax_t { b = 1ull << (bits - 1), m = b * 2 - 1 }; return (x & m); } -template inline intmax_t sclamp(const intmax_t x) { +template inline auto sclamp(const intmax_t x) -> intmax_t { enum : intmax_t { b = 1ull << (bits - 1), m = b - 1 }; return (x > m) ? m : (x < -b) ? -b : x; } -template inline intmax_t sclip(const intmax_t x) { +template inline auto sclip(const intmax_t x) -> intmax_t { enum : uintmax_t { b = 1ull << (bits - 1), m = b * 2 - 1 }; return ((x & m) ^ b) - b; } namespace bit { - constexpr inline uintmax_t mask(const char* s, uintmax_t sum = 0) { + constexpr inline auto mask(const char* s, uintmax_t sum = 0) -> uintmax_t { return ( *s == '0' || *s == '1' ? mask(s + 1, (sum << 1) | 1) : *s == ' ' || *s == '_' ? mask(s + 1, sum) : @@ -35,7 +35,7 @@ namespace bit { ); } - constexpr inline uintmax_t test(const char* s, uintmax_t sum = 0) { + constexpr inline auto test(const char* s, uintmax_t sum = 0) -> uintmax_t { return ( *s == '0' || *s == '1' ? test(s + 1, (sum << 1) | (*s - '0')) : *s == ' ' || *s == '_' ? test(s + 1, sum) : @@ -45,22 +45,22 @@ namespace bit { } //lowest(0b1110) == 0b0010 - constexpr inline uintmax_t lowest(const uintmax_t x) { + constexpr inline auto lowest(const uintmax_t x) -> uintmax_t { return x & -x; } //clear_lowest(0b1110) == 0b1100 - constexpr inline uintmax_t clear_lowest(const uintmax_t x) { + constexpr inline auto clear_lowest(const uintmax_t x) -> uintmax_t { return x & (x - 1); } //set_lowest(0b0101) == 0b0111 - constexpr inline uintmax_t set_lowest(const uintmax_t x) { + constexpr inline auto set_lowest(const uintmax_t x) -> uintmax_t { return x | (x + 1); } //count number of bits set in a byte - inline unsigned count(uintmax_t x) { + inline auto count(uintmax_t x) -> unsigned { unsigned count = 0; do count += x & 1; while(x >>= 1); return count; @@ -68,7 +68,7 @@ namespace bit { //return index of the first bit set (or zero of no bits are set) //first(0b1000) == 3 - inline unsigned first(uintmax_t x) { + inline auto first(uintmax_t x) -> unsigned { unsigned first = 0; while(x) { if(x & 1) break; x >>= 1; first++; } return first; @@ -76,7 +76,7 @@ namespace bit { //round up to next highest single bit: //round(15) == 16, round(16) == 16, round(17) == 32 - inline uintmax_t round(uintmax_t x) { + inline auto round(uintmax_t x) -> uintmax_t { if((x & (x - 1)) == 0) return x; while(x & (x - 1)) x &= x - 1; return x << 1; diff --git a/nall/bitvector.hpp b/nall/bitvector.hpp index 0294b111..24e9d8e4 100644 --- a/nall/bitvector.hpp +++ b/nall/bitvector.hpp @@ -4,25 +4,20 @@ namespace nall { struct bitvector { -protected: - uint8_t* pool = nullptr; - unsigned bits = 0; - -public: - bitvector() {} + bitvector() = default; bitvector(unsigned size) { resize(size); } bitvector(const bitvector& source) { operator=(source); } - bitvector(bitvector&& source) { operator=(std::move(source)); } + bitvector(bitvector&& source) { operator=(move(source)); } ~bitvector() { reset(); } - bitvector& operator=(const bitvector& source) { + auto operator=(const bitvector& source) -> bitvector& { bits = source.bits; - pool = (uint8_t*)realloc(pool, bytes()); - memcpy(pool, source.pool, bytes()); + pool = (uint8_t*)memory::resize(pool, bytes()); + memory::copy(pool, source.pool, bytes()); return *this; } - bitvector& operator=(bitvector&& source) { + auto operator=(bitvector&& source) -> bitvector& { pool = source.pool; bits = source.bits; source.pool = nullptr; @@ -31,86 +26,90 @@ public: } explicit operator bool() const { return bits > 0; } - bool empty() const { return bits == 0; } - unsigned size() const { return bits; } - unsigned bytes() const { return (bits + 7) / 8; } - uint8_t* data() { return pool; } - const uint8_t* data() const { return pool; } + auto empty() const -> bool { return bits == 0; } + auto size() const -> unsigned { return bits; } + auto bytes() const -> unsigned { return (bits + 7) / 8; } + auto data() -> uint8_t* { return pool; } + auto data() const -> const uint8_t* { return pool; } - void reset() { + auto reset() -> void { if(pool) free(pool); pool = nullptr; bits = 0; } - void resize(unsigned size) { + auto resize(unsigned size) -> void { unsigned from = bits; bits = size; for(unsigned n = size; n < from; n++) clear(n); //on reduce - pool = (uint8_t*)realloc(pool, bytes()); + pool = (uint8_t*)memory::resize(pool, bytes()); for(unsigned n = from; n < size; n++) clear(n); //on expand } - bool get(unsigned position) const { + auto get(unsigned position) const -> bool { return pool[position >> 3] & (0x80 >> (position & 7)); } - void clear() { - memset(pool, 0x00, bytes()); + auto clear() -> void { + memory::fill(pool, bytes(), 0x00); } - void set() { - memset(pool, 0xff, bytes()); + auto set() -> void { + memory::fill(pool, bytes(), 0xff); for(unsigned n = bits; n < bytes() * 8; n++) clear(n); } - void clear(unsigned position) { + auto clear(unsigned position) -> void { pool[position >> 3] &= ~(0x80 >> (position & 7)); } - void set(unsigned position) { + auto set(unsigned position) -> void { pool[position >> 3] |= (0x80 >> (position & 7)); } - void invert(unsigned position) { + auto invert(unsigned position) -> void { get(position) ? clear(position) : set(position); } - void set(unsigned position, bool value) { + auto set(unsigned position, bool value) -> void { value ? set(position) : clear(position); } struct reference { reference(bitvector& self, unsigned position) : self(self), position(position) {} operator bool() const { return self.get(position); } - void operator=(bool value) { self.set(position, value); } + auto operator=(bool value) -> reference& { self.set(position, value); return *this; } protected: bitvector& self; unsigned position; }; - reference operator[](unsigned position) { + auto operator[](unsigned position) -> reference { return reference(*this, position); } - bool operator[](unsigned position) const { + auto operator[](unsigned position) const -> bool { return get(position); } struct iterator { iterator(bitvector& self, unsigned position) : self(self), position(position) {} - bool operator!=(const iterator& source) const { return position != source.position; } - iterator& operator++() { position++; return *this; } - reference operator*() { return self.operator[](position); } + auto operator!=(const iterator& source) const -> bool { return position != source.position; } + auto operator++() -> iterator& { position++; return *this; } + auto operator*() -> reference { return self.operator[](position); } protected: bitvector& self; unsigned position; }; - iterator begin() { return iterator(*this, 0); } - iterator end() { return iterator(*this, bits); } + auto begin() -> iterator { return iterator(*this, 0); } + auto end() -> iterator { return iterator(*this, bits); } + +protected: + uint8_t* pool = nullptr; + unsigned bits = 0; }; } diff --git a/nall/bmp.hpp b/nall/bmp.hpp index 9e68617e..6c39f13a 100644 --- a/nall/bmp.hpp +++ b/nall/bmp.hpp @@ -9,11 +9,11 @@ namespace nall { struct bmp { - inline static bool read(const string& filename, uint32_t*& data, unsigned& width, unsigned& height); - inline static bool write(const string& filename, const uint32_t* data, unsigned width, unsigned height, unsigned pitch, bool alpha = false); + inline static auto read(const string& filename, uint32_t*& data, unsigned& width, unsigned& height) -> bool; + inline static auto write(const string& filename, const uint32_t* data, unsigned width, unsigned height, unsigned pitch, bool alpha = false) -> bool; }; -bool bmp::read(const string& filename, uint32_t*& data, unsigned& width, unsigned& height) { +auto bmp::read(const string& filename, uint32_t*& data, unsigned& width, unsigned& height) -> bool { file fp; if(fp.open(filename, file::mode::read) == false) return false; if(fp.size() < 0x36) return false; @@ -55,7 +55,7 @@ bool bmp::read(const string& filename, uint32_t*& data, unsigned& width, unsigne return true; } -bool bmp::write(const string& filename, const uint32_t* data, unsigned width, unsigned height, unsigned pitch, bool alpha) { +auto bmp::write(const string& filename, const uint32_t* data, unsigned width, unsigned height, unsigned pitch, bool alpha) -> bool { file fp; if(fp.open(filename, file::mode::write) == false) return false; diff --git a/nall/config.hpp b/nall/config.hpp index b655b515..9937b764 100644 --- a/nall/config.hpp +++ b/nall/config.hpp @@ -15,11 +15,11 @@ struct Node { void* data = nullptr; vector children; - bool empty() const { + auto empty() const -> bool { return data == nullptr; } - string get() const { + auto get() const -> string { switch(type) { case Type::Bool: return {*(bool*)data}; case Type::Signed: return {*(signed*)data}; @@ -30,7 +30,7 @@ struct Node { return ""; } - void set(const string& value) { + auto set(const string& value) -> void { switch(type) { case Type::Bool: *(bool*)data = (value != "false"); break; case Type::Signed: *(signed*)data = integer(value); break; @@ -40,15 +40,15 @@ struct Node { } } - void assign() { type = Type::Null; data = nullptr; } - void assign(bool& bind) { type = Type::Bool; data = (void*)&bind; } - void assign(signed& bind) { type = Type::Signed; data = (void*)&bind; } - void assign(unsigned& bind) { type = Type::Unsigned; data = (void*)&bind; } - void assign(double& bind) { type = Type::Double; data = (void*)&bind; } - void assign(string& bind) { type = Type::String; data = (void*)&bind; } - void assign(const Node& node) { operator=(node); } + auto assign() { type = Type::Null; data = nullptr; } + auto assign(bool& bind) { type = Type::Bool; data = (void*)&bind; } + auto assign(signed& bind) { type = Type::Signed; data = (void*)&bind; } + auto assign(unsigned& bind) { type = Type::Unsigned; data = (void*)&bind; } + auto assign(double& bind) { type = Type::Double; data = (void*)&bind; } + auto assign(string& bind) { type = Type::String; data = (void*)&bind; } + auto assign(const Node& node) { operator=(node); } - template void append(T& data, const string& name, const string& desc = "") { + template auto append(T& data, const string& name, const string& desc = "") -> void { Node node; node.assign(data); node.name = name; @@ -56,7 +56,7 @@ struct Node { children.append(node); } - void load(Markup::Node path) { + auto load(Markup::Node path) -> void { for(auto& child : children) { if(auto leaf = path[child.name]) { if(!child.empty()) child.set(leaf.text()); @@ -65,7 +65,7 @@ struct Node { } } - void save(file& fp, unsigned depth = 0) { + auto save(file& fp, unsigned depth = 0) -> void { for(auto& child : children) { if(child.desc) { for(unsigned n = 0; n < depth; n++) fp.print(" "); @@ -82,14 +82,14 @@ struct Node { }; struct Document : Node { - bool load(const string& filename) { + auto load(const string& filename) -> bool { if(!file::exists(filename)) return false; auto document = BML::unserialize(string::read(filename)); Node::load(document); return true; } - bool save(const string& filename) { + auto save(const string& filename) -> bool { file fp(filename, file::mode::write); if(!fp.open()) return false; Node::save(fp); diff --git a/nall/database/odbc.hpp b/nall/database/odbc.hpp new file mode 100644 index 00000000..5abf2062 --- /dev/null +++ b/nall/database/odbc.hpp @@ -0,0 +1,274 @@ +#ifndef NALL_DATABASE_ODBC_HPP +#define NALL_DATABASE_ODBC_HPP + +#include + +#include +#include +#include + +namespace nall { namespace Database { + +struct ODBC { + struct Statement { + Statement(const Statement& source) = delete; + auto operator=(const Statement& source) -> Statement& = delete; + + Statement(SQLHANDLE statement) : _statement(statement) {} + Statement(Statement&& source) { operator=(move(source)); } + + auto operator=(Statement&& source) -> Statement& { + _statement = source._statement; + _output = source._output; + source._statement = nullptr; + source._output = 0; + return *this; + } + + auto integer(unsigned column) -> int64_t { + int64_t value = 0; + SQLGetData(statement(), 1 + column, SQL_C_SBIGINT, &value, 0, nullptr); + return value; + } + + auto decimal(unsigned column) -> uint64_t { + uint64_t value = 0; + SQLGetData(statement(), 1 + column, SQL_C_UBIGINT, &value, 0, nullptr); + return value; + } + + auto real(unsigned column) -> double { + double value = 0.0; + SQLGetData(statement(), 1 + column, SQL_C_DOUBLE, &value, 0, nullptr); + return value; + } + + auto text(unsigned column) -> string { + string value; + value.resize(65535); + SQLLEN size = 0; + SQLGetData(statement(), 1 + column, SQL_C_CHAR, value.pointer(), value.size(), &size); + value.resize(size); + return value; + } + + auto data(unsigned column) -> vector { + vector value; + value.resize(65535); + SQLLEN size = 0; + SQLGetData(statement(), 1 + column, SQL_C_CHAR, value.data(), value.size(), &size); + value.resize(size); + return value; + } + + auto integer() -> int64_t { return integer(_output++); } + auto decimal() -> uint64_t { return decimal(_output++); } + auto real() -> double { return real(_output++); } + auto text() -> string { return text(_output++); } + auto data() -> vector { return data(_output++); } + + protected: + virtual auto statement() -> SQLHANDLE { return _statement; } + + SQLHANDLE _statement = nullptr; + unsigned _output = 0; + }; + + struct Query : Statement { + Query(const Query& source) = delete; + auto operator=(const Query& source) -> Query& = delete; + + Query(SQLHANDLE statement) : Statement(statement) {} + Query(Query&& source) : Statement(source._statement) { operator=(move(source)); } + + ~Query() { + if(statement()) { + SQLFreeHandle(SQL_HANDLE_STMT, _statement); + _statement = nullptr; + } + } + + auto operator=(Query&& source) -> Query& { + _bindings = move(source._bindings); + _statement = source._statement; + _result = source._result; + _input = source._input; + _stepped = source._stepped; + source._statement = nullptr; + source._result = SQL_SUCCESS; + source._input = 0; + source._stepped = false; + return *this; + } + + //ODBC SQLBindParameter only holds pointers to data values + //if the bound paramters go out of scope before the query is executed, binding would reference dangling pointers + //so to work around this, we cache all parameters inside Query until the query is executed + + auto& bind(unsigned column, nullptr_t) { return _bindings.append({column, any{(nullptr_t)nullptr}}), *this; } + auto& bind(unsigned column, int32_t value) { return _bindings.append({column, any{(int32_t)value}}), *this; } + auto& bind(unsigned column, uint32_t value) { return _bindings.append({column, any{(uint32_t)value}}), *this; } + auto& bind(unsigned column, int64_t value) { return _bindings.append({column, any{(int64_t)value}}), *this; } + auto& bind(unsigned column, uint64_t value) { return _bindings.append({column, any{(uint64_t)value}}), *this; } + auto& bind(unsigned column, double value) { return _bindings.append({column, any{(double)value}}), *this; } + auto& bind(unsigned column, const string& value) { return _bindings.append({column, any{(string)value}}), *this; } + auto& bind(unsigned column, const vector& value) { return _bindings.append({column, any{(vector)value}}), *this; } + + auto& bind(nullptr_t) { return bind(_input++, nullptr); } + auto& bind(int32_t value) { return bind(_input++, value); } + auto& bind(uint32_t value) { return bind(_input++, value); } + auto& bind(int64_t value) { return bind(_input++, value); } + auto& bind(uint64_t value) { return bind(_input++, value); } + auto& bind(double value) { return bind(_input++, value); } + auto& bind(const string& value) { return bind(_input++, value); } + auto& bind(const vector& value) { return bind(_input++, value); } + + auto step() -> bool { + if(!_stepped) { + for(auto& binding : _bindings) { + if(binding.value.is()) { + SQLLEN length = SQL_NULL_DATA; + SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_NUMERIC, SQL_NUMERIC, 0, 0, nullptr, 0, &length); + } else if(binding.value.is()) { + SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &binding.value.get(), 0, nullptr); + } else if(binding.value.is()) { + SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, 0, 0, &binding.value.get(), 0, nullptr); + } else if(binding.value.is()) { + SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_INTEGER, 0, 0, &binding.value.get(), 0, nullptr); + } else if(binding.value.is()) { + SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_UBIGINT, SQL_INTEGER, 0, 0, &binding.value.get(), 0, nullptr); + } else if(binding.value.is()) { + SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, 0, 0, &binding.value.get(), 0, nullptr); + } else if(binding.value.is()) { + SQLLEN length = SQL_NTS; + SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 0, 0, (SQLPOINTER)binding.value.get().data(), 0, &length); + } else if(binding.value.is>()) { + SQLLEN length = binding.value.get>().size(); + SQLBindParameter(_statement, 1 + binding.column, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARBINARY, 0, 0, (SQLPOINTER)binding.value.get>().data(), 0, &length); + } + } + + _stepped = true; + _result = SQLExecute(_statement); + if(!success()) return false; + } + + _result = SQLFetch(_statement); + _output = 0; + return success(); + } + + struct Iterator { + Iterator(Query& query, bool finished) : query(query), finished(finished) {} + auto operator*() -> Statement { return query._statement; } + auto operator!=(const Iterator& source) const -> bool { return finished != source.finished; } + auto operator++() -> Iterator& { finished = !query.step(); return *this; } + + protected: + Query& query; + bool finished = false; + }; + + auto begin() -> Iterator { return Iterator(*this, !step()); } + auto end() -> Iterator { return Iterator(*this, true); } + + private: + auto success() const -> bool { + return _result == SQL_SUCCESS || _result == SQL_SUCCESS_WITH_INFO; + } + + auto statement() -> SQLHANDLE override { + if(!_stepped) step(); + return _statement; + } + + struct Binding { + unsigned column; + any value; + }; + vector _bindings; + + SQLRETURN _result = SQL_SUCCESS; + unsigned _input = 0; + bool _stepped = false; + }; + + ODBC() { + _result = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &_environment); + if(!success()) return; + + SQLSetEnvAttr(_environment, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0); + } + + ODBC(const string& database, const string& username, const string& password) : ODBC() { + open(database, username, password); + } + + ~ODBC() { + if(_environment) { + close(); + SQLFreeHandle(SQL_HANDLE_ENV, _environment); + _environment = nullptr; + } + } + + explicit operator bool() const { return _connection; } + + auto open(const string& database, const string& username, const string& password) -> bool { + if(!_environment) return false; + close(); + + _result = SQLAllocHandle(SQL_HANDLE_DBC, _environment, &_connection); + if(!success()) return false; + + SQLSetConnectAttr(_connection, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0); + _result = SQLConnectA(_connection, + (SQLCHAR*)database.data(), SQL_NTS, + (SQLCHAR*)username.data(), SQL_NTS, + (SQLCHAR*)password.data(), SQL_NTS + ); + if(!success()) return close(), false; + + return true; + } + + auto close() -> void { + if(_connection) { + SQLDisconnect(_connection); + SQLFreeHandle(SQL_HANDLE_DBC, _connection); + _connection = nullptr; + } + } + + template auto execute(const string& statement, P&&... p) -> Query { + if(!_connection) return {nullptr}; + + SQLHANDLE _statement = nullptr; + _result = SQLAllocHandle(SQL_HANDLE_STMT, _connection, &_statement); + if(!success()) return {nullptr}; + + Query query{_statement}; + _result = SQLPrepareA(_statement, (SQLCHAR*)statement.data(), SQL_NTS); + if(!success()) return {nullptr}; + + bind(query, forward

(p)...); + return query; + } + +private: + auto success() const -> bool { return _result == SQL_SUCCESS || _result == SQL_SUCCESS_WITH_INFO; } + + auto bind(Query&) -> void {} + template auto bind(Query& query, const T& value, P&&... p) -> void { + query.bind(value); + bind(query, forward

(p)...); + } + + SQLHANDLE _environment = nullptr; + SQLHANDLE _connection = nullptr; + SQLRETURN _result = SQL_SUCCESS; +}; + +}} + +#endif diff --git a/nall/database/sqlite3.hpp b/nall/database/sqlite3.hpp index bd4b1791..6e03e14d 100644 --- a/nall/database/sqlite3.hpp +++ b/nall/database/sqlite3.hpp @@ -15,33 +15,38 @@ namespace nall { namespace Database { struct SQLite3 { struct Statement { - using type = Statement; + Statement(const Statement& source) = delete; + auto operator=(const Statement& source) -> Statement& = delete; - Statement(sqlite3_stmt* stmt) : stmt(stmt) {} - Statement(const Statement& source) { operator=(source); } + Statement(sqlite3_stmt* statement) : _statement(statement) {} Statement(Statement&& source) { operator=(move(source)); } - auto operator=(const Statement& source) -> type& { stmt = source.stmt, stepped = source.stepped, response = source.response; return *this; } - auto operator=(Statement&& source) -> type& { operator=(source); source.stmt = nullptr, source.stepped = false, source.response = SQLITE_OK; return *this; } - explicit operator bool() { return !finished(); } + auto operator=(Statement&& source) -> Statement& { + _statement = source._statement; + _response = source._response; + _output = source._output; + source._statement = nullptr; + source._response = SQLITE_OK; + source._output = 0; + return *this; + } - auto bind(unsigned column, nullptr_t) -> type& { sqlite3_bind_null(stmt, 1 + column); return *this; } - auto bind(unsigned column, int32_t value) -> type& { sqlite3_bind_int(stmt, 1 + column, value); return *this; } - auto bind(unsigned column, uint32_t value) -> type& { sqlite3_bind_int(stmt, 1 + column, value); return *this; } - auto bind(unsigned column, int64_t value) -> type& { sqlite3_bind_int64(stmt, 1 + column, value); return *this; } - auto bind(unsigned column, uint64_t value) -> type& { sqlite3_bind_int64(stmt, 1 + column, value); return *this; } - auto bind(unsigned column, double value) -> type& { sqlite3_bind_double(stmt, 1 + column, value); return *this; } - auto bind(unsigned column, const string& value) -> type& { sqlite3_bind_text(stmt, 1 + column, value.data(), value.size(), SQLITE_TRANSIENT); return *this; } - auto bind(unsigned column, const vector& value) -> type& { sqlite3_bind_blob(stmt, 1 + column, value.data(), value.size(), SQLITE_TRANSIENT); return *this; } + auto integer(unsigned column) -> int64_t { + return sqlite3_column_int64(statement(), column); + } - auto integer(unsigned column) -> int64_t { return sqlite3_column_int64(handle(), column); } - auto decimal(unsigned column) -> uint64_t { return sqlite3_column_int64(handle(), column); } - auto real(unsigned column) -> double { return sqlite3_column_double(handle(), column); } + auto decimal(unsigned column) -> uint64_t { + return sqlite3_column_int64(statement(), column); + } + + auto real(unsigned column) -> double { + return sqlite3_column_double(statement(), column); + } auto text(unsigned column) -> string { string result; - if(auto text = sqlite3_column_text(handle(), column)) { - result.resize(sqlite3_column_bytes(handle(), column)); + if(auto text = sqlite3_column_text(statement(), column)) { + result.resize(sqlite3_column_bytes(statement(), column)); memory::copy(result.pointer(), text, result.size()); } return result; @@ -49,109 +54,143 @@ struct SQLite3 { auto data(unsigned column) -> vector { vector result; - if(auto data = sqlite3_column_blob(handle(), column)) { - result.resize(sqlite3_column_bytes(handle(), column)); + if(auto data = sqlite3_column_blob(statement(), column)) { + result.resize(sqlite3_column_bytes(statement(), column)); memory::copy(result.data(), data, result.size()); } return result; } - auto integer() -> int64_t { return integer(column++); } - auto decimal() -> uint64_t { return decimal(column++); } - auto real() -> double { return real(column++); } - auto text() -> string { return text(column++); } - auto data() -> vector { return data(column++); } + auto integer() -> int64_t { return integer(_output++); } + auto decimal() -> uint64_t { return decimal(_output++); } + auto real() -> double { return real(_output++); } + auto text() -> string { return text(_output++); } + auto data() -> vector { return data(_output++); } protected: - auto step() -> bool { stepped = true; response = sqlite3_step(stmt); return response == SQLITE_ROW; } - auto handle() -> sqlite3_stmt* { if(!stepped) step(); return stmt; } - auto finished() -> bool { handle(); return response != SQLITE_ROW; } - auto finalize() -> void { handle(); sqlite3_finalize(stmt); stmt = nullptr; } + virtual auto statement() -> sqlite3_stmt* { return _statement; } - private: - sqlite3_stmt* stmt = nullptr; - bool stepped = false; - int response = SQLITE_OK; - unsigned column = 0; //this value is not copied/moved via operator= + sqlite3_stmt* _statement = nullptr; + signed _response = SQLITE_OK; + unsigned _output = 0; }; struct Query : Statement { - Query(sqlite3_stmt* stmt) : Statement(stmt) {} - Query(const Query& source) : Statement(source) {} - Query(Query&& source) : Statement(move(source)) {} - ~Query() { finalize(); } + Query(const Query& source) = delete; + auto operator=(const Query& source) -> Query& = delete; - auto operator=(const Query& source) -> Query& { return Statement::operator=(source), *this; } - auto operator=(Query&& source) -> Query& { return Statement::operator=(move(source)), *this; } - explicit operator bool() { return !finished(); } + Query(sqlite3_stmt* statement) : Statement(statement) {} + Query(Query&& source) : Statement(source._statement) { operator=(move(source)); } - using Statement::step; - using Statement::finalize; + ~Query() { + sqlite3_finalize(statement()); + _statement = nullptr; + } + + auto operator=(Query&& source) -> Query& { + _statement = source._statement; + _input = source._input; + source._statement = nullptr; + source._input = 0; + return *this; + } + + auto& bind(unsigned column, nullptr_t) { sqlite3_bind_null(_statement, 1 + column); return *this; } + auto& bind(unsigned column, int32_t value) { sqlite3_bind_int(_statement, 1 + column, value); return *this; } + auto& bind(unsigned column, uint32_t value) { sqlite3_bind_int(_statement, 1 + column, value); return *this; } + auto& bind(unsigned column, int64_t value) { sqlite3_bind_int64(_statement, 1 + column, value); return *this; } + auto& bind(unsigned column, uint64_t value) { sqlite3_bind_int64(_statement, 1 + column, value); return *this; } + auto& bind(unsigned column, double value) { sqlite3_bind_double(_statement, 1 + column, value); return *this; } + auto& bind(unsigned column, const string& value) { sqlite3_bind_text(_statement, 1 + column, value.data(), value.size(), SQLITE_TRANSIENT); return *this; } + auto& bind(unsigned column, const vector& value) { sqlite3_bind_blob(_statement, 1 + column, value.data(), value.size(), SQLITE_TRANSIENT); return *this; } + + auto& bind(nullptr_t) { return bind(_input++, nullptr); } + auto& bind(int32_t value) { return bind(_input++, value); } + auto& bind(uint32_t value) { return bind(_input++, value); } + auto& bind(int64_t value) { return bind(_input++, value); } + auto& bind(uint64_t value) { return bind(_input++, value); } + auto& bind(double value) { return bind(_input++, value); } + auto& bind(const string& value) { return bind(_input++, value); } + auto& bind(const vector& value) { return bind(_input++, value); } + + auto step() -> bool { + _stepped = true; + return sqlite3_step(_statement) == SQLITE_ROW; + } struct Iterator { - auto operator*() -> Statement { return Statement(query); } + Iterator(Query& query, bool finished) : query(query), finished(finished) {} + auto operator*() -> Statement { return query._statement; } auto operator!=(const Iterator& source) const -> bool { return finished != source.finished; } auto operator++() -> Iterator& { finished = !query.step(); return *this; } - Iterator(Query& query, bool finished) : query(query), finished(finished) {} protected: Query& query; bool finished = false; }; - auto begin() -> Iterator { return Iterator(*this, finished()); } + auto begin() -> Iterator { return Iterator(*this, !step()); } auto end() -> Iterator { return Iterator(*this, true); } + + private: + auto statement() -> sqlite3_stmt* override { + if(!_stepped) step(); + return _statement; + } + + unsigned _input = 0; + bool _stepped = false; }; SQLite3() = default; SQLite3(const string& filename) { open(filename); } ~SQLite3() { close(); } - explicit operator bool() const { return database; } + explicit operator bool() const { return _database; } auto open(const string& filename) -> bool { close(); - sqlite3_open(filename, &database); - return database; + sqlite3_open(filename, &_database); + return _database; } auto close() -> void { - sqlite3_close(database); - database = nullptr; + sqlite3_close(_database); + _database = nullptr; } template auto execute(const string& statement, P&&... p) -> Query { - if(!database) return {nullptr}; + if(!_database) return {nullptr}; - sqlite3_stmt* stmt = nullptr; - sqlite3_prepare_v2(database, statement.data(), statement.size(), &stmt, nullptr); - if(!stmt) { - if(debug) print("[sqlite3_prepare_v2] ", sqlite3_errmsg(database), "\n"); + sqlite3_stmt* _statement = nullptr; + sqlite3_prepare_v2(_database, statement.data(), statement.size(), &_statement, nullptr); + if(!_statement) { + if(_debug) print("[sqlite3_prepare_v2] ", sqlite3_errmsg(_database), "\n"); return {nullptr}; } - Query query{stmt}; - _bind(query, 0, forward

(p)...); + Query query{_statement}; + bind(query, forward

(p)...); return query; } auto lastInsertID() const -> uint64_t { - return database ? sqlite3_last_insert_rowid(database) : 0; + return _database ? sqlite3_last_insert_rowid(_database) : 0; } auto setDebug(bool debug = true) -> void { - this->debug = debug; + _debug = debug; } protected: - auto _bind(Query&, unsigned) -> void {} - template auto _bind(Query& query, unsigned column, const T& value, P&&... p) -> void { - query.bind(column, value); - _bind(query, column + 1, forward

(p)...); + auto bind(Query&) -> void {} + template auto bind(Query& query, const T& value, P&&... p) -> void { + query.bind(value); + bind(query, forward

(p)...); } - bool debug = false; - sqlite3* database = nullptr; + bool _debug = false; + sqlite3* _database = nullptr; }; }} diff --git a/nall/directory.hpp b/nall/directory.hpp index f2983df6..1f19619e 100644 --- a/nall/directory.hpp +++ b/nall/directory.hpp @@ -19,23 +19,23 @@ namespace nall { struct directory : storage { - static bool create(const string& pathname, unsigned permissions = 0755); //recursive - static bool remove(const string& pathname); //recursive - static bool exists(const string& pathname); + static auto create(const string& pathname, unsigned permissions = 0755) -> bool; //recursive + static auto remove(const string& pathname) -> bool; //recursive + static auto exists(const string& pathname) -> bool; - static lstring folders(const string& pathname, const string& pattern = "*") { + static auto folders(const string& pathname, const string& pattern = "*") -> lstring { lstring folders = directory::ufolders(pathname, pattern); folders.sort(); return folders; } - static lstring files(const string& pathname, const string& pattern = "*") { + static auto files(const string& pathname, const string& pattern = "*") -> lstring { lstring files = directory::ufiles(pathname, pattern); files.sort(); return files; } - static lstring contents(const string& pathname, const string& pattern = "*") { + static auto contents(const string& pathname, const string& pattern = "*") -> lstring { lstring folders = directory::ufolders(pathname); //pattern search of contents should only filter files lstring files = directory::ufiles(pathname, pattern); folders.sort(); @@ -44,19 +44,19 @@ struct directory : storage { return folders; } - static lstring ifolders(const string& pathname, const string& pattern = "*") { + static auto ifolders(const string& pathname, const string& pattern = "*") -> lstring { lstring folders = ufolders(pathname, pattern); folders.isort(); return folders; } - static lstring ifiles(const string& pathname, const string& pattern = "*") { + static auto ifiles(const string& pathname, const string& pattern = "*") -> lstring { lstring files = ufiles(pathname, pattern); files.isort(); return files; } - static lstring icontents(const string& pathname, const string& pattern = "*") { + static auto icontents(const string& pathname, const string& pattern = "*") -> lstring { lstring folders = directory::ufolders(pathname); //pattern search of contents should only filter files lstring files = directory::ufiles(pathname, pattern); folders.isort(); @@ -67,12 +67,12 @@ struct directory : storage { private: //internal functions; these return unsorted lists - static lstring ufolders(const string& pathname, const string& pattern = "*"); - static lstring ufiles(const string& pathname, const string& pattern = "*"); + static auto ufolders(const string& pathname, const string& pattern = "*") -> lstring; + static auto ufiles(const string& pathname, const string& pattern = "*") -> lstring; }; #if defined(PLATFORM_WINDOWS) - inline bool directory::create(const string& pathname, unsigned permissions) { + inline auto directory::create(const string& pathname, unsigned permissions) -> bool { string path; lstring list = string{pathname}.transform("\\", "/").rtrim("/").split("/"); bool result = true; @@ -83,7 +83,7 @@ private: return result; } - inline bool directory::remove(const string& pathname) { + inline auto directory::remove(const string& pathname) -> bool { lstring list = directory::contents(pathname); for(auto& name : list) { if(name.endsWith("/")) directory::remove({pathname, name}); @@ -92,7 +92,7 @@ private: return _wrmdir(utf16_t(pathname)) == 0; } - inline bool directory::exists(const string& pathname) { + inline auto directory::exists(const string& pathname) -> bool { string name = pathname; name.trim("\"", "\""); DWORD result = GetFileAttributes(utf16_t(name)); @@ -100,7 +100,7 @@ private: return (result & FILE_ATTRIBUTE_DIRECTORY); } - inline lstring directory::ufolders(const string& pathname, const string& pattern) { + inline auto directory::ufolders(const string& pathname, const string& pattern) -> lstring { lstring list; string path = pathname; path.transform("/", "\\"); @@ -130,7 +130,7 @@ private: return list; } - inline lstring directory::ufiles(const string& pathname, const string& pattern) { + inline auto directory::ufiles(const string& pathname, const string& pattern) -> lstring { lstring list; string path = pathname; path.transform("/", "\\"); @@ -155,7 +155,7 @@ private: return list; } #else - inline bool directory_is_folder(DIR* dp, struct dirent* ep) { + inline auto directory_is_folder(DIR* dp, struct dirent* ep) -> bool { if(ep->d_type == DT_DIR) return true; if(ep->d_type == DT_LNK || ep->d_type == DT_UNKNOWN) { //symbolic links must be resolved to determine type @@ -166,7 +166,7 @@ private: return false; } - inline bool directory::create(const string& pathname, unsigned permissions) { + inline auto directory::create(const string& pathname, unsigned permissions) -> bool { string path; lstring list = string{pathname}.rtrim("/").split("/"); bool result = true; @@ -178,7 +178,7 @@ private: return result; } - inline bool directory::remove(const string& pathname) { + inline auto directory::remove(const string& pathname) -> bool { lstring list = directory::contents(pathname); for(auto& name : list) { if(name.endsWith("/")) directory::remove({pathname, name}); @@ -187,14 +187,14 @@ private: return rmdir(pathname) == 0; } - inline bool directory::exists(const string& pathname) { + inline auto directory::exists(const string& pathname) -> bool { DIR* dp = opendir(pathname); if(!dp) return false; closedir(dp); return true; } - inline lstring directory::ufolders(const string& pathname, const string& pattern) { + inline auto directory::ufolders(const string& pathname, const string& pattern) -> lstring { lstring list; DIR* dp; struct dirent* ep; @@ -213,7 +213,7 @@ private: return list; } - inline lstring directory::ufiles(const string& pathname, const string& pattern) { + inline auto directory::ufiles(const string& pathname, const string& pattern) -> lstring { lstring list; DIR* dp; struct dirent* ep; diff --git a/nall/dl.hpp b/nall/dl.hpp index 289e3a9f..b7b1e653 100644 --- a/nall/dl.hpp +++ b/nall/dl.hpp @@ -18,25 +18,25 @@ namespace nall { struct library { - explicit operator bool() const { return open(); } - bool open() const { return handle; } - bool open(const string&, const string& = ""); - bool open_absolute(const string&); - void* sym(const string&); - void close(); - library() = default; ~library() { close(); } library& operator=(const library&) = delete; library(const library&) = delete; + explicit operator bool() const { return open(); } + auto open() const -> bool { return handle; } + auto open(const string&, const string& = "") -> bool; + auto openAbsolute(const string&) -> bool; + auto sym(const string&) -> void*; + auto close() -> void; + private: uintptr_t handle = 0; }; #if defined(PLATFORM_LINUX) || defined(PLATFORM_BSD) -inline bool library::open(const string& name, const string& path) { +inline auto library::open(const string& name, const string& path) -> bool { if(handle) close(); if(path) handle = (uintptr_t)dlopen(string(path, "lib", name, ".so"), RTLD_LAZY); if(!handle) handle = (uintptr_t)dlopen(string(userpath(), ".local/lib/lib", name, ".so"), RTLD_LAZY); @@ -45,24 +45,24 @@ inline bool library::open(const string& name, const string& path) { return handle; } -inline bool library::open_absolute(const string& name) { +inline auto library::openAbsolute(const string& name) -> bool { if(handle) close(); handle = (uintptr_t)dlopen(name, RTLD_LAZY); return handle; } -inline void* library::sym(const string& name) { +inline auto library::sym(const string& name) -> void* { if(!handle) return nullptr; return dlsym((void*)handle, name); } -inline void library::close() { +inline auto library::close() -> void { if(!handle) return; dlclose((void*)handle); handle = 0; } #elif defined(PLATFORM_MACOSX) -inline bool library::open(const string& name, const string& path) { +inline auto library::open(const string& name, const string& path) -> bool { if(handle) close(); if(path) handle = (uintptr_t)dlopen(string(path, "lib", name, ".dylib"), RTLD_LAZY); if(!handle) handle = (uintptr_t)dlopen(string(userpath(), ".local/lib/lib", name, ".dylib"), RTLD_LAZY); @@ -71,24 +71,24 @@ inline bool library::open(const string& name, const string& path) { return handle; } -inline bool library::open_absolute(const string& name) { +inline auto library::openAbsolute(const string& name) -> bool { if(handle) close(); handle = (uintptr_t)dlopen(name, RTLD_LAZY); return handle; } -inline void* library::sym(const string& name) { +inline auto library::sym(const string& name) -> void* { if(!handle) return nullptr; return dlsym((void*)handle, name); } -inline void library::close() { +inline auto library::close() -> void { if(!handle) return; dlclose((void*)handle); handle = 0; } #elif defined(PLATFORM_WINDOWS) -inline bool library::open(const string& name, const string& path) { +inline auto library::open(const string& name, const string& path) -> bool { if(handle) close(); if(path) { string filepath = {path, name, ".dll"}; @@ -101,27 +101,27 @@ inline bool library::open(const string& name, const string& path) { return handle; } -inline bool library::open_absolute(const string& name) { +inline auto library::openAbsolute(const string& name) -> bool { if(handle) close(); handle = (uintptr_t)LoadLibraryW(utf16_t(name)); return handle; } -inline void* library::sym(const string& name) { +inline auto library::sym(const string& name) -> void* { if(!handle) return nullptr; return (void*)GetProcAddress((HMODULE)handle, name); } -inline void library::close() { +inline auto library::close() -> void { if(!handle) return; FreeLibrary((HMODULE)handle); handle = 0; } #else -inline bool library::open(const string&, const string&) { return false; } -inline bool library::open_absolute(const string&) { return false; } -inline void* library::sym(const string&) { return nullptr; } -inline void library::close() {} +inline auto library::open(const string&, const string&) -> bool { return false; } +inline auto library::openAbsolute(const string&) -> bool { return false; } +inline auto library::sym(const string&) -> void* { return nullptr; } +inline auto library::close() -> void {} #endif } diff --git a/nall/file.hpp b/nall/file.hpp index f73ec4b3..9bf15d9d 100644 --- a/nall/file.hpp +++ b/nall/file.hpp @@ -153,6 +153,13 @@ struct file : storage, varint { return data; } + auto reads(unsigned length) -> string { + string result; + result.resize(length); + for(auto& byte : result) byte = read(); + return result; + } + auto read(uint8_t* buffer, unsigned length) -> void { while(length--) *buffer++ = read(); } @@ -179,6 +186,10 @@ struct file : storage, varint { } } + auto writes(const string& s) -> void { + for(auto byte : s) write(byte); + } + auto write(const uint8_t* buffer, unsigned length) -> void { while(length--) write(*buffer++); } diff --git a/nall/filemap.hpp b/nall/filemap.hpp index 0c9ef5fa..5020ccfe 100644 --- a/nall/filemap.hpp +++ b/nall/filemap.hpp @@ -22,33 +22,35 @@ namespace nall { struct filemap { enum class mode : unsigned { read, write, readwrite, writeread }; - explicit operator bool() const { return open(); } - bool open() const { return p_open(); } - bool open(const string& filename, mode mode_) { return p_open(filename, mode_); } - void close() { return p_close(); } - unsigned size() const { return p_size; } - uint8_t* data() { return p_handle; } - const uint8_t* data() const { return p_handle; } filemap() { p_ctor(); } filemap(const string& filename, mode mode_) { p_ctor(); p_open(filename, mode_); } ~filemap() { p_dtor(); } + explicit operator bool() const { return open(); } + auto open() const -> bool { return p_open(); } + auto open(const string& filename, mode mode_) -> bool { return p_open(filename, mode_); } + auto close() -> void { return p_close(); } + auto size() const -> unsigned { return p_size; } + auto data() -> uint8_t* { return p_handle; } + auto data() const -> const uint8_t* { return p_handle; } + private: - uint8_t *p_handle = nullptr; + uint8_t* p_handle = nullptr; unsigned p_size = 0; - #if defined(_WIN32) + #if defined(API_WINDOWS) //============= //MapViewOfFile //============= - HANDLE p_filehandle, p_maphandle; + HANDLE p_filehandle; + HANDLE p_maphandle; - bool p_open() const { + auto p_open() const -> bool { return p_handle; } - bool p_open(const string& filename, mode mode_) { + auto p_open(const string& filename, mode mode_) -> bool { if(file::exists(filename) && file::size(filename) == 0) { p_handle = nullptr; p_size = 0; @@ -103,7 +105,7 @@ private: return p_handle; } - void p_close() { + auto p_close() -> void { if(p_handle) { UnmapViewOfFile(p_handle); p_handle = nullptr; @@ -120,12 +122,12 @@ private: } } - void p_ctor() { + auto p_ctor() -> void { p_filehandle = INVALID_HANDLE_VALUE; p_maphandle = INVALID_HANDLE_VALUE; } - void p_dtor() { + auto p_dtor() -> void { close(); } @@ -136,11 +138,11 @@ private: int p_fd; - bool p_open() const { + auto p_open() const -> bool { return p_handle; } - bool p_open(const string& filename, mode mode_) { + auto p_open(const string& filename, mode mode_) -> bool { if(file::exists(filename) && file::size(filename) == 0) { p_handle = nullptr; p_size = 0; @@ -187,7 +189,7 @@ private: return p_handle; } - void p_close() { + auto p_close() -> void { if(p_handle) { munmap(p_handle, p_size); p_handle = nullptr; @@ -199,11 +201,11 @@ private: } } - void p_ctor() { + auto p_ctor() -> void { p_fd = -1; } - void p_dtor() { + auto p_dtor() -> void { p_close(); } diff --git a/nall/function.hpp b/nall/function.hpp index fe7382f1..7c889600 100644 --- a/nall/function.hpp +++ b/nall/function.hpp @@ -5,52 +5,30 @@ namespace nall { -template class function; +template struct function; -template class function { - struct container { - virtual R operator()(P... p) const = 0; - virtual container* copy() const = 0; - virtual ~container() {} - }; - - container* callback = nullptr; - - struct global : container { - R (*function)(P...); - R operator()(P... p) const { return function(forward

(p)...); } - container* copy() const { return new global(function); } - global(R (*function)(P...)) : function(function) {} - }; - - template struct member : container { - R (C::*function)(P...); - C* object; - R operator()(P... p) const { return (object->*function)(forward

(p)...); } - container* copy() const { return new member(function, object); } - member(R (C::*function)(P...), C* object) : function(function), object(object) {} - }; - - template struct lambda : container { - mutable L object; - R operator()(P... p) const { return object(forward

(p)...); } - container* copy() const { return new lambda(object); } - lambda(const L& object) : object(object) {} - }; - - //value = true if R L::operator()(P...) exists +template struct function { + //value = true if auto L::operator()(P...) -> R exists template struct is_compatible { - template static const typename is_same().operator()(declval

()...))>::type exists(T*); - template static const false_type exists(...); + template static auto exists(T*) -> const typename is_same().operator()(declval

()...))>::type; + template static auto exists(...) -> const false_type; static constexpr bool value = decltype(exists(0))::value; }; -public: - explicit operator bool() const { return callback; } - R operator()(P... p) const { return (*callback)(forward

(p)...); } - void reset() { if(callback) { delete callback; callback = nullptr; } } + function() = default; + function(const function& source) { operator=(source); } + function(void* function) { if(function) callback = new global((auto (*)(P...) -> R)function); } + function(auto (*function)(P...) -> R) { callback = new global(function); } + template function(auto (C::*function)(P...) -> R, C* object) { callback = new member(function, object); } + template function(auto (C::*function)(P...) const -> R, C* object) { callback = new member((auto (C::*)(P...) -> R)function, object); } + template>> function(const L& object) { callback = new lambda(object); } + ~function() { if(callback) delete callback; } - function& operator=(const function& source) { + explicit operator bool() const { return callback; } + auto operator()(P... p) const -> R { return (*callback)(forward

(p)...); } + auto reset() -> void { if(callback) { delete callback; callback = nullptr; } } + + auto operator=(const function& source) -> function& { if(this != &source) { if(callback) { delete callback; callback = nullptr; } if(source.callback) callback = source.callback->copy(); @@ -58,14 +36,36 @@ public: return *this; } - function() = default; - function(const function& source) { operator=(source); } - function(void* function) { if(function) callback = new global((R (*)(P...))function); } - function(R (*function)(P...)) { callback = new global(function); } - template function(R (C::*function)(P...), C* object) { callback = new member(function, object); } - template function(R (C::*function)(P...) const, C* object) { callback = new member((R (C::*)(P...))function, object); } - template>> function(const L& object) { callback = new lambda(object); } - ~function() { if(callback) delete callback; } +private: + struct container { + virtual auto operator()(P... p) const -> R = 0; + virtual auto copy() const -> container* = 0; + virtual ~container() = default; + }; + + container* callback = nullptr; + + struct global : container { + auto (*function)(P...) -> R; + auto operator()(P... p) const -> R { return function(forward

(p)...); } + auto copy() const -> container* { return new global(function); } + global(auto (*function)(P...) -> R) : function(function) {} + }; + + template struct member : container { + auto (C::*function)(P...) -> R; + C* object; + auto operator()(P... p) const -> R { return (object->*function)(forward

(p)...); } + auto copy() const -> container* { return new member(function, object); } + member(auto (C::*function)(P...) -> R, C* object) : function(function), object(object) {} + }; + + template struct lambda : container { + mutable L object; + auto operator()(P... p) const -> R { return object(forward

(p)...); } + auto copy() const -> container* { return new lambda(object); } + lambda(const L& object) : object(object) {} + }; }; } diff --git a/nall/group.hpp b/nall/group.hpp deleted file mode 100644 index f4ae68a2..00000000 --- a/nall/group.hpp +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef NALL_GROUP_HPP -#define NALL_GROUP_HPP - -//group -//vector of unique references - -#include - -namespace nall { - -template struct group : protected vector { - group& operator=(const group& source) { vector::operator=(source); return *this; } - group& operator=(group&& source) { vector::operator=(std::move(source)); return *this; } - template group(Args&&... args) { construct(std::forward(args)...); } - - bool empty() const { return vector::empty(); } - unsigned size() const { return vector::size(); } - void reset() { vector::reset(); } - - T& first() const { return *vector::operator[](0); } - - //return true if at least one item was appended - template bool append(T& value, Args&&... args) { - bool result = append(value); - return append(std::forward(args)...) | result; - } - - bool append(T& value) { - if(vector::find(&value)) return false; - return vector::append(&value), true; - } - - //return true if at least one item was removed - template bool remove(T& value, Args&&... args) { - bool result = remove(value); - return remove(std::forward(args)...) | result; - } - - bool remove(T& value) { - if(auto position = vector::find(&value)) return vector::remove(position()), true; - return false; - } - - struct iterator : protected vector::constIterator { - T& operator*() const { return *vector::constIterator::operator*(); } - bool operator!=(const iterator& source) const { return vector::constIterator::operator!=(source); } - iterator& operator++() { vector::constIterator::operator++(); return *this; } - iterator(const group& source, unsigned position) : vector::constIterator(source, position) {} - }; - - const iterator begin() const { return iterator(*this, 0); } - const iterator end() const { return iterator(*this, size()); } - -private: - void construct() {} - void construct(const group& source) { vector::operator=(source); } - void construct(group&& source) { vector::operator=(std::move(source)); } - template void construct(T& value, Args&&... args) { - append(value); - construct(std::forward(args)...); - } -}; - -} - -#endif diff --git a/nall/hashset.hpp b/nall/hashset.hpp index 58bc136f..2dc6367d 100644 --- a/nall/hashset.hpp +++ b/nall/hashset.hpp @@ -8,26 +8,20 @@ //remove: O(1) average; O(n) worst // //requirements: -// unsigned T::hash() const; -// bool T::operator==(const T&) const; +// auto T::hash() const -> unsigned; +// auto T::operator==(const T&) const -> bool; namespace nall { template struct hashset { -protected: - T** pool = nullptr; - unsigned length = 8; //length of pool - unsigned count = 0; //number of objects inside of the pool - -public: - hashset() {} + hashset() = default; hashset(unsigned length) : length(bit::round(length)) {} hashset(const hashset& source) { operator=(source); } - hashset(hashset&& source) { operator=(std::move(source)); } + hashset(hashset&& source) { operator=(move(source)); } ~hashset() { reset(); } - hashset& operator=(const hashset& source) { + auto operator=(const hashset& source) -> hashset& { reset(); if(source.pool) { for(unsigned n = 0; n < source.count; n++) { @@ -37,7 +31,7 @@ public: return *this; } - hashset& operator=(hashset&& source) { + auto operator=(hashset&& source) -> hashset& { reset(); pool = source.pool; length = source.length; @@ -48,11 +42,11 @@ public: return *this; } - unsigned capacity() const { return length; } - unsigned size() const { return count; } - bool empty() const { return count == 0; } + auto capacity() const -> unsigned { return length; } + auto size() const -> unsigned { return count; } + auto empty() const -> bool { return count == 0; } - void reset() { + auto reset() -> void { if(pool) { for(unsigned n = 0; n < length; n++) { if(pool[n]) { @@ -67,7 +61,7 @@ public: count = 0; } - void reserve(unsigned size) { + auto reserve(unsigned size) -> void { //ensure all items will fit into pool (with <= 50% load) and amortize growth size = bit::round(max(size, count << 1)); T** copy = new T*[size](); @@ -88,7 +82,7 @@ public: length = size; } - maybe find(const T& value) { + auto find(const T& value) -> maybe { if(!pool) return nothing; unsigned hash = value.hash() & (length - 1); @@ -100,7 +94,7 @@ public: return nothing; } - maybe insert(const T& value) { + auto insert(const T& value) -> maybe { if(!pool) pool = new T*[length](); //double pool size when load is >= 50% @@ -114,7 +108,7 @@ public: return *pool[hash]; } - bool remove(const T& value) { + auto remove(const T& value) -> bool { if(!pool) return false; unsigned hash = value.hash() & (length - 1); @@ -130,6 +124,11 @@ public: return false; } + +protected: + T** pool = nullptr; + unsigned length = 8; //length of pool + unsigned count = 0; //number of objects inside of the pool }; } diff --git a/nall/http/request.hpp b/nall/http/request.hpp index bca7ae1e..a21676ea 100644 --- a/nall/http/request.hpp +++ b/nall/http/request.hpp @@ -18,9 +18,9 @@ struct httpRequest : httpMessage { inline auto body(const function& callback) const -> bool; inline auto setBody() -> bool; - auto ip() const -> string { - return {(uint8_t)(_ip >> 24), ".", (uint8_t)(_ip >> 16), ".", (uint8_t)(_ip >> 8), ".", (uint8_t)(_ip >> 0)}; - } + auto ipv4() const -> bool { return _ipv6 == false; } + auto ipv6() const -> bool { return _ipv6 == true; } + auto ip() const -> string { return _ip; } auto requestType() const -> RequestType { return _requestType; } auto setRequestType(RequestType value) -> void { _requestType = value; } @@ -42,7 +42,8 @@ struct httpRequest : httpMessage { auto setPost(const string& name, const string& value = "") -> void { _post.set(name, value); } //private: - uint32_t _ip = 0; + bool _ipv6 = false; + string _ip; RequestType _requestType = RequestType::None; string _path; httpVariables _cookie; @@ -60,7 +61,7 @@ auto httpRequest::head(const function& callback for(auto& get : _get) { request.append(get.name, "=", get.value, "&"); } - request.rtrim("&"); + request.rtrim("&", 1L); } switch(requestType()) { @@ -83,43 +84,43 @@ auto httpRequest::setHead() -> bool { string request = headers.takeFirst().rtrim("\r"); string requestHost; - if(irtrim(request, " HTTP/1.0")); - else if(irtrim(request, " HTTP/1.1")); + if(request.iendsWith(" HTTP/1.0")) request.irtrim(" HTTP/1.0", 1L); + else if(request.iendsWith(" HTTP/1.1")) request.irtrim(" HTTP/1.1", 1L); else return false; - if(iltrim(request, "HEAD ")) setRequestType(RequestType::Head); - else if(iltrim(request, "GET " )) setRequestType(RequestType::Get ); - else if(iltrim(request, "POST ")) setRequestType(RequestType::Post); + if(request.ibeginsWith("HEAD ")) request.iltrim("HEAD ", 1L), setRequestType(RequestType::Head); + else if(request.ibeginsWith("GET " )) request.iltrim("GET ", 1L), setRequestType(RequestType::Get ); + else if(request.ibeginsWith("POST ")) request.iltrim("POST ", 1L), setRequestType(RequestType::Post); else return false; //decode absolute URIs - request.strip().iltrim("http://"); + request.strip().iltrim("http://", 1L); if(!request.beginsWith("/")) { - lstring components = request.split<1>("/"); + lstring components = request.split("/", 1L); requestHost = components(0); request = {"/", components(1)}; } - lstring components = request.split<1>("?"); + lstring components = request.split("?", 1L); setPath(components(0)); if(auto queryString = components(1)) { for(auto& block : queryString.split("&")) { - lstring variable = block.split<1>("="); + lstring variable = block.split("=", 1L); if(variable(0)) setGet(variable(0), variable(1)); } } for(auto& header : headers) { if(header.beginsWith(" ") || header.beginsWith("\t")) continue; - auto part = header.split<1>(":").strip(); + auto part = header.split(":", 1L).strip(); if(!part[0] || part.size() != 2) continue; appendHeader(part[0], part[1]); if(part[0].iequals("Cookie")) { for(auto& block : part[1].split(";")) { - lstring variable = block.split<1>("=").strip(); - variable(1).ltrim("\"").rtrim("\""); + lstring variable = block.split("=", 1L).strip(); + variable(1).trim("\"", "\""); if(variable(0)) setCookie(variable(0), variable(1)); } } @@ -143,7 +144,7 @@ auto httpRequest::setBody() -> bool { if(requestType() == RequestType::Post) { if(header("Content-Type").iequals("application/x-www-form-urlencoded")) { for(auto& block : _body.split("&")) { - lstring variable = block.rtrim("\r").split<1>("="); + lstring variable = block.rtrim("\r").split("=", 1L); if(variable(0)) setPost(variable(0), variable(1)); } } diff --git a/nall/http/response.hpp b/nall/http/response.hpp index 7bca9201..07d80bc7 100644 --- a/nall/http/response.hpp +++ b/nall/http/response.hpp @@ -95,15 +95,15 @@ auto httpResponse::setHead() -> bool { lstring headers = _head.split("\n"); string response = headers.takeFirst().rtrim("\r"); - if(iltrim(response, "HTTP/1.0 ")); - else if(iltrim(response, "HTTP/1.1 ")); + if(response.ibeginsWith("HTTP/1.0 ")) response.iltrim("HTTP/1.0 ", 1L); + else if(response.ibeginsWith("HTTP/1.1 ")) response.iltrim("HTTP/1.1 ", 1L); else return false; setResponseType(decimal(response)); for(auto& header : headers) { if(header.beginsWith(" ") || header.beginsWith("\t")) continue; - lstring variable = header.split<1>(":").strip(); + lstring variable = header.split(":", 1L).strip(); if(variable.size() != 2) continue; appendHeader(variable[0], variable[1]); } diff --git a/nall/http/server.hpp b/nall/http/server.hpp index 6718a29f..bd073af8 100644 --- a/nall/http/server.hpp +++ b/nall/http/server.hpp @@ -14,10 +14,22 @@ struct httpServer : httpRole, service { ~httpServer() { close(); } private: - signed fd = -1; function callback; - struct sockaddr_in addrin = {0}; std::atomic connections{0}; + + signed fd4 = -1; + signed fd6 = -1; + struct sockaddr_in addrin4 = {0}; + struct sockaddr_in6 addrin6 = {0}; + + auto ipv4() const -> bool { return fd4 >= 0; } + auto ipv6() const -> bool { return fd6 >= 0; } + + auto ipv4_close() -> void { if(fd4 >= 0) ::close(fd4); fd4 = -1; } + auto ipv6_close() -> void { if(fd6 >= 0) ::close(fd6); fd6 = -1; } + + auto ipv4_scan() -> bool; + auto ipv6_scan() -> bool; }; auto httpServer::open(unsigned port, const string& serviceName, const string& command) -> bool { @@ -25,8 +37,9 @@ auto httpServer::open(unsigned port, const string& serviceName, const string& co if(!service::command(serviceName, command)) return false; } - fd = socket(AF_INET, SOCK_STREAM, 0); - if(fd < 0) return false; + fd4 = socket(AF_INET, SOCK_STREAM, 0); + fd6 = socket(AF_INET6, SOCK_STREAM, 0); + if(!ipv4() && !ipv6()) return false; { #if defined(SO_RCVTIMEO) @@ -34,7 +47,8 @@ auto httpServer::open(unsigned port, const string& serviceName, const string& co struct timeval rcvtimeo; rcvtimeo.tv_sec = settings.timeoutReceive / 1000; rcvtimeo.tv_usec = settings.timeoutReceive % 1000 * 1000; - setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &rcvtimeo, sizeof(struct timeval)); + if(ipv4()) setsockopt(fd4, SOL_SOCKET, SO_RCVTIMEO, &rcvtimeo, sizeof(struct timeval)); + if(ipv6()) setsockopt(fd6, SOL_SOCKET, SO_RCVTIMEO, &rcvtimeo, sizeof(struct timeval)); } #endif @@ -43,37 +57,41 @@ auto httpServer::open(unsigned port, const string& serviceName, const string& co struct timeval sndtimeo; sndtimeo.tv_sec = settings.timeoutSend / 1000; sndtimeo.tv_usec = settings.timeoutSend % 1000 * 1000; - setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &sndtimeo, sizeof(struct timeval)); + if(ipv4()) setsockopt(fd4, SOL_SOCKET, SO_SNDTIMEO, &sndtimeo, sizeof(struct timeval)); + if(ipv6()) setsockopt(fd6, SOL_SOCKET, SO_SNDTIMEO, &sndtimeo, sizeof(struct timeval)); } #endif #if defined(SO_NOSIGPIPE) //BSD, OSX signed nosigpipe = 1; - setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(signed)); + if(ipv4()) setsockopt(fd4, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(signed)); + if(ipv6()) setsockopt(fd6, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(signed)); #endif #if defined(SO_REUSEADDR) //BSD, Linux, OSX signed reuseaddr = 1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(signed)); + if(ipv4()) setsockopt(fd4, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(signed)); + if(ipv6()) setsockopt(fd6, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(signed)); #endif #if defined(SO_REUSEPORT) //BSD, OSX signed reuseport = 1; - setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &reuseport, sizeof(signed)); + if(ipv4()) setsockopt(fd4, SOL_SOCKET, SO_REUSEPORT, &reuseport, sizeof(signed)); + if(ipv6()) setsockopt(fd6, SOL_SOCKET, SO_REUSEPORT, &reuseport, sizeof(signed)); #endif } - addrin.sin_family = AF_INET; - addrin.sin_addr.s_addr = htonl(INADDR_ANY); - addrin.sin_port = htons(port); + addrin4.sin_family = AF_INET; + addrin4.sin_addr.s_addr = htonl(INADDR_ANY); + addrin4.sin_port = htons(port); - signed result = bind(fd, (struct sockaddr*)&addrin, sizeof(addrin)); - if(result < 0) return close(), false; + addrin6.sin6_family = AF_INET6; + addrin6.sin6_addr = in6addr_any; + addrin6.sin6_port = htons(port); - result = listen(fd, SOMAXCONN); //system-wide limit (per port) - if(result < 0) return close(), false; - - return true; + if(bind(fd4, (struct sockaddr*)&addrin4, sizeof(addrin4)) < 0 || listen(fd4, SOMAXCONN) < 0) ipv4_close(); + if(bind(fd6, (struct sockaddr*)&addrin6, sizeof(addrin6)) < 0 || listen(fd6, SOMAXCONN) < 0) ipv6_close(); + return ipv4() || ipv6(); } auto httpServer::main(const function& function) -> void { @@ -82,15 +100,19 @@ auto httpServer::main(const function& function) -> auto httpServer::scan() -> string { if(auto command = service::receive()) return command; - if(connections >= settings.connectionLimit) return "busy"; + if(ipv4() && ipv4_scan()) return "ok"; + if(ipv6() && ipv6_scan()) return "ok"; + return "idle"; +} +auto httpServer::ipv4_scan() -> bool { struct pollfd query = {0}; - query.fd = fd; + query.fd = fd4; query.events = POLLIN; poll(&query, 1, 0); - if(query.fd == fd && query.revents & POLLIN) { + if(query.fd == fd4 && query.revents & POLLIN) { ++connections; thread::create([&](uintptr_t) { @@ -100,11 +122,19 @@ auto httpServer::scan() -> string { struct sockaddr_in settings = {0}; socklen_t socklen = sizeof(sockaddr_in); - clientfd = accept(fd, (struct sockaddr*)&settings, &socklen); + clientfd = accept(fd4, (struct sockaddr*)&settings, &socklen); if(clientfd < 0) return; + uint32_t ip = ntohl(settings.sin_addr.s_addr); + httpRequest request; - request._ip = ntohl(settings.sin_addr.s_addr); + request._ipv6 = false; + request._ip = { + (uint8_t)(ip >> 24), ".", + (uint8_t)(ip >> 16), ".", + (uint8_t)(ip >> 8), ".", + (uint8_t)(ip >> 0) + }; if(download(clientfd, request) && callback) { auto response = callback(request); @@ -116,16 +146,64 @@ auto httpServer::scan() -> string { ::close(clientfd); --connections; }, 0, settings.threadStackSize); + + return true; } - return "ok"; + return false; +} + +auto httpServer::ipv6_scan() -> bool { + struct pollfd query = {0}; + query.fd = fd6; + query.events = POLLIN; + poll(&query, 1, 0); + + if(query.fd == fd6 && query.revents & POLLIN) { + ++connections; + + thread::create([&](uintptr_t) { + thread::detach(); + + signed clientfd = -1; + struct sockaddr_in6 settings = {0}; + socklen_t socklen = sizeof(sockaddr_in6); + + clientfd = accept(fd6, (struct sockaddr*)&settings, &socklen); + if(clientfd < 0) return; + + unsigned char* ip = settings.sin6_addr.s6_addr; + uint16_t ipSegment[8] = {0}; + for(auto n : range(8)) ipSegment[n] = ip[n * 2 + 0] * 256 + ip[n * 2 + 1]; + + httpRequest request; + request._ipv6 = true; + for(auto n : range(8)) { + uint16_t value = ip[n * 2 + 0] * 256 + ip[n * 2 + 1]; + request._ip.append(hex(value, 4L)); + if(n != 7) request._ip.append(":"); + } + + if(download(clientfd, request) && callback) { + auto response = callback(request); + upload(clientfd, response); + } else { + upload(clientfd, httpResponse()); //"501 Not Implemented" + } + + ::close(clientfd); + --connections; + }, 0, settings.threadStackSize); + + return true; + } + + return false; } auto httpServer::close() -> void { - if(fd) { - ::close(fd); - fd = -1; - } + ipv4_close(); + ipv6_close(); } } diff --git a/nall/interpolation.hpp b/nall/interpolation.hpp index afc7108b..39a3c501 100644 --- a/nall/interpolation.hpp +++ b/nall/interpolation.hpp @@ -4,27 +4,27 @@ namespace nall { struct Interpolation { - static inline double Nearest(double mu, double a, double b, double c, double d) { + static inline auto Nearest(double mu, double a, double b, double c, double d) -> double { return (mu <= 0.5 ? b : c); } - static inline double Sublinear(double mu, double a, double b, double c, double d) { + static inline auto Sublinear(double mu, double a, double b, double c, double d) -> double { mu = ((mu - 0.5) * 2.0) + 0.5; if(mu < 0) mu = 0; if(mu > 1) mu = 1; return b * (1.0 - mu) + c * mu; } - static inline double Linear(double mu, double a, double b, double c, double d) { + static inline auto Linear(double mu, double a, double b, double c, double d) -> double { return b * (1.0 - mu) + c * mu; } - static inline double Cosine(double mu, double a, double b, double c, double d) { + static inline auto Cosine(double mu, double a, double b, double c, double d) -> double { mu = (1.0 - cos(mu * 3.14159265)) / 2.0; return b * (1.0 - mu) + c * mu; } - static inline double Cubic(double mu, double a, double b, double c, double d) { + static inline auto Cubic(double mu, double a, double b, double c, double d) -> double { double A = d - c - a + b; double B = a - b - A; double C = c - a; @@ -32,7 +32,7 @@ struct Interpolation { return A * (mu * mu * mu) + B * (mu * mu) + C * mu + D; } - static inline double Hermite(double mu1, double a, double b, double c, double d) { + static inline auto Hermite(double mu1, double a, double b, double c, double d) -> double { const double tension = 0.0; //-1 = low, 0 = normal, +1 = high const double bias = 0.0; //-1 = left, 0 = even, +1 = right double mu2, mu3, m0, m1, a0, a1, a2, a3; diff --git a/nall/map.hpp b/nall/map.hpp index 72c99ea5..a35f94d0 100644 --- a/nall/map.hpp +++ b/nall/map.hpp @@ -9,45 +9,47 @@ template struct map { struct node_t { T key; U value; - bool operator< (const node_t& source) const { return key < source.key; } - bool operator==(const node_t& source) const { return key == source.key; } node_t() = default; node_t(const T& key) : key(key) {} node_t(const T& key, const U& value) : key(key), value(value) {} + auto operator< (const node_t& source) const -> bool { return key < source.key; } + auto operator==(const node_t& source) const -> bool { return key == source.key; } }; - maybe find(const T& key) const { + auto find(const T& key) const -> maybe { if(auto node = root.find({key})) return node().value; return nothing; } - void insert(const T& key, const U& value) { root.insert({key, value}); } - void remove(const T& key) { root.remove({key}); } - unsigned size() const { return root.size(); } - void reset() { root.reset(); } + auto insert(const T& key, const U& value) -> void { root.insert({key, value}); } + auto remove(const T& key) -> void { root.remove({key}); } + auto size() const -> unsigned { return root.size(); } + auto reset() -> void { root.reset(); } - typename set::iterator begin() { return root.begin(); } - typename set::iterator end() { return root.end(); } - const typename set::iterator begin() const { return root.begin(); } - const typename set::iterator end() const { return root.end(); } + auto begin() -> typename set::iterator { return root.begin(); } + auto end() -> typename set::iterator { return root.end(); } + + auto begin() const -> const typename set::iterator { return root.begin(); } + auto end() const -> const typename set::iterator { return root.end(); } protected: set root; }; template struct bimap { - maybe find(const T& key) const { return tmap.find(key); } - maybe find(const U& key) const { return umap.find(key); } - void insert(const T& key, const U& value) { tmap.insert(key, value); umap.insert(value, key); } - void remove(const T& key) { if(auto p = tmap.find(key)) { umap.remove(p().value); tmap.remove(key); } } - void remove(const U& key) { if(auto p = umap.find(key)) { tmap.remove(p().value); umap.remove(key); } } - unsigned size() const { return tmap.size(); } - void reset() { tmap.reset(); umap.reset(); } + auto find(const T& key) const -> maybe { return tmap.find(key); } + auto find(const U& key) const -> maybe { return umap.find(key); } + auto insert(const T& key, const U& value) -> void { tmap.insert(key, value); umap.insert(value, key); } + auto remove(const T& key) -> void { if(auto p = tmap.find(key)) { umap.remove(p().value); tmap.remove(key); } } + auto remove(const U& key) -> void { if(auto p = umap.find(key)) { tmap.remove(p().value); umap.remove(key); } } + auto size() const -> unsigned { return tmap.size(); } + auto reset() -> void { tmap.reset(); umap.reset(); } - typename set::node_t>::iterator begin() { return tmap.begin(); } - typename set::node_t>::iterator end() { return tmap.end(); } - const typename set::node_t>::iterator begin() const { return tmap.begin(); } - const typename set::node_t>::iterator end() const { return tmap.end(); } + auto begin() -> typename set::node_t>::iterator { return tmap.begin(); } + auto end() -> typename set::node_t>::iterator { return tmap.end(); } + + auto begin() const -> const typename set::node_t>::iterator { return tmap.begin(); } + auto end() const -> const typename set::node_t>::iterator { return tmap.end(); } protected: map tmap; diff --git a/nall/matrix.hpp b/nall/matrix.hpp index 991c7e68..a1705335 100644 --- a/nall/matrix.hpp +++ b/nall/matrix.hpp @@ -5,7 +5,7 @@ namespace nall { namespace Matrix { -template inline void Multiply(T* output, const T* xdata, unsigned xrows, unsigned xcols, const T* ydata, unsigned yrows, unsigned ycols) { +template inline auto Multiply(T* output, const T* xdata, unsigned xrows, unsigned xcols, const T* ydata, unsigned yrows, unsigned ycols) -> void { if(xcols != yrows) return; for(unsigned y = 0; y < xrows; y++) { @@ -19,7 +19,7 @@ template inline void Multiply(T* output, const T* xdata, unsigned xr } } -template inline vector Multiply(const T* xdata, unsigned xrows, unsigned xcols, const T* ydata, unsigned yrows, unsigned ycols) { +template inline auto Multiply(const T* xdata, unsigned xrows, unsigned xcols, const T* ydata, unsigned yrows, unsigned ycols) -> vector { vector output; output.resize(xrows * ycols); Multiply(output.data(), xdata, xrows, xcols, ydata, yrows, ycols); diff --git a/nall/method.hpp b/nall/method.hpp index c79eab0a..36a203fe 100644 --- a/nall/method.hpp +++ b/nall/method.hpp @@ -20,7 +20,7 @@ template struct method { template struct chain { chain(T& self, const F& f) : self(self), f(f) {} template auto operator()(P&&... p) -> T& { - return f(self, std::forward

(p)...), self; + return f(self, forward

(p)...), self; } private: T& self; @@ -30,7 +30,7 @@ template struct method { template struct const_chain { const_chain(const T& self, const F& f) : self(self), f(f) {} template auto operator()(P&&... p) const -> const T& { - return f(self, std::forward

(p)...), self; + return f(self, forward

(p)...), self; } private: const T& self; @@ -44,13 +44,13 @@ template struct method { auto operator[](const F& f) const -> const_chain { return const_chain((const T&)*this, f); } template>> - auto operator()(const F& f, P&&... p) -> decltype(f((T&)*this, std::forward

(p)...)) { - return f((T&)*this, std::forward

(p)...); + auto operator()(const F& f, P&&... p) -> decltype(f((T&)*this, forward

(p)...)) { + return f((T&)*this, forward

(p)...); } template>> - auto operator()(const F& f, P&&... p) const -> decltype(f((const T&)*this, std::forward

(p)...)) { - return f((const T&)*this, std::forward

(p)...); + auto operator()(const F& f, P&&... p) const -> decltype(f((const T&)*this, forward

(p)...)) { + return f((const T&)*this, forward

(p)...); } }; diff --git a/nall/mosaic/context.hpp b/nall/mosaic/context.hpp index 97719ffa..d4ca1932 100644 --- a/nall/mosaic/context.hpp +++ b/nall/mosaic/context.hpp @@ -64,9 +64,9 @@ struct context { for(auto& item : list) { item.strip(); if(item.match("f(?*) ?*")) { - item.ltrim("f("); - lstring part = item.split<1>(") "); - lstring args = part[0].split<3>(";").strip(); + item.ltrim("f(", 1L); + lstring part = item.split(") ", 1L); + lstring args = part[0].split(";", 3L).strip(); unsigned length = eval(args(0, "0")); unsigned offset = eval(args(1, "0")); @@ -85,10 +85,10 @@ struct context { } } else if(item.match("base64*")) { unsigned offset = 0; - item.ltrim("base64"); + item.ltrim("base64", 1L); if(item.match("(?*) *")) { - item.ltrim("("); - lstring part = item.split<1>(") "); + item.ltrim("(", 1L); + lstring part = item.split(") ", 1L); offset = eval(part[0]); item = part(1, ""); } @@ -101,7 +101,7 @@ struct context { if(c == '_') buffer.append(offset + 63); } } else if(item.match("file *")) { - item.ltrim("file "); + item.ltrim("file ", 1L); item.strip(); //... } else if(item.empty() == false) { @@ -115,7 +115,7 @@ struct context { lstring lines = data.split("\n"); for(auto& line : lines) { - lstring part = line.split<1>(":").strip(); + lstring part = line.split(":", 1L).strip(); if(part.size() != 2) continue; if(part[0] == "offset") offset = eval(part[1]); diff --git a/nall/nall.hpp b/nall/nall.hpp index be7017f9..86566576 100644 --- a/nall/nall.hpp +++ b/nall/nall.hpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/nall/odbc.hpp b/nall/odbc.hpp deleted file mode 100644 index cfcd5c0e..00000000 --- a/nall/odbc.hpp +++ /dev/null @@ -1,153 +0,0 @@ -#ifndef NALL_ODBC_HPP -#define NALL_ODBC_HPP - -//minimal wrapper for core ODBC v3 API -//requires Windows or unixODBC - -#include -#include - -#include -#include -#include - -namespace nall { - -struct ODBC { - inline ODBC(); - inline ODBC(const string& database, const string& username, const string& password); - inline ~ODBC(); - - inline bool connected(); - inline bool connect(const string& hostname, const string& username, const string& password); - inline void disconnect(); - template inline bool execute(Args&&... args); - inline void release(); - inline unsigned rows(); - inline lstring read(); - -private: - char* buffer = nullptr; - SQLHANDLE sqlEnvironment = nullptr; - SQLHANDLE sqlConnection = nullptr; - SQLHANDLE sqlStatement = nullptr; -}; - -ODBC::ODBC() { - auto result = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &sqlEnvironment); - if(result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) return; - - SQLSetEnvAttr(sqlEnvironment, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0); - buffer = new char[65536](); -} - -ODBC::ODBC(const string& database, const string& username, const string& password) : ODBC() { - connect(database, username, password); -} - -ODBC::~ODBC() { - if(sqlEnvironment) { - disconnect(); - SQLFreeHandle(SQL_HANDLE_ENV, sqlEnvironment); - sqlEnvironment = nullptr; - - delete[] buffer; - buffer = nullptr; - } -} - -bool ODBC::connected() { - return sqlConnection; -} - -bool ODBC::connect(const string& hostname, const string& username, const string& password) { - if(!sqlEnvironment) return false; - disconnect(); - - auto result = SQLAllocHandle(SQL_HANDLE_DBC, sqlEnvironment, &sqlConnection); - if(result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) return false; - - SQLSetConnectAttr(sqlConnection, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0); - result = SQLConnectA(sqlConnection, - (SQLCHAR*)(const char*)hostname, SQL_NTS, - (SQLCHAR*)(const char*)username, SQL_NTS, - (SQLCHAR*)(const char*)password, SQL_NTS - ); - if(result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) { - disconnect(); - return false; - } - - return true; -} - -void ODBC::disconnect() { - if(sqlConnection) { - release(); - SQLDisconnect(sqlConnection); - SQLFreeHandle(SQL_HANDLE_DBC, sqlConnection); - sqlConnection = nullptr; - } -} - -template -bool ODBC::execute(Args&&... args) { - string statement({args...}); - - if(!sqlConnection) return false; - release(); - - auto result = SQLAllocHandle(SQL_HANDLE_STMT, sqlConnection, &sqlStatement); - if(result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) return false; - - result = SQLExecDirectA(sqlStatement, (SQLCHAR*)(const char*)statement, SQL_NTS); - if(result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) { - release(); - return false; - } - - return true; -} - -void ODBC::release() { - if(sqlStatement) { - SQLFreeHandle(SQL_HANDLE_STMT, sqlStatement); - sqlStatement = nullptr; - } -} - -//valid after update, insert or delete -unsigned ODBC::rows() { - if(!sqlStatement) return 0; - - SQLLEN sqlRows = 0; - auto result = SQLRowCount(sqlStatement, &sqlRows); - if(result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) return 0; - - return sqlRows; -} - -//valid after select -lstring ODBC::read() { - if(!sqlStatement) return {}; - - auto result = SQLFetch(sqlStatement); - if(result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) return {}; - - SQLSMALLINT sqlColumns = 0; - result = SQLNumResultCols(sqlStatement, &sqlColumns); - if(result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO) return {}; - - lstring data; - for(unsigned column = 0; column < sqlColumns; column++) { - SQLLEN length = 0; - SQLGetData(sqlStatement, 1 + column, SQL_C_CHAR, buffer, 65535, &length); - data.append(buffer); - } - - return data; -} - -} - -#endif diff --git a/nall/posix/shared-memory.hpp b/nall/posix/shared-memory.hpp index 549308d6..8a50294e 100644 --- a/nall/posix/shared-memory.hpp +++ b/nall/posix/shared-memory.hpp @@ -55,7 +55,7 @@ struct shared_memory { auto create(const string& name, unsigned size) -> bool { reset(); - _name = {"/nall::", string{name}.transform("/", ":")}; + _name = {"/nall-", string{name}.transform("/:", "--")}; _size = size; //O_CREAT | O_EXCL seems to throw ENOENT even when semaphore does not exist ... @@ -102,7 +102,7 @@ struct shared_memory { auto open(const string& name, unsigned size) -> bool { reset(); - _name = {"/nall::", string{name}.transform("/", ":")}; + _name = {"/nall-", string{name}.transform("/:", "--")}; _size = size; _semaphore = sem_open(_name, 0, 0644); diff --git a/nall/priority-queue.hpp b/nall/priority-queue.hpp index b1576993..35eaf1d3 100644 --- a/nall/priority-queue.hpp +++ b/nall/priority-queue.hpp @@ -8,7 +8,7 @@ namespace nall { -template void priority_queue_nocallback(type_t) {} +template auto priority_queue_nocallback(type_t) -> void {} //priority queue implementation using binary min-heap array; //does not require normalize() function. @@ -16,14 +16,27 @@ template void priority_queue_nocallback(type_t) {} //O(log n) append (enqueue) //O(log n) remove (dequeue) template struct priority_queue { - inline void tick(unsigned ticks) { + priority_queue(unsigned size, function callback = &priority_queue_nocallback) : callback(callback) { + heap = new heap_t[size]; + heapcapacity = size; + reset(); + } + + ~priority_queue() { + delete[] heap; + } + + priority_queue(const priority_queue&) = delete; + auto operator=(const priority_queue&) -> priority_queue& = delete; + + inline auto tick(unsigned ticks) -> void { basecounter += ticks; while(heapsize && gte(basecounter, heap[0].counter)) callback(dequeue()); } //counter is relative to current time (eg enqueue(64, ...) fires in 64 ticks); //counter cannot exceed std::numeric_limits::max() >> 1. - void enqueue(unsigned counter, type_t event) { + auto enqueue(unsigned counter, type_t event) -> void { unsigned child = heapsize++; counter += basecounter; @@ -40,7 +53,7 @@ template struct priority_queue { heap[child].event = event; } - type_t dequeue() { + auto dequeue() -> type_t { type_t event(heap[0].event); unsigned parent = 0; unsigned counter = heap[--heapsize].counter; @@ -61,12 +74,12 @@ template struct priority_queue { return event; } - void reset() { + auto reset() -> void { basecounter = 0; heapsize = 0; } - void serialize(serializer& s) { + auto serialize(serializer& s) -> void { s.integer(basecounter); s.integer(heapsize); for(unsigned n = 0; n < heapcapacity; n++) { @@ -75,20 +88,6 @@ template struct priority_queue { } } - priority_queue(unsigned size, function callback = &priority_queue_nocallback) - : callback(callback) { - heap = new heap_t[size]; - heapcapacity = size; - reset(); - } - - ~priority_queue() { - delete[] heap; - } - - priority_queue& operator=(const priority_queue&) = delete; - priority_queue(const priority_queue&) = delete; - private: function callback; unsigned basecounter; @@ -100,7 +99,7 @@ private: } *heap; //return true if x is greater than or equal to y - inline bool gte(unsigned x, unsigned y) { + inline auto gte(unsigned x, unsigned y) -> bool { return x - y < (std::numeric_limits::max() >> 1); } }; diff --git a/nall/property.hpp b/nall/property.hpp index 575acba1..17e9352c 100644 --- a/nall/property.hpp +++ b/nall/property.hpp @@ -5,36 +5,36 @@ namespace nall { template struct property { template struct readonly { - const T* operator->() const { return &value; } - const T& operator()() const { return value; } + auto operator->() const -> const T* { return &value; } + auto operator()() const -> const T& { return value; } operator const T&() const { return value; } private: - T* operator->() { return &value; } + auto operator->() -> T* { return &value; } operator T&() { return value; } - const T& operator=(const T& value_) { return value = value_; } + auto operator=(const T& value_) -> const T& { return value = value_; } T value; friend C; }; template struct writeonly { - void operator=(const T& value_) { value = value_; } + auto operator=(const T& value_) -> void { value = value_; } private: - const T* operator->() const { return &value; } - const T& operator()() const { return value; } + auto operator->() const -> const T* { return &value; } + auto operator()() const -> const T& { return value; } operator const T&() const { return value; } - T* operator->() { return &value; } + auto operator->() -> T* { return &value; } operator T&() { return value; } T value; friend C; }; template struct readwrite { - const T* operator->() const { return &value; } - const T& operator()() const { return value; } + auto operator->() const -> const T* { return &value; } + auto operator()() const -> const T& { return value; } operator const T&() const { return value; } - T* operator->() { return &value; } + auto operator->() -> T* { return &value; } operator T&() { return value; } - const T& operator=(const T& value_) { return value = value_; } + auto operator=(const T& value_) -> const T& { return value = value_; } T value; }; }; diff --git a/nall/random.hpp b/nall/random.hpp index bd443f40..7cfce97b 100644 --- a/nall/random.hpp +++ b/nall/random.hpp @@ -7,23 +7,23 @@ namespace nall { struct RandomNumberGenerator { - virtual void seed(uint64_t) = 0; - virtual uint64_t operator()() = 0; - virtual void serialize(serializer&) = 0; + virtual auto seed(uint64_t) -> void = 0; + virtual auto operator()() -> uint64_t = 0; + virtual auto serialize(serializer&) -> void = 0; }; //Galois LFSR using CRC64 polynomials struct LinearFeedbackShiftRegisterGenerator : RandomNumberGenerator { - void seed(uint64_t seed) { + auto seed(uint64_t seed) -> void { lfsr = seed; for(unsigned n = 0; n < 8; n++) operator()(); } - uint64_t operator()() { + auto operator()() -> uint64_t { return lfsr = (lfsr >> 1) ^ (-(lfsr & 1) & crc64jones); } - void serialize(serializer& s) { + auto serialize(serializer& s) -> void { s.integer(lfsr); } @@ -33,7 +33,7 @@ private: uint64_t lfsr = crc64ecma; }; -inline uint64_t random() { +inline auto random() -> uint64_t { static LinearFeedbackShiftRegisterGenerator lfsr; return lfsr(); } diff --git a/nall/range.hpp b/nall/range.hpp index 54efbb25..159a30d2 100644 --- a/nall/range.hpp +++ b/nall/range.hpp @@ -5,41 +5,41 @@ namespace nall { struct range_t { struct iterator { - signed operator*() const { return position; } - bool operator!=(const iterator& source) const { return step > 0 ? position < source.position : position > source.position; } - iterator& operator++() { position += step; return *this; } iterator(signed position, signed step = 0) : position(position), step(step) {} + auto operator*() const -> signed { return position; } + auto operator!=(const iterator& source) const -> bool { return step > 0 ? position < source.position : position > source.position; } + auto operator++() -> iterator& { position += step; return *this; } private: signed position; const signed step; }; - const iterator begin() const { return iterator(origin, stride); } - const iterator end() const { return iterator(target); } + auto begin() const -> const iterator { return iterator(origin, stride); } + auto end() const -> const iterator { return iterator(target); } signed origin; signed target; signed stride; }; -inline range_t range(signed size) { +inline auto range(signed size) { return range_t{0, size, 1}; } -inline range_t range(signed offset, signed size) { +inline auto range(signed offset, signed size) { return range_t{offset, size, 1}; } -inline range_t range(signed offset, signed size, signed step) { +inline auto range(signed offset, signed size, signed step) { return range_t{offset, size, step}; } -inline range_t range_reverse(signed size) { +inline auto rangeReverse(signed size) { return range_t{size - 1, -1, -1}; } -template inline range_t range(const vector& container) { +template inline auto range(const vector& container) { return range_t{0, (signed)container.size(), 1}; } diff --git a/nall/serial.hpp b/nall/serial.hpp index 14d2b321..6bdc810f 100644 --- a/nall/serial.hpp +++ b/nall/serial.hpp @@ -17,7 +17,16 @@ namespace nall { struct serial { - bool readable() { + serial() { + port = -1; + port_open = false; + } + + ~serial() { + close(); + } + + auto readable() -> bool { if(port_open == false) return false; fd_set fdset; FD_ZERO(&fdset); @@ -31,12 +40,12 @@ struct serial { } //-1 on error, otherwise return bytes read - int read(uint8_t* data, unsigned length) { + auto read(uint8_t* data, unsigned length) -> int { if(port_open == false) return -1; return ::read(port, (void*)data, length); } - bool writable() { + auto writable() -> bool { if(port_open == false) return false; fd_set fdset; FD_ZERO(&fdset); @@ -50,12 +59,12 @@ struct serial { } //-1 on error, otherwise return bytes written - int write(const uint8_t* data, unsigned length) { + auto write(const uint8_t* data, unsigned length) -> int { if(port_open == false) return -1; return ::write(port, (void*)data, length); } - bool open(const string& portname, unsigned rate, bool flowcontrol) { + auto open(const string& portname, unsigned rate, bool flowcontrol) -> bool { close(); port = ::open(portname, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK); @@ -86,7 +95,7 @@ struct serial { return port_open = true; } - void close() { + auto close() -> void { if(port != -1) { tcdrain(port); if(port_open == true) { @@ -98,15 +107,6 @@ struct serial { } } - serial() { - port = -1; - port_open = false; - } - - ~serial() { - close(); - } - private: int port; bool port_open; diff --git a/nall/serializer.hpp b/nall/serializer.hpp index 5b2c8ef6..ce4171c4 100644 --- a/nall/serializer.hpp +++ b/nall/serializer.hpp @@ -23,31 +23,31 @@ struct serializer; template struct has_serialize { - template static char test(decltype(std::declval().serialize(std::declval()))*); - template static long test(...); + template static auto test(decltype(std::declval().serialize(std::declval()))*) -> char; + template static auto test(...) -> long; static const bool value = sizeof(test(0)) == sizeof(char); }; struct serializer { enum mode_t { Load, Save, Size }; - mode_t mode() const { + auto mode() const -> mode_t { return _mode; } - const uint8_t* data() const { + auto data() const -> const uint8_t* { return _data; } - unsigned size() const { + auto size() const -> unsigned { return _size; } - unsigned capacity() const { + auto capacity() const -> unsigned { return _capacity; } - template serializer& floatingpoint(T& value) { + template auto floatingpoint(T& value) -> serializer& { enum { size = sizeof(T) }; //this is rather dangerous, and not cross-platform safe; //but there is no standardized way to export FP-values @@ -62,7 +62,7 @@ struct serializer { return *this; } - template serializer& integer(T& value) { + template auto integer(T& value) -> serializer& { enum { size = std::is_same::value ? 1 : sizeof(T) }; if(_mode == Save) { for(unsigned n = 0; n < size; n++) _data[_size++] = (uintmax_t)value >> (n << 3); @@ -75,23 +75,23 @@ struct serializer { return *this; } - template serializer& array(T (&array)[N]) { + template auto array(T (&array)[N]) -> serializer& { for(unsigned n = 0; n < N; n++) operator()(array[n]); return *this; } - template serializer& array(T array, unsigned size) { + template auto array(T array, unsigned size) -> serializer& { for(unsigned n = 0; n < size; n++) operator()(array[n]); return *this; } - template serializer& operator()(T& value, typename std::enable_if::value>::type* = 0) { value.serialize(*this); return *this; } - template serializer& operator()(T& value, typename std::enable_if::value>::type* = 0) { return integer(value); } - template serializer& operator()(T& value, typename std::enable_if::value>::type* = 0) { return floatingpoint(value); } - template serializer& operator()(T& value, typename std::enable_if::value>::type* = 0) { return array(value); } - template serializer& operator()(T& value, unsigned size, typename std::enable_if::value>::type* = 0) { return array(value, size); } + template auto operator()(T& value, typename std::enable_if::value>::type* = 0) -> serializer& { value.serialize(*this); return *this; } + template auto operator()(T& value, typename std::enable_if::value>::type* = 0) -> serializer& { return integer(value); } + template auto operator()(T& value, typename std::enable_if::value>::type* = 0) -> serializer& { return floatingpoint(value); } + template auto operator()(T& value, typename std::enable_if::value>::type* = 0) -> serializer& { return array(value); } + template auto operator()(T& value, unsigned size, typename std::enable_if::value>::type* = 0) -> serializer& { return array(value, size); } - serializer& operator=(const serializer& s) { + auto operator=(const serializer& s) -> serializer& { if(_data) delete[] _data; _mode = s._mode; @@ -103,7 +103,7 @@ struct serializer { return *this; } - serializer& operator=(serializer&& s) { + auto operator=(serializer&& s) -> serializer& { if(_data) delete[] _data; _mode = s._mode; @@ -117,7 +117,7 @@ struct serializer { serializer() = default; serializer(const serializer& s) { operator=(s); } - serializer(serializer&& s) { operator=(std::move(s)); } + serializer(serializer&& s) { operator=(move(s)); } serializer(unsigned capacity) { _mode = Save; diff --git a/nall/set.hpp b/nall/set.hpp index d463296d..14121c5d 100644 --- a/nall/set.hpp +++ b/nall/set.hpp @@ -29,33 +29,33 @@ template struct set { node_t* root = nullptr; unsigned nodes = 0; - set& operator=(const set& source) { copy(source); return *this; } - set& operator=(set&& source) { move(std::move(source)); return *this; } + auto operator=(const set& source) -> set& { copy(source); return *this; } + auto operator=(set&& source) -> set& { move(std::move(source)); return *this; } set(const set& source) { operator=(source); } - set(set&& source) { operator=(std::move(source)); } + set(set&& source) { operator=(move(source)); } set(std::initializer_list list) { for(auto& value : list) insert(value); } set() = default; ~set() { reset(); } - unsigned size() const { return nodes; } - bool empty() const { return nodes == 0; } + auto size() const -> unsigned { return nodes; } + auto empty() const -> bool { return nodes == 0; } - void reset() { + auto reset() -> void { reset(root); nodes = 0; } - maybe find(const T& value) { + auto find(const T& value) -> maybe { if(node_t* node = find(root, value)) return node->value; return nothing; } - maybe find(const T& value) const { + auto find(const T& value) const -> maybe { if(node_t* node = find(root, value)) return node->value; return nothing; } - maybe insert(const T& value) { + auto insert(const T& value) -> maybe { unsigned count = size(); node_t* v = insert(root, value); root->red = 0; @@ -63,13 +63,13 @@ template struct set { return v->value; } - template bool insert(const T& value, Args&&... args) { + template auto insert(const T& value, Args&&... args) -> bool { bool result = insert(value); - insert(std::forward(args)...) | result; + insert(forward(args)...) | result; return result; } - bool remove(const T& value) { + auto remove(const T& value) -> bool { unsigned count = size(); bool done = 0; remove(root, &value, done); @@ -77,15 +77,15 @@ template struct set { return size() < count; } - template bool remove(const T& value, Args&&... args) { + template auto remove(const T& value, Args&&... args) -> bool { bool result = remove(value); - return remove(std::forward(args)...) | result; + return remove(forward(args)...) | result; } struct base_iterator { - bool operator!=(const base_iterator& source) const { return position != source.position; } + auto operator!=(const base_iterator& source) const -> bool { return position != source.position; } - base_iterator& operator++() { + auto operator++() -> base_iterator& { if(++position >= source.size()) { position = source.size(); return *this; } if(stack.last()->link[1]) { @@ -115,23 +115,23 @@ template struct set { }; struct iterator : base_iterator { - T& operator*() const { return base_iterator::stack.last()->value; } iterator(const set& source, unsigned position) : base_iterator(source, position) {} + auto operator*() const -> T& { return base_iterator::stack.last()->value; } }; - iterator begin() { return iterator(*this, 0); } - iterator end() { return iterator(*this, size()); } + auto begin() -> iterator { return iterator(*this, 0); } + auto end() -> iterator { return iterator(*this, size()); } struct const_iterator : base_iterator { - const T& operator*() const { return base_iterator::stack.last()->value; } const_iterator(const set& source, unsigned position) : base_iterator(source, position) {} + auto operator*() const -> const T& { return base_iterator::stack.last()->value; } }; - const const_iterator begin() const { return const_iterator(*this, 0); } - const const_iterator end() const { return const_iterator(*this, size()); } + auto begin() const -> const const_iterator { return const_iterator(*this, 0); } + auto end() const -> const const_iterator { return const_iterator(*this, size()); } private: - void reset(node_t*& node) { + auto reset(node_t*& node) -> void { if(!node) return; if(node->link[0]) reset(node->link[0]); if(node->link[1]) reset(node->link[1]); @@ -139,13 +139,13 @@ private: node = nullptr; } - void copy(const set& source) { + auto copy(const set& source) -> void { reset(); copy(root, source.root); nodes = source.nodes; } - void copy(node_t*& target, const node_t* source) { + auto copy(node_t*& target, const node_t* source) -> void { if(!source) return; target = new node_t(source->value); target->red = source->red; @@ -153,23 +153,23 @@ private: copy(target->link[1], source->link[1]); } - void move(set&& source) { + auto move(set&& source) -> void { root = source.root; nodes = source.nodes; source.root = nullptr; source.nodes = 0; } - node_t* find(node_t* node, const T& value) const { + auto find(node_t* node, const T& value) const -> node_t* { if(node == nullptr) return nullptr; if(node->value == value) return node; return find(node->link[node->value < value], value); } - bool red(node_t* node) const { return node && node->red; } - bool black(node_t* node) const { return !red(node); } + auto red(node_t* node) const -> bool { return node && node->red; } + auto black(node_t* node) const -> bool { return !red(node); } - void rotate(node_t*& a, bool dir) { + auto rotate(node_t*& a, bool dir) -> void { node_t*& b = a->link[!dir]; node_t*& c = b->link[dir]; a->red = 1, b->red = 0; @@ -177,12 +177,12 @@ private: std::swap(b, c); } - void rotateTwice(node_t*& node, bool dir) { + auto rotateTwice(node_t*& node, bool dir) -> void { rotate(node->link[!dir], !dir); rotate(node, dir); } - node_t* insert(node_t*& node, const T& value) { + auto insert(node_t*& node, const T& value) -> node_t* { if(!node) { nodes++; node = new node_t(value); return node; } if(node->value == value) { node->value = value; return node; } //prevent duplicate entries @@ -203,7 +203,7 @@ private: return v; } - void balance(node_t*& node, bool dir, bool& done) { + auto balance(node_t*& node, bool dir, bool& done) -> void { node_t* p = node; node_t* s = node->link[!dir]; if(!s) return; @@ -234,7 +234,7 @@ private: } } - void remove(node_t*& node, const T* value, bool& done) { + auto remove(node_t*& node, const T* value, bool& done) -> void { if(!node) { done = 1; return; } if(node->value == *value) { diff --git a/nall/smtp.hpp b/nall/smtp.hpp index 54197e9a..17d78624 100644 --- a/nall/smtp.hpp +++ b/nall/smtp.hpp @@ -21,22 +21,22 @@ namespace nall { struct SMTP { enum class Format : unsigned { Plain, HTML }; - inline void server(string server, uint16_t port = 25); - inline void from(string mail, string name = ""); - inline void to(string mail, string name = ""); - inline void cc(string mail, string name = ""); - inline void bcc(string mail, string name = ""); - inline void attachment(const uint8_t* data, unsigned size, string name); - inline bool attachment(string filename, string name = ""); - inline void subject(string subject); - inline void body(string body, Format format = Format::Plain); + inline auto server(string server, uint16_t port = 25) -> void; + inline auto from(string mail, string name = "") -> void; + inline auto to(string mail, string name = "") -> void; + inline auto cc(string mail, string name = "") -> void; + inline auto bcc(string mail, string name = "") -> void; + inline auto attachment(const uint8_t* data, unsigned size, string name) -> void; + inline auto attachment(string filename, string name = "") -> bool; + inline auto subject(string subject) -> void; + inline auto body(string body, Format format = Format::Plain) -> void; - inline bool send(); - inline string message(); - inline string response(); + inline auto send() -> bool; + inline auto message() -> string; + inline auto response() -> string; - #ifdef _WIN32 - inline int close(int); + #if defined(API_WINDOWS) + inline auto close(int) -> int; inline SMTP(); #endif @@ -65,44 +65,44 @@ private: string response; } info; - inline bool send(int sock, const string& text); - inline string recv(int sock); - inline string boundary(); - inline string filename(const string& filename); - inline string contact(const Information::Contact& contact); - inline string contacts(const vector& contacts); - inline string split(const string& text); + inline auto send(int sock, const string& text) -> bool; + inline auto recv(int sock) -> string; + inline auto boundary() -> string; + inline auto filename(const string& filename) -> string; + inline auto contact(const Information::Contact& contact) -> string; + inline auto contacts(const vector& contacts) -> string; + inline auto split(const string& text) -> string; }; -void SMTP::server(string server, uint16_t port) { +auto SMTP::server(string server, uint16_t port) -> void { info.server = server; info.port = port; } -void SMTP::from(string mail, string name) { +auto SMTP::from(string mail, string name) -> void { info.from = {mail, name}; } -void SMTP::to(string mail, string name) { +auto SMTP::to(string mail, string name) -> void { info.to.append({mail, name}); } -void SMTP::cc(string mail, string name) { +auto SMTP::cc(string mail, string name) -> void { info.cc.append({mail, name}); } -void SMTP::bcc(string mail, string name) { +auto SMTP::bcc(string mail, string name) -> void { info.bcc.append({mail, name}); } -void SMTP::attachment(const uint8_t* data, unsigned size, string name) { +auto SMTP::attachment(const uint8_t* data, unsigned size, string name) -> void { vector buffer; buffer.resize(size); memcpy(buffer.data(), data, size); info.attachments.append({std::move(buffer), name}); } -bool SMTP::attachment(string filename, string name) { +auto SMTP::attachment(string filename, string name) -> bool { if(!file::exists(filename)) return false; if(name == "") name = notdir(filename); auto buffer = file::read(filename); @@ -110,16 +110,16 @@ bool SMTP::attachment(string filename, string name) { return true; } -void SMTP::subject(string subject) { +auto SMTP::subject(string subject) -> void { info.subject = subject; } -void SMTP::body(string body, Format format) { +auto SMTP::body(string body, Format format) -> void { info.body = body; info.format = format; } -bool SMTP::send() { +auto SMTP::send() -> bool { info.message.append("From: =?UTF-8?B?", Base64::encode(contact(info.from)), "?=\r\n"); info.message.append("To: =?UTF-8?B?", Base64::encode(contacts(info.to)), "?=\r\n"); info.message.append("Cc: =?UTF-8?B?", Base64::encode(contacts(info.cc)), "?=\r\n"); @@ -214,15 +214,15 @@ bool SMTP::send() { return true; } -string SMTP::message() { +auto SMTP::message() -> string { return info.message; } -string SMTP::response() { +auto SMTP::response() -> string { return info.response; } -bool SMTP::send(int sock, const string& text) { +auto SMTP::send(int sock, const string& text) -> bool { const char* data = text.data(); unsigned size = text.size(); while(size) { @@ -234,7 +234,7 @@ bool SMTP::send(int sock, const string& text) { return true; } -string SMTP::recv(int sock) { +auto SMTP::recv(int sock) -> string { vector buffer; while(true) { char c; @@ -246,7 +246,7 @@ string SMTP::recv(int sock) { return buffer; } -string SMTP::boundary() { +auto SMTP::boundary() -> string { random_lfsr random; random.seed(time(0)); string boundary; @@ -254,7 +254,7 @@ string SMTP::boundary() { return boundary; } -string SMTP::filename(const string& filename) { +auto SMTP::filename(const string& filename) -> string { string result; for(auto& n : filename) { if(n <= 32 || n >= 127) result.append("%", hex<2>(n)); @@ -263,21 +263,21 @@ string SMTP::filename(const string& filename) { return result; } -string SMTP::contact(const Information::Contact& contact) { +auto SMTP::contact(const Information::Contact& contact) -> string { if(!contact.name) return contact.mail; return {"\"", contact.name, "\" <", contact.mail, ">"}; } -string SMTP::contacts(const vector& contacts) { +auto SMTP::contacts(const vector& contacts) -> string { string result; for(auto& contact : contacts) { result.append(this->contact(contact), "; "); } - result.rtrim("; "); + result.rtrim("; ", 1L); return result; } -string SMTP::split(const string& text) { +auto SMTP::split(const string& text) -> string { string result; unsigned offset = 0; @@ -294,8 +294,8 @@ string SMTP::split(const string& text) { return result; } -#ifdef _WIN32 -int SMTP::close(int sock) { +#if defined(API_WINDOWS) +auto SMTP::close(int sock) -> int { return closesocket(sock); } diff --git a/nall/sort.hpp b/nall/sort.hpp index 5517dd3a..1eaec2fe 100644 --- a/nall/sort.hpp +++ b/nall/sort.hpp @@ -20,7 +20,7 @@ namespace nall { -template void sort(T list[], unsigned size, const Comparator& lessthan) { +template auto sort(T list[], unsigned size, const Comparator& lessthan) -> void { if(size <= 1) return; //nothing to sort //use insertion sort to quickly sort smaller blocks @@ -68,7 +68,7 @@ template void sort(T list[], unsigned size, con delete[] buffer; } -template void sort(T list[], unsigned size) { +template auto sort(T list[], unsigned size) -> void { return sort(list, size, [](const T& l, const T& r) { return l < r; }); } diff --git a/nall/string/atoi.hpp b/nall/string/atoi.hpp index 9af86f16..97e2d91c 100644 --- a/nall/string/atoi.hpp +++ b/nall/string/atoi.hpp @@ -16,6 +16,10 @@ auto string::decimal() const -> uintmax_t { return nall::decimal(data()); } +auto string::real() const -> double { + return nall::real(data()); +} + } #endif diff --git a/nall/string/base.hpp b/nall/string/base.hpp index f531699e..23eecfd7 100644 --- a/nall/string/base.hpp +++ b/nall/string/base.hpp @@ -59,13 +59,13 @@ inline auto ifindFrom(const string& self, signed offset, rstring source) -> mayb //format.hpp template inline auto print(P&&...) -> void; -template inline auto integer(intmax_t value) -> string; -template inline auto decimal(uintmax_t value) -> string; -template inline auto hex(uintmax_t value) -> string; -template inline auto octal(uintmax_t value) -> string; -template inline auto binary(uintmax_t value) -> string; -template inline auto pointer(const T* value) -> string; -template inline auto pointer(uintptr_t value) -> string; +inline auto integer(intmax_t value, long precision = 0, char padchar = '0') -> string; +inline auto decimal(uintmax_t value, long precision = 0, char padchar = '0') -> string; +inline auto hex(uintmax_t value, long precision = 0, char padchar = '0') -> string; +inline auto octal(uintmax_t value, long precision = 0, char padchar = '0') -> string; +inline auto binary(uintmax_t value, long precision = 0, char padchar = '0') -> string; +template inline auto pointer(const T* value, long precision = 0) -> string; +inline auto pointer(uintptr_t value, long precision = 0) -> string; inline auto real(long double value) -> string; //hash.hpp @@ -98,31 +98,31 @@ inline auto sharedpath() -> string; inline auto temppath() -> string; //replace.hpp -template inline auto _replace(string& self, rstring from, rstring to) -> string&; -template inline auto replace(string& self, rstring from, rstring to) -> string&; -template inline auto ireplace(string& self, rstring from, rstring to) -> string&; -template inline auto qreplace(string& self, rstring from, rstring to) -> string&; -template inline auto iqreplace(string& self, rstring from, rstring to) -> string&; +template inline auto _replace(string& self, rstring from, rstring to, long limit = LONG_MAX) -> string&; +inline auto replace(string& self, rstring from, rstring to, long limit = LONG_MAX) -> string&; +inline auto ireplace(string& self, rstring from, rstring to, long limit = LONG_MAX) -> string&; +inline auto qreplace(string& self, rstring from, rstring to, long limit = LONG_MAX) -> string&; +inline auto iqreplace(string& self, rstring from, rstring to, long limit = LONG_MAX) -> string&; //split.hpp -template inline auto _split(lstring& self, rstring source, rstring find) -> lstring&; -template inline auto split(string& self, rstring key) -> lstring; -template inline auto isplit(string& self, rstring key) -> lstring; -template inline auto qsplit(string& self, rstring key) -> lstring; -template inline auto iqsplit(string& self, rstring key) -> lstring; +template inline auto _split(lstring& self, rstring source, rstring find, long limit = LONG_MAX) -> lstring&; +inline auto split(string& self, rstring key, long limit = LONG_MAX) -> lstring; +inline auto isplit(string& self, rstring key, long limit = LONG_MAX) -> lstring; +inline auto qsplit(string& self, rstring key, long limit = LONG_MAX) -> lstring; +inline auto iqsplit(string& self, rstring key, long limit = LONG_MAX) -> lstring; //trim.hpp -inline auto trim(string& self, rstring lhs, rstring rhs) -> bool; -inline auto ltrim(string& self, rstring lhs) -> bool; -inline auto rtrim(string& self, rstring rhs) -> bool; +inline auto trim(string& self, rstring lhs, rstring rhs, long limit = LONG_MAX) -> string&; +inline auto ltrim(string& self, rstring lhs, long limit = LONG_MAX) -> string&; +inline auto rtrim(string& self, rstring rhs, long limit = LONG_MAX) -> string&; -inline auto itrim(string& self, rstring lhs, rstring rhs) -> bool; -inline auto iltrim(string& self, rstring lhs) -> bool; -inline auto irtrim(string& self, rstring rhs) -> bool; +inline auto itrim(string& self, rstring lhs, rstring rhs, long limit = LONG_MAX) -> string&; +inline auto iltrim(string& self, rstring lhs, long limit = LONG_MAX) -> string&; +inline auto irtrim(string& self, rstring rhs, long limit = LONG_MAX) -> string&; -inline auto strip(string& self) -> bool; -inline auto lstrip(string& self) -> bool; -inline auto rstrip(string& self) -> bool; +inline auto strip(string& self) -> string&; +inline auto lstrip(string& self) -> string&; +inline auto rstrip(string& self) -> string&; //utility.hpp inline auto fill(string& self, char fill = ' ') -> string&; @@ -190,7 +190,7 @@ public: inline auto operator=(const string&) -> type&; inline auto operator=(string&&) -> type&; - template string(T&& s, P&&... p) : string() { append(std::forward(s), std::forward

(p)...); } + template string(T&& s, P&&... p) : string() { append(forward(s), forward

(p)...); } ~string() { reset(); } explicit operator bool() const { return _size; } @@ -222,6 +222,7 @@ public: //atoi.hpp inline auto integer() const -> intmax_t; inline auto decimal() const -> uintmax_t; + inline auto real() const -> double; //core.hpp inline auto operator[](signed) const -> const char&; @@ -236,7 +237,7 @@ public: //utility.hpp inline static auto read(const string& filename) -> string; - template inline static auto repeat(const string& pattern) -> string; + inline static auto repeat(const string& pattern, unsigned times) -> string; //extension methods //================= @@ -264,8 +265,8 @@ public: auto transform(rstring from, rstring to) -> type& { return nall::transform(*this, from, to); } //core.hpp - template auto assign(P&&... p) -> type& { return nall::assign(*this, std::forward

(p)...); } - template auto append(P&&... p) -> type& { return nall::append(*this, std::forward

(p)...); } + template auto assign(P&&... p) -> type& { return nall::assign(*this, forward

(p)...); } + template auto append(P&&... p) -> type& { return nall::append(*this, forward

(p)...); } auto empty() const -> bool { return nall::empty(*this); } auto length() const -> unsigned { return nall::length(*this); } @@ -297,29 +298,29 @@ public: auto suffixname() const -> string { return nall::suffixname(*this); } //replace.hpp - template auto replace(rstring from, rstring to) -> type& { return nall::_replace(*this, from, to); } - template auto ireplace(rstring from, rstring to) -> type& { return nall::_replace(*this, from, to); } - template auto qreplace(rstring from, rstring to) -> type& { return nall::_replace(*this, from, to); } - template auto iqreplace(rstring from, rstring to) -> type& { return nall::_replace(*this, from, to); } + auto replace(rstring from, rstring to, long limit = LONG_MAX) -> type& { return nall::_replace<0, 0>(*this, from, to, limit); } + auto ireplace(rstring from, rstring to, long limit = LONG_MAX) -> type& { return nall::_replace<1, 0>(*this, from, to, limit); } + auto qreplace(rstring from, rstring to, long limit = LONG_MAX) -> type& { return nall::_replace<0, 1>(*this, from, to, limit); } + auto iqreplace(rstring from, rstring to, long limit = LONG_MAX) -> type& { return nall::_replace<1, 1>(*this, from, to, limit); } //split.hpp - template inline auto split(rstring key) const -> lstring; - template inline auto isplit(rstring key) const -> lstring; - template inline auto qsplit(rstring key) const -> lstring; - template inline auto iqsplit(rstring key) const -> lstring; + inline auto split(rstring key, long limit = LONG_MAX) const -> lstring; + inline auto isplit(rstring key, long limit = LONG_MAX) const -> lstring; + inline auto qsplit(rstring key, long limit = LONG_MAX) const -> lstring; + inline auto iqsplit(rstring key, long limit = LONG_MAX) const -> lstring; //trim.hpp - auto trim(rstring lhs, rstring rhs) -> type& { return nall::trim(*this, lhs, rhs), *this; } - auto ltrim(rstring lhs) -> type& { return nall::ltrim(*this, lhs), *this; } - auto rtrim(rstring rhs) -> type& { return nall::rtrim(*this, rhs), *this; } + auto trim(rstring lhs, rstring rhs, long limit = LONG_MAX) -> type& { return nall::trim(*this, lhs, rhs, limit); } + auto ltrim(rstring lhs, long limit = LONG_MAX) -> type& { return nall::ltrim(*this, lhs, limit); } + auto rtrim(rstring rhs, long limit = LONG_MAX) -> type& { return nall::rtrim(*this, rhs, limit); } - auto itrim(rstring lhs, rstring rhs) -> type& { return nall::itrim(*this, lhs, rhs), *this; } - auto iltrim(rstring lhs) -> type& { return nall::iltrim(*this, lhs), *this; } - auto irtrim(rstring rhs) -> type& { return nall::irtrim(*this, rhs), *this; } + auto itrim(rstring lhs, rstring rhs, long limit = LONG_MAX) -> type& { return nall::itrim(*this, lhs, rhs, limit); } + auto iltrim(rstring lhs, long limit = LONG_MAX) -> type& { return nall::iltrim(*this, lhs, limit); } + auto irtrim(rstring rhs, long limit = LONG_MAX) -> type& { return nall::irtrim(*this, rhs, limit); } - auto strip() -> type& { return nall::strip(*this), *this; } - auto lstrip() -> type& { return nall::lstrip(*this), *this; } - auto rstrip() -> type& { return nall::rstrip(*this), *this; } + auto strip() -> type& { return nall::strip(*this); } + auto lstrip() -> type& { return nall::lstrip(*this); } + auto rstrip() -> type& { return nall::rstrip(*this); } //utility.hpp auto fill(char fill = ' ') -> type& { return nall::fill(*this, fill); } @@ -348,7 +349,7 @@ struct lstring : vector { lstring(const lstring& source) { vector::operator=(source); } lstring(lstring& source) { vector::operator=(source); } lstring(lstring&& source) { vector::operator=(std::move(source)); } - template lstring(P&&... p) { append(std::forward

(p)...); } + template lstring(P&&... p) { append(forward

(p)...); } //list.hpp inline auto operator==(const lstring&) const -> bool; @@ -364,17 +365,17 @@ struct lstring : vector { //================= //list.hpp - template auto append(P&&... p) -> type& { return nall::append(*this, std::forward

(p)...); } + template auto append(P&&... p) -> type& { return nall::append(*this, forward

(p)...); } auto find(const string& source) const -> maybe { return nall::find(*this, source); } auto ifind(const string& source) const -> maybe { return nall::ifind(*this, source); } auto merge(const string& separator) const -> string { return nall::merge(*this, separator); } auto strip() -> type& { return nall::strip(*this); } //split.hpp - template auto split(rstring source, rstring on) -> type& { return nall::_split(*this, source, on); } - template auto isplit(rstring source, rstring on) -> type& { return nall::_split(*this, source, on); } - template auto qsplit(rstring source, rstring on) -> type& { return nall::_split(*this, source, on); } - template auto iqsplit(rstring source, rstring on) -> type& { return nall::_split(*this, source, on); } + auto split(rstring source, rstring on, long limit = LONG_MAX) -> type& { return nall::_split<0, 0>(*this, source, on, limit); } + auto isplit(rstring source, rstring on, long limit = LONG_MAX) -> type& { return nall::_split<1, 0>(*this, source, on, limit); } + auto qsplit(rstring source, rstring on, long limit = LONG_MAX) -> type& { return nall::_split<0, 1>(*this, source, on, limit); } + auto iqsplit(rstring source, rstring on, long limit = LONG_MAX) -> type& { return nall::_split<1, 1>(*this, source, on, limit); } }; //format.hpp @@ -384,8 +385,8 @@ inline auto append(format& self) -> format&; struct format : vector { using type = format; - template format(P&&... p) { reserve(sizeof...(p)); append(std::forward

(p)...); } - template auto append(P&&... p) -> type& { return nall::append(*this, std::forward

(p)...); } + template format(P&&... p) { reserve(sizeof...(p)); append(forward

(p)...); } + template auto append(P&&... p) -> type& { return nall::append(*this, forward

(p)...); } }; } diff --git a/nall/string/datetime.hpp b/nall/string/datetime.hpp index bf27007c..95016026 100644 --- a/nall/string/datetime.hpp +++ b/nall/string/datetime.hpp @@ -6,9 +6,9 @@ auto string::date(time_t timestamp) -> string { if(timestamp == 0) timestamp = ::time(nullptr); tm* info = localtime(×tamp); return { - nall::decimal<4>(1900 + info->tm_year), "-", - nall::decimal<2>(1 + info->tm_mon), "-", - nall::decimal<2>(info->tm_mday) + nall::decimal(1900 + info->tm_year, 4L), "-", + nall::decimal(1 + info->tm_mon, 2L), "-", + nall::decimal(info->tm_mday, 2L) }; } @@ -16,9 +16,9 @@ auto string::time(time_t timestamp) -> string { if(timestamp == 0) timestamp = ::time(nullptr); tm* info = localtime(×tamp); return { - nall::decimal<2>(info->tm_hour), ":", - nall::decimal<2>(info->tm_min), ":", - nall::decimal<2>(info->tm_sec) + nall::decimal(info->tm_hour, 2L), ":", + nall::decimal(info->tm_min, 2L), ":", + nall::decimal(info->tm_sec, 2L) }; } diff --git a/nall/string/eval/evaluator.hpp b/nall/string/eval/evaluator.hpp index 5e77ff7f..da6023b1 100644 --- a/nall/string/eval/evaluator.hpp +++ b/nall/string/eval/evaluator.hpp @@ -29,7 +29,7 @@ inline string evaluateExpression(Node* node) { for(auto& link : node->link) { result.append(evaluateExpression(link), ", "); } - return result.rtrim(", ").append(")"); + return result.rtrim(", ", 1L).append(")"); } } #undef p diff --git a/nall/string/format.hpp b/nall/string/format.hpp index 827850c5..739895d2 100644 --- a/nall/string/format.hpp +++ b/nall/string/format.hpp @@ -73,7 +73,7 @@ template auto print(P&&... p) -> void { fputs(s.data(), stdout); } -template auto integer(intmax_t value) -> string { +auto integer(intmax_t value, long precision, char padchar) -> string { string buffer; buffer.resize(1 + sizeof(intmax_t) * 3); char* p = buffer.pointer(); @@ -92,7 +92,7 @@ template auto integer(intmax_t value) -> string return buffer; } -template auto decimal(uintmax_t value) -> string { +auto decimal(uintmax_t value, long precision, char padchar) -> string { string buffer; buffer.resize(sizeof(uintmax_t) * 3); char* p = buffer.pointer(); @@ -108,7 +108,7 @@ template auto decimal(uintmax_t value) -> string return buffer; } -template auto hex(uintmax_t value) -> string { +auto hex(uintmax_t value, long precision, char padchar) -> string { string buffer; buffer.resize(sizeof(uintmax_t) * 2); char* p = buffer.pointer(); @@ -125,7 +125,7 @@ template auto hex(uintmax_t value) -> string { return buffer; } -template auto octal(uintmax_t value) -> string { +auto octal(uintmax_t value, long precision, char padchar) -> string { string buffer; buffer.resize(sizeof(uintmax_t) * 3); char* p = buffer.pointer(); @@ -141,7 +141,7 @@ template auto octal(uintmax_t value) -> string { return buffer; } -template auto binary(uintmax_t value) -> string { +auto binary(uintmax_t value, long precision, char padchar) -> string { string buffer; buffer.resize(sizeof(uintmax_t) * 8); char* p = buffer.pointer(); @@ -157,14 +157,14 @@ template auto binary(uintmax_t value) -> string return buffer; } -template auto pointer(const T* value) -> string { +template auto pointer(const T* value, long precision) -> string { if(value == nullptr) return "(null)"; - return {"0x", hex((uintptr_t)value)}; + return {"0x", hex((uintptr_t)value, precision)}; } -template auto pointer(uintptr_t value) -> string { +auto pointer(uintptr_t value, long precision) -> string { if(value == 0) return "(null)"; - return {"0x", hex(value)}; + return {"0x", hex(value, precision)}; } auto real(long double value) -> string { diff --git a/nall/string/hash.hpp b/nall/string/hash.hpp index 98084ec4..52c3a825 100644 --- a/nall/string/hash.hpp +++ b/nall/string/hash.hpp @@ -4,16 +4,16 @@ namespace nall { namespace Hash { auto CRC16::digest() -> string { - return hex<4>(value()); + return hex(value(), 4L); } auto CRC32::digest() -> string { - return hex<8>(value()); + return hex(value(), 8L); } auto SHA256::digest() const -> string { string result; - for(auto n : value()) result.append(hex<2>(n)); + for(auto n : value()) result.append(hex(n, 2L)); return result; } } diff --git a/nall/string/markup/bml.hpp b/nall/string/markup/bml.hpp index 3df074ed..17d62b08 100644 --- a/nall/string/markup/bml.hpp +++ b/nall/string/markup/bml.hpp @@ -75,7 +75,7 @@ protected: if(length == 0) throw "Invalid attribute name"; node->_name = substr(p, 0, length); node->parseData(p += length); - node->_value.rtrim("\n"); + node->_value.rtrim("\n", 1L); _children.append(node); } } @@ -102,7 +102,7 @@ protected: _children.append(node); } - _value.rtrim("\n"); + _value.rtrim("\n", 1L); } //read top-level nodes diff --git a/nall/string/markup/find.hpp b/nall/string/markup/find.hpp index e0080cb1..ca8e7a93 100644 --- a/nall/string/markup/find.hpp +++ b/nall/string/markup/find.hpp @@ -23,12 +23,12 @@ auto ManagedNode::_evaluate(string query) const -> bool { lstring side; switch(comparator) { - case Comparator::EQ: side = rule.split<1> ("="); break; - case Comparator::NE: side = rule.split<1>("!="); break; - case Comparator::LT: side = rule.split<1> ("<"); break; - case Comparator::LE: side = rule.split<1>("<="); break; - case Comparator::GT: side = rule.split<1> (">"); break; - case Comparator::GE: side = rule.split<1>(">="); break; + case Comparator::EQ: side = rule.split ("=", 1L); break; + case Comparator::NE: side = rule.split("!=", 1L); break; + case Comparator::LT: side = rule.split ("<", 1L); break; + case Comparator::LE: side = rule.split("<=", 1L); break; + case Comparator::GT: side = rule.split (">", 1L); break; + case Comparator::GE: side = rule.split(">=", 1L); break; } string data = string{_value}.strip(); @@ -61,10 +61,10 @@ auto ManagedNode::_find(const string& query) const -> vector { unsigned lo = 0u, hi = ~0u; if(name.match("*[*]")) { - auto p = name.rtrim("]").split<1>("["); + auto p = name.rtrim("]", 1L).split("[", 1L); name = p(0); if(p(1).find("-")) { - p = p(1).split<1>("-"); + p = p(1).split("-", 1L); lo = p(0).empty() ? 0u : p(0).decimal(); hi = p(1).empty() ? ~0u : p(1).decimal(); } else { @@ -73,7 +73,7 @@ auto ManagedNode::_find(const string& query) const -> vector { } if(name.match("*(*)")) { - auto p = name.rtrim(")").split<1>("("); + auto p = name.rtrim(")", 1L).split("(", 1L); name = p(0); rule = p(1); } diff --git a/nall/string/replace.hpp b/nall/string/replace.hpp index f27b06ad..96cd2537 100644 --- a/nall/string/replace.hpp +++ b/nall/string/replace.hpp @@ -2,9 +2,9 @@ namespace nall { -template -auto _replace(string& self, rstring from, rstring to) -> string& { - if(Limit == 0 || from.size() == 0) return self; +template +auto _replace(string& self, rstring from, rstring to, long limit) -> string& { + if(limit <= 0 || from.size() == 0) return self; signed size = self.size(); signed matches = 0; @@ -17,7 +17,7 @@ auto _replace(string& self, rstring from, rstring to) -> string& { if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } } if(_compare(p + n, size - n, from.data(), from.size())) { n++; continue; } - if(++matches >= Limit) break; + if(++matches >= limit) break; n += from.size(); } } @@ -86,10 +86,10 @@ auto _replace(string& self, rstring from, rstring to) -> string& { return self; } -template auto replace(string& self, rstring from, rstring to) -> string& { return _replace(self, from, to); } -template auto ireplace(string& self, rstring from, rstring to) -> string& { return _replace(self, from, to); } -template auto qreplace(string& self, rstring from, rstring to) -> string& { return _replace(self, from, to); } -template auto iqreplace(string& self, rstring from, rstring to) -> string& { return _replace(self, from, to); } +auto replace(string& self, rstring from, rstring to, long limit) -> string& { return _replace<0, 0>(self, from, to, limit); } +auto ireplace(string& self, rstring from, rstring to, long limit) -> string& { return _replace<1, 0>(self, from, to, limit); } +auto qreplace(string& self, rstring from, rstring to, long limit) -> string& { return _replace<0, 1>(self, from, to, limit); } +auto iqreplace(string& self, rstring from, rstring to, long limit) -> string& { return _replace<1, 1>(self, from, to, limit); } }; diff --git a/nall/string/split.hpp b/nall/string/split.hpp index f5c5e516..ee4bc845 100644 --- a/nall/string/split.hpp +++ b/nall/string/split.hpp @@ -2,9 +2,9 @@ namespace nall { -template auto _split(lstring& self, rstring source, rstring find) -> lstring& { +template auto _split(lstring& self, rstring source, rstring find, long limit) -> lstring& { self.reset(); - if(find.size() == 0) return self; + if(limit <= 0 || find.size() == 0) return self; const char* p = source.data(); signed size = source.size(); @@ -14,7 +14,7 @@ template auto _split(lstring& sel for(signed n = 0, quoted = 0; n <= size - (signed)find.size();) { if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } } if(_compare(p + n, size - n, find.data(), find.size())) { n++; continue; } - if(matches >= Limit) break; + if(matches >= limit) break; string& s = self(matches); s.resize(n - base); @@ -32,15 +32,15 @@ template auto _split(lstring& sel return self; } -template auto split(string& self, rstring on) -> lstring { return lstring().split(self, on); } -template auto isplit(string& self, rstring on) -> lstring { return lstring().isplit(self, on); } -template auto qsplit(string& self, rstring on) -> lstring { return lstring().qsplit(self, on); } -template auto iqsplit(string& self, rstring on) -> lstring { return lstring().iqsplit(self, on); } +auto split(string& self, rstring on, long limit) -> lstring { return lstring().split(self, on, limit); } +auto isplit(string& self, rstring on, long limit) -> lstring { return lstring().isplit(self, on, limit); } +auto qsplit(string& self, rstring on, long limit) -> lstring { return lstring().qsplit(self, on, limit); } +auto iqsplit(string& self, rstring on, long limit) -> lstring { return lstring().iqsplit(self, on, limit); } -template auto string::split(rstring on) const -> lstring { return lstring().split(*this, on); } -template auto string::isplit(rstring on) const -> lstring { return lstring().isplit(*this, on); } -template auto string::qsplit(rstring on) const -> lstring { return lstring().qsplit(*this, on); } -template auto string::iqsplit(rstring on) const -> lstring { return lstring().iqsplit(*this, on); } +auto string::split(rstring on, long limit) const -> lstring { return lstring().split(*this, on, limit); } +auto string::isplit(rstring on, long limit) const -> lstring { return lstring().isplit(*this, on, limit); } +auto string::qsplit(rstring on, long limit) const -> lstring { return lstring().qsplit(*this, on, limit); } +auto string::iqsplit(rstring on, long limit) const -> lstring { return lstring().iqsplit(*this, on, limit); } } diff --git a/nall/string/transform/cml.hpp b/nall/string/transform/cml.hpp index 17a1b266..3557afb6 100644 --- a/nall/string/transform/cml.hpp +++ b/nall/string/transform/cml.hpp @@ -1,17 +1,24 @@ #ifdef NALL_STRING_INTERNAL_HPP /* CSS Markup Language (CML) v1.0 parser - * revision 0.01 + * revision 0.02 */ namespace nall { namespace { struct CML { - CML(const string& filedata, const string& pathname); - CML(const string& filename); - auto output() -> string; + auto& setPath(const string& pathname) { settings.path = pathname; return *this; } + auto& setReader(const function& reader) { settings.reader = reader; return *this; } + + auto parse(const string& filename) -> string; + auto parse(const string& filedata, const string& pathname) -> string; private: + struct Settings { + string path; + function reader; + } settings; + struct State { string output; } state; @@ -22,22 +29,25 @@ private: }; vector variables; - auto parse(const string& filedata, const string& pathname) -> bool; + auto parseDocument(const string& filedata, const string& pathname, unsigned depth) -> bool; }; -CML::CML(const string& filedata, const string& pathname) { - parse(filedata, pathname); -} - -CML::CML(const string& filename) { - parse(string::read(filename), filename.pathname()); -} - -auto CML::output() -> string { +auto CML::parse(const string& filename) -> string { + if(!settings.path) settings.path = filename.pathname(); + string document = settings.reader ? settings.reader(filename) : string::read(filename); + parseDocument(document, settings.path, 0); return state.output; } -auto CML::parse(const string& filedata, const string& pathname) -> bool { +auto CML::parse(const string& filedata, const string& pathname) -> string { + settings.path = pathname; + parseDocument(filedata, settings.path, 0); + return state.output; +} + +auto CML::parseDocument(const string& filedata, const string& pathname, unsigned depth) -> bool { + if(depth >= 100) return false; //prevent infinite recursion + auto vendorAppend = [&](const string& name, const string& value) { state.output.append(" -moz-", name, ": ", value, ";\n"); state.output.append(" -webkit-", name, ": ", value, ";\n"); @@ -47,15 +57,17 @@ auto CML::parse(const string& filedata, const string& pathname) -> bool { lstring lines = block.rstrip().split("\n"); string name = lines.takeFirst(); - if(ltrim(name, "include ")) { + if(name.beginsWith("include ")) { + name.ltrim("include ", 1L); string filename{pathname, name}; - parse(string::read(filename), filename.pathname()); + string document = settings.reader ? settings.reader(filename) : string::read(filename); + parseDocument(document, filename.pathname(), depth + 1); continue; } if(name == "variables") { for(auto& line : lines) { - auto data = line.split<1>(":").strip(); + auto data = line.split(":", 1L).strip(); variables.append({data(0), data(1)}); } continue; @@ -63,7 +75,7 @@ auto CML::parse(const string& filedata, const string& pathname) -> bool { state.output.append(name, " {\n"); for(auto& line : lines) { - auto data = line.split<1>(":").strip(); + auto data = line.split(":", 1L).strip(); auto name = data(0), value = data(1); while(auto offset = value.find("var(")) { bool found = false; diff --git a/nall/string/transform/dml.hpp b/nall/string/transform/dml.hpp index 0c5e94d5..b027233d 100644 --- a/nall/string/transform/dml.hpp +++ b/nall/string/transform/dml.hpp @@ -1,92 +1,104 @@ #ifdef NALL_STRING_INTERNAL_HPP /* Document Markup Language (DML) v1.0 parser - * revision 0.01 + * revision 0.03 */ namespace nall { namespace { struct DML { + auto& setAllowHTML(bool allowHTML) { settings.allowHTML = allowHTML; return *this; } + auto& setHost(const string& hostname) { settings.host = {hostname, "/"}; return *this; } + auto& setPath(const string& pathname) { settings.path = pathname; return *this; } + auto& setReader(const function& reader) { settings.reader = reader; return *this; } + auto& setSectioned(bool sectioned) { settings.sectioned = sectioned; return *this; } + + auto parse(const string& filedata, const string& pathname) -> string; + auto parse(const string& filename) -> string; + +private: struct Settings { bool allowHTML = true; + string host = "localhost/"; + string path; + function reader; bool sectioned = true; } settings; - DML(const string& filedata, const string& pathname); - DML(const string& filename); - auto output() -> string; - -private: struct State { string output; unsigned sections = 0; } state; - auto parse(const string& filedata, const string& pathname) -> bool; - auto parseBlock(string& block, const string& pathname) -> bool; + auto parseDocument(const string& filedata, const string& pathname, unsigned depth) -> bool; + auto parseBlock(string& block, const string& pathname, unsigned depth) -> bool; auto count(const string& text, char value) -> unsigned; + auto escape(const string& text) -> string; auto markup(const string& text) -> string; }; -DML::DML(const string& filedata, const string& pathname) { - parse(filedata, pathname); -} - -DML::DML(const string& filename) { - parse(string::read(filename), filename.pathname()); -} - -auto DML::output() -> string { +auto DML::parse(const string& filedata, const string& pathname) -> string { + settings.path = pathname; + parseDocument(filedata, settings.path, 0); return state.output; } -auto DML::parse(const string& filedata, const string& pathname) -> bool { +auto DML::parse(const string& filename) -> string { + if(!settings.path) settings.path = filename.pathname(); + string document = settings.reader ? settings.reader(filename) : string::read(filename); + parseDocument(document, settings.path, 0); + return state.output; +} + +auto DML::parseDocument(const string& filedata, const string& pathname, unsigned depth) -> bool { + if(depth >= 100) return false; //attempt to prevent infinite recursion with reasonable limit + auto blocks = filedata.split("\n\n"); - for(auto& block : blocks) parseBlock(block, pathname); - if(settings.sectioned && state.sections) state.output.append("\n"); + for(auto& block : blocks) parseBlock(block, pathname, depth); + if(settings.sectioned && state.sections && depth == 0) state.output.append("\n"); return true; } -auto DML::parseBlock(string& block, const string& pathname) -> bool { +auto DML::parseBlock(string& block, const string& pathname, unsigned depth) -> bool { if(block.rstrip().empty()) return true; auto lines = block.split("\n"); //include - if(block.beginsWith("{{include}}")) { - string filename{pathname, block.ltrim("{{include}}").strip()}; - parse(string::read(filename), filename.pathname()); + if(block.beginsWith("")) { + string filename{pathname, block.trim("", 1L).strip()}; + string document = settings.reader ? settings.reader(filename) : string::read(filename); + parseDocument(document, filename.pathname(), depth + 1); } //html - else if(ltrim(block, "{{html}}") && settings.allowHTML) { - auto data = lines.takeFirst(); - if(ltrim(data, "{{html}} ")) state.output.append(data, "\n"); - for(auto& line : lines) { - if(ltrim(line, " ")) state.output.append(line, "\n"); + else if(block.beginsWith("\n") && settings.allowHTML) { + for(auto n : range(lines)) { + if(n == 0 || !lines[n].beginsWith(" ")) continue; + state.output.append(lines[n].ltrim(" ", 1L), "\n"); } } - //header + //section else if(block.beginsWith("# ")) { if(settings.sectioned) { if(state.sections++) state.output.append(""); state.output.append("

"); } - auto content = lines.takeFirst().ltrim("# ").split<1>(" => "); + auto content = lines.takeFirst().ltrim("# ", 1L).split(" => ", 1L); auto data = markup(content[0]); auto name = escape(content(1, data.crc32())); state.output.append("
", data); for(auto& line : lines) { if(!line.beginsWith("# ")) continue; - state.output.append("", line.ltrim("# "), ""); + state.output.append("", line.ltrim("# ", 1L), ""); } state.output.append("
\n"); } - //subheader + //header else if(auto depth = count(block, '=')) { - auto content = lines.takeFirst().slice(depth + 1).split<1>(" => "); + auto content = lines.takeFirst().slice(depth + 1).split(" => ", 1L); auto data = markup(content[0]); auto name = escape(content(1, data.crc32())); if(depth <= 6) { @@ -99,7 +111,7 @@ auto DML::parseBlock(string& block, const string& pathname) -> bool { } } - //contents + //navigation else if(count(block, '-')) { state.output.append("