From 285fc3a7f6e7329f8daf3529857eec36db03e2fa Mon Sep 17 00:00:00 2001 From: Morten Delenk Date: Sun, 3 Jul 2016 13:35:22 +0200 Subject: [PATCH] updated to higan v099r13 release --- any.hpp | 1 - beat/archive.hpp | 4 +- beat/delta.hpp | 1 + beat/multi.hpp | 12 +- bit-field.hpp | 85 +++++ bitvector.hpp => bit-vector.hpp | 1 - bit.hpp | 36 +- config.hpp | 14 +- directory.hpp | 4 +- dl.hpp | 5 +- dsp.hpp | 10 - dsp/buffer.hpp | 50 --- dsp/core.hpp | 164 --------- dsp/iir/biquad.hpp | 153 ++++++++ dsp/resample/average.hpp | 72 ---- dsp/resample/cosine.hpp | 44 --- dsp/resample/cubic.hpp | 50 --- dsp/resample/hermite.hpp | 62 ---- dsp/resample/lib/sinc.hpp | 600 -------------------------------- dsp/resample/linear.hpp | 43 --- dsp/resample/nearest.hpp | 43 --- dsp/resample/sinc.hpp | 62 ---- dsp/resampler/cubic.hpp | 56 +++ dsp/settings.hpp | 46 --- emulation/21fx.hpp | 134 +++++++ encode/base64.hpp | 9 +- file.hpp | 3 +- hash/crc16.hpp | 49 ++- hash/crc32.hpp | 89 ++--- hash/crc64.hpp | 65 ++++ hash/sha256.hpp | 29 +- hashset.hpp | 30 +- hid.hpp | 18 +- http/request.hpp | 26 +- http/response.hpp | 20 +- image/base.hpp | 1 - image/core.hpp | 6 +- inode.hpp | 10 +- interpolation.hpp | 2 +- intrinsics.hpp | 14 +- main.hpp | 3 + matrix.hpp | 10 +- maybe.hpp | 1 - memory.hpp | 132 ++++++- memory/memory.hpp | 129 ------- memory/pool.hpp | 62 ---- mosaic/context.hpp | 10 +- nall.hpp | 7 +- string/platform.hpp => path.hpp | 54 +-- posix/shared-memory.hpp | 4 - primitives.hpp | 72 ++-- priority-queue.hpp | 106 ------ property.hpp | 90 +++-- queue.hpp | 101 ++++++ random.hpp | 9 +- range.hpp | 8 - run.hpp | 112 ++++-- serial.hpp | 34 +- set.hpp | 32 +- shared-pointer.hpp | 12 +- smtp.hpp | 16 +- sort.hpp | 18 +- stream.hpp | 19 - stream/auto.hpp | 21 -- stream/file.hpp | 39 --- stream/gzip.hpp | 31 -- stream/memory.hpp | 48 --- stream/mmap.hpp | 41 --- stream/stream.hpp | 98 ------ stream/vector.hpp | 37 -- stream/zip.hpp | 35 -- string.hpp | 304 +++++++++++++++- string/allocator/adaptive.hpp | 14 +- string/base.hpp | 293 ---------------- string/cast.hpp | 46 +-- string/compare.hpp | 22 +- string/convert.hpp | 14 +- string/core.hpp | 6 +- string/eval/evaluator.hpp | 2 +- string/eval/literal.hpp | 6 +- string/eval/parser.hpp | 4 +- string/find.hpp | 14 +- string/format.hpp | 11 +- string/hash.hpp | 33 -- string/list.hpp | 10 +- string/markup/bml.hpp | 6 +- string/markup/find.hpp | 14 +- string/markup/xml.hpp | 4 +- string/match.hpp | 4 +- string/path.hpp | 20 +- string/replace.hpp | 32 +- string/split.hpp | 18 +- string/transform/cml.hpp | 6 +- string/transform/dml.hpp | 20 +- string/trim.hpp | 56 +-- string/utility.hpp | 8 +- string/view.hpp | 143 ++++---- thread.hpp | 16 +- utility.hpp | 4 +- varint.hpp | 12 +- vector.hpp | 359 +++++-------------- vector/access.hpp | 39 +++ vector/assign.hpp | 28 ++ vector/core.hpp | 42 +++ vector/iterator.hpp | 37 ++ vector/memory.hpp | 90 +++++ vector/modify.hpp | 127 +++++++ vector/utility.hpp | 14 + vfs.hpp | 3 + vfs/fs/file.hpp | 51 +++ vfs/memory/file.hpp | 48 +++ vfs/vfs.hpp | 75 ++++ windows/detour.hpp | 2 +- windows/guid.hpp | 22 +- windows/registry.hpp | 22 +- windows/utf8.hpp | 2 +- 116 files changed, 2424 insertions(+), 3193 deletions(-) create mode 100644 bit-field.hpp rename bitvector.hpp => bit-vector.hpp (98%) delete mode 100644 dsp.hpp delete mode 100644 dsp/buffer.hpp delete mode 100644 dsp/core.hpp create mode 100644 dsp/iir/biquad.hpp delete mode 100644 dsp/resample/average.hpp delete mode 100644 dsp/resample/cosine.hpp delete mode 100644 dsp/resample/cubic.hpp delete mode 100644 dsp/resample/hermite.hpp delete mode 100644 dsp/resample/lib/sinc.hpp delete mode 100644 dsp/resample/linear.hpp delete mode 100644 dsp/resample/nearest.hpp delete mode 100644 dsp/resample/sinc.hpp create mode 100644 dsp/resampler/cubic.hpp delete mode 100644 dsp/settings.hpp create mode 100644 emulation/21fx.hpp create mode 100644 hash/crc64.hpp delete mode 100644 memory/memory.hpp delete mode 100644 memory/pool.hpp rename string/platform.hpp => path.hpp (73%) delete mode 100644 priority-queue.hpp create mode 100644 queue.hpp delete mode 100644 stream.hpp delete mode 100644 stream/auto.hpp delete mode 100644 stream/file.hpp delete mode 100644 stream/gzip.hpp delete mode 100644 stream/memory.hpp delete mode 100644 stream/mmap.hpp delete mode 100644 stream/stream.hpp delete mode 100644 stream/vector.hpp delete mode 100644 stream/zip.hpp delete mode 100644 string/base.hpp delete mode 100644 string/hash.hpp create mode 100644 vector/access.hpp create mode 100644 vector/assign.hpp create mode 100644 vector/core.hpp create mode 100644 vector/iterator.hpp create mode 100644 vector/memory.hpp create mode 100644 vector/modify.hpp create mode 100644 vector/utility.hpp create mode 100644 vfs.hpp create mode 100644 vfs/fs/file.hpp create mode 100644 vfs/memory/file.hpp create mode 100644 vfs/vfs.hpp diff --git a/any.hpp b/any.hpp index ed1971e..239e100 100644 --- a/any.hpp +++ b/any.hpp @@ -13,7 +13,6 @@ struct any { ~any() { reset(); } explicit operator bool() const { return container; } - auto empty() const -> bool { return !container; } auto reset() -> void { if(container) { delete container; container = nullptr; } } auto type() const -> const std::type_info& { diff --git a/beat/archive.hpp b/beat/archive.hpp index 65be338..df3d3c4 100644 --- a/beat/archive.hpp +++ b/beat/archive.hpp @@ -31,7 +31,7 @@ auto Archive::create(const string& beatname, const string& pathname, const strin bool directory = name.endsWith("/"); bool writable = inode::writable(location); bool executable = inode::executable(location); - uint info = directory << 0 | writable << 1 | executable << 2 | (name.rtrim("/").size() - 1) << 3; + uint info = directory << 0 | writable << 1 | executable << 2 | (name.trimRight("/").size() - 1) << 3; beat.writevu(info); beat.writes(name); @@ -123,7 +123,7 @@ auto Archive::extract(const string& beatname, const string& filename) -> vector< 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)); + result.append(string{pathname, name}.trimLeft(basename, 1L)); if(name.endsWith("/")) scan(result, basename, {pathname, name}); } } diff --git a/beat/delta.hpp b/beat/delta.hpp index 17c9834..b9114b5 100644 --- a/beat/delta.hpp +++ b/beat/delta.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace nall { diff --git a/beat/multi.hpp b/beat/multi.hpp index 7fb9add..342bfcb 100644 --- a/beat/multi.hpp +++ b/beat/multi.hpp @@ -34,7 +34,7 @@ struct bpsmulti { for(auto& targetName : targetList) { if(targetName.endsWith("/")) { - targetName.rtrim("/"); + targetName.trimRight("/"); writeNumber(CreatePath | ((targetName.length() - 1) << 2)); writeString(targetName); } else if(auto position = sourceList.find(targetName)) { //if sourceName == targetName @@ -65,15 +65,15 @@ struct bpsmulti { bpslinear patch; patch.source({sourcePath, targetName}); patch.target({targetPath, targetName}); - patch.create({temppath(), "temp.bps"}); + patch.create({Path::temp(), "temp.bps"}); } else { bpsdelta patch; patch.source({sourcePath, targetName}); patch.target({targetPath, targetName}); - patch.create({temppath(), "temp.bps"}); + patch.create({Path::temp(), "temp.bps"}); } - auto buffer = file::read({temppath(), "temp.bps"}); + auto buffer = file::read({Path::temp(), "temp.bps"}); writeNumber(buffer.size()); for(auto &byte : buffer) write(byte); } @@ -159,13 +159,13 @@ protected: auto ls(lstring& list, const string& path, const string& basepath) -> void { lstring paths = directory::folders(path); for(auto& pathname : paths) { - list.append(string{path, pathname}.ltrim(basepath, 1L)); + list.append(string{path, pathname}.trimLeft(basepath, 1L)); ls(list, {path, pathname}, basepath); } lstring files = directory::files(path); for(auto& filename : files) { - list.append(string{path, filename}.ltrim(basepath, 1L)); + list.append(string{path, filename}.trimLeft(basepath, 1L)); } } diff --git a/bit-field.hpp b/bit-field.hpp new file mode 100644 index 0000000..85ac5a6 --- /dev/null +++ b/bit-field.hpp @@ -0,0 +1,85 @@ +#pragma once + +namespace nall { + +template struct NaturalBitField { + enum : uint { lo = Lo <= Hi ? Lo : Hi }; + enum : uint { hi = Hi >= Lo ? Hi : Lo }; + enum : uint { bits = hi - lo + 1 }; + enum : uint { mask = (~0ull >> (64 - bits)) << lo }; + static_assert(hi < sizeof(type) * 8, ""); + + inline NaturalBitField() = default; + inline NaturalBitField(const NaturalBitField& value) { set(value.data); } + template inline NaturalBitField(const T& value) { set(value << lo); } + + inline explicit operator bool() const { return data & mask; } + inline operator type() const { return get(); } + + inline auto& operator=(const NaturalBitField& value) { return set(value.data); } + template inline auto& operator=(const T& value) { return set(value << lo); } + + inline auto operator++(int) { type value = get(); set(data + (1 << lo)); return value; } + inline auto operator--(int) { type value = get(); set(data - (1 << lo)); return value; } + + inline auto& operator++() { return set(data + (1 << lo)); } + inline auto& operator--() { return set(data - (1 << lo)); } + + inline auto& operator &=(const type value) { return set(data & (value << lo)); } + inline auto& operator |=(const type value) { return set(data | (value << lo)); } + inline auto& operator ^=(const type value) { return set(data ^ (value << lo)); } + inline auto& operator<<=(const type value) { return set((data & mask) << value); } + inline auto& operator>>=(const type value) { return set((data & mask) >> value); } + inline auto& operator +=(const type value) { return set(data + (value << lo)); } + inline auto& operator -=(const type value) { return set(data - (value << lo)); } + inline auto& operator *=(const type value) { return set((get() * value) << lo); } + inline auto& operator /=(const type value) { return set((get() / value) << lo); } + inline auto& operator %=(const type value) { return set((get() % value) << lo); } + +private: + type data; + + inline auto get() const -> type { + return (data & mask) >> lo; + } + + inline auto set(type value) -> NaturalBitField& { + return data = (data & ~mask) | (value & mask), *this; + } +}; + +template struct BooleanBitField { + enum : uint { bit = Bit }; + enum : uint { mask = 1ull << bit }; + static_assert(bit < sizeof(type) * 8, ""); + + inline BooleanBitField() = default; + inline BooleanBitField(const BooleanBitField& value) { set(value.get()); } + template inline BooleanBitField(const bool value) { set(value); } + + inline operator bool() const { return get(); } + + inline auto& operator=(const BooleanBitField& value) { return set(value.get()); } + inline auto& operator=(const bool value) { return set(value); } + + inline auto& operator&=(const bool value) { return set(get() & value); } + inline auto& operator|=(const bool value) { return set(get() | value); } + inline auto& operator^=(const bool value) { return set(get() ^ value); } + + inline auto raise() { return get() == 0 ? set(1), true : false; } + inline auto lower() { return get() == 1 ? set(0), true : false; } + inline auto& invert() { return set(get() ^ 1); } + +private: + type data; + + inline auto get() const -> bool { + return data & mask; + } + + inline auto set(bool value) -> BooleanBitField& { + return data = (data & ~mask) | (value << bit), *this; + } +}; + +} diff --git a/bitvector.hpp b/bit-vector.hpp similarity index 98% rename from bitvector.hpp rename to bit-vector.hpp index f968cc3..12fc08f 100644 --- a/bitvector.hpp +++ b/bit-vector.hpp @@ -27,7 +27,6 @@ struct bitvector { } explicit operator bool() const { return bits > 0; } - auto empty() const -> bool { return bits == 0; } auto size() const -> uint { return bits; } auto bytes() const -> uint { return (bits + 7) / 8; } auto data() -> uint8_t* { return pool; } diff --git a/bit.hpp b/bit.hpp index e182104..f2a54b6 100644 --- a/bit.hpp +++ b/bit.hpp @@ -4,28 +4,28 @@ namespace nall { -template inline auto uclamp(const uintmax_t x) -> uintmax_t { - enum : uintmax_t { b = 1ull << (bits - 1), y = b * 2 - 1 }; +template inline auto uclamp(const uintmax x) -> uintmax { + enum : uintmax { b = 1ull << (bits - 1), y = b * 2 - 1 }; return y + ((x - y) & -(x < y)); //min(x, y); } -template inline auto uclip(const uintmax_t x) -> uintmax_t { - enum : uintmax_t { b = 1ull << (bits - 1), m = b * 2 - 1 }; +template inline auto uclip(const uintmax x) -> uintmax { + enum : uintmax { b = 1ull << (bits - 1), m = b * 2 - 1 }; return (x & m); } -template inline auto sclamp(const intmax_t x) -> intmax_t { - enum : intmax_t { b = 1ull << (bits - 1), m = b - 1 }; +template inline auto sclamp(const intmax x) -> intmax { + enum : intmax { b = 1ull << (bits - 1), m = b - 1 }; return (x > m) ? m : (x < -b) ? -b : x; } -template inline auto sclip(const intmax_t x) -> intmax_t { - enum : uintmax_t { b = 1ull << (bits - 1), m = b * 2 - 1 }; +template inline auto sclip(const intmax x) -> intmax { + enum : uintmax { b = 1ull << (bits - 1), m = b * 2 - 1 }; return ((x & m) ^ b) - b; } namespace bit { - constexpr inline auto mask(const char* s, uintmax_t sum = 0) -> uintmax_t { + constexpr inline auto mask(const char* s, uintmax sum = 0) -> uintmax { return ( *s == '0' || *s == '1' ? mask(s + 1, (sum << 1) | 1) : *s == ' ' || *s == '_' ? mask(s + 1, sum) : @@ -34,7 +34,7 @@ namespace bit { ); } - constexpr inline auto test(const char* s, uintmax_t sum = 0) -> uintmax_t { + constexpr inline auto test(const char* s, uintmax sum = 0) -> uintmax { return ( *s == '0' || *s == '1' ? test(s + 1, (sum << 1) | (*s - '0')) : *s == ' ' || *s == '_' ? test(s + 1, sum) : @@ -44,38 +44,38 @@ namespace bit { } //lowest(0b1110) == 0b0010 - constexpr inline auto lowest(const uintmax_t x) -> uintmax_t { + constexpr inline auto lowest(const uintmax x) -> uintmax { return x & -x; } //clear_lowest(0b1110) == 0b1100 - constexpr inline auto clear_lowest(const uintmax_t x) -> uintmax_t { + constexpr inline auto clearLowest(const uintmax x) -> uintmax { return x & (x - 1); } //set_lowest(0b0101) == 0b0111 - constexpr inline auto set_lowest(const uintmax_t x) -> uintmax_t { + constexpr inline auto setLowest(const uintmax x) -> uintmax { return x | (x + 1); } //count number of bits set in a byte - inline auto count(uintmax_t x) -> unsigned { - unsigned count = 0; + inline auto count(uintmax x) -> uint { + uint count = 0; do count += x & 1; while(x >>= 1); return count; } //return index of the first bit set (or zero of no bits are set) //first(0b1000) == 3 - inline auto first(uintmax_t x) -> unsigned { - unsigned first = 0; + inline auto first(uintmax x) -> uint { + uint first = 0; while(x) { if(x & 1) break; x >>= 1; first++; } return first; } //round up to next highest single bit: //round(15) == 16, round(16) == 16, round(17) == 32 - inline auto round(uintmax_t x) -> uintmax_t { + inline auto round(uintmax x) -> uintmax { if((x & (x - 1)) == 0) return x; while(x & (x - 1)) x &= x - 1; return x << 1; diff --git a/config.hpp b/config.hpp index 3201cfe..2efb538 100644 --- a/config.hpp +++ b/config.hpp @@ -10,13 +10,11 @@ namespace Configuration { struct Node { string name; string desc; - enum class Type : unsigned { Null, Boolean, Integer, Natural, Double, String } type = Type::Null; + enum class Type : uint { Null, Boolean, Integer, Natural, Double, String } type = Type::Null; void* data = nullptr; vector children; - auto empty() const -> bool { - return data == nullptr; - } + explicit operator bool() const { return data; } auto get() const -> string { switch(type) { @@ -57,7 +55,7 @@ struct Node { auto find(const string& path) -> maybe { auto p = path.split("/"); - auto name = p.takeFirst(); + auto name = p.takeLeft(); for(auto& child : children) { if(child.name == name) { if(p.size() == 0) return child; @@ -70,13 +68,13 @@ struct Node { auto load(Markup::Node path) -> void { for(auto& child : children) { if(auto leaf = path[child.name]) { - if(!child.empty()) child.set(leaf.text()); + if(child) child.set(leaf.text()); child.load(leaf); } } } - auto save(file& fp, unsigned depth = 0) -> void { + auto save(file& fp, uint depth = 0) -> void { for(auto& child : children) { if(child.desc) { for(auto n : range(depth)) fp.print(" "); @@ -84,7 +82,7 @@ struct Node { } for(auto n : range(depth)) fp.print(" "); fp.print(child.name); - if(!child.empty()) fp.print(": ", child.get()); + if(child) fp.print(": ", child.get()); fp.print("\n"); child.save(fp, depth + 1); if(depth == 0) fp.print("\n"); diff --git a/directory.hpp b/directory.hpp index 34ced00..52c9a5e 100644 --- a/directory.hpp +++ b/directory.hpp @@ -73,7 +73,7 @@ private: #if defined(PLATFORM_WINDOWS) inline auto directory::create(const string& pathname, unsigned permissions) -> bool { string path; - lstring list = string{pathname}.transform("\\", "/").rtrim("/").split("/"); + lstring list = string{pathname}.transform("\\", "/").trimRight("/").split("/"); bool result = true; for(auto& part : list) { path.append(part, "/"); @@ -168,7 +168,7 @@ private: inline auto directory::create(const string& pathname, unsigned permissions) -> bool { string path; - lstring list = string{pathname}.rtrim("/").split("/"); + lstring list = string{pathname}.trimRight("/").split("/"); bool result = true; for(auto& part : list) { path.append(part, "/"); diff --git a/dl.hpp b/dl.hpp index 46d6a10..28f3d43 100644 --- a/dl.hpp +++ b/dl.hpp @@ -3,6 +3,7 @@ //dynamic linking support #include +#include #include #include #include @@ -38,7 +39,7 @@ private: 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); + if(!handle) handle = (uintptr_t)dlopen(string(Path::user(), ".local/lib/lib", name, ".so"), RTLD_LAZY); if(!handle) handle = (uintptr_t)dlopen(string("/usr/local/lib/lib", name, ".so"), RTLD_LAZY); if(!handle) handle = (uintptr_t)dlopen(string("lib", name, ".so"), RTLD_LAZY); return handle; @@ -64,7 +65,7 @@ inline auto library::close() -> void { 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); + if(!handle) handle = (uintptr_t)dlopen(string(Path::user(), ".local/lib/lib", name, ".dylib"), RTLD_LAZY); if(!handle) handle = (uintptr_t)dlopen(string("/usr/local/lib/lib", name, ".dylib"), RTLD_LAZY); if(!handle) handle = (uintptr_t)dlopen(string("lib", name, ".dylib"), RTLD_LAZY); return handle; diff --git a/dsp.hpp b/dsp.hpp deleted file mode 100644 index 4a3ffc0..0000000 --- a/dsp.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include - -#include -#ifdef __SSE__ - #include -#endif - -#include diff --git a/dsp/buffer.hpp b/dsp/buffer.hpp deleted file mode 100644 index 22934d0..0000000 --- a/dsp/buffer.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -struct Buffer { - Buffer() { - } - - ~Buffer() { - setChannels(0); - } - - auto setChannels(uint channels) -> void { - if(sample) { - for(auto c : range(this->channels)) { - if(sample[c]) delete[] sample[c]; - } - delete[] sample; - } - - this->channels = channels; - if(channels == 0) return; - - sample = new double*[channels]; - for(auto c : range(channels)) { - sample[c] = new double[65536](); - } - } - - inline auto read(uint channel, int offset = 0) -> double& { - return sample[channel][(uint16_t)(rdoffset + offset)]; - } - - inline auto write(uint channel, int offset = 0) -> double& { - return sample[channel][(uint16_t)(wroffset + offset)]; - } - - inline auto clear() -> void { - for(auto c : range(channels)) { - for(auto n : range(65536)) { - sample[c][n] = 0; - } - } - rdoffset = 0; - wroffset = 0; - } - - double** sample = nullptr; - uint16_t rdoffset = 0; - uint16_t wroffset = 0; - uint channels = 0; -}; diff --git a/dsp/core.hpp b/dsp/core.hpp deleted file mode 100644 index f273578..0000000 --- a/dsp/core.hpp +++ /dev/null @@ -1,164 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace nall { - -struct DSP; - -struct Resampler { - Resampler(DSP& dsp) : dsp(dsp) {} - virtual ~Resampler() {} - - virtual auto setFrequency() -> void = 0; - virtual auto clear() -> void = 0; - virtual auto sample() -> void = 0; - - DSP& dsp; - double frequency = 44100.0; -}; - -struct DSP { - enum class ResampleEngine : uint { - Nearest, - Linear, - Cosine, - Cubic, - Hermite, - Average, - Sinc, - }; - - inline DSP(); - inline ~DSP(); - - inline auto setChannels(uint channels) -> void; - inline auto setPrecision(uint precision) -> void; - inline auto setFrequency(double frequency) -> void; //inputFrequency - inline auto setVolume(double volume) -> void; - inline auto setBalance(double balance) -> void; - - inline auto setResampler(ResampleEngine resamplingEngine) -> void; - inline auto setResamplerFrequency(double frequency) -> void; //outputFrequency - - inline auto sample(int channel[]) -> void; - inline auto pending() const -> bool; - inline auto read(int channel[]) -> void; - - inline auto clear() -> void; - -protected: - inline auto write(double channel[]) -> void; - inline auto adjustVolume() -> void; - inline auto adjustBalance() -> void; - inline auto clamp(const uint bits, const int input) -> int; - - struct Settings { - uint channels; - uint precision; - double frequency; - double volume; - double balance; - - //internal - double intensity; - double intensityInverse; - } settings; - - Resampler* resampler = nullptr; - - #include "buffer.hpp" - Buffer buffer; - Buffer output; - - friend class ResampleNearest; - friend class ResampleLinear; - friend class ResampleCosine; - friend class ResampleCubic; - friend class ResampleAverage; - friend class ResampleHermite; - friend class ResampleSinc; -}; - -#include "resample/nearest.hpp" -#include "resample/linear.hpp" -#include "resample/cosine.hpp" -#include "resample/cubic.hpp" -#include "resample/hermite.hpp" -#include "resample/average.hpp" -#include "resample/sinc.hpp" -#include "settings.hpp" - -DSP::DSP() { - setResampler(ResampleEngine::Hermite); - setResamplerFrequency(44100.0); - - setChannels(2); - setPrecision(16); - setFrequency(44100.0); - setVolume(1.0); - setBalance(0.0); - - clear(); -} - -DSP::~DSP() { - if(resampler) delete resampler; -} - -auto DSP::sample(int channel[]) -> void { - for(auto c : range(settings.channels)) { - buffer.write(c) = (double)channel[c] * settings.intensityInverse; - } - buffer.wroffset++; - resampler->sample(); -} - -auto DSP::pending() const -> bool { - return output.rdoffset != output.wroffset; -} - -auto DSP::read(int channel[]) -> void { - adjustVolume(); - adjustBalance(); - - for(auto c : range(settings.channels)) { - channel[c] = clamp(settings.precision, output.read(c) * settings.intensity); - } - output.rdoffset++; -} - -auto DSP::write(double channel[]) -> void { - for(auto c : range(settings.channels)) { - output.write(c) = channel[c]; - } - output.wroffset++; -} - -auto DSP::adjustVolume() -> void { - for(auto c : range(settings.channels)) { - output.read(c) *= settings.volume; - } -} - -auto DSP::adjustBalance() -> void { - if(settings.channels != 2) return; //TODO: support > 2 channels - if(settings.balance < 0.0) output.read(1) *= 1.0 + settings.balance; - if(settings.balance > 0.0) output.read(0) *= 1.0 - settings.balance; -} - -auto DSP::clamp(const uint bits, const int x) -> int { - const int b = 1U << (bits - 1); - const int m = (1U << (bits - 1)) - 1; - return (x > m) ? m : (x < -b) ? -b : x; -} - -auto DSP::clear() -> void { - buffer.clear(); - output.clear(); - resampler->clear(); -} - -} diff --git a/dsp/iir/biquad.hpp b/dsp/iir/biquad.hpp new file mode 100644 index 0000000..7a3ce0e --- /dev/null +++ b/dsp/iir/biquad.hpp @@ -0,0 +1,153 @@ +#pragma once + +//transposed direct form II biquadratic second-order IIR filter + +namespace nall { namespace DSP { namespace IIR { + +struct Biquad { + enum class Type : uint { + LowPass, + HighPass, + BandPass, + Notch, + Peak, + LowShelf, + HighShelf, + }; + + inline auto reset(Type type, double cutoff, double quality, double gain = 0.0) -> void; + inline auto process(double in) -> double; //normalized sample (-1.0 to +1.0) + + inline static auto butterworth(uint order, uint phase) -> double; + +private: + Type type; //filter type + double cutoff; //frequency cutoff + double quality; //frequency response quality + double gain; //peak gain + double a0, a1, a2, b1, b2; //coefficients + double z1, z2; //second-order IIR +}; + +auto Biquad::reset(Type type, double cutoff, double quality, double gain) -> void { + this->type = type; + this->cutoff = cutoff; + this->quality = quality; + this->gain = gain; + + z1 = 0.0; + z2 = 0.0; + + double v = pow(10, fabs(gain) / 20.0); + double k = tan(Math::Pi * cutoff); + double q = quality; + double n = 0.0; + + switch(type) { + + case Type::LowPass: + n = 1 / (1 + k / q + k * k); + a0 = k * k * n; + a1 = 2 * a0; + a2 = a0; + b1 = 2 * (k * k - 1) * n; + b2 = (1 - k / q + k * k) * n; + break; + + case Type::HighPass: + n = 1 / (1 + k / q + k * k); + a0 = 1 * n; + a1 = -2 * a0; + a2 = a0; + b1 = 2 * (k * k - 1) * n; + b2 = (1 - k / q + k * k) * n; + break; + + case Type::BandPass: + n = 1 / (1 + k / q + k * k); + a0 = k / q * n; + a1 = 0; + a2 = -a0; + b1 = 2 * (k * k - 1) * n; + b2 = (1 - k / q + k * k) * n; + break; + + case Type::Notch: + n = 1 / (1 + k / q + k * k); + a0 = (1 + k * k) * n; + a1 = 2 * (k * k - 1) * n; + a2 = a0; + b1 = a1; + b2 = (1 - k / q + k * k) * n; + break; + + case Type::Peak: + if(gain >= 0) { + n = 1 / (1 + 1 / q * k + k * k); + a0 = (1 + v / q * k + k * k) * n; + a1 = 2 * (k * k - 1) * n; + a2 = (1 - v / q * k + k * k) * n; + b1 = a1; + b2 = (1 - 1 / q * k + k * k) * n; + } else { + n = 1 / (1 + v / q * k + k * k); + a0 = (1 + 1 / q * k + k * k) * n; + a1 = 2 * (k * k - 1) * n; + a2 = (1 - 1 / q * k + k * k) * n; + b1 = a1; + b2 = (1 - v / q * k + k * k) * n; + } + break; + + case Type::LowShelf: + if(gain >= 0) { + n = 1 / (1 + sqrt(2) * k + k * k); + a0 = (1 + sqrt(2 * v) * k + v * k * k) * n; + a1 = 2 * (v * k * k - 1) * n; + a2 = (1 - sqrt(2 * v) * k + v * k * k) * n; + b1 = 2 * (k * k - 1) * n; + b2 = (1 - sqrt(2) * k + k * k) * n; + } else { + n = 1 / (1 + sqrt(2 * v) * k + v * k * k); + a0 = (1 + sqrt(2) * k + k * k) * n; + a1 = 2 * (k * k - 1) * n; + a2 = (1 - sqrt(2) * k + k * k) * n; + b1 = 2 * (v * k * k - 1) * n; + b2 = (1 - sqrt(2 * v) * k + v * k * k) * n; + } + break; + + case Type::HighShelf: + if(gain >= 0) { + n = 1 / (1 + sqrt(2) * k + k * k); + a0 = (v + sqrt(2 * v) * k + k * k) * n; + a1 = 2 * (k * k - v) * n; + a2 = (v - sqrt(2 * v) * k + k * k) * n; + b1 = 2 * (k * k - 1) * n; + b2 = (1 - sqrt(2) * k + k * k) * n; + } else { + n = 1 / (v + sqrt(2 * v) * k + k * k); + a0 = (1 + sqrt(2) * k + k * k) * n; + a1 = 2 * (k * k - 1) * n; + a2 = (1 - sqrt(2) * k + k * k) * n; + b1 = 2 * (k * k - v) * n; + b2 = (v - sqrt(2 * v) * k + k * k) * n; + } + break; + + } +} + +auto Biquad::process(double in) -> double { + double out = in * a0 + z1; + z1 = in * a1 + z2 - b1 * out; + z2 = in * a2 - b2 * out; + return out; +} + +//compute Q values for N-order butterworth filtering +auto Biquad::butterworth(uint order, uint phase) -> double { + return -0.5 / cos(Math::Pi * (phase + order + 0.5) / order); +} + +}}} diff --git a/dsp/resample/average.hpp b/dsp/resample/average.hpp deleted file mode 100644 index c98b7fe..0000000 --- a/dsp/resample/average.hpp +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once - -struct ResampleAverage : Resampler { - ResampleAverage(DSP& dsp) : Resampler(dsp) {} - - inline auto setFrequency() -> void; - inline auto clear() -> void; - inline auto sample() -> void; - inline auto sampleLinear() -> void; - -private: - double fraction; - double step; -}; - -auto ResampleAverage::setFrequency() -> void { - fraction = 0.0; - step = dsp.settings.frequency / frequency; -} - -auto ResampleAverage::clear() -> void { - fraction = 0.0; -} - -auto ResampleAverage::sample() -> void { - //can only average if input frequency >= output frequency - if(step < 1.0) return sampleLinear(); - - fraction += 1.0; - - double scalar = 1.0; - if(fraction > step) scalar = 1.0 - (fraction - step); - - for(auto c : range(dsp.settings.channels)) { - dsp.output.write(c) += dsp.buffer.read(c) * scalar; - } - - if(fraction >= step) { - for(auto c : range(dsp.settings.channels)) { - dsp.output.write(c) /= step; - } - dsp.output.wroffset++; - - fraction -= step; - for(auto c : range(dsp.settings.channels)) { - dsp.output.write(c) = dsp.buffer.read(c) * fraction; - } - } - - dsp.buffer.rdoffset++; -} - -auto ResampleAverage::sampleLinear() -> void { - while(fraction <= 1.0) { - double channel[dsp.settings.channels]; - - for(auto n : range(dsp.settings.channels)) { - double a = dsp.buffer.read(n, -1); - double b = dsp.buffer.read(n, -0); - - double mu = fraction; - - channel[n] = a * (1.0 - mu) + b * mu; - } - - dsp.write(channel); - fraction += step; - } - - dsp.buffer.rdoffset++; - fraction -= 1.0; -} diff --git a/dsp/resample/cosine.hpp b/dsp/resample/cosine.hpp deleted file mode 100644 index 68c0a44..0000000 --- a/dsp/resample/cosine.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -struct ResampleCosine : Resampler { - ResampleCosine(DSP& dsp) : Resampler(dsp) {} - - inline auto setFrequency() -> void; - inline auto clear() -> void; - inline auto sample() -> void; - -private: - double fraction; - double step; -}; - -auto ResampleCosine::setFrequency() -> void { - fraction = 0.0; - step = dsp.settings.frequency / frequency; -} - -auto ResampleCosine::clear() -> void { - fraction = 0.0; -} - -auto ResampleCosine::sample() -> void { - while(fraction <= 1.0) { - double channel[dsp.settings.channels]; - - for(auto n : range(dsp.settings.channels)) { - double a = dsp.buffer.read(n, -1); - double b = dsp.buffer.read(n, -0); - - double mu = fraction; - mu = (1.0 - cos(mu * 3.14159265)) / 2.0; - - channel[n] = a * (1.0 - mu) + b * mu; - } - - dsp.write(channel); - fraction += step; - } - - dsp.buffer.rdoffset++; - fraction -= 1.0; -} diff --git a/dsp/resample/cubic.hpp b/dsp/resample/cubic.hpp deleted file mode 100644 index 1b297d9..0000000 --- a/dsp/resample/cubic.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -struct ResampleCubic : Resampler { - ResampleCubic(DSP& dsp) : Resampler(dsp) {} - - inline auto setFrequency() -> void; - inline auto clear() -> void; - inline auto sample() -> void; - -private: - double fraction; - double step; -}; - -auto ResampleCubic::setFrequency() -> void { - fraction = 0.0; - step = dsp.settings.frequency / frequency; -} - -auto ResampleCubic::clear() -> void { - fraction = 0.0; -} - -auto ResampleCubic::sample() -> void { - while(fraction <= 1.0) { - double channel[dsp.settings.channels]; - - for(auto n : range(dsp.settings.channels)) { - double a = dsp.buffer.read(n, -3); - double b = dsp.buffer.read(n, -2); - double c = dsp.buffer.read(n, -1); - double d = dsp.buffer.read(n, -0); - - double mu = fraction; - - double A = d - c - a + b; - double B = a - b - A; - double C = c - a; - double D = b; - - channel[n] = A * (mu * 3) + B * (mu * 2) + C * mu + D; - } - - dsp.write(channel); - fraction += step; - } - - dsp.buffer.rdoffset++; - fraction -= 1.0; -} diff --git a/dsp/resample/hermite.hpp b/dsp/resample/hermite.hpp deleted file mode 100644 index a6215e0..0000000 --- a/dsp/resample/hermite.hpp +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -struct ResampleHermite : Resampler { - ResampleHermite(DSP& dsp) : Resampler(dsp) {} - - inline auto setFrequency() -> void; - inline auto clear() -> void; - inline auto sample() -> void; - -private: - double fraction; - double step; -}; - -auto ResampleHermite::setFrequency() -> void { - fraction = 0.0; - step = dsp.settings.frequency / frequency; -} - -auto ResampleHermite::clear() -> void { - fraction = 0.0; -} - -auto ResampleHermite::sample() -> void { - while(fraction <= 1.0) { - double channel[dsp.settings.channels]; - - for(auto n : range(dsp.settings.channels)) { - double a = dsp.buffer.read(n, -3); - double b = dsp.buffer.read(n, -2); - double c = dsp.buffer.read(n, -1); - double d = dsp.buffer.read(n, -0); - - const double tension = 0.0; //-1 = low, 0 = normal, +1 = high - const double bias = 0.0; //-1 = left, 0 = even, +1 = right - - double mu1, mu2, mu3, m0, m1, a0, a1, a2, a3; - - mu1 = fraction; - mu2 = mu1 * mu1; - mu3 = mu2 * mu1; - - m0 = (b - a) * (1.0 + bias) * (1.0 - tension) / 2.0; - m0 += (c - b) * (1.0 - bias) * (1.0 - tension) / 2.0; - m1 = (c - b) * (1.0 + bias) * (1.0 - tension) / 2.0; - m1 += (d - c) * (1.0 - bias) * (1.0 - tension) / 2.0; - - a0 = +2 * mu3 - 3 * mu2 + 1; - a1 = mu3 - 2 * mu2 + mu1; - a2 = mu3 - mu2; - a3 = -2 * mu3 + 3 * mu2; - - channel[n] = (a0 * b) + (a1 * m0) + (a2 * m1) + (a3 * c); - } - - dsp.write(channel); - fraction += step; - } - - dsp.buffer.rdoffset++; - fraction -= 1.0; -} diff --git a/dsp/resample/lib/sinc.hpp b/dsp/resample/lib/sinc.hpp deleted file mode 100644 index 135b45e..0000000 --- a/dsp/resample/lib/sinc.hpp +++ /dev/null @@ -1,600 +0,0 @@ -// If these types are changed to anything other than "float", you should comment out the SSE detection directives below -// so that the SSE code is not used. - -typedef float resample_coeff_t; // note: sizeof(resample_coeff_t) must be == to a power of 2, and not larger than 16 -typedef float resample_samp_t; - - -// ...but don't comment this single RESAMPLE_SSEREGPARM define out when disabling SSE. -#define RESAMPLE_SSEREGPARM - -#if defined(__SSE__) - #define SINCRESAMPLE_USE_SSE 1 - #ifndef __x86_64__ - #undef RESAMPLE_SSEREGPARM - #define RESAMPLE_SSEREGPARM __attribute__((sseregparm)) - #endif -#else - // TODO: altivec here -#endif - -namespace ResampleUtility -{ - inline void kaiser_window(double* io, int count, double beta); - inline void gen_sinc(double* out, int size, double cutoff, double kaiser); - inline void gen_sinc_os(double* out, int size, double cutoff, double kaiser); - inline void normalize(double* io, int size, double gain = 1.0); - - inline void* make_aligned(void* ptr, unsigned boundary); // boundary must be a power of 2 -} - -class SincResampleHR -{ - private: - - inline void Init(unsigned ratio_arg, double desired_bandwidth, double beta, double d); - - inline void write(resample_samp_t sample) RESAMPLE_SSEREGPARM; - inline resample_samp_t read(void) RESAMPLE_SSEREGPARM; - inline bool output_avail(void); - - private: - - inline resample_samp_t mac(const resample_samp_t *wave, const resample_coeff_t *coeff, unsigned count); - - unsigned ratio; - unsigned num_convolutions; - - resample_coeff_t *coeffs; - std::vector coeffs_mem; - - // second half of ringbuffer should be copy of first half. - resample_samp_t *rb; - std::vector rb_mem; - - signed rb_readpos; - signed rb_writepos; - signed rb_in; - signed rb_eff_size; - - friend class SincResample; -}; - -class SincResample -{ - public: - - enum - { - QUALITY_LOW = 0, - QUALITY_MEDIUM = 2, - QUALITY_HIGH = 4 - }; - - inline SincResample(double input_rate, double output_rate, double desired_bandwidth, unsigned quality = QUALITY_HIGH); - - inline void write(resample_samp_t sample) RESAMPLE_SSEREGPARM; - inline resample_samp_t read(void) RESAMPLE_SSEREGPARM; - inline bool output_avail(void); - - private: - - inline void Init(double input_rate, double output_rate, double desired_bandwidth, double beta, double d, unsigned pn_nume, unsigned phases_min); - - inline resample_samp_t mac(const resample_samp_t *wave, const resample_coeff_t *coeffs_a, const resample_coeff_t *coeffs_b, const double ffract, unsigned count) RESAMPLE_SSEREGPARM; - - unsigned num_convolutions; - unsigned num_phases; - - unsigned step_int; - double step_fract; - - double input_pos_fract; - - - std::vector coeffs; // Pointers into coeff_mem. - std::vector coeff_mem; - - - std::vector rb; // second half should be copy of first half. - signed rb_readpos; - signed rb_writepos; - signed rb_in; - - bool hr_used; - SincResampleHR hr; -}; - - -// -// Code: -// -//#include "resample.hpp" - -#if 0 -namespace bit -{ - inline unsigned round(unsigned x) { - if((x & (x - 1)) == 0) return x; - while(x & (x - 1)) x &= x - 1; - return x << 1; - } -} -#endif - -void SincResampleHR::Init(unsigned ratio_arg, double desired_bandwidth, double beta, double d) -{ - const unsigned align_boundary = 16; - std::vector coeffs_tmp; - double cutoff; // 1.0 = f/2 - - ratio = ratio_arg; - - //num_convolutions = ((unsigned)ceil(d / ((1.0 - desired_bandwidth) / ratio)) + 1) &~ 1; // round up to be even - num_convolutions = ((unsigned)ceil(d / ((1.0 - desired_bandwidth) / ratio)) | 1); - - cutoff = (1.0 / ratio) - (d / num_convolutions); - -//printf("%d %d %.20f\n", ratio, num_convolutions, cutoff); - assert(num_convolutions > ratio); - - - // Generate windowed sinc of POWER - coeffs_tmp.resize(num_convolutions); - //ResampleUtility::gen_sinc(&coeffs_tmp[0], num_convolutions, cutoff, beta); - ResampleUtility::gen_sinc_os(&coeffs_tmp[0], num_convolutions, cutoff, beta); - ResampleUtility::normalize(&coeffs_tmp[0], num_convolutions); - - // Copy from coeffs_tmp to coeffs~ - // We multiply many coefficients at a time in the mac loop, so make sure the last few that don't really - // exist are allocated, zero'd mem. - - coeffs_mem.resize(((num_convolutions + 7) &~ 7) * sizeof(resample_coeff_t) + (align_boundary - 1)); - coeffs = (resample_coeff_t *)ResampleUtility::make_aligned(&coeffs_mem[0], align_boundary); - - - for(unsigned i = 0; i < num_convolutions; i++) - coeffs[i] = coeffs_tmp[i]; - - rb_eff_size = nall::bit::round(num_convolutions * 2) >> 1; - rb_readpos = 0; - rb_writepos = 0; - rb_in = 0; - - rb_mem.resize(rb_eff_size * 2 * sizeof(resample_samp_t) + (align_boundary - 1)); - rb = (resample_samp_t *)ResampleUtility::make_aligned(&rb_mem[0], align_boundary); -} - - -inline bool SincResampleHR::output_avail(void) -{ - return(rb_in >= (signed)num_convolutions); -} - -inline void SincResampleHR::write(resample_samp_t sample) -{ - assert(!output_avail()); - - rb[rb_writepos] = sample; - rb[rb_writepos + rb_eff_size] = sample; - rb_writepos = (rb_writepos + 1) & (rb_eff_size - 1); - rb_in++; -} - -resample_samp_t SincResampleHR::mac(const resample_samp_t *wave, const resample_coeff_t *coeff, unsigned count) -{ -#if SINCRESAMPLE_USE_SSE - __m128 accum_veca[2] = { _mm_set1_ps(0), _mm_set1_ps(0) }; - - resample_samp_t accum; - - for(unsigned c = 0; c < count; c += 8) - { - for(unsigned i = 0; i < 2; i++) - { - __m128 co[2]; - __m128 w[2]; - - co[i] = _mm_load_ps(&coeff[c + i * 4]); - w[i] = _mm_load_ps(&wave[c + i * 4]); - - w[i] = _mm_mul_ps(w[i], co[i]); - - accum_veca[i] = _mm_add_ps(w[i], accum_veca[i]); - } - } - - __m128 accum_vec = _mm_add_ps(accum_veca[0], accum_veca[1]); //_mm_add_ps(_mm_add_ps(accum_veca[0], accum_veca[1]), _mm_add_ps(accum_veca[2], accum_veca[3])); - - accum_vec = _mm_add_ps(accum_vec, _mm_shuffle_ps(accum_vec, accum_vec, (3 << 0) | (2 << 2) | (1 << 4) | (0 << 6))); - accum_vec = _mm_add_ps(accum_vec, _mm_shuffle_ps(accum_vec, accum_vec, (1 << 0) | (0 << 2) | (1 << 4) | (0 << 6))); - - _mm_store_ss(&accum, accum_vec); - - return accum; -#else - resample_samp_t accum[4] = { 0, 0, 0, 0 }; - - for(unsigned c = 0; c < count; c+= 4) - { - accum[0] += wave[c + 0] * coeff[c + 0]; - accum[1] += wave[c + 1] * coeff[c + 1]; - accum[2] += wave[c + 2] * coeff[c + 2]; - accum[3] += wave[c + 3] * coeff[c + 3]; - } - - return (accum[0] + accum[1]) + (accum[2] + accum[3]); // don't mess with parentheses(assuming compiler doesn't already, which it may... - -#endif -} - - -resample_samp_t SincResampleHR::read(void) -{ - assert(output_avail()); - resample_samp_t ret; - - ret = mac(&rb[rb_readpos], &coeffs[0], num_convolutions); - - rb_readpos = (rb_readpos + ratio) & (rb_eff_size - 1); - rb_in -= ratio; - - return ret; -} - - -SincResample::SincResample(double input_rate, double output_rate, double desired_bandwidth, unsigned quality) -{ - const struct - { - double beta; - double d; - unsigned pn_nume; - unsigned phases_min; - } qtab[5] = - { - { 5.658, 3.62, 4096, 4 }, - { 6.764, 4.32, 8192, 4 }, - { 7.865, 5.0, 16384, 8 }, - { 8.960, 5.7, 32768, 16 }, - { 10.056, 6.4, 65536, 32 } - }; - - // Sanity checks - assert(ceil(input_rate) > 0); - assert(ceil(output_rate) > 0); - assert(ceil(input_rate / output_rate) <= 1024); - assert(ceil(output_rate / input_rate) <= 1024); - - // The simplistic number-of-phases calculation code doesn't work well enough for when desired_bandwidth is close to 1.0 and when - // upsampling. - assert(desired_bandwidth >= 0.25 && desired_bandwidth < 0.96); - assert(quality >= 0 && quality <= 4); - - hr_used = false; - -#if 1 - // Round down to the nearest multiple of 4(so wave buffer remains aligned) - // It also adjusts the effective intermediate sampling rate up slightly, so that the upper frequencies below f/2 - // aren't overly attenuated so much. In the future, we might want to do an FFT or something to choose the intermediate rate more accurately - // to virtually eliminate over-attenuation. - unsigned ioratio_rd = (unsigned)floor(input_rate / (output_rate * (1.0 + (1.0 - desired_bandwidth) / 2) )) & ~3; - - if(ioratio_rd >= 8) - { - hr.Init(ioratio_rd, desired_bandwidth, qtab[quality].beta, qtab[quality].d); //10.056, 6.4); - hr_used = true; - - input_rate /= ioratio_rd; - } -#endif - - Init(input_rate, output_rate, desired_bandwidth, qtab[quality].beta, qtab[quality].d, qtab[quality].pn_nume, qtab[quality].phases_min); -} - -void SincResample::Init(double input_rate, double output_rate, double desired_bandwidth, double beta, double d, unsigned pn_nume, unsigned phases_min) -{ - const unsigned max_mult_atatime = 8; // multiply "granularity". must be power of 2. - const unsigned max_mult_minus1 = (max_mult_atatime - 1); - const unsigned conv_alignment_bytes = 16; // must be power of 2 - const double input_to_output_ratio = input_rate / output_rate; - const double output_to_input_ratio = output_rate / input_rate; - double cutoff; // 1.0 = input_rate / 2 - std::vector coeff_init_buffer; - - // Round up num_convolutions to be even. - if(output_rate > input_rate) - num_convolutions = ((unsigned)ceil(d / (1.0 - desired_bandwidth)) + 1) & ~1; - else - num_convolutions = ((unsigned)ceil(d / (output_to_input_ratio * (1.0 - desired_bandwidth))) + 1) & ~1; - - if(output_rate > input_rate) // Upsampling - cutoff = desired_bandwidth; - else // Downsampling - cutoff = output_to_input_ratio * desired_bandwidth; - - // Round up to be even. - num_phases = (std::max(pn_nume / num_convolutions, phases_min) + 1) &~1; - - // Adjust cutoff to account for the multiple phases. - cutoff = cutoff / num_phases; - - assert((num_convolutions & 1) == 0); - assert((num_phases & 1) == 0); - -// fprintf(stderr, "num_convolutions=%u, num_phases=%u, total expected coeff byte size=%lu\n", num_convolutions, num_phases, -// (long)((num_phases + 2) * ((num_convolutions + max_mult_minus1) & ~max_mult_minus1) * sizeof(float) + conv_alignment_bytes)); - - coeff_init_buffer.resize(num_phases * num_convolutions); - - coeffs.resize(num_phases + 1 + 1); - - coeff_mem.resize((num_phases + 1 + 1) * ((num_convolutions + max_mult_minus1) &~ max_mult_minus1) * sizeof(resample_coeff_t) + conv_alignment_bytes); - - // Assign aligned pointers into coeff_mem - { - resample_coeff_t *base_ptr = (resample_coeff_t *)ResampleUtility::make_aligned(&coeff_mem[0], conv_alignment_bytes); - - for(unsigned phase = 0; phase < (num_phases + 1 + 1); phase++) - { - coeffs[phase] = base_ptr + (((num_convolutions + max_mult_minus1) & ~max_mult_minus1) * phase); - } - } - - ResampleUtility::gen_sinc(&coeff_init_buffer[0], num_phases * num_convolutions, cutoff, beta); - ResampleUtility::normalize(&coeff_init_buffer[0], num_phases * num_convolutions, num_phases); - - // Reorder coefficients to allow for more efficient convolution. - for(int phase = -1; phase < ((int)num_phases + 1); phase++) - { - for(int conv = 0; conv < (int)num_convolutions; conv++) - { - double coeff; - - if(phase == -1 && conv == 0) - coeff = 0; - else if(phase == (int)num_phases && conv == ((int)num_convolutions - 1)) - coeff = 0; - else - coeff = coeff_init_buffer[conv * num_phases + phase]; - - coeffs[phase + 1][conv] = coeff; - } - } - - // Free a bit of mem - coeff_init_buffer.resize(0); - - step_int = floor(input_to_output_ratio); - step_fract = input_to_output_ratio - step_int; - - input_pos_fract = 0; - - // Do NOT use rb.size() later in the code, since it'll include the padding. - // We should only need one "max_mult_minus1" here, not two, since it won't matter if it over-reads(due to doing "max_mult_atatime" multiplications at a time - // rather than just 1, in which case this over-read wouldn't happen), from the first half into the duplicated half, - // since those corresponding coefficients will be zero anyway; this is just to handle the case of reading off the end of the duplicated half to - // prevent illegal memory accesses. - rb.resize(num_convolutions * 2 + max_mult_minus1); - - rb_readpos = 0; - rb_writepos = 0; - rb_in = 0; -} - -resample_samp_t SincResample::mac(const resample_samp_t *wave, const resample_coeff_t *coeffs_a, const resample_coeff_t *coeffs_b, const double ffract, unsigned count) -{ - resample_samp_t accum = 0; -#if SINCRESAMPLE_USE_SSE - __m128 accum_vec_a[2] = { _mm_set1_ps(0), _mm_set1_ps(0) }; - __m128 accum_vec_b[2] = { _mm_set1_ps(0), _mm_set1_ps(0) }; - - for(unsigned c = 0; c < count; c += 8) //8) //4) - { - __m128 coeff_a[2]; - __m128 coeff_b[2]; - __m128 w[2]; - __m128 result_a[2], result_b[2]; - - for(unsigned i = 0; i < 2; i++) - { - coeff_a[i] = _mm_load_ps(&coeffs_a[c + (i * 4)]); - coeff_b[i] = _mm_load_ps(&coeffs_b[c + (i * 4)]); - w[i] = _mm_loadu_ps(&wave[c + (i * 4)]); - - result_a[i] = _mm_mul_ps(coeff_a[i], w[i]); - result_b[i] = _mm_mul_ps(coeff_b[i], w[i]); - - accum_vec_a[i] = _mm_add_ps(result_a[i], accum_vec_a[i]); - accum_vec_b[i] = _mm_add_ps(result_b[i], accum_vec_b[i]); - } - } - - __m128 accum_vec, av_a, av_b; - __m128 mult_a_vec = _mm_set1_ps(1.0 - ffract); - __m128 mult_b_vec = _mm_set1_ps(ffract); - - av_a = _mm_mul_ps(mult_a_vec, /*accum_vec_a[0]);*/ _mm_add_ps(accum_vec_a[0], accum_vec_a[1])); - av_b = _mm_mul_ps(mult_b_vec, /*accum_vec_b[0]);*/ _mm_add_ps(accum_vec_b[0], accum_vec_b[1])); - - accum_vec = _mm_add_ps(av_a, av_b); - - accum_vec = _mm_add_ps(accum_vec, _mm_shuffle_ps(accum_vec, accum_vec, (3 << 0) | (2 << 2) | (1 << 4) | (0 << 6))); - accum_vec = _mm_add_ps(accum_vec, _mm_shuffle_ps(accum_vec, accum_vec, (1 << 0) | (0 << 2) | (1 << 4) | (0 << 6))); - - _mm_store_ss(&accum, accum_vec); -#else - resample_coeff_t mult_a = 1.0 - ffract; - resample_coeff_t mult_b = ffract; - - for(unsigned c = 0; c < count; c += 4) - { - accum += wave[c + 0] * (coeffs_a[c + 0] * mult_a + coeffs_b[c + 0] * mult_b); - accum += wave[c + 1] * (coeffs_a[c + 1] * mult_a + coeffs_b[c + 1] * mult_b); - accum += wave[c + 2] * (coeffs_a[c + 2] * mult_a + coeffs_b[c + 2] * mult_b); - accum += wave[c + 3] * (coeffs_a[c + 3] * mult_a + coeffs_b[c + 3] * mult_b); - } -#endif - - return accum; -} - -inline bool SincResample::output_avail(void) -{ - return(rb_in >= (int)num_convolutions); -} - -resample_samp_t SincResample::read(void) -{ - assert(output_avail()); - double phase = input_pos_fract * num_phases - 0.5; - signed phase_int = (signed)floor(phase); - double phase_fract = phase - phase_int; - unsigned phase_a = num_phases - 1 - phase_int; - unsigned phase_b = phase_a - 1; - resample_samp_t ret; - - ret = mac(&rb[rb_readpos], &coeffs[phase_a + 1][0], &coeffs[phase_b + 1][0], phase_fract, num_convolutions); - - unsigned int_increment = step_int; - - input_pos_fract += step_fract; - int_increment += floor(input_pos_fract); - input_pos_fract -= floor(input_pos_fract); - - rb_readpos = (rb_readpos + int_increment) % num_convolutions; - rb_in -= int_increment; - - return ret; -} - -inline void SincResample::write(resample_samp_t sample) -{ - assert(!output_avail()); - - if(hr_used) - { - hr.write(sample); - - if(hr.output_avail()) - { - sample = hr.read(); - } - else - { - return; - } - } - - rb[rb_writepos + 0 * num_convolutions] = sample; - rb[rb_writepos + 1 * num_convolutions] = sample; - rb_writepos = (rb_writepos + 1) % num_convolutions; - rb_in++; -} - -void ResampleUtility::kaiser_window( double* io, int count, double beta) -{ - int const accuracy = 24; //16; //12; - - double* end = io + count; - - double beta2 = beta * beta * (double) -0.25; - double to_fract = beta2 / ((double) count * count); - double i = 0; - double rescale = 0; // Doesn't need an initializer, to shut up gcc - - for ( ; io < end; ++io, i += 1 ) - { - double x = i * i * to_fract - beta2; - double u = x; - double k = x + 1; - - double n = 2; - do - { - u *= x / (n * n); - n += 1; - k += u; - } - while ( k <= u * (1 << accuracy) ); - - if ( !i ) - rescale = 1 / k; // otherwise values get large - - *io *= k * rescale; - } -} - -void ResampleUtility::gen_sinc(double* out, int size, double cutoff, double kaiser) -{ - assert( size % 2 == 0 ); // size must be even - - int const half_size = size / 2; - double* const mid = &out [half_size]; - - // Generate right half of sinc - for ( int i = 0; i < half_size; i++ ) - { - double angle = (i * 2 + 1) * (Math::Pi / 2); - mid [i] = sin( angle * cutoff ) / angle; - } - - kaiser_window( mid, half_size, kaiser ); - - // Mirror for left half - for ( int i = 0; i < half_size; i++ ) - out [i] = mid [half_size - 1 - i]; -} - -void ResampleUtility::gen_sinc_os(double* out, int size, double cutoff, double kaiser) -{ - assert( size % 2 == 1); // size must be odd - - for(int i = 0; i < size; i++) - { - if(i == (size / 2)) - out[i] = 2 * Math::Pi * (cutoff / 2); //0.078478; //1.0; //sin(2 * M_PI * (cutoff / 2) * (i - size / 2)) / (i - (size / 2)); - else - out[i] = sin(2 * Math::Pi * (cutoff / 2) * (i - size / 2)) / (i - (size / 2)); - -// out[i] *= 0.3635819 - 0.4891775 * cos(2 * M_PI * i / (size - 1)) + 0.1365995 * cos(4 * M_PI * i / (size - 1)) - 0.0106411 * cos(6 * M_PI * i / (size - 1)); -//0.42 - 0.5 * cos(2 * M_PI * i / (size - 1)) + 0.08 * cos(4 * M_PI * i / (size - 1)); - -// printf("%d %f\n", i, out[i]); - } - - kaiser_window(&out[size / 2], size / 2 + 1, kaiser); - - // Mirror for left half - for ( int i = 0; i < size / 2; i++ ) - out [i] = out [size - 1 - i]; - -} - -void ResampleUtility::normalize(double* io, int size, double gain) -{ - double sum = 0; - for ( int i = 0; i < size; i++ ) - sum += io [i]; - - double scale = gain / sum; - for ( int i = 0; i < size; i++ ) - io [i] *= scale; -} - -void* ResampleUtility::make_aligned(void* ptr, unsigned boundary) -{ - unsigned char* null_ptr = (unsigned char *)nullptr; - unsigned char* uc_ptr = (unsigned char *)ptr; - - uc_ptr += (boundary - ((uc_ptr - null_ptr) & (boundary - 1))) & (boundary - 1); - - //while((uc_ptr - null_ptr) & (boundary - 1)) - // uc_ptr++; - - //printf("%16llx %16llx\n", (unsigned long long)ptr, (unsigned long long)uc_ptr); - - assert((uc_ptr - (unsigned char *)ptr) < boundary && (uc_ptr >= (unsigned char *)ptr)); - - return uc_ptr; -} diff --git a/dsp/resample/linear.hpp b/dsp/resample/linear.hpp deleted file mode 100644 index b7aa7ec..0000000 --- a/dsp/resample/linear.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -struct ResampleLinear : Resampler { - ResampleLinear(DSP& dsp) : Resampler(dsp) {} - - inline auto setFrequency() -> void; - inline auto clear() -> void; - inline auto sample() -> void; - -private: - double fraction; - double step; -}; - -auto ResampleLinear::setFrequency() -> void { - fraction = 0.0; - step = dsp.settings.frequency / frequency; -} - -auto ResampleLinear::clear() -> void { - fraction = 0.0; -} - -auto ResampleLinear::sample() -> void { - while(fraction <= 1.0) { - double channel[dsp.settings.channels]; - - for(auto n : range(dsp.settings.channels)) { - double a = dsp.buffer.read(n, -1); - double b = dsp.buffer.read(n, -0); - - double mu = fraction; - - channel[n] = a * (1.0 - mu) + b * mu; - } - - dsp.write(channel); - fraction += step; - } - - dsp.buffer.rdoffset++; - fraction -= 1.0; -} diff --git a/dsp/resample/nearest.hpp b/dsp/resample/nearest.hpp deleted file mode 100644 index 50d6da7..0000000 --- a/dsp/resample/nearest.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -struct ResampleNearest : Resampler { - ResampleNearest(DSP& dsp) : Resampler(dsp) {} - - inline auto setFrequency() -> void; - inline auto clear() -> void; - inline auto sample() -> void; - -private: - double fraction; - double step; -}; - -auto ResampleNearest::setFrequency() -> void { - fraction = 0.0; - step = dsp.settings.frequency / frequency; -} - -auto ResampleNearest::clear() -> void { - fraction = 0.0; -} - -auto ResampleNearest::sample() -> void { - while(fraction <= 1.0) { - double channel[dsp.settings.channels]; - - for(auto n : range(dsp.settings.channels)) { - double a = dsp.buffer.read(n, -1); - double b = dsp.buffer.read(n, -0); - - double mu = fraction; - - channel[n] = mu < 0.5 ? a : b; - } - - dsp.write(channel); - fraction += step; - } - - dsp.buffer.rdoffset++; - fraction -= 1.0; -} diff --git a/dsp/resample/sinc.hpp b/dsp/resample/sinc.hpp deleted file mode 100644 index e39e9fe..0000000 --- a/dsp/resample/sinc.hpp +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -#include "lib/sinc.hpp" - -struct ResampleSinc : Resampler { - inline ResampleSinc(DSP& dsp); - inline ~ResampleSinc(); - - inline auto setFrequency() -> void; - inline auto clear() -> void; - inline auto sample() -> void; - -private: - inline void remakeSinc(); - SincResample* sincResampler[8] = {0}; -}; - -ResampleSinc::ResampleSinc(DSP& dsp) : Resampler(dsp) { - for(auto n : range(8)) { - sincResampler[n] = nullptr; - } -} - -ResampleSinc::~ResampleSinc() { - for(auto n : range(8)) { - if(sincResampler[n]) delete sincResampler[n]; - } -} - -auto ResampleSinc::setFrequency() -> void { - remakeSinc(); -} - -auto ResampleSinc::clear() -> void { - remakeSinc(); -} - -auto ResampleSinc::sample() -> void { - for(auto c : range(dsp.settings.channels)) { - sincResampler[c]->write(dsp.buffer.read(c)); - } - - if(sincResampler[0]->output_avail()) { - do { - for(auto c : range(dsp.settings.channels)) { - dsp.output.write(c) = sincResampler[c]->read(); - } - dsp.output.wroffset++; - } while(sincResampler[0]->output_avail()); - } - - dsp.buffer.rdoffset++; -} - -auto ResampleSinc::remakeSinc() -> void { - assert(dsp.settings.channels < 8); - - for(auto c : range(dsp.settings.channels)) { - if(sincResampler[c]) delete sincResampler[c]; - sincResampler[c] = new SincResample(dsp.settings.frequency, frequency, 0.85, SincResample::QUALITY_HIGH); - } -} diff --git a/dsp/resampler/cubic.hpp b/dsp/resampler/cubic.hpp new file mode 100644 index 0000000..df37977 --- /dev/null +++ b/dsp/resampler/cubic.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include + +namespace nall { namespace DSP { namespace Resampler { + +struct Cubic { + inline auto reset(double inputFrequency, double outputFrequency, uint queueSize = 0) -> void; + inline auto pending() const -> bool { return samples.pending(); } + inline auto read() -> double { return samples.read(); } + inline auto write(double sample) -> void; + +private: + double inputFrequency; + double outputFrequency; + + double ratio; + double fraction; + double history[4]; + queue samples; +}; + +auto Cubic::reset(double inputFrequency, double outputFrequency, uint queueSize) -> void { + this->inputFrequency = inputFrequency; + this->outputFrequency = outputFrequency; + if(!queueSize) queueSize = outputFrequency * 0.02; //20ms + + ratio = inputFrequency / outputFrequency; + fraction = 0.0; + for(auto& sample: history) sample = 0.0; + samples.resize(queueSize); +} + +auto Cubic::write(double sample) -> void { + auto& mu = fraction; + auto& s = history; + + s[0] = s[1]; + s[1] = s[2]; + s[2] = s[3]; + s[3] = sample; + + while(mu <= 1.0) { + double A = s[3] - s[2] - s[0] + s[1]; + double B = s[0] - s[1] - A; + double C = s[2] - s[0]; + double D = s[1]; + + samples.write(A * mu * mu * mu + B * mu * mu + C * mu + D); + mu += ratio; + } + + mu -= 1.0; +} + +}}} diff --git a/dsp/settings.hpp b/dsp/settings.hpp deleted file mode 100644 index 3254c14..0000000 --- a/dsp/settings.hpp +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -auto DSP::setChannels(uint channels) -> void { - channels = max(1u, channels); - buffer.setChannels(channels); - output.setChannels(channels); - settings.channels = channels; -} - -auto DSP::setPrecision(uint precision) -> void { - settings.precision = precision; - settings.intensity = 1 << (settings.precision - 1); - settings.intensityInverse = 1.0 / settings.intensity; -} - -auto DSP::setFrequency(double frequency) -> void { - settings.frequency = frequency; - resampler->setFrequency(); -} - -auto DSP::setVolume(double volume) -> void { - settings.volume = volume; -} - -auto DSP::setBalance(double balance) -> void { - settings.balance = balance; -} - -auto DSP::setResampler(ResampleEngine engine) -> void { - if(resampler) delete resampler; - - switch(engine) { default: - case ResampleEngine::Nearest: resampler = new ResampleNearest(*this); return; - case ResampleEngine::Linear: resampler = new ResampleLinear (*this); return; - case ResampleEngine::Cosine: resampler = new ResampleCosine (*this); return; - case ResampleEngine::Cubic: resampler = new ResampleCubic (*this); return; - case ResampleEngine::Hermite: resampler = new ResampleHermite(*this); return; - case ResampleEngine::Average: resampler = new ResampleAverage(*this); return; - case ResampleEngine::Sinc: resampler = new ResampleSinc (*this); return; - } -} - -auto DSP::setResamplerFrequency(double frequency) -> void { - resampler->frequency = frequency; - resampler->setFrequency(); -} diff --git a/emulation/21fx.hpp b/emulation/21fx.hpp new file mode 100644 index 0000000..c6613f3 --- /dev/null +++ b/emulation/21fx.hpp @@ -0,0 +1,134 @@ +#pragma once + +#include +#include +using namespace nall; + +struct FX { + auto open(lstring& args) -> bool; + auto close() -> void; + auto readable() -> bool; + auto read() -> uint8_t; + auto writable() -> bool; + auto write(uint8_t data) -> void; + + auto read(uint offset, uint length) -> vector; + auto write(uint offset, const void* buffer, uint length) -> void; + auto write(uint offset, const vector& buffer) -> void { write(offset, buffer.data(), buffer.size()); } + auto execute(uint offset) -> void; + + auto read(uint offset) -> uint8_t; + auto write(uint offset, uint8_t data) -> void; + + serial device; +}; + +auto FX::open(lstring& args) -> bool { + //device name override support + string name; + for(uint n : range(args)) { + if(args[n].beginsWith("--device=")) { + name = args.take(n).trimLeft("--device=", 1L); + break; + } + } + + if(!device.open(name)) { + print("[21fx] error: unable to open hardware device\n"); + return false; + } + + //flush the device (to clear floating inputs) + while(true) { + while(readable()) read(); + auto iplrom = read(0x2184, 122); + auto sha256 = Hash::SHA256(iplrom.data(), iplrom.size()).digest(); + if(sha256 == "41b79712a4a2d16d39894ae1b38cde5c41dad22eadc560df631d39f13df1e4b9") break; + } + + return true; +} + +auto FX::close() -> void { + device.close(); +} + +auto FX::readable() -> bool { + return device.readable(); +} + +//1000ns delay avoids burning CPU core at 100%; does not slow down max transfer rate at all +auto FX::read() -> uint8_t { + while(!readable()) usleep(1000); + uint8_t buffer[1] = {0}; + device.read(buffer, 1); + return buffer[0]; +} + +auto FX::writable() -> bool { + return device.writable(); +} + +auto FX::write(uint8_t data) -> void { + while(!writable()) usleep(1000); + uint8_t buffer[1] = {data}; + device.write(buffer, 1); +} + +// + +auto FX::read(uint offset, uint length) -> vector { + write(0x21); + write(0x66); + write(0x78); + write(offset >> 16); + write(offset >> 8); + write(offset >> 0); + write(0x01); + write(length >> 8); + write(length >> 0); + write(0x00); + + vector buffer; + while(length--) buffer.append(read()); + return buffer; +} + +auto FX::write(uint offset, const void* data, uint length) -> void { + write(0x21); + write(0x66); + write(0x78); + write(offset >> 16); + write(offset >> 8); + write(offset >> 0); + write(0x01); + write(length >> 8); + write(length >> 0); + write(0x01); + + auto buffer = (uint8_t*)data; + for(auto n : range(length)) write(buffer[n]); + write(0x00); +} + +auto FX::execute(uint offset) -> void { + write(0x21); + write(0x66); + write(0x78); + write(offset >> 16); + write(offset >> 8); + write(offset >> 0); + write(0x00); +} + +// + +auto FX::read(uint offset) -> uint8_t { + auto buffer = read(offset, 1); + return buffer[0]; +} + +auto FX::write(uint offset, uint8_t data) -> void { + vector buffer = {data}; + write(offset, buffer); +} diff --git a/encode/base64.hpp b/encode/base64.hpp index 46fa5f5..42d6ced 100644 --- a/encode/base64.hpp +++ b/encode/base64.hpp @@ -2,7 +2,8 @@ namespace nall { namespace Encode { -inline auto Base64(const uint8_t* data, unsigned size, const string& format = "MIME") -> string { +inline auto Base64(const void* vdata, unsigned size, const string& format = "MIME") -> string { + auto data = (const uint8_t*)vdata; vector result; char lookup[65]; @@ -34,14 +35,14 @@ inline auto Base64(const uint8_t* data, unsigned size, const string& format = "M case 1: buffer |= data[i] >> 4; - result.last() = lookup[buffer]; + result.right() = lookup[buffer]; buffer = (data[i] & 15) << 2; result.append(lookup[buffer]); break; case 2: buffer |= data[i] >> 6; - result.last() = lookup[buffer]; + result.right() = lookup[buffer]; buffer = (data[i] & 63); result.append(lookup[buffer]); break; @@ -61,7 +62,7 @@ inline auto Base64(const vector& buffer, const string& format = "MIME") } inline auto Base64(const string& text, const string& format = "MIME") -> string { - return Base64(text.binary(), text.size(), format); + return Base64(text.data(), text.size(), format); } }} diff --git a/file.hpp b/file.hpp index b4495ac..cc5228f 100644 --- a/file.hpp +++ b/file.hpp @@ -7,7 +7,6 @@ #include #include #include -#include namespace nall { @@ -239,7 +238,7 @@ struct file : inode, varint { #endif } - auto end() -> bool { + auto end() const -> bool { if(!fp) return true; //file not open return file_offset >= file_size; } diff --git a/hash/crc16.hpp b/hash/crc16.hpp index 63d3c47..879f31d 100644 --- a/hash/crc16.hpp +++ b/hash/crc16.hpp @@ -1,39 +1,64 @@ #pragma once #include +#include -namespace nall { -struct string; -namespace Hash { +namespace nall { namespace Hash { struct CRC16 { CRC16() { reset(); } - CRC16(const void* values, unsigned size) : CRC16() { data(values, size); } + CRC16(const void* values, uint size) : CRC16() { data(values, size); } + CRC16(const vector& values) : CRC16() { data(values); } + CRC16(const string& values) : CRC16() { data(values); } auto reset() -> void { checksum = ~0; } auto data(uint8_t value) -> void { - for(auto n : range(8)) { - if((checksum & 1) ^ (value & 1)) checksum = (checksum >> 1) ^ 0x8408; - else checksum >>= 1; - value >>= 1; - } + checksum = (checksum >> 8) ^ table(checksum ^ value); } - auto data(const void* values, unsigned size) -> void { + auto data(const void* values, uint size) -> void { auto p = (const uint8_t*)values; while(size--) data(*p++); } - auto value() -> uint16_t { + auto data(const vector& values) -> void { + for(auto value : values) data(value); + } + + auto data(const string& values) -> void { + for(auto value : values) data(value); + } + + auto value() const -> uint16_t { return ~checksum; } - inline auto digest() -> string; + inline auto digest() const -> string { + return hex(value(), 4L); + } private: + static auto table(uint8_t index) -> uint16_t { + static uint16_t table[256] = {0}; + static bool initialized = false; + + if(!initialized) { + initialized = true; + for(auto index : range(256)) { + uint16_t crc = index; + for(auto bit : range(8)) { + crc = (crc >> 1) ^ (crc & 1 ? 0x8408 : 0); + } + table[index] = crc; + } + } + + return table[index]; + } + uint16_t checksum; }; diff --git a/hash/crc32.hpp b/hash/crc32.hpp index 73ded1a..b1a7b57 100644 --- a/hash/crc32.hpp +++ b/hash/crc32.hpp @@ -1,81 +1,64 @@ #pragma once #include +#include -namespace nall { -struct string; -namespace Hash { - -const uint32_t _crc32_table[256] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, - 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, - 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, - 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, - 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, - 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, - 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, - 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, - 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, - 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, - 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, - 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, - 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, - 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, - 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, - 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, - 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, - 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, - 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, - 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, - 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, -}; +namespace nall { namespace Hash { struct CRC32 { CRC32() { reset(); } - CRC32(const void* values, unsigned size) : CRC32() { data(values, size); } + CRC32(const void* values, uint size) : CRC32() { data(values, size); } + CRC32(const vector& values) : CRC32() { data(values); } + CRC32(const string& values) : CRC32() { data(values); } auto reset() -> void { checksum = ~0; } auto data(uint8_t value) -> void { - checksum = ((checksum >> 8) & 0xffffff) ^ _crc32_table[(checksum ^ value) & 0xff]; + checksum = (checksum >> 8) ^ table(checksum ^ value); } - auto data(const void* values, unsigned size) -> void { + auto data(const void* values, uint size) -> void { auto p = (const uint8_t*)values; while(size--) data(*p++); } + auto data(const vector& values) -> void { + for(auto value : values) data(value); + } + + auto data(const string& values) -> void { + for(auto value : values) data(value); + } + auto value() const -> uint32_t { return ~checksum; } - inline auto digest() -> string; + inline auto digest() const -> string { + return hex(value(), 8L); + } private: + static auto table(uint8_t index) -> uint32_t { + static uint32_t table[256] = {0}; + static bool initialized = false; + + if(!initialized) { + initialized = true; + for(auto index : range(256)) { + uint32_t crc = index; + for(auto bit : range(8)) { + crc = (crc >> 1) ^ (crc & 1 ? 0xedb8'8320 : 0); + } + table[index] = crc; + } + } + + return table[index]; + } + uint32_t checksum; }; diff --git a/hash/crc64.hpp b/hash/crc64.hpp new file mode 100644 index 0000000..c97de7f --- /dev/null +++ b/hash/crc64.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include +#include + +namespace nall { namespace Hash { + +struct CRC64 { + CRC64() { reset(); } + CRC64(const void* values, uint size) : CRC64() { data(values, size); } + CRC64(const vector& values) : CRC64() { data(values); } + CRC64(const string& values) : CRC64() { data(values); } + + auto reset() -> void { + checksum = ~0; + } + + auto data(uint8_t value) -> void { + checksum = (checksum >> 8) ^ table(checksum ^ value); + } + + auto data(const void* values, uint size) -> void { + auto p = (const uint8_t*)values; + while(size--) data(*p++); + } + + auto data(const vector& values) -> void { + for(auto value : values) data(value); + } + + auto data(const string& values) -> void { + for(auto value : values) data(value); + } + + auto value() const -> uint64_t { + return ~checksum; + } + + inline auto digest() const -> string { + return hex(value(), 16L); + } + +private: + static auto table(uint8_t index) -> uint64_t { + static uint64_t table[256] = {0}; + static bool initialized = false; + + if(!initialized) { + initialized = true; + for(auto index : range(256)) { + uint64_t crc = index; + for(auto bit : range(8)) { + crc = (crc >> 1) ^ (crc & 1 ? 0xc96c'5795'd787'0f42 : 0); + } + table[index] = crc; + } + } + + return table[index]; + } + + uint64_t checksum; +}; + +}} diff --git a/hash/sha256.hpp b/hash/sha256.hpp index 0e71f72..3bc354c 100644 --- a/hash/sha256.hpp +++ b/hash/sha256.hpp @@ -1,14 +1,15 @@ #pragma once #include +#include -namespace nall { -struct string; -namespace Hash { +namespace nall { namespace Hash { struct SHA256 { SHA256() { reset(); } - SHA256(const void* values, unsigned size) : SHA256() { data(values, size); } + SHA256(const void* values, uint size) : SHA256() { data(values, size); } + SHA256(const vector& values) : SHA256() { data(values); } + SHA256(const string& values) : SHA256() { data(values); } auto reset() -> void { for(auto n : input) n = 0; @@ -22,12 +23,20 @@ struct SHA256 { length++; } - auto data(const void* values, unsigned size) -> void { + auto data(const void* values, uint size) -> void { length += size; auto p = (const uint8_t*)values; while(size--) byte(*p++); } + auto data(const vector& values) -> void { + for(auto value : values) data(value); + } + + auto data(const string& values) -> void { + for(auto value : values) data(value); + } + auto value() const -> vector { SHA256 self(*this); self.finish(); @@ -36,7 +45,11 @@ struct SHA256 { return result; } - inline auto digest() const -> nall::string; + inline auto digest() const -> string { + string result; + for(auto n : value()) result.append(hex(n, 2L)); + return result; + } private: auto byte(uint8_t value) -> void { @@ -77,14 +90,14 @@ private: return (x >> n) | (x << 32 - n); } - auto square(unsigned n) -> uint32_t { + auto square(uint n) -> uint32_t { static const uint32_t value[8] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, }; return value[n]; } - auto cube(unsigned n) -> uint32_t { + auto cube(uint n) -> uint32_t { static const uint32_t value[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, diff --git a/hashset.hpp b/hashset.hpp index 7efd057..6812eaf 100644 --- a/hashset.hpp +++ b/hashset.hpp @@ -7,7 +7,7 @@ //remove: O(1) average; O(n) worst // //requirements: -// auto T::hash() const -> unsigned; +// auto T::hash() const -> uint; // auto T::operator==(const T&) const -> bool; namespace nall { @@ -15,7 +15,7 @@ namespace nall { template struct hashset { hashset() = default; - hashset(unsigned length) : length(bit::round(length)) {} + hashset(uint length) : length(bit::round(length)) {} hashset(const hashset& source) { operator=(source); } hashset(hashset&& source) { operator=(move(source)); } ~hashset() { reset(); } @@ -23,7 +23,7 @@ struct hashset { auto operator=(const hashset& source) -> hashset& { reset(); if(source.pool) { - for(unsigned n = 0; n < source.count; n++) { + for(uint n : range(source.count)) { insert(*source.pool[n]); } } @@ -41,13 +41,13 @@ struct hashset { return *this; } - auto capacity() const -> unsigned { return length; } - auto size() const -> unsigned { return count; } - auto empty() const -> bool { return count == 0; } + explicit operator bool() const { return count; } + auto capacity() const -> uint { return length; } + auto size() const -> uint { return count; } auto reset() -> void { if(pool) { - for(unsigned n = 0; n < length; n++) { + for(uint n : range(length)) { if(pool[n]) { delete pool[n]; pool[n] = nullptr; @@ -60,15 +60,15 @@ struct hashset { count = 0; } - auto reserve(unsigned size) -> void { + auto reserve(uint 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](); if(pool) { - for(unsigned n = 0; n < length; n++) { + for(uint n : range(length)) { if(pool[n]) { - unsigned hash = (*pool[n]).hash() & (size - 1); + uint hash = (*pool[n]).hash() & (size - 1); while(copy[hash]) if(++hash >= size) hash = 0; copy[hash] = pool[n]; pool[n] = nullptr; @@ -84,7 +84,7 @@ struct hashset { auto find(const T& value) -> maybe { if(!pool) return nothing; - unsigned hash = value.hash() & (length - 1); + uint hash = value.hash() & (length - 1); while(pool[hash]) { if(value == *pool[hash]) return *pool[hash]; if(++hash >= length) hash = 0; @@ -100,7 +100,7 @@ struct hashset { if(count >= (length >> 1)) reserve(length << 1); count++; - unsigned hash = value.hash() & (length - 1); + uint hash = value.hash() & (length - 1); while(pool[hash]) if(++hash >= length) hash = 0; pool[hash] = new T(value); @@ -110,7 +110,7 @@ struct hashset { auto remove(const T& value) -> bool { if(!pool) return false; - unsigned hash = value.hash() & (length - 1); + uint hash = value.hash() & (length - 1); while(pool[hash]) { if(value == *pool[hash]) { delete pool[hash]; @@ -126,8 +126,8 @@ struct hashset { protected: T** pool = nullptr; - unsigned length = 8; //length of pool - unsigned count = 0; //number of objects inside of the pool + uint length = 8; //length of pool + uint count = 0; //number of objects inside of the pool }; } diff --git a/hid.hpp b/hid.hpp index fbbe06c..205a91a 100644 --- a/hid.hpp +++ b/hid.hpp @@ -19,10 +19,10 @@ struct Group : vector { Group(const string& name) : _name(name) {} auto name() const -> string { return _name; } - auto input(unsigned id) -> Input& { return operator[](id); } - auto append(const string& name) -> void { vector::append({name}); } + auto input(uint id) -> Input& { return operator[](id); } + auto append(const string& name) -> void { vector::append(Input{name}); } - auto find(const string& name) const -> maybe { + auto find(const string& name) const -> maybe { for(auto id : range(size())) { if(operator[](id)._name == name) return id; } @@ -50,10 +50,10 @@ struct Device : vector { auto name() const -> string { return _name; } auto id() const -> uint64_t { return _id; } auto setID(uint64_t id) -> void { _id = id; } - auto group(unsigned id) -> Group& { return operator[](id); } - auto append(const string& name) -> void { vector::append({name}); } + auto group(uint id) -> Group& { return operator[](id); } + auto append(const string& name) -> void { vector::append(Group{name}); } - auto find(const string& name) const -> maybe { + auto find(const string& name) const -> maybe { for(auto id : range(size())) { if(operator[](id)._name == name) return id; } @@ -71,7 +71,7 @@ struct Null : Device { }; struct Keyboard : Device { - enum GroupID : unsigned { Button }; + enum GroupID : uint { Button }; Keyboard() : Device("Keyboard") { append("Button"); } auto isKeyboard() const -> bool { return true; } @@ -79,7 +79,7 @@ struct Keyboard : Device { }; struct Mouse : Device { - enum GroupID : unsigned { Axis, Button }; + enum GroupID : uint { Axis, Button }; Mouse() : Device("Mouse") { append("Axis"), append("Button"); } auto isMouse() const -> bool { return true; } @@ -88,7 +88,7 @@ struct Mouse : Device { }; struct Joypad : Device { - enum GroupID : unsigned { Axis, Hat, Trigger, Button }; + enum GroupID : uint { Axis, Hat, Trigger, Button }; Joypad() : Device("Joypad") { append("Axis"), append("Hat"), append("Trigger"), append("Button"); } auto isJoypad() const -> bool { return true; } diff --git a/http/request.hpp b/http/request.hpp index a9afe8d..da81dd7 100644 --- a/http/request.hpp +++ b/http/request.hpp @@ -50,7 +50,7 @@ auto Request::head(const function& callback) co for(auto& variable : get) { request.append(Encode::URL(variable.name()), "=", Encode::URL(variable.value()), "&"); } - request.rtrim("&", 1L); + request.trimRight("&", 1L); } switch(requestType()) { @@ -65,25 +65,25 @@ auto Request::head(const function& callback) co } output.append("\r\n"); - return callback(output.binary(), output.size()); + return callback(output.data(), output.size()); } auto Request::setHead() -> bool { lstring headers = _head.split("\n"); - string request = headers.takeFirst().rtrim("\r", 1L); + string request = headers.takeLeft().trimRight("\r", 1L); string requestHost; - 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); + if(request.iendsWith(" HTTP/1.0")) request.itrimRight(" HTTP/1.0", 1L); + else if(request.iendsWith(" HTTP/1.1")) request.itrimRight(" HTTP/1.1", 1L); else return false; - 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); + if(request.ibeginsWith("HEAD ")) request.itrimLeft("HEAD ", 1L), setRequestType(RequestType::Head); + else if(request.ibeginsWith("GET " )) request.itrimLeft("GET ", 1L), setRequestType(RequestType::Get ); + else if(request.ibeginsWith("POST ")) request.itrimLeft("POST ", 1L), setRequestType(RequestType::Post); else return false; //decode absolute URIs - request.strip().iltrim("http://", 1L); + request.strip().itrimLeft("http://", 1L); if(!request.beginsWith("/")) { lstring components = request.split("/", 1L); requestHost = components(0); @@ -126,7 +126,7 @@ auto Request::body(const function& callback) co if(!callback) return false; if(_body) { - return callback(_body.binary(), _body.size()); + return callback(_body.data(), _body.size()); } return true; @@ -137,16 +137,16 @@ auto Request::setBody() -> bool { auto contentType = header["Content-Type"].value(); if(contentType.iequals("application/x-www-form-urlencoded")) { for(auto& block : _body.split("&")) { - auto p = block.rtrim("\r").split("=", 1L); + auto p = block.trimRight("\r").split("=", 1L); auto name = Decode::URL(p(0)); auto value = Decode::URL(p(1)); if(name) post.append(name, value); } } else if(contentType.imatch("multipart/form-data; boundary=?*")) { - auto boundary = contentType.iltrim("multipart/form-data; boundary=", 1L).trim("\"", "\"", 1L); + auto boundary = contentType.itrimLeft("multipart/form-data; boundary=", 1L).trim("\"", "\"", 1L); auto blocks = _body.split({"--", boundary}, 1024L); //limit blocks to prevent memory exhaustion for(auto& block : blocks) block.trim("\r\n", "\r\n", 1L); - if(blocks.size() < 2 || (blocks.takeFirst(), !blocks.takeLast().beginsWith("--"))) return false; + if(blocks.size() < 2 || (blocks.takeLeft(), !blocks.takeRight().beginsWith("--"))) return false; for(auto& block : blocks) { string name; string filename; diff --git a/http/response.hpp b/http/response.hpp index 9b00f99..3e4b315 100644 --- a/http/response.hpp +++ b/http/response.hpp @@ -61,7 +61,7 @@ auto Response::head(const function& callback) c output.append("HTTP/1.1 304 Not Modified\r\n"); output.append("Connection: close\r\n"); output.append("\r\n"); - return callback(output.binary(), output.size()); + return callback(output.data(), output.size()); } } } @@ -83,15 +83,15 @@ auto Response::head(const function& callback) c } output.append("\r\n"); - return callback(output.binary(), output.size()); + return callback(output.data(), output.size()); } auto Response::setHead() -> bool { lstring headers = _head.split("\n"); - string response = headers.takeFirst().rtrim("\r"); + string response = headers.takeLeft().trimRight("\r"); - if(response.ibeginsWith("HTTP/1.0 ")) response.iltrim("HTTP/1.0 ", 1L); - else if(response.ibeginsWith("HTTP/1.1 ")) response.iltrim("HTTP/1.1 ", 1L); + if(response.ibeginsWith("HTTP/1.0 ")) response.itrimLeft("HTTP/1.0 ", 1L); + else if(response.ibeginsWith("HTTP/1.1 ")) response.itrimLeft("HTTP/1.1 ", 1L); else return false; setResponseType(natural(response)); @@ -113,26 +113,26 @@ auto Response::body(const function& callback) c if(chunked) { string prefix = {hex(findContentLength()), "\r\n"}; - if(!callback(prefix.binary(), prefix.size())) return false; + if(!callback(prefix.data(), prefix.size())) return false; } if(_body) { - if(!callback(_body.binary(), _body.size())) return false; + if(!callback(_body.data(), _body.size())) return false; } else if(hasData()) { if(!callback(data().data(), data().size())) return false; } else if(hasFile()) { filemap map(file(), filemap::mode::read); if(!callback(map.data(), map.size())) return false; } else if(hasText()) { - if(!callback(text().binary(), text().size())) return false; + if(!callback(text().data(), text().size())) return false; } else { string response = findResponseType(); - if(!callback(response.binary(), response.size())) return false; + if(!callback(response.data(), response.size())) return false; } if(chunked) { string suffix = {"\r\n0\r\n\r\n"}; - if(!callback(suffix.binary(), suffix.size())) return false; + if(!callback(suffix.data(), suffix.size())) return false; } return true; diff --git a/image/base.hpp b/image/base.hpp index 83742e9..9e3ac2e 100644 --- a/image/base.hpp +++ b/image/base.hpp @@ -54,7 +54,6 @@ struct image { inline auto write(uint8_t* data, uint64_t value) const -> void; inline auto free() -> void; - inline auto empty() const -> bool; inline auto load(const string& filename) -> bool; inline auto allocate(unsigned width, unsigned height) -> void; diff --git a/image/core.hpp b/image/core.hpp index e018935..8fd61d7 100644 --- a/image/core.hpp +++ b/image/core.hpp @@ -86,7 +86,7 @@ auto image::operator=(image&& source) -> image& { } image::operator bool() const { - return !empty(); + return _data && _width && _height; } auto image::operator==(const image& source) const -> bool { @@ -137,10 +137,6 @@ auto image::free() -> void { _data = nullptr; } -auto image::empty() const -> bool { - return !_data || !_width || !_height; -} - auto image::load(const string& filename) -> bool { if(loadBMP(filename) == true) return true; if(loadPNG(filename) == true) return true; diff --git a/inode.hpp b/inode.hpp index a5f9e90..b56374c 100644 --- a/inode.hpp +++ b/inode.hpp @@ -9,7 +9,7 @@ namespace nall { struct inode { - enum class time : unsigned { access, modify }; + enum class time : uint { access, modify }; static auto exists(const string& name) -> bool { return access(name, F_OK) == 0; @@ -27,19 +27,19 @@ struct inode { return access(name, X_OK) == 0; } - static auto uid(const string& name) -> unsigned { + static auto uid(const string& name) -> uint { struct stat data{0}; stat(name, &data); return data.st_uid; } - static auto gid(const string& name) -> unsigned { + static auto gid(const string& name) -> uint { struct stat data{0}; stat(name, &data); return data.st_gid; } - static auto mode(const string& name) -> unsigned { + static auto mode(const string& name) -> uint { struct stat data{0}; stat(name, &data); return data.st_mode; @@ -55,7 +55,7 @@ struct inode { } //returns true if 'name' already exists - static auto create(const string& name, unsigned permissions = 0755) -> bool { + static auto create(const string& name, uint permissions = 0755) -> bool { if(exists(name)) return true; if(name.endsWith("/")) return mkdir(name, permissions) == 0; int fd = open(name, O_CREAT | O_EXCL, permissions); diff --git a/interpolation.hpp b/interpolation.hpp index 587a9b2..007f2ec 100644 --- a/interpolation.hpp +++ b/interpolation.hpp @@ -19,7 +19,7 @@ struct Interpolation { } static inline auto Cosine(double mu, double a, double b, double c, double d) -> double { - mu = (1.0 - cos(mu * 3.14159265)) / 2.0; + mu = (1.0 - cos(mu * Math::Pi)) / 2.0; return b * (1.0 - mu) + c * mu; } diff --git a/intrinsics.hpp b/intrinsics.hpp index 8f5ad9c..e5dcaf6 100644 --- a/intrinsics.hpp +++ b/intrinsics.hpp @@ -1,13 +1,15 @@ #pragma once namespace nall { + using uint = unsigned; + struct Intrinsics { - enum class Compiler : unsigned { Clang, GCC, VisualCPP, Unknown }; - enum class Platform : unsigned { Windows, MacOSX, Linux, BSD, Unknown }; - enum class API : unsigned { Windows, Posix, Unknown }; - enum class Display : unsigned { Windows, Quartz, Xorg, Unknown }; - enum class Processor : unsigned { x86, amd64, ARM, PPC32, PPC64, Unknown }; - enum class Endian : unsigned { LSB, MSB, Unknown }; + enum class Compiler : uint { Clang, GCC, VisualCPP, Unknown }; + enum class Platform : uint { Windows, MacOSX, Linux, BSD, Unknown }; + enum class API : uint { Windows, Posix, Unknown }; + enum class Display : uint { Windows, Quartz, Xorg, Unknown }; + enum class Processor : uint { x86, amd64, ARM, PPC32, PPC64, Unknown }; + enum class Endian : uint { LSB, MSB, Unknown }; static inline auto compiler() -> Compiler; static inline auto platform() -> Platform; diff --git a/main.hpp b/main.hpp index 925e8f4..eecc005 100644 --- a/main.hpp +++ b/main.hpp @@ -11,6 +11,9 @@ namespace nall { CoInitialize(0); WSAData wsaData{0}; WSAStartup(MAKEWORD(2, 2), &wsaData); + _setmode(_fileno(stdin), O_BINARY); + _setmode(_fileno(stdout), O_BINARY); + _setmode(_fileno(stderr), O_BINARY); utf8_args(argc, argv); #endif diff --git a/matrix.hpp b/matrix.hpp index fd79686..76a4da0 100644 --- a/matrix.hpp +++ b/matrix.hpp @@ -4,13 +4,13 @@ namespace nall { namespace Matrix { -template inline auto Multiply(T* output, const T* xdata, unsigned xrows, unsigned xcols, const T* ydata, unsigned yrows, unsigned ycols) -> void { +template inline auto Multiply(T* output, const T* xdata, uint xrows, uint xcols, const T* ydata, uint yrows, uint ycols) -> void { if(xcols != yrows) return; - for(unsigned y = 0; y < xrows; y++) { - for(unsigned x = 0; x < ycols; x++) { + for(uint y : range(xrows)) { + for(uint x : range(ycols)) { T sum = 0; - for(unsigned z = 0; z < xcols; z++) { + for(uint z : range(xcols)) { sum += xdata[y * xcols + z] * ydata[z * ycols + x]; } *output++ = sum; @@ -18,7 +18,7 @@ template inline auto Multiply(T* output, const T* xdata, unsigned xr } } -template inline auto Multiply(const T* xdata, unsigned xrows, unsigned xcols, const T* ydata, unsigned yrows, unsigned ycols) -> vector { +template inline auto Multiply(const T* xdata, uint xrows, uint xcols, const T* ydata, uint yrows, uint ycols) -> vector { vector output; output.resize(xrows * ycols); Multiply(output.data(), xdata, xrows, xcols, ydata, yrows, ycols); diff --git a/maybe.hpp b/maybe.hpp index 6ebd2ab..3444e08 100644 --- a/maybe.hpp +++ b/maybe.hpp @@ -30,7 +30,6 @@ struct maybe { if(this == &source) return *this; reset(); if(_valid = source._valid) new(&_value.t) T(move(source.get())); - source._valid = false; return *this; } diff --git a/memory.hpp b/memory.hpp index 7331dd2..d56101f 100644 --- a/memory.hpp +++ b/memory.hpp @@ -1,3 +1,133 @@ #pragma once -#include +#include +#include + +namespace nall { namespace memory { + inline auto allocate(uint size) -> void*; + inline auto allocate(uint size, uint8_t data) -> void*; + + inline auto resize(void* target, uint size) -> void*; + + inline auto free(void* target) -> void; + + inline auto compare(const void* target, uint capacity, const void* source, uint size) -> int; + inline auto compare(const void* target, const void* source, uint size) -> int; + + inline auto icompare(const void* target, uint capacity, const void* source, uint size) -> int; + inline auto icompare(const void* target, const void* source, uint size) -> int; + + inline auto copy(void* target, uint capacity, const void* source, uint size) -> void*; + inline auto copy(void* target, const void* source, uint size) -> void*; + + inline auto move(void* target, uint capacity, const void* source, uint size) -> void*; + inline auto move(void* target, const void* source, uint size) -> void*; + + inline auto fill(void* target, uint capacity, uint8_t data = 0x00) -> void*; + + template inline auto assign(T* target) -> void {} + template inline auto assign(T* target, const U& value, P&&... p) -> void; +}} + +namespace nall { + +//implementation notes: +//memcmp, memcpy, memmove have terrible performance on small block sizes (FreeBSD 10.0-amd64) +//as this library is used extensively by nall/string, and most strings tend to be small, +//this library hand-codes these functions instead. surprisingly, it's a substantial speedup + +auto memory::allocate(uint size) -> void* { + return malloc(size); +} + +auto memory::allocate(uint size, uint8_t data) -> void* { + auto result = malloc(size); + if(result) fill(result, size, data); + return result; +} + +auto memory::resize(void* target, uint size) -> void* { + return realloc(target, size); +} + +auto memory::free(void* target) -> void { + ::free(target); +} + +auto memory::compare(const void* target, uint capacity, const void* source, uint size) -> int { + auto t = (int8_t*)target; + auto s = (int8_t*)source; + auto l = min(capacity, size); + while(l--) { + auto x = *t++; + auto y = *s++; + if(x != y) return x - y; + } + return 0; +} + +auto memory::compare(const void* target, const void* source, uint size) -> int { + return compare(target, size, source, size); +} + +auto memory::icompare(const void* target, uint capacity, const void* source, uint size) -> int { + auto t = (int8_t*)target; + auto s = (int8_t*)source; + auto l = min(capacity, size); + while(l--) { + auto x = *t++; + auto y = *s++; + if(x - 'A' < 26) x += 32; + if(y - 'A' < 26) y += 32; + if(x != y) return x - y; + } + return 0; +} + +auto memory::icompare(const void* target, const void* source, uint size) -> int { + return icompare(target, size, source, size); +} + +auto memory::copy(void* target, uint capacity, const void* source, uint size) -> void* { + auto t = (uint8_t*)target; + auto s = (uint8_t*)source; + auto l = min(capacity, size); + while(l--) *t++ = *s++; + return target; +} + +auto memory::copy(void* target, const void* source, uint size) -> void* { + return copy(target, size, source, size); +} + +auto memory::move(void* target, uint capacity, const void* source, uint size) -> void* { + auto t = (uint8_t*)target; + auto s = (uint8_t*)source; + auto l = min(capacity, size); + if(t < s) { + while(l--) *t++ = *s++; + } else { + t += l; + s += l; + while(l--) *--t = *--s; + } + return target; +} + +auto memory::move(void* target, const void* source, uint size) -> void* { + return move(target, size, source, size); +} + +auto memory::fill(void* target, uint capacity, uint8_t data) -> void* { + auto t = (uint8_t*)target; + while(capacity--) *t++ = data; + return target; +} + +template +auto memory::assign(T* target, const U& value, P&&... p) -> void { + *target++ = value; + assign(target, forward

(p)...); +} + +} diff --git a/memory/memory.hpp b/memory/memory.hpp deleted file mode 100644 index f73297d..0000000 --- a/memory/memory.hpp +++ /dev/null @@ -1,129 +0,0 @@ -#pragma once - -#include - -namespace nall { - -namespace memory { - inline auto allocate(unsigned size) -> void*; - inline auto allocate(unsigned size, uint8_t data) -> void*; - - inline auto resize(void* target, unsigned size) -> void*; - - inline auto free(void* target) -> void; - - inline auto compare(const void* target, unsigned capacity, const void* source, unsigned size) -> signed; - inline auto compare(const void* target, const void* source, unsigned size) -> signed; - - inline auto icompare(const void* target, unsigned capacity, const void* source, unsigned size) -> signed; - inline auto icompare(const void* target, const void* source, unsigned size) -> signed; - - inline auto copy(void* target, unsigned capacity, const void* source, unsigned size) -> void*; - inline auto copy(void* target, const void* source, unsigned size) -> void*; - - inline auto move(void* target, unsigned capacity, const void* source, unsigned size) -> void*; - inline auto move(void* target, const void* source, unsigned size) -> void*; - - inline auto fill(void* target, unsigned capacity, uint8_t data = 0x00) -> void*; -} - -} - -#include - -namespace nall { - -//implementation notes: -//memcmp, memcpy, memmove have terrible performance on small block sizes (FreeBSD 10.0-amd64) -//as this library is used extensively by nall/string, and most strings tend to be small, -//this library hand-codes these functions instead. surprisingly, it's a substantial speedup - -auto memory::allocate(unsigned size) -> void* { - return malloc(size); -} - -auto memory::allocate(unsigned size, uint8_t data) -> void* { - auto result = malloc(size); - if(result) fill(result, size, data); - return result; -} - -auto memory::resize(void* target, unsigned size) -> void* { - return realloc(target, size); -} - -auto memory::free(void* target) -> void { - ::free(target); -} - -auto memory::compare(const void* target, unsigned capacity, const void* source, unsigned size) -> signed { - auto t = (int8_t*)target; - auto s = (int8_t*)source; - auto l = min(capacity, size); - while(l--) { - auto x = *t++; - auto y = *s++; - if(x != y) return x - y; - } - return 0; -} - -auto memory::compare(const void* target, const void* source, unsigned size) -> signed { - return compare(target, size, source, size); -} - -auto memory::icompare(const void* target, unsigned capacity, const void* source, unsigned size) -> signed { - auto t = (int8_t*)target; - auto s = (int8_t*)source; - auto l = min(capacity, size); - while(l--) { - auto x = *t++; - auto y = *s++; - if(x - 'A' < 26) x += 32; - if(y - 'A' < 26) y += 32; - if(x != y) return x - y; - } - return 0; -} - -auto memory::icompare(const void* target, const void* source, unsigned size) -> signed { - return icompare(target, size, source, size); -} - -auto memory::copy(void* target, unsigned capacity, const void* source, unsigned size) -> void* { - auto t = (uint8_t*)target; - auto s = (uint8_t*)source; - auto l = min(capacity, size); - while(l--) *t++ = *s++; - return target; -} - -auto memory::copy(void* target, const void* source, unsigned size) -> void* { - return copy(target, size, source, size); -} - -auto memory::move(void* target, unsigned capacity, const void* source, unsigned size) -> void* { - auto t = (uint8_t*)target; - auto s = (uint8_t*)source; - auto l = min(capacity, size); - if(t < s) { - while(l--) *t++ = *s++; - } else { - t += l; - s += l; - while(l--) *--t = *--s; - } - return target; -} - -auto memory::move(void* target, const void* source, unsigned size) -> void* { - return move(target, size, source, size); -} - -auto memory::fill(void* target, unsigned capacity, uint8_t data) -> void* { - auto t = (uint8_t*)target; - while(capacity--) *t++ = data; - return target; -} - -} diff --git a/memory/pool.hpp b/memory/pool.hpp deleted file mode 100644 index 17d11f7..0000000 --- a/memory/pool.hpp +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -namespace nall { -namespace memory { - -template -struct pool_spsc { - signed* list = nullptr; - uint8_t* data = nullptr; - unsigned slot = 0; - - pool_spsc() { - list = (signed*)memory::allocate(Capacity * sizeof(signed)); - data = (uint8_t*)memory::allocate(Capacity * Size); - for(unsigned n = 0; n < Capacity; n++) list[n] = n; - } - - ~pool_spsc() { - memory::free(list); - memory::free(data); - } - - auto allocate(unsigned size) -> void* { - if(size == 0) return nullptr; - if(size > Size) return memory::allocate(size); - signed offset = list[slot]; - if(offset < 0) return memory::allocate(size); - list[slot] = -1; - slot = (slot + 1) % Capacity; - return (void*)(data + offset * Size); - } - - auto allocate(unsigned size, uint8_t data) -> void* { - auto result = allocate(size); - memset(result, data, size); - return result; - } - - auto resize(void* target, unsigned size) -> void* { - if(target == nullptr) return allocate(size); - signed offset = ((uint8_t*)target - data) / Size; - if(offset < 0 || offset >= Capacity) return memory::resize(target, size); - if(size <= Size) return target; - slot = (slot - 1) % Capacity; - list[slot] = offset; - return memory::allocate(size); - } - - auto free(void* target) -> void { - if(target == nullptr) return; - signed offset = ((uint8_t*)target - data) / Size; - if(offset < 0 || offset >= Capacity) return memory::free(target); - slot = (slot - 1) % Capacity; - list[slot] = offset; - } - - pool_spsc(const pool_spsc&) = delete; - pool_spsc& operator=(const pool_spsc&) = delete; -}; - -} -} diff --git a/mosaic/context.hpp b/mosaic/context.hpp index 32950db..256d926 100644 --- a/mosaic/context.hpp +++ b/mosaic/context.hpp @@ -69,7 +69,7 @@ struct context { for(auto& item : list) { item.strip(); if(item.match("f(?*) ?*")) { - item.ltrim("f(", 1L); + item.trimLeft("f(", 1L); lstring part = item.split(") ", 1L); lstring args = part[0].split(";", 3L).strip(); @@ -90,9 +90,9 @@ struct context { } } else if(item.match("base64*")) { uint offset = 0; - item.ltrim("base64", 1L); + item.trimLeft("base64", 1L); if(item.match("(?*) *")) { - item.ltrim("(", 1L); + item.trimLeft("(", 1L); lstring part = item.split(") ", 1L); offset = eval(part[0]); item = part(1, ""); @@ -106,10 +106,10 @@ struct context { if(c == '_') buffer.append(offset + 63); } } else if(item.match("file *")) { - item.ltrim("file ", 1L); + item.trimLeft("file ", 1L); item.strip(); //... - } else if(item.empty() == false) { + } else if(item) { buffer.append(eval(item)); } } diff --git a/nall.hpp b/nall.hpp index fe5ea45..24389e0 100644 --- a/nall.hpp +++ b/nall.hpp @@ -17,7 +17,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -35,8 +36,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -45,7 +48,6 @@ #include #include #include -#include #include #include #include @@ -64,6 +66,7 @@ #include #include #include +#include #include #if defined(PLATFORM_WINDOWS) diff --git a/string/platform.hpp b/path.hpp similarity index 73% rename from string/platform.hpp rename to path.hpp index 86e38e0..945a144 100644 --- a/string/platform.hpp +++ b/path.hpp @@ -1,44 +1,46 @@ #pragma once -namespace nall { +#include -auto activepath() -> string { +namespace nall { namespace Path { + +inline auto active() -> string { char path[PATH_MAX] = ""; auto unused = getcwd(path, PATH_MAX); string result = path; if(!result) result = "."; result.transform("\\", "/"); - if(result.endsWith("/") == false) result.append("/"); + if(!result.endsWith("/")) result.append("/"); return result; } -auto realpath(rstring name) -> string { +inline auto real(string_view name) -> string { string result; char path[PATH_MAX] = ""; if(::realpath(name, path)) result = pathname(string{path}.transform("\\", "/")); - if(!result) return activepath(); + if(!result) return active(); result.transform("\\", "/"); - if(result.endsWith("/") == false) result.append("/"); + if(!result.endsWith("/")) result.append("/"); return result; } -auto programpath() -> string { +inline auto program() -> string { #if defined(PLATFORM_WINDOWS) wchar_t path[PATH_MAX] = L""; GetModuleFileName(nullptr, path, PATH_MAX); string result = (const char*)utf8_t(path); result.transform("\\", "/"); - return realpath(result); + return Path::real(result); #else Dl_info info; - dladdr((void*)&programpath, &info); - return realpath(info.dli_fname); + dladdr((void*)&program, &info); + return Path::real(info.dli_fname); #endif } // / // c:/ -auto rootpath() -> string { +inline auto root() -> string { #if defined(PLATFORM_WINDOWS) wchar_t path[PATH_MAX] = L""; SHGetFolderPathW(nullptr, CSIDL_WINDOWS | CSIDL_FLAG_CREATE, nullptr, 0, path); @@ -52,7 +54,7 @@ auto rootpath() -> string { // /home/username/ // c:/users/username/ -auto userpath() -> string { +inline auto user() -> string { #if defined(PLATFORM_WINDOWS) wchar_t path[PATH_MAX] = L""; SHGetFolderPathW(nullptr, CSIDL_PROFILE | CSIDL_FLAG_CREATE, nullptr, 0, path); @@ -63,50 +65,50 @@ auto userpath() -> string { string result = userinfo->pw_dir; #endif if(!result) result = "."; - if(result.endsWith("/") == false) result.append("/"); + if(!result.endsWith("/")) result.append("/"); return result; } // /home/username/.config/ // c:/users/username/appdata/roaming/ -auto configpath() -> string { +inline auto config() -> string { #if defined(PLATFORM_WINDOWS) wchar_t path[PATH_MAX] = L""; SHGetFolderPathW(nullptr, CSIDL_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path); string result = (const char*)utf8_t(path); result.transform("\\", "/"); #elif defined(PLATFORM_MACOSX) - string result = {userpath(), "Library/Application Support/"}; + string result = {Path::user(), "Library/Application Support/"}; #else - string result = {userpath(), ".config/"}; + string result = {Path::user(), ".config/"}; #endif if(!result) result = "."; - if(result.endsWith("/") == false) result.append("/"); + if(!result.endsWith("/")) result.append("/"); return result; } // /home/username/.local/share/ // c:/users/username/appdata/local/ -auto localpath() -> string { +inline auto local() -> string { #if defined(PLATFORM_WINDOWS) wchar_t path[PATH_MAX] = L""; SHGetFolderPathW(nullptr, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path); string result = (const char*)utf8_t(path); result.transform("\\", "/"); #elif defined(PLATFORM_MACOSX) - string result = {userpath(), "Library/Application Support/"}; + string result = {Path::user(), "Library/Application Support/"}; #else - string result = {userpath(), ".local/share/"}; + string result = {Path::user(), ".local/share/"}; #endif if(!result) result = "."; - if(result.endsWith("/") == false) result.append("/"); + if(!result.endsWith("/")) result.append("/"); return result; } // /usr/share // /Library/Application Support/ // c:/ProgramData/ -auto sharedpath() -> string { +inline auto shared() -> string { #if defined(PLATFORM_WINDOWS) wchar_t path[PATH_MAX] = L""; SHGetFolderPathW(nullptr, CSIDL_COMMON_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path); @@ -118,13 +120,13 @@ auto sharedpath() -> string { string result = "/usr/share/"; #endif if(!result) result = "."; - if(result.endsWith("/") == false) result.append("/"); + if(!result.endsWith("/")) result.append("/"); return result; } // /tmp // c:/users/username/AppData/Local/Temp/ -auto temppath() -> string { +inline auto temp() -> string { #if defined(PLATFORM_WINDOWS) wchar_t path[PATH_MAX] = L""; GetTempPathW(PATH_MAX, path); @@ -135,8 +137,8 @@ auto temppath() -> string { #else string result = "/tmp/"; #endif - if(result.endsWith("/") == false) result.append("/"); + if(!result.endsWith("/")) result.append("/"); return result; } -} +}} diff --git a/posix/shared-memory.hpp b/posix/shared-memory.hpp index c5e2756..af66563 100644 --- a/posix/shared-memory.hpp +++ b/posix/shared-memory.hpp @@ -18,10 +18,6 @@ struct shared_memory { return _mode != mode::inactive; } - auto empty() const -> bool { - return _mode == mode::inactive; - } - auto size() const -> unsigned { return _size; } diff --git a/primitives.hpp b/primitives.hpp index f551aa5..5c08e44 100644 --- a/primitives.hpp +++ b/primitives.hpp @@ -29,27 +29,27 @@ template struct Natural { enum : type { Mask = ~0ull >> (64 - Bits) }; inline Natural() : data(0) {} - template inline Natural(const T& value) { assign(value); } + template inline Natural(const T& value) { set(value); } inline operator type() const { return data; } - template inline auto& operator=(const T& value) { assign(value); return *this; } + template inline auto& operator=(const T& value) { set(value); return *this; } - inline auto operator++(int) { type value = data; assign(data + 1); return value; } - inline auto operator--(int) { type value = data; assign(data - 1); return value; } + inline auto operator++(int) { type value = data; set(data + 1); return value; } + inline auto operator--(int) { type value = data; set(data - 1); return value; } - inline auto& operator++() { assign(data + 1); return *this; } - inline auto& operator--() { assign(data - 1); return *this; } + inline auto& operator++() { set(data + 1); return *this; } + inline auto& operator--() { set(data - 1); return *this; } - inline auto& operator &=(const type value) { assign(data & value); return *this; } - inline auto& operator |=(const type value) { assign(data | value); return *this; } - inline auto& operator ^=(const type value) { assign(data ^ value); return *this; } - inline auto& operator<<=(const type value) { assign(data << value); return *this; } - inline auto& operator>>=(const type value) { assign(data >> value); return *this; } - inline auto& operator +=(const type value) { assign(data + value); return *this; } - inline auto& operator -=(const type value) { assign(data - value); return *this; } - inline auto& operator *=(const type value) { assign(data * value); return *this; } - inline auto& operator /=(const type value) { assign(data / value); return *this; } - inline auto& operator %=(const type value) { assign(data % value); return *this; } + inline auto& operator &=(const type value) { set(data & value); return *this; } + inline auto& operator |=(const type value) { set(data | value); return *this; } + inline auto& operator ^=(const type value) { set(data ^ value); return *this; } + inline auto& operator<<=(const type value) { set(data << value); return *this; } + inline auto& operator>>=(const type value) { set(data >> value); return *this; } + inline auto& operator +=(const type value) { set(data + value); return *this; } + inline auto& operator -=(const type value) { set(data - value); return *this; } + inline auto& operator *=(const type value) { set(data * value); return *this; } + inline auto& operator /=(const type value) { set(data / value); return *this; } + inline auto& operator %=(const type value) { set(data % value); return *this; } inline auto serialize(serializer& s) { s(data); } @@ -92,7 +92,7 @@ template struct Natural { } private: - auto assign(type value) -> void { + auto set(type value) -> void { data = value & Mask; } @@ -111,27 +111,27 @@ template struct Integer { enum : utype { Mask = ~0ull >> (64 - Bits), Sign = 1ull << (Bits - 1) }; inline Integer() : data(0) {} - template inline Integer(const T& value) { assign(value); } + template inline Integer(const T& value) { set(value); } inline operator type() const { return data; } - template inline auto& operator=(const T& value) { assign(value); return *this; } + template inline auto& operator=(const T& value) { set(value); return *this; } - inline auto operator++(int) { type value = data; assign(data + 1); return value; } - inline auto operator--(int) { type value = data; assign(data - 1); return value; } + inline auto operator++(int) { type value = data; set(data + 1); return value; } + inline auto operator--(int) { type value = data; set(data - 1); return value; } - inline auto& operator++() { assign(data + 1); return *this; } - inline auto& operator--() { assign(data - 1); return *this; } + inline auto& operator++() { set(data + 1); return *this; } + inline auto& operator--() { set(data - 1); return *this; } - inline auto& operator &=(const type value) { assign(data & value); return *this; } - inline auto& operator |=(const type value) { assign(data | value); return *this; } - inline auto& operator ^=(const type value) { assign(data ^ value); return *this; } - inline auto& operator<<=(const type value) { assign(data << value); return *this; } - inline auto& operator>>=(const type value) { assign(data >> value); return *this; } - inline auto& operator +=(const type value) { assign(data + value); return *this; } - inline auto& operator -=(const type value) { assign(data - value); return *this; } - inline auto& operator *=(const type value) { assign(data * value); return *this; } - inline auto& operator /=(const type value) { assign(data / value); return *this; } - inline auto& operator %=(const type value) { assign(data % value); return *this; } + inline auto& operator &=(const type value) { set(data & value); return *this; } + inline auto& operator |=(const type value) { set(data | value); return *this; } + inline auto& operator ^=(const type value) { set(data ^ value); return *this; } + inline auto& operator<<=(const type value) { set(data << value); return *this; } + inline auto& operator>>=(const type value) { set(data >> value); return *this; } + inline auto& operator +=(const type value) { set(data + value); return *this; } + inline auto& operator -=(const type value) { set(data - value); return *this; } + inline auto& operator *=(const type value) { set(data * value); return *this; } + inline auto& operator /=(const type value) { set(data / value); return *this; } + inline auto& operator %=(const type value) { set(data % value); return *this; } inline auto serialize(serializer& s) { s(data); } @@ -174,7 +174,7 @@ template struct Integer { } private: - auto assign(type value) -> void { + auto set(type value) -> void { data = ((value & Mask) ^ Sign) - Sign; } @@ -208,12 +208,16 @@ template struct Real { inline auto serialize(serializer& s) { s(data); } +private: type data; }; } using boolean = nall::Boolean; +//note: these conflict with nall/atoi.hpp functions +//using integer = nall::Integer; +//using natural = nall::Natural; using int1 = nall::Integer< 1>; using int2 = nall::Integer< 2>; diff --git a/priority-queue.hpp b/priority-queue.hpp deleted file mode 100644 index 49b5fa9..0000000 --- a/priority-queue.hpp +++ /dev/null @@ -1,106 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace nall { - -template auto priority_queue_nocallback(type_t) -> void {} - -//priority queue implementation using binary min-heap array; -//does not require normalize() function. -//O(1) find (tick) -//O(log n) append (enqueue) -//O(log n) remove (dequeue) -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(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. - auto enqueue(unsigned counter, type_t event) -> void { - unsigned child = heapsize++; - counter += basecounter; - - while(child) { - unsigned parent = (child - 1) >> 1; - if(gte(counter, heap[parent].counter)) break; - - heap[child].counter = heap[parent].counter; - heap[child].event = heap[parent].event; - child = parent; - } - - heap[child].counter = counter; - heap[child].event = event; - } - - auto dequeue() -> type_t { - type_t event(heap[0].event); - unsigned parent = 0; - unsigned counter = heap[--heapsize].counter; - - while(true) { - unsigned child = (parent << 1) + 1; - if(child >= heapsize) break; - if(child + 1 < heapsize && gte(heap[child].counter, heap[child + 1].counter)) child++; - if(gte(heap[child].counter, counter)) break; - - heap[parent].counter = heap[child].counter; - heap[parent].event = heap[child].event; - parent = child; - } - - heap[parent].counter = counter; - heap[parent].event = heap[heapsize].event; - return event; - } - - auto reset() -> void { - basecounter = 0; - heapsize = 0; - } - - auto serialize(serializer& s) -> void { - s.integer(basecounter); - s.integer(heapsize); - for(unsigned n = 0; n < heapcapacity; n++) { - s.integer(heap[n].counter); - s.integer(heap[n].event); - } - } - -private: - function callback; - unsigned basecounter; - unsigned heapsize; - unsigned heapcapacity; - struct heap_t { - unsigned counter; - type_t event; - } *heap; - - //return true if x is greater than or equal to y - inline auto gte(unsigned x, unsigned y) -> bool { - return x - y < (std::numeric_limits::max() >> 1); - } -}; - -} diff --git a/property.hpp b/property.hpp index e6c076b..5f6dbe4 100644 --- a/property.hpp +++ b/property.hpp @@ -2,40 +2,66 @@ namespace nall { -template struct property { - template struct readonly { - auto operator->() const -> const T* { return &value; } - auto operator()() const -> const T& { return value; } - operator const T&() const { return value; } - private: - auto operator->() -> T* { return &value; } - operator T&() { return value; } - auto operator=(const T& value_) -> const T& { return value = value_; } - T value; - friend C; - }; +template struct property { + property() = default; + property(const T& value) : value(value) {} - template struct writeonly { - auto operator=(const T& value_) -> void { value = value_; } - private: - auto operator->() const -> const T* { return &value; } - auto operator()() const -> const T& { return value; } - operator const T&() const { return value; } - auto operator->() -> T* { return &value; } - operator T&() { return value; } - T value; - friend C; - }; + operator T&() { return value; } //direct assignment + auto operator->() -> T* { return &value; } //class-member access - template struct readwrite { - auto operator->() const -> const T* { return &value; } - auto operator()() const -> const T& { return value; } - operator const T&() const { return value; } - auto operator->() -> T* { return &value; } - operator T&() { return value; } - auto operator=(const T& value_) -> const T& { return value = value_; } - T value; - }; + operator const T&() const { return value; } + auto operator()() const -> const T& { return value; } + auto get() const -> const T& { return value; } + + auto operator=(const T& value) -> T& { return this->value = value; } + auto set(const T& value) -> T& { return this->value = value; } + + T value; +}; + +template struct functional_property { + functional_property( + const function& getter = {}, + const function& setter = {}, + const T& value = {} + ) { + getter ? this->getter = getter : this->getter = [](const T& self) -> R { return self; }; + setter ? this->setter = setter : this->setter = [](T& self, const T& value) -> R { return self = value; }; + this->setter(this->value, value); + } + + operator R() const { return getter(value); } + auto operator()() const -> R { return getter(value); } + auto get() const -> R { return getter(value); } + + auto operator=(const T& value) -> R { return setter(this->value, value); } + auto set(const T& value) -> R { return setter(this->value, value); } + + T value; + function getter; + function setter; +}; + +template struct virtual_property { + virtual_property( + const function& getter = {}, + const function& setter = {}, + const T& value = {} + ) { + this->getter = getter; + this->setter = setter; + if(this->setter) this->setter(value); + } + + operator R() const { return getter(); } + auto operator()() const -> R { return getter(); } + auto get() const -> R { return getter(); } + + auto operator=(const T& value) -> R { return setter(value); } + auto set(const T& value) -> R { return setter(value); } + + function getter; + function setter; }; } diff --git a/queue.hpp b/queue.hpp new file mode 100644 index 0000000..244aec3 --- /dev/null +++ b/queue.hpp @@ -0,0 +1,101 @@ +#pragma once + +//simple circular ring buffer + +namespace nall { + +template +struct queue { + queue() = default; + + queue(const queue& source) { + operator=(source); + } + + queue(queue&& source) { + operator=(move(source)); + } + + auto operator=(const queue& source) -> queue& { + if(this == &source) return *this; + reset(); + _size = source._size; + _data = new T[_size]; + for(auto n : range(_size)) _data[n] = source._data[n]; + _read = source._read; + _write = source._write; + return *this; + } + + auto operator=(queue&& source) -> queue& { + if(this == &source) return *this; + _data = source._data; + _size = source._size; + _read = source._read; + _write = source._write; + source._data = nullptr; + source.reset(); + } + + ~queue() { + reset(); + } + + explicit operator bool() const { + return _size; + } + + auto size() const -> uint { + return _size; + } + + auto data() -> T* { + return _data; + } + + auto data() const -> const T* { + return _data; + } + + auto reset() { + delete[] _data; + _data = nullptr; + _size = 0; + _read = 0; + _write = 0; + } + + auto resize(uint size, const T& value = {}) -> void { + reset(); + _size = size; + _data = new T[_size]; + for(auto n : range(_size)) _data[n] = value; + } + + auto pending() const -> bool { + return _read != _write; + } + + auto read() -> T { + T result = _data[_read]; + if(++_read >= _size) _read = 0; + return result; + } + + auto last() const -> T { + return _data[_write]; + } + + auto write(const T& value) -> void { + _data[_write] = value; + if(++_write >= _size) _write = 0; + } + +private: + T* _data = nullptr; + uint _size = 0; + uint _read = 0; + uint _write = 0; +}; + +} diff --git a/random.hpp b/random.hpp index 4187eab..3f9d20b 100644 --- a/random.hpp +++ b/random.hpp @@ -15,11 +15,11 @@ struct RandomNumberGenerator { struct LinearFeedbackShiftRegisterGenerator : RandomNumberGenerator { auto seed(uint64_t seed) -> void { lfsr = seed; - for(unsigned n = 0; n < 8; n++) operator()(); + for(uint n = 0; n < 8; n++) operator()(); } auto operator()() -> uint64_t { - return lfsr = (lfsr >> 1) ^ (-(lfsr & 1) & crc64jones); + return lfsr = (lfsr >> 1) ^ (-(lfsr & 1) & crc64); } auto serialize(serializer& s) -> void { @@ -27,9 +27,8 @@ struct LinearFeedbackShiftRegisterGenerator : RandomNumberGenerator { } private: - static const uint64_t crc64ecma = 0x42f0e1eba9ea3693; - static const uint64_t crc64jones = 0xad93d23594c935a9; - uint64_t lfsr = crc64ecma; + static const uint64_t crc64 = 0xc96c'5795'd787'0f42; + uint64_t lfsr = crc64; }; inline auto random() -> uint64_t { diff --git a/range.hpp b/range.hpp index f29a838..a64fd3e 100644 --- a/range.hpp +++ b/range.hpp @@ -39,12 +39,4 @@ inline auto rrange(int size) { return range_t{size - 1, -1, -1}; } -template inline auto range(const vector& container) { - return range_t{0, (int)container.size(), 1}; -} - -template inline auto rrange(const vector& container) { - return range_t{(int)container.size() - 1, -1, -1}; -} - } diff --git a/run.hpp b/run.hpp index eb4955e..7fcc224 100644 --- a/run.hpp +++ b/run.hpp @@ -16,11 +16,21 @@ namespace nall { +struct execute_result_t { + explicit operator bool() const { return code == EXIT_SUCCESS; } + + int code = EXIT_FAILURE; + string output; + string error; +}; + #if defined(PLATFORM_MACOSX) || defined(PLATFORM_LINUX) || defined(PLATFORM_BSD) -template inline auto execute(const string& name, P&&... p) -> string { - int fd[2]; - if(pipe(fd) == -1) return ""; +template inline auto execute(const string& name, P&&... p) -> execute_result_t { + int fdout[2]; + int fderr[2]; + if(pipe(fdout) == -1) return {}; + if(pipe(fderr) == -1) return {}; pid_t pid = fork(); if(pid == 0) { @@ -31,28 +41,48 @@ template inline auto execute(const string& name, P&&... p) -> str for(auto& arg : argl) *argp++ = (const char*)arg; *argp++ = nullptr; - dup2(fd[1], STDOUT_FILENO); - dup2(fd[1], STDERR_FILENO); - close(fd[0]); - close(fd[1]); + dup2(fdout[1], STDOUT_FILENO); + dup2(fderr[1], STDERR_FILENO); + close(fdout[0]); + close(fderr[0]); + close(fdout[1]); + close(fderr[1]); execvp(name, (char* const*)argv); - exit(0); + //this is called only if execvp fails: + //use _exit instead of exit, to avoid destroying key shared file descriptors + _exit(EXIT_FAILURE); } else { - close(fd[1]); + close(fdout[1]); + close(fderr[1]); + + char buffer[256]; + execute_result_t result; - string result; while(true) { - char buffer[256]; - auto size = read(fd[0], buffer, sizeof(buffer)); + auto size = read(fdout[0], buffer, sizeof(buffer)); if(size <= 0) break; - auto offset = result.size(); - result.resize(offset + size); - memory::copy(result.get() + offset, buffer, size); + auto offset = result.output.size(); + result.output.resize(offset + size); + memory::copy(result.output.get() + offset, buffer, size); } - close(fd[0]); - wait(nullptr); + while(true) { + auto size = read(fderr[0], buffer, sizeof(buffer)); + if(size <= 0) break; + + auto offset = result.error.size(); + result.error.resize(offset + size); + memory::copy(result.error.get() + offset, buffer, size); + } + + close(fdout[0]); + close(fderr[0]); + + int status = 0; + waitpid(pid, &status, 0); + if(!WIFEXITED(status)) return {}; + result.code = WEXITSTATUS(status); return result; } } @@ -76,7 +106,7 @@ template inline auto invoke(const string& name, P&&... p) -> void #elif defined(PLATFORM_WINDOWS) -template inline auto execute(const string& name, P&&... p) -> string { +template inline auto execute(const string& name, P&&... p) -> execute_result_t { lstring argl(name, forward

(p)...); for(auto& arg : argl) if(arg.find(" ")) arg = {"\"", arg, "\""}; string arguments = argl.merge(" "); @@ -89,19 +119,24 @@ template inline auto execute(const string& name, P&&... p) -> str HANDLE stdoutRead; HANDLE stdoutWrite; - if(!CreatePipe(&stdoutRead, &stdoutWrite, &sa, 0)) return ""; - if(!SetHandleInformation(stdoutRead, HANDLE_FLAG_INHERIT, 0)) return ""; + if(!CreatePipe(&stdoutRead, &stdoutWrite, &sa, 0)) return {}; + if(!SetHandleInformation(stdoutRead, HANDLE_FLAG_INHERIT, 0)) return {}; + + HANDLE stderrRead; + HANDLE stderrWrite; + if(!CreatePipe(&stderrRead, &stderrWrite, &sa, 0)) return {}; + if(!SetHandleInformation(stderrRead, HANDLE_FLAG_INHERIT, 0)) return {}; HANDLE stdinRead; HANDLE stdinWrite; - if(!CreatePipe(&stdinRead, &stdinWrite, &sa, 0)) return ""; - if(!SetHandleInformation(stdinWrite, HANDLE_FLAG_INHERIT, 0)) return ""; + if(!CreatePipe(&stdinRead, &stdinWrite, &sa, 0)) return {}; + if(!SetHandleInformation(stdinWrite, HANDLE_FLAG_INHERIT, 0)) return {}; STARTUPINFO si; ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); - si.hStdError = stdoutWrite; si.hStdOutput = stdoutWrite; + si.hStdError = stderrWrite; si.hStdInput = stdinRead; si.dwFlags = STARTF_USESTDHANDLES; @@ -112,15 +147,19 @@ template inline auto execute(const string& name, P&&... p) -> str nullptr, utf16_t(arguments), nullptr, nullptr, true, CREATE_NO_WINDOW, nullptr, nullptr, &si, &pi - )) return ""; + )) return {}; - if(WaitForSingleObject(pi.hProcess, INFINITE)) return ""; + DWORD exitCode = EXIT_FAILURE; + if(WaitForSingleObject(pi.hProcess, INFINITE)) return {}; + if(!GetExitCodeProcess(pi.hProcess, &exitCode)) return {}; CloseHandle(pi.hThread); CloseHandle(pi.hProcess); - string result; + char buffer[256]; + execute_result_t result; + result.code = exitCode; + while(true) { - char buffer[256]; DWORD read, available, remaining; if(!PeekNamedPipe(stdoutRead, nullptr, sizeof(buffer), &read, &available, &remaining)) break; if(read == 0) break; @@ -128,9 +167,22 @@ template inline auto execute(const string& name, P&&... p) -> str if(!ReadFile(stdoutRead, buffer, sizeof(buffer), &read, nullptr)) break; if(read == 0) break; - auto offset = result.size(); - result.resize(offset + read); - memory::copy(result.get() + offset, buffer, read); + auto offset = result.output.size(); + result.output.resize(offset + read); + memory::copy(result.output.get() + offset, buffer, read); + } + + while(true) { + DWORD read, available, remaining; + if(!PeekNamedPipe(stderrRead, nullptr, sizeof(buffer), &read, &available, &remaining)) break; + if(read == 0) break; + + if(!ReadFile(stderrRead, buffer, sizeof(buffer), &read, nullptr)) break; + if(read == 0) break; + + auto offset = result.error.size(); + result.error.resize(offset + read); + memory::copy(result.error.get() + offset, buffer, read); } return result; diff --git a/serial.hpp b/serial.hpp index 4d580dc..671e8ff 100644 --- a/serial.hpp +++ b/serial.hpp @@ -16,17 +16,12 @@ namespace nall { struct serial { - serial() { - port = -1; - port_open = false; - } - ~serial() { close(); } auto readable() -> bool { - if(port_open == false) return false; + if(!opened) return false; fd_set fdset; FD_ZERO(&fdset); FD_SET(port, &fdset); @@ -40,12 +35,12 @@ struct serial { //-1 on error, otherwise return bytes read auto read(uint8_t* data, uint length) -> int { - if(port_open == false) return -1; + if(!opened) return -1; return ::read(port, (void*)data, length); } auto writable() -> bool { - if(port_open == false) return false; + if(!opened) return false; fd_set fdset; FD_ZERO(&fdset); FD_SET(port, &fdset); @@ -59,14 +54,17 @@ struct serial { //-1 on error, otherwise return bytes written auto write(const uint8_t* data, uint length) -> int { - if(port_open == false) return -1; + if(!opened) return -1; return ::write(port, (void*)data, length); } - auto open(const string& portname, uint rate, bool flowcontrol) -> bool { + //rate==0: use flow control (synchronous mode) + //rate!=0: baud-rate (asynchronous mode) + auto open(string device, uint rate = 0) -> bool { close(); - port = ::open(portname, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK); + if(!device) device = "/dev/ttyU0"; //note: default device name is for FreeBSD 10+ + port = ::open(device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK); if(port == -1) return false; if(ioctl(port, TIOCEXCL) == -1) { close(); return false; } @@ -75,7 +73,7 @@ struct serial { termios attr = original_attr; cfmakeraw(&attr); - cfsetspeed(&attr, rate); + cfsetspeed(&attr, rate ? rate : 57600); //rate value has no effect in synchronous mode attr.c_lflag &=~ (ECHO | ECHONL | ISIG | ICANON | IEXTEN); attr.c_iflag &=~ (BRKINT | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY); @@ -83,7 +81,7 @@ struct serial { attr.c_oflag &=~ (OPOST); attr.c_cflag &=~ (CSIZE | CSTOPB | PARENB | CLOCAL); attr.c_cflag |= (CS8 | CREAD); - if(flowcontrol == false) { + if(rate) { attr.c_cflag &= ~CRTSCTS; } else { attr.c_cflag |= CRTSCTS; @@ -91,15 +89,15 @@ struct serial { attr.c_cc[VTIME] = attr.c_cc[VMIN] = 0; if(tcsetattr(port, TCSANOW, &attr) == -1) { close(); return false; } - return port_open = true; + return opened = true; } auto close() -> void { if(port != -1) { tcdrain(port); - if(port_open == true) { + if(opened) { tcsetattr(port, TCSANOW, &original_attr); - port_open = false; + opened = false; } ::close(port); port = -1; @@ -107,8 +105,8 @@ struct serial { } private: - int port; - bool port_open; + int port = -1; + bool opened = false; termios original_attr; }; diff --git a/set.hpp b/set.hpp index 2c3a405..1376ede 100644 --- a/set.hpp +++ b/set.hpp @@ -26,7 +26,7 @@ template struct set { }; node_t* root = nullptr; - unsigned nodes = 0; + uint nodes = 0; set() = default; set(const set& source) { operator=(source); } @@ -49,8 +49,8 @@ template struct set { return *this; } - auto size() const -> unsigned { return nodes; } - auto empty() const -> bool { return nodes == 0; } + explicit operator bool() const { return nodes; } + auto size() const -> uint { return nodes; } auto reset() -> void { reset(root); @@ -68,7 +68,7 @@ template struct set { } auto insert(const T& value) -> maybe { - unsigned count = size(); + uint count = size(); node_t* v = insert(root, value); root->red = 0; if(size() == count) return nothing; @@ -82,7 +82,7 @@ template struct set { } auto remove(const T& value) -> bool { - unsigned count = size(); + uint count = size(); bool done = 0; remove(root, &value, done); if(root) root->red = 0; @@ -100,19 +100,19 @@ template struct set { auto operator++() -> base_iterator& { if(++position >= source.size()) { position = source.size(); return *this; } - if(stack.last()->link[1]) { - stack.append(stack.last()->link[1]); - while(stack.last()->link[0]) stack.append(stack.last()->link[0]); + if(stack.right()->link[1]) { + stack.append(stack.right()->link[1]); + while(stack.right()->link[0]) stack.append(stack.right()->link[0]); } else { node_t* child; - do child = stack.take(); - while(child == stack.last()->link[1]); + do child = stack.takeRight(); + while(child == stack.right()->link[1]); } return *this; } - base_iterator(const set& source, unsigned position) : source(source), position(position) { + base_iterator(const set& source, uint position) : source(source), position(position) { node_t* node = source.root; while(node) { stack.append(node); @@ -122,21 +122,21 @@ template struct set { protected: const set& source; - unsigned position; + uint position; vector stack; }; struct iterator : base_iterator { - iterator(const set& source, unsigned position) : base_iterator(source, position) {} - auto operator*() const -> T& { return base_iterator::stack.last()->value; } + iterator(const set& source, uint position) : base_iterator(source, position) {} + auto operator*() const -> T& { return base_iterator::stack.right()->value; } }; auto begin() -> iterator { return iterator(*this, 0); } auto end() -> iterator { return iterator(*this, size()); } struct const_iterator : base_iterator { - const_iterator(const set& source, unsigned position) : base_iterator(source, position) {} - auto operator*() const -> const T& { return base_iterator::stack.last()->value; } + const_iterator(const set& source, uint position) : base_iterator(source, position) {} + auto operator*() const -> const T& { return base_iterator::stack.right()->value; } }; auto begin() const -> const const_iterator { return const_iterator(*this, 0); } diff --git a/shared-pointer.hpp b/shared-pointer.hpp index af44bde..634d02a 100644 --- a/shared-pointer.hpp +++ b/shared-pointer.hpp @@ -170,11 +170,7 @@ struct shared_pointer { } explicit operator bool() const { - return !empty(); - } - - auto empty() const -> bool { - return !manager || !manager->strong; + return manager && manager->strong; } auto unique() const -> bool { @@ -242,11 +238,7 @@ struct shared_pointer_weak { } explicit operator bool() const { - return !empty(); - } - - auto empty() const -> bool { - return !manager || !manager->strong; + return manager && manager->strong; } auto acquire() const -> shared_pointer { diff --git a/smtp.hpp b/smtp.hpp index f1f60de..a738847 100644 --- a/smtp.hpp +++ b/smtp.hpp @@ -18,14 +18,14 @@ namespace nall { struct SMTP { - enum class Format : unsigned { Plain, HTML }; + enum class Format : uint { Plain, HTML }; 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(const uint8_t* data, uint 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; @@ -94,7 +94,7 @@ auto SMTP::bcc(string mail, string name) -> void { info.bcc.append({mail, name}); } -auto SMTP::attachment(const uint8_t* data, unsigned size, string name) -> void { +auto SMTP::attachment(const uint8_t* data, uint size, string name) -> void { vector buffer; buffer.resize(size); memcpy(buffer.data(), data, size); @@ -223,7 +223,7 @@ auto SMTP::response() -> string { auto SMTP::send(int sock, const string& text) -> bool { const char* data = text.data(); - unsigned size = text.size(); + uint size = text.size(); while(size) { int length = ::send(sock, (const char*)data, size, 0); if(length == -1) return false; @@ -249,7 +249,7 @@ auto SMTP::boundary() -> string { random_lfsr random; random.seed(time(0)); string boundary; - for(unsigned n = 0; n < 16; n++) boundary.append(hex<2>(random())); + for(uint n = 0; n < 16; n++) boundary.append(hex<2>(random())); return boundary; } @@ -272,16 +272,16 @@ auto SMTP::contacts(const vector& contacts) -> string { for(auto& contact : contacts) { result.append(this->contact(contact), "; "); } - result.rtrim("; ", 1L); + result.trimRight("; ", 1L); return result; } auto SMTP::split(const string& text) -> string { string result; - unsigned offset = 0; + uint offset = 0; while(offset < text.size()) { - unsigned length = min(76, text.size() - offset); + uint length = min(76, text.size() - offset); if(length < 76) { result.append(text.slice(offset)); } else { diff --git a/sort.hpp b/sort.hpp index 1f74aa9..63053cc 100644 --- a/sort.hpp +++ b/sort.hpp @@ -19,13 +19,13 @@ namespace nall { -template auto sort(T list[], unsigned size, const Comparator& lessthan) -> void { +template auto sort(T list[], uint size, const Comparator& lessthan) -> void { if(size <= 1) return; //nothing to sort //use insertion sort to quickly sort smaller blocks if(size < 64) { #if defined(NALL_SORT_INSERTION) - for(signed i = 1, j; i < size; i++) { + for(int i = 1, j; i < size; i++) { T copy = std::move(list[i]); for(j = i - 1; j >= 0; j--) { if(!lessthan(copy, list[j])) break; @@ -34,9 +34,9 @@ template auto sort(T list[], unsigned size, con list[j + 1] = std::move(copy); } #elif defined(NALL_SORT_SELECTION) - for(unsigned i = 0; i < size; i++) { - unsigned min = i; - for(unsigned j = i + 1; j < size; j++) { + for(uint i = 0; i < size; i++) { + uint min = i; + for(uint j = i + 1; j < size; j++) { if(lessthan(list[j], list[min])) min = j; } if(min != i) std::swap(list[i], list[min]); @@ -46,13 +46,13 @@ template auto sort(T list[], unsigned size, con } //split list in half and recursively sort both - unsigned middle = size / 2; + uint middle = size / 2; sort(list, middle, lessthan); sort(list + middle, size - middle, lessthan); //left and right are sorted here; perform merge sort T* buffer = new T[size]; - unsigned offset = 0, left = 0, right = middle; + uint offset = 0, left = 0, right = middle; while(left < middle && right < size) { if(!lessthan(list[right], list[left])) { buffer[offset++] = std::move(list[left++]); @@ -63,11 +63,11 @@ template auto sort(T list[], unsigned size, con while(left < middle) buffer[offset++] = std::move(list[left++]); while(right < size) buffer[offset++] = std::move(list[right++]); - for(unsigned i = 0; i < size; i++) list[i] = std::move(buffer[i]); + for(uint i = 0; i < size; i++) list[i] = std::move(buffer[i]); delete[] buffer; } -template auto sort(T list[], unsigned size) -> void { +template auto sort(T list[], uint size) -> void { return sort(list, size, [](const T& l, const T& r) { return l < r; }); } diff --git a/stream.hpp b/stream.hpp deleted file mode 100644 index 3ea0c2c..0000000 --- a/stream.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include diff --git a/stream/auto.hpp b/stream/auto.hpp deleted file mode 100644 index 0c5fc65..0000000 --- a/stream/auto.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -namespace nall { - -#define autostream(...) (*makestream(__VA_ARGS__)) - -inline auto makestream(const string& path) -> std::unique_ptr { - if(path.iendsWith(".gz")) return std::unique_ptr(new gzipstream(filestream{path})); - if(path.iendsWith(".zip")) return std::unique_ptr(new zipstream(filestream{path})); - return std::unique_ptr(new mmapstream(path)); -} - -inline auto makestream(uint8_t* data, uint size) -> std::unique_ptr { - return std::unique_ptr(new memorystream(data, size)); -} - -inline auto makestream(const uint8_t* data, uint size) -> std::unique_ptr { - return std::unique_ptr(new memorystream(data, size)); -} - -} diff --git a/stream/file.hpp b/stream/file.hpp deleted file mode 100644 index 1ce9984..0000000 --- a/stream/file.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include - -namespace nall { - -struct filestream : stream { - using stream::read; - using stream::write; - - filestream(const string& filename) { - pfile.open(filename, file::mode::readwrite); - pwritable = pfile.open(); - if(!pwritable) pfile.open(filename, file::mode::read); - } - - filestream(const string& filename, file::mode mode) { - pfile.open(filename, mode); - pwritable = mode == file::mode::write || mode == file::mode::readwrite; - } - - auto seekable() const -> bool { return true; } - auto readable() const -> bool { return true; } - auto writable() const -> bool { return pwritable; } - auto randomaccess() const -> bool { return false; } - - auto size() const -> uint { return pfile.size(); } - auto offset() const -> uint { return pfile.offset(); } - auto seek(uint offset) const -> void { pfile.seek(offset); } - - auto read() const -> uint8_t { return pfile.read(); } - auto write(uint8_t data) const -> void { pfile.write(data); } - -private: - mutable file pfile; - bool pwritable; -}; - -} diff --git a/stream/gzip.hpp b/stream/gzip.hpp deleted file mode 100644 index f4a4e0a..0000000 --- a/stream/gzip.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include - -namespace nall { - -struct gzipstream : memorystream { - using stream::read; - using stream::write; - - gzipstream(const stream& stream) { - uint size = stream.size(); - auto data = new uint8_t[size]; - stream.read(data, size); - - Decode::GZIP archive; - bool result = archive.decompress(data, size); - delete[] data; - if(!result) return; - - psize = archive.size; - pdata = new uint8_t[psize]; - memcpy(pdata, archive.data, psize); - } - - ~gzipstream() { - if(pdata) delete[] pdata; - } -}; - -} diff --git a/stream/memory.hpp b/stream/memory.hpp deleted file mode 100644 index 3f873d4..0000000 --- a/stream/memory.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include - -namespace nall { - -struct memorystream : stream { - using stream::read; - using stream::write; - - memorystream() = default; - - memorystream(uint8_t* data, uint size) { - pdata = data; - psize = size; - pwritable = true; - } - - memorystream(const uint8_t* data, uint size) { - pdata = (uint8_t*)data; - psize = size; - pwritable = false; - } - - auto seekable() const -> bool { return true; } - auto readable() const -> bool { return true; } - auto writable() const -> bool { return pwritable; } - auto randomaccess() const -> bool { return true; } - - auto data() const -> uint8_t* { return pdata; } - auto size() const -> uint { return psize; } - auto offset() const -> uint { return poffset; } - auto seek(uint offset) const -> void { poffset = offset; } - - auto read() const -> uint8_t { return pdata[poffset++]; } - auto write(uint8_t data) const -> void { pdata[poffset++] = data; } - - auto read(uint offset) const -> uint8_t { return pdata[offset]; } - auto write(uint offset, uint8_t data) const -> void { pdata[offset] = data; } - -protected: - mutable uint8_t* pdata = nullptr; - mutable uint psize = 0; - mutable uint poffset = 0; - mutable bool pwritable = false; -}; - -} diff --git a/stream/mmap.hpp b/stream/mmap.hpp deleted file mode 100644 index 8c116f1..0000000 --- a/stream/mmap.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include - -namespace nall { - -struct mmapstream : stream { - using stream::read; - using stream::write; - - mmapstream(const string& filename) { - pmmap.open(filename, filemap::mode::readwrite); - pwritable = pmmap.open(); - if(!pwritable) pmmap.open(filename, filemap::mode::read); - pdata = pmmap.data(); - poffset = 0; - } - - auto seekable() const -> bool { return true; } - auto readable() const -> bool { return true; } - auto writable() const -> bool { return pwritable; } - auto randomaccess() const -> bool { return true; } - - auto size() const -> uint { return pmmap.size(); } - auto offset() const -> uint { return poffset; } - auto seek(uint offset) const -> void { poffset = offset; } - - auto read() const -> uint8_t { return pdata[poffset++]; } - auto write(uint8_t data) const -> void { pdata[poffset++] = data; } - - auto read(uint offset) const -> uint8_t { return pdata[offset]; } - auto write(uint offset, uint8_t data) const -> void { pdata[offset] = data; } - -private: - mutable filemap pmmap; - mutable uint8_t* pdata = nullptr; - mutable uint poffset = 0; - mutable bool pwritable = false; -}; - -} diff --git a/stream/stream.hpp b/stream/stream.hpp deleted file mode 100644 index a9e1a64..0000000 --- a/stream/stream.hpp +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once - -namespace nall { - -struct stream { - stream() = default; - virtual ~stream() = default; - - stream(const stream&) = delete; - auto operator=(const stream&) -> stream& = delete; - - virtual auto seekable() const -> bool = 0; - virtual auto readable() const -> bool = 0; - virtual auto writable() const -> bool = 0; - virtual auto randomaccess() const -> bool = 0; - - virtual auto data() const -> uint8_t* { return nullptr; } - virtual auto size() const -> uint = 0; - virtual auto offset() const -> uint = 0; - virtual auto seek(uint offset) const -> void = 0; - - virtual auto read() const -> uint8_t = 0; - virtual auto write(uint8_t data) const -> void = 0; - - virtual auto read(uint) const -> uint8_t { return 0; } - virtual auto write(uint, uint8_t) const -> void {} - - explicit operator bool() const { - return size(); - } - - auto empty() const -> bool { - return size() == 0; - } - - auto end() const -> bool { - return offset() >= size(); - } - - auto readl(uint length = 1) const -> uintmax { - uintmax data = 0, shift = 0; - while(length--) { data |= read() << shift; shift += 8; } - return data; - } - - auto readm(uint length = 1) const -> uintmax { - uintmax data = 0; - while(length--) data = (data << 8) | read(); - return data; - } - - auto read(uint8_t* data, uint length) const -> void { - while(length--) *data++ = read(); - } - - auto text() const -> string { - string buffer; - buffer.resize(size()); - seek(0); - read((uint8_t*)buffer.get(), size()); - return buffer; - } - - auto writel(uintmax data, uint length = 1) const -> void { - while(length--) { - write(data); - data >>= 8; - } - } - - auto writem(uintmax data, uint length = 1) const -> void { - uintmax shift = 8 * length; - while(length--) { - shift -= 8; - write(data >> shift); - } - } - - auto write(const uint8_t* data, uint length) const -> void { - while(length--) write(*data++); - } - - struct byte { - byte(const stream& s, uint offset) : s(s), offset(offset) {} - operator uint8_t() const { return s.read(offset); } - auto operator=(uint8_t data) -> byte& { s.write(offset, data); return *this; } - - private: - const stream& s; - const uint offset; - }; - - auto operator[](uint offset) const -> byte { - return byte(*this, offset); - } -}; - -} diff --git a/stream/vector.hpp b/stream/vector.hpp deleted file mode 100644 index 5f6ddac..0000000 --- a/stream/vector.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include -#include - -namespace nall { - -struct vectorstream : stream { - using stream::read; - using stream::write; - - vectorstream(vector& memory) : memory(memory), pwritable(true) {} - vectorstream(const vector& memory) : memory((vector&)memory), pwritable(false) {} - - auto seekable() const -> bool { return true; } - auto readable() const -> bool { return true; } - auto writable() const -> bool { return pwritable; } - auto randomaccess() const -> bool { return true; } - - auto data() const -> uint8_t* { return memory.data(); } - auto size() const -> uint { return memory.size(); } - auto offset() const -> uint { return poffset; } - auto seek(uint offset) const -> void { poffset = offset; } - - auto read() const -> uint8_t { return memory[poffset++]; } - auto write(uint8_t data) const -> void { memory[poffset++] = data; } - - auto read(uint offset) const -> uint8_t { return memory[offset]; } - auto write(uint offset, uint8_t data) const -> void { memory[offset] = data; } - -protected: - vector& memory; - mutable uint poffset = 0; - mutable bool pwritable = false; -}; - -} diff --git a/stream/zip.hpp b/stream/zip.hpp deleted file mode 100644 index 7f928dc..0000000 --- a/stream/zip.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include - -namespace nall { - -struct zipstream : memorystream { - using stream::read; - using stream::write; - - zipstream(const stream& stream, const string& filter = "*") { - uint size = stream.size(); - auto data = new uint8_t[size]; - stream.read(data, size); - - Decode::ZIP archive; - if(archive.open(data, size) == false) return; - delete[] data; - - for(auto& file : archive.file) { - if(file.name.match(filter)) { - auto buffer = archive.extract(file); - psize = buffer.size(); - pdata = buffer.release(); - return; - } - } - } - - ~zipstream() { - if(pdata) delete[] pdata; - } -}; - -} diff --git a/string.hpp b/string.hpp index a774fdc..63e7112 100644 --- a/string.hpp +++ b/string.hpp @@ -20,11 +20,305 @@ #include #include #include -#include -#include -#include -#include +namespace nall { + +struct string; +struct format; +struct lstring; + +struct string_view { + inline string_view(); + inline string_view(const string_view& source); + inline string_view(string_view&& source); + inline string_view(const char* data); + inline string_view(const char* data, uint size); + inline string_view(const string& source); + template inline string_view(P&&... p); + inline ~string_view(); + + inline auto operator=(const string_view& source) -> string_view&; + inline auto operator=(string_view&& source) -> string_view&; + + inline operator const char*() const; + inline auto data() const -> const char*; + inline auto size() const -> uint; + +protected: + string* _string; + const char* _data; + mutable int _size; +}; + +#define NALL_STRING_ALLOCATOR_ADAPTIVE +//#define NALL_STRING_ALLOCATOR_COPY_ON_WRITE +//#define NALL_STRING_ALLOCATOR_SMALL_STRING_OPTIMIZATION +//#define NALL_STRING_ALLOCATOR_VECTOR + +//cast.hpp +template struct stringify; + +//format.hpp +template inline auto print(P&&...) -> void; +template inline auto print(FILE*, P&&...) -> void; +inline auto integer(intmax value, long precision = 0, char padchar = '0') -> string; +inline auto natural(uintmax value, long precision = 0, char padchar = '0') -> string; +inline auto hex(uintmax value, long precision = 0, char padchar = '0') -> string; +inline auto octal(uintmax value, long precision = 0, char padchar = '0') -> string; +inline auto binary(uintmax value, long precision = 0, char padchar = '0') -> string; +template inline auto pointer(const T* value, long precision = 0) -> string; +inline auto pointer(uintptr value, long precision = 0) -> string; +inline auto real(long double value) -> string; + +//match.hpp +inline auto tokenize(const char* s, const char* p) -> bool; +inline auto tokenize(lstring& list, const char* s, const char* p) -> bool; + +//path.hpp +inline auto pathname(string_view self) -> string; +inline auto filename(string_view self) -> string; + +inline auto dirname(string_view self) -> string; +inline auto basename(string_view self) -> string; +inline auto prefixname(string_view self) -> string; +inline auto suffixname(string_view self) -> string; + +//utility.hpp +inline auto slice(string_view self, int offset = 0, int length = -1) -> string; + +inline auto integer(char* result, intmax value) -> char*; +inline auto natural(char* result, uintmax value) -> char*; +inline auto real(char* str, long double value) -> uint; + +struct string { + using type = string; + +protected: + #if defined(NALL_STRING_ALLOCATOR_ADAPTIVE) + enum : uint { SSO = 24 }; + union { + struct { //copy-on-write + char* _data; + uint* _refs; + }; + struct { //small-string-optimization + char _text[SSO]; + }; + }; + inline auto _allocate() -> void; + inline auto _copy() -> void; + inline auto _resize() -> void; + #endif + + #if defined(NALL_STRING_ALLOCATOR_COPY_ON_WRITE) + char* _data; + mutable uint* _refs; + inline auto _allocate() -> char*; + inline auto _copy() -> char*; + #endif + + #if defined(NALL_STRING_ALLOCATOR_SMALL_STRING_OPTIMIZATION) + enum : uint { SSO = 24 }; + union { + char* _data; + char _text[SSO]; + }; + #endif + + #if defined(NALL_STRING_ALLOCATOR_VECTOR) + char* _data; + #endif + + uint _capacity; + uint _size; + +public: + inline string(); + template inline auto get() -> T*; + template inline auto data() const -> const T*; + inline auto reset() -> type&; + inline auto reserve(uint) -> type&; + inline auto resize(uint) -> type&; + inline auto operator=(const string&) -> type&; + inline auto operator=(string&&) -> type&; + + template string(T&& s, P&&... p) : string() { + append(forward(s), forward

(p)...); + } + ~string() { reset(); } + + explicit operator bool() const { return _size; } + operator const char*() const { return (const char*)data(); } + + auto size() const -> uint { return _size; } + auto capacity() const -> uint { return _capacity; } + + auto operator==(const string& source) const -> bool { + return size() == source.size() && memory::compare(data(), source.data(), size()) == 0; + } + auto operator!=(const string& source) const -> bool { + return size() != source.size() || memory::compare(data(), source.data(), size()) != 0; + } + + auto operator==(const char* source) const -> bool { return strcmp(data(), source) == 0; } + auto operator!=(const char* source) const -> bool { return strcmp(data(), source) != 0; } + + auto operator==(string_view source) const -> bool { return compare(source) == 0; } + auto operator!=(string_view source) const -> bool { return compare(source) != 0; } + auto operator< (string_view source) const -> bool { return compare(source) < 0; } + auto operator<=(string_view source) const -> bool { return compare(source) <= 0; } + auto operator> (string_view source) const -> bool { return compare(source) > 0; } + auto operator>=(string_view source) const -> bool { return compare(source) >= 0; } + + string(const string& source) : string() { operator=(source); } + string(string&& source) : string() { operator=(move(source)); } + + auto begin() -> char* { return &get()[0]; } + auto end() -> char* { return &get()[size()]; } + auto begin() const -> const char* { return &data()[0]; } + auto end() const -> const char* { return &data()[size()]; } + + //atoi.hpp + inline auto integer() const -> intmax; + inline auto natural() const -> uintmax; + inline auto real() const -> double; + + //core.hpp + inline auto operator[](int) const -> const char&; + template inline auto assign(P&&...) -> type&; + template inline auto append(const T&, P&&...) -> type&; + template inline auto append(const nall::format&, P&&...) -> type&; + inline auto append() -> type&; + template inline auto _append(const stringify&) -> string&; + inline auto length() const -> uint; + + //datetime.hpp + inline static auto date(time_t = 0) -> string; + inline static auto time(time_t = 0) -> string; + inline static auto datetime(time_t = 0) -> string; + + //find.hpp + template inline auto _find(int, string_view) const -> maybe; + + inline auto find(string_view source) const -> maybe; + inline auto ifind(string_view source) const -> maybe; + inline auto qfind(string_view source) const -> maybe; + inline auto iqfind(string_view source) const -> maybe; + + inline auto findFrom(int offset, string_view source) const -> maybe; + inline auto ifindFrom(int offset, string_view source) const -> maybe; + + //format.hpp + inline auto format(const nall::format& params) -> type&; + + //compare.hpp + template inline static auto _compare(const char*, uint, const char*, uint) -> int; + + inline static auto compare(string_view, string_view) -> int; + inline static auto icompare(string_view, string_view) -> int; + + inline auto compare(string_view source) const -> int; + inline auto icompare(string_view source) const -> int; + + inline auto equals(string_view source) const -> bool; + inline auto iequals(string_view source) const -> bool; + + inline auto beginsWith(string_view source) const -> bool; + inline auto ibeginsWith(string_view source) const -> bool; + + inline auto endsWith(string_view source) const -> bool; + inline auto iendsWith(string_view source) const -> bool; + + //convert.hpp + inline auto downcase() -> type&; + inline auto upcase() -> type&; + + inline auto qdowncase() -> type&; + inline auto qupcase() -> type&; + + inline auto transform(string_view from, string_view to) -> type&; + + //match.hpp + inline auto match(string_view source) const -> bool; + inline auto imatch(string_view source) const -> bool; + + //replace.hpp + template inline auto _replace(string_view, string_view, long) -> type&; + inline auto replace(string_view from, string_view to, long limit = LONG_MAX) -> type&; + inline auto ireplace(string_view from, string_view to, long limit = LONG_MAX) -> type&; + inline auto qreplace(string_view from, string_view to, long limit = LONG_MAX) -> type&; + inline auto iqreplace(string_view from, string_view to, long limit = LONG_MAX) -> type&; + + //split.hpp + inline auto split(string_view key, long limit = LONG_MAX) const -> lstring; + inline auto isplit(string_view key, long limit = LONG_MAX) const -> lstring; + inline auto qsplit(string_view key, long limit = LONG_MAX) const -> lstring; + inline auto iqsplit(string_view key, long limit = LONG_MAX) const -> lstring; + + //trim.hpp + inline auto trim(string_view lhs, string_view rhs, long limit = LONG_MAX) -> type&; + inline auto trimLeft(string_view lhs, long limit = LONG_MAX) -> type&; + inline auto trimRight(string_view rhs, long limit = LONG_MAX) -> type&; + + inline auto itrim(string_view lhs, string_view rhs, long limit = LONG_MAX) -> type&; + inline auto itrimLeft(string_view lhs, long limit = LONG_MAX) -> type&; + inline auto itrimRight(string_view rhs, long limit = LONG_MAX) -> type&; + + inline auto strip() -> type&; + inline auto stripLeft() -> type&; + inline auto stripRight() -> type&; + + //utility.hpp + inline static auto read(string_view filename) -> string; + inline static auto repeat(string_view pattern, uint times) -> string; + inline auto fill(char fill = ' ') -> type&; + inline auto hash() const -> uint; + inline auto remove(uint offset, uint length) -> type&; + inline auto reverse() -> type&; + inline auto size(int length, char fill = ' ') -> type&; +}; + +struct lstring : vector { + using type = lstring; + + lstring(const lstring& source) { vector::operator=(source); } + lstring(lstring& source) { vector::operator=(source); } + lstring(lstring&& source) { vector::operator=(move(source)); } + template lstring(P&&... p) { append(forward

(p)...); } + + //list.hpp + inline auto operator==(const lstring&) const -> bool; + inline auto operator!=(const lstring&) const -> bool; + + inline auto operator=(const lstring& source) -> type& { return vector::operator=(source), *this; } + inline auto operator=(lstring& source) -> type& { return vector::operator=(source), *this; } + inline auto operator=(lstring&& source) -> type& { return vector::operator=(move(source)), *this; } + + inline auto isort() -> type&; + + template inline auto append(const string&, P&&...) -> type&; + inline auto append() -> type&; + + inline auto find(string_view source) const -> maybe; + inline auto ifind(string_view source) const -> maybe; + inline auto match(string_view pattern) const -> lstring; + inline auto merge(string_view separator) const -> string; + inline auto strip() -> type&; + + //split.hpp + template inline auto _split(string_view, string_view, long) -> lstring&; +}; + +struct format : vector { + using type = format; + + template format(P&&... p) { reserve(sizeof...(p)); append(forward

(p)...); } + template inline auto append(const T&, P&&... p) -> type&; + inline auto append() -> type&; +}; + +} + #include #include #include @@ -34,11 +328,9 @@ #include #include #include -#include #include #include #include -#include #include #include #include diff --git a/string/allocator/adaptive.hpp b/string/allocator/adaptive.hpp index 224cc15..f919c0b 100644 --- a/string/allocator/adaptive.hpp +++ b/string/allocator/adaptive.hpp @@ -22,15 +22,17 @@ namespace nall { string::string() : _data(nullptr), _capacity(SSO - 1), _size(0) { } -auto string::get() -> char* { - if(_capacity < SSO) return _text; +template +auto string::get() -> T* { + if(_capacity < SSO) return (T*)_text; if(*_refs > 1) _copy(); - return _data; + return (T*)_data; } -auto string::data() const -> const char* { - if(_capacity < SSO) return _text; - return _data; +template +auto string::data() const -> const T* { + if(_capacity < SSO) return (const T*)_text; + return (const T*)_data; } auto string::reset() -> type& { diff --git a/string/base.hpp b/string/base.hpp deleted file mode 100644 index e72c702..0000000 --- a/string/base.hpp +++ /dev/null @@ -1,293 +0,0 @@ -#pragma once - -namespace nall { - -struct string_view; -struct string; -struct format; -struct lstring; - -using rstring = const string_view&; -using cstring = const string&; - -#define NALL_STRING_ALLOCATOR_ADAPTIVE -//#define NALL_STRING_ALLOCATOR_COPY_ON_WRITE -//#define NALL_STRING_ALLOCATOR_SMALL_STRING_OPTIMIZATION -//#define NALL_STRING_ALLOCATOR_VECTOR - -//cast.hpp -template struct stringify; - -//format.hpp -template inline auto print(P&&...) -> void; -inline auto integer(intmax value, long precision = 0, char padchar = '0') -> string; -inline auto natural(uintmax value, long precision = 0, char padchar = '0') -> string; -inline auto hex(uintmax value, long precision = 0, char padchar = '0') -> string; -inline auto octal(uintmax value, long precision = 0, char padchar = '0') -> string; -inline auto binary(uintmax value, long precision = 0, char padchar = '0') -> string; -template inline auto pointer(const T* value, long precision = 0) -> string; -inline auto pointer(uintptr value, long precision = 0) -> string; -inline auto real(long double value) -> string; - -//hash.hpp -inline auto crc16(rstring self) -> string; -inline auto crc32(rstring self) -> string; -inline auto sha256(rstring self) -> string; - -//match.hpp -inline auto tokenize(const char* s, const char* p) -> bool; -inline auto tokenize(lstring& list, const char* s, const char* p) -> bool; - -//path.hpp -inline auto pathname(rstring self) -> string; -inline auto filename(rstring self) -> string; - -inline auto dirname(rstring self) -> string; -inline auto basename(rstring self) -> string; -inline auto prefixname(rstring self) -> string; -inline auto suffixname(rstring self) -> string; - -//platform.hpp -inline auto activepath() -> string; -inline auto realpath(rstring name) -> string; -inline auto programpath() -> string; -inline auto rootpath() -> string; -inline auto userpath() -> string; -inline auto configpath() -> string; -inline auto localpath() -> string; -inline auto sharedpath() -> string; -inline auto temppath() -> string; - -//utility.hpp -inline auto slice(rstring self, int offset = 0, int length = -1) -> string; - -inline auto integer(char* result, intmax value) -> char*; -inline auto natural(char* result, uintmax value) -> char*; -inline auto real(char* str, long double value) -> uint; - -struct string { - using type = string; - struct exception_out_of_bounds{}; - -protected: - #if defined(NALL_STRING_ALLOCATOR_ADAPTIVE) - enum : uint { SSO = 24 }; - union { - struct { //copy-on-write - char* _data; - uint* _refs; - }; - struct { //small-string-optimization - char _text[SSO]; - }; - }; - inline auto _allocate() -> void; - inline auto _copy() -> void; - inline auto _resize() -> void; - #endif - - #if defined(NALL_STRING_ALLOCATOR_COPY_ON_WRITE) - char* _data; - mutable uint* _refs; - inline auto _allocate() -> char*; - inline auto _copy() -> char*; - #endif - - #if defined(NALL_STRING_ALLOCATOR_SMALL_STRING_OPTIMIZATION) - enum : uint { SSO = 24 }; - union { - char* _data; - char _text[SSO]; - }; - #endif - - #if defined(NALL_STRING_ALLOCATOR_VECTOR) - char* _data; - #endif - - uint _capacity; - uint _size; - -public: - inline string(); - inline auto get() -> char*; - inline auto data() const -> const char*; - inline auto reset() -> type&; - inline auto reserve(uint) -> type&; - inline auto resize(uint) -> type&; - inline auto operator=(const string&) -> type&; - inline auto operator=(string&&) -> type&; - - template string(T&& s, P&&... p) : string() { append(forward(s), forward

(p)...); } - ~string() { reset(); } - - explicit operator bool() const { return _size; } - operator const uint8_t*() const { return (const uint8_t*)data(); } - operator const char*() const { return (const char*)data(); } - - auto binary() const -> const uint8_t* { return (const uint8_t*)data(); } - auto size() const -> uint { return _size; } - auto capacity() const -> uint { return _capacity; } - - auto operator==(const string& source) const -> bool { return size() == source.size() && memory::compare(data(), source.data(), size()) == 0; } - auto operator!=(const string& source) const -> bool { return size() != source.size() || memory::compare(data(), source.data(), size()) != 0; } - - auto operator==(const char* source) const -> bool { return strcmp(data(), source) == 0; } - auto operator!=(const char* source) const -> bool { return strcmp(data(), source) != 0; } - - auto operator==(rstring source) const -> bool { return compare(source) == 0; } - auto operator!=(rstring source) const -> bool { return compare(source) != 0; } - auto operator< (rstring source) const -> bool { return compare(source) < 0; } - auto operator<=(rstring source) const -> bool { return compare(source) <= 0; } - auto operator> (rstring source) const -> bool { return compare(source) > 0; } - auto operator>=(rstring source) const -> bool { return compare(source) >= 0; } - - string(const string& source) : string() { operator=(source); } - string(string&& source) : string() { operator=(move(source)); } - - auto begin() -> char* { return &get()[0]; } - auto end() -> char* { return &get()[size()]; } - auto begin() const -> const char* { return &data()[0]; } - auto end() const -> const char* { return &data()[size()]; } - - //atoi.hpp - inline auto integer() const -> intmax; - inline auto natural() const -> uintmax; - inline auto real() const -> double; - - //core.hpp - inline auto operator[](int) const -> const char&; - template inline auto assign(P&&...) -> type&; - template inline auto append(const T&, P&&...) -> type&; - template inline auto append(const nall::format&, P&&...) -> type&; - inline auto append() -> type&; - template inline auto _append(const stringify&) -> string&; - inline auto empty() const -> bool; - inline auto length() const -> uint; - - //datetime.hpp - inline static auto date(time_t = 0) -> string; - inline static auto time(time_t = 0) -> string; - inline static auto datetime(time_t = 0) -> string; - - //find.hpp - template inline auto _find(int, rstring) const -> maybe; - - inline auto find(rstring source) const -> maybe; - inline auto ifind(rstring source) const -> maybe; - inline auto qfind(rstring source) const -> maybe; - inline auto iqfind(rstring source) const -> maybe; - - inline auto findFrom(int offset, rstring source) const -> maybe; - inline auto ifindFrom(int offset, rstring source) const -> maybe; - - //format.hpp - inline auto format(const nall::format& params) -> type&; - - //compare.hpp - template inline static auto _compare(const char*, uint, const char*, uint) -> signed; - - inline static auto compare(rstring, rstring) -> signed; - inline static auto icompare(rstring, rstring) -> signed; - - inline auto compare(rstring source) const -> signed; - inline auto icompare(rstring source) const -> signed; - - inline auto equals(rstring source) const -> bool; - inline auto iequals(rstring source) const -> bool; - - inline auto beginsWith(rstring source) const -> bool; - inline auto ibeginsWith(rstring source) const -> bool; - - inline auto endsWith(rstring source) const -> bool; - inline auto iendsWith(rstring source) const -> bool; - - //convert.hpp - inline auto downcase() -> type&; - inline auto upcase() -> type&; - - inline auto qdowncase() -> type&; - inline auto qupcase() -> type&; - - inline auto transform(rstring from, rstring to) -> type&; - - //match.hpp - inline auto match(rstring source) const -> bool; - inline auto imatch(rstring source) const -> bool; - - //replace.hpp - template inline auto _replace(rstring, rstring, long) -> type&; - inline auto replace(rstring from, rstring to, long limit = LONG_MAX) -> type&; - inline auto ireplace(rstring from, rstring to, long limit = LONG_MAX) -> type&; - inline auto qreplace(rstring from, rstring to, long limit = LONG_MAX) -> type&; - inline auto iqreplace(rstring from, rstring to, long limit = LONG_MAX) -> type&; - - //split.hpp - 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 - inline auto trim(rstring lhs, rstring rhs, long limit = LONG_MAX) -> type&; - inline auto ltrim(rstring lhs, long limit = LONG_MAX) -> type&; - inline auto rtrim(rstring rhs, long limit = LONG_MAX) -> type&; - - inline auto itrim(rstring lhs, rstring rhs, long limit = LONG_MAX) -> type&; - inline auto iltrim(rstring lhs, long limit = LONG_MAX) -> type&; - inline auto irtrim(rstring rhs, long limit = LONG_MAX) -> type&; - - inline auto strip() -> type&; - inline auto lstrip() -> type&; - inline auto rstrip() -> type&; - - //utility.hpp - inline static auto read(rstring filename) -> string; - inline static auto repeat(rstring pattern, uint times) -> string; - inline auto fill(char fill = ' ') -> type&; - inline auto hash() const -> uint; - inline auto remove(uint offset, uint length) -> type&; - inline auto reverse() -> type&; - inline auto size(int length, char fill = ' ') -> type&; -}; - -struct lstring : vector { - using type = lstring; - - lstring(const lstring& source) { vector::operator=(source); } - lstring(lstring& source) { vector::operator=(source); } - lstring(lstring&& source) { vector::operator=(move(source)); } - template lstring(P&&... p) { append(forward

(p)...); } - - //list.hpp - inline auto operator==(const lstring&) const -> bool; - inline auto operator!=(const lstring&) const -> bool; - - inline auto operator=(const lstring& source) -> type& { return vector::operator=(source), *this; } - inline auto operator=(lstring& source) -> type& { return vector::operator=(source), *this; } - inline auto operator=(lstring&& source) -> type& { return vector::operator=(move(source)), *this; } - - inline auto isort() -> type&; - - template inline auto append(const string&, P&&...) -> type&; - inline auto append() -> type&; - - inline auto find(rstring source) const -> maybe; - inline auto ifind(rstring source) const -> maybe; - inline auto match(rstring pattern) const -> lstring; - inline auto merge(rstring separator) const -> string; - inline auto strip() -> type&; - - //split.hpp - template inline auto _split(rstring, rstring, long) -> lstring&; -}; - -struct format : vector { - using type = format; - - template format(P&&... p) { reserve(sizeof...(p)); append(forward

(p)...); } - template inline auto append(const T&, P&&... p) -> type&; - inline auto append() -> type&; -}; - -} diff --git a/string/cast.hpp b/string/cast.hpp index 2574eca..2c68071 100644 --- a/string/cast.hpp +++ b/string/cast.hpp @@ -10,7 +10,7 @@ namespace nall { template<> struct stringify { stringify(bool value) : _value(value) {} auto data() const -> const char* { return _value ? "true" : "false"; } - auto size() const -> unsigned { return _value ? 4 : 5; } + auto size() const -> uint { return _value ? 4 : 5; } bool _value; }; @@ -26,7 +26,7 @@ template<> struct stringify { template<> struct stringify { stringify(char source) { _data[0] = source; _data[1] = 0; } auto data() const -> const char* { return _data; } - auto size() const -> unsigned { return 1; } + auto size() const -> uint { return 1; } char _data[2]; }; @@ -35,35 +35,35 @@ template<> struct stringify { template<> struct stringify { stringify(signed char source) { integer(_data, source); } auto data() const -> const char* { return _data; } - auto size() const -> unsigned { return strlen(_data); } + auto size() const -> uint { return strlen(_data); } char _data[2 + sizeof(signed char) * 3]; }; template<> struct stringify { stringify(signed short source) { integer(_data, source); } auto data() const -> const char* { return _data; } - auto size() const -> unsigned { return strlen(_data); } + auto size() const -> uint { return strlen(_data); } char _data[2 + sizeof(signed short) * 3]; }; template<> struct stringify { stringify(signed int source) { integer(_data, source); } auto data() const -> const char* { return _data; } - auto size() const -> unsigned { return strlen(_data); } + auto size() const -> uint { return strlen(_data); } char _data[2 + sizeof(signed int) * 3]; }; template<> struct stringify { stringify(signed long source) { integer(_data, source); } auto data() const -> const char* { return _data; } - auto size() const -> unsigned { return strlen(_data); } + auto size() const -> uint { return strlen(_data); } char _data[2 + sizeof(signed long) * 3]; }; template<> struct stringify { stringify(signed long long source) { integer(_data, source); } auto data() const -> const char* { return _data; } - auto size() const -> unsigned { return strlen(_data); } + auto size() const -> uint { return strlen(_data); } char _data[2 + sizeof(signed long long) * 3]; }; @@ -79,35 +79,35 @@ template struct stringify> { template<> struct stringify { stringify(unsigned char source) { natural(_data, source); } auto data() const -> const char* { return _data; } - auto size() const -> unsigned { return strlen(_data); } + auto size() const -> uint { return strlen(_data); } char _data[1 + sizeof(unsigned char) * 3]; }; template<> struct stringify { stringify(unsigned short source) { natural(_data, source); } auto data() const -> const char* { return _data; } - auto size() const -> unsigned { return strlen(_data); } + auto size() const -> uint { return strlen(_data); } char _data[1 + sizeof(unsigned short) * 3]; }; template<> struct stringify { stringify(unsigned int source) { natural(_data, source); } auto data() const -> const char* { return _data; } - auto size() const -> unsigned { return strlen(_data); } + auto size() const -> uint { return strlen(_data); } char _data[1 + sizeof(unsigned int) * 3]; }; template<> struct stringify { stringify(unsigned long source) { natural(_data, source); } auto data() const -> const char* { return _data; } - auto size() const -> unsigned { return strlen(_data); } + auto size() const -> uint { return strlen(_data); } char _data[1 + sizeof(unsigned long) * 3]; }; template<> struct stringify { stringify(unsigned long long source) { natural(_data, source); } auto data() const -> const char* { return _data; } - auto size() const -> unsigned { return strlen(_data); } + auto size() const -> uint { return strlen(_data); } char _data[1 + sizeof(unsigned long long) * 3]; }; @@ -123,21 +123,21 @@ template struct stringify> { template<> struct stringify { stringify(float source) { real(_data, source); } auto data() const -> const char* { return _data; } - auto size() const -> unsigned { return strlen(_data); } + auto size() const -> uint { return strlen(_data); } char _data[256]; }; template<> struct stringify { stringify(double source) { real(_data, source); } auto data() const -> const char* { return _data; } - auto size() const -> unsigned { return strlen(_data); } + auto size() const -> uint { return strlen(_data); } char _data[256]; }; template<> struct stringify { stringify(long double source) { real(_data, source); } auto data() const -> const char* { return _data; } - auto size() const -> unsigned { return strlen(_data); } + auto size() const -> uint { return strlen(_data); } char _data[256]; }; @@ -156,7 +156,7 @@ template<> struct stringify> { memory::copy(_text.data(), source.data(), source.size()); } auto data() const -> const char* { return _text.data(); } - auto size() const -> unsigned { return _text.size(); } + auto size() const -> uint { return _text.size(); } vector _text; }; @@ -166,7 +166,7 @@ template<> struct stringify&> { memory::copy(_text.data(), source.data(), source.size()); } auto data() const -> const char* { return _text.data(); } - auto size() const -> unsigned { return _text.size(); } + auto size() const -> uint { return _text.size(); } vector _text; }; @@ -175,14 +175,14 @@ template<> struct stringify&> { template<> struct stringify { stringify(char* source) : _data(source ? source : "") {} auto data() const -> const char* { return _data; } - auto size() const -> unsigned { return strlen(_data); } + auto size() const -> uint { return strlen(_data); } const char* _data; }; template<> struct stringify { stringify(const char* source) : _data(source ? source : "") {} auto data() const -> const char* { return _data; } - auto size() const -> unsigned { return strlen(_data); } + auto size() const -> uint { return strlen(_data); } const char* _data; }; @@ -191,28 +191,28 @@ template<> struct stringify { template<> struct stringify { stringify(const string& source) : _text(source) {} auto data() const -> const char* { return _text.data(); } - auto size() const -> unsigned { return _text.size(); } + auto size() const -> uint { return _text.size(); } const string& _text; }; template<> struct stringify { stringify(const string& source) : _text(source) {} auto data() const -> const char* { return _text.data(); } - auto size() const -> unsigned { return _text.size(); } + auto size() const -> uint { return _text.size(); } const string& _text; }; template<> struct stringify { stringify(const string_view& source) : _view(source) {} auto data() const -> const char* { return _view.data(); } - auto size() const -> unsigned { return _view.size(); } + auto size() const -> uint { return _view.size(); } const string_view& _view; }; template<> struct stringify { stringify(const string_view& source) : _view(source) {} auto data() const -> const char* { return _view.data(); } - auto size() const -> unsigned { return _view.size(); } + auto size() const -> uint { return _view.size(); } const string_view& _view; }; diff --git a/string/compare.hpp b/string/compare.hpp index 0fb933d..08479ba 100644 --- a/string/compare.hpp +++ b/string/compare.hpp @@ -3,54 +3,54 @@ namespace nall { template -auto string::_compare(const char* target, uint capacity, const char* source, uint size) -> signed { +auto string::_compare(const char* target, uint capacity, const char* source, uint size) -> int { if(Insensitive) return memory::icompare(target, capacity, source, size); return memory::compare(target, capacity, source, size); } //size() + 1 includes null-terminator; required to properly compare strings of differing lengths -auto string::compare(rstring x, rstring y) -> int { +auto string::compare(string_view x, string_view y) -> int { return memory::compare(x.data(), x.size() + 1, y.data(), y.size() + 1); } -auto string::icompare(rstring x, rstring y) -> int { +auto string::icompare(string_view x, string_view y) -> int { return memory::icompare(x.data(), x.size() + 1, y.data(), y.size() + 1); } -auto string::compare(rstring source) const -> int { +auto string::compare(string_view source) const -> int { return memory::compare(data(), size() + 1, source.data(), source.size() + 1); } -auto string::icompare(rstring source) const -> int { +auto string::icompare(string_view source) const -> int { return memory::icompare(data(), size() + 1, source.data(), source.size() + 1); } -auto string::equals(rstring source) const -> bool { +auto string::equals(string_view source) const -> bool { if(size() != source.size()) return false; return memory::compare(data(), source.data(), source.size()) == 0; } -auto string::iequals(rstring source) const -> bool { +auto string::iequals(string_view source) const -> bool { if(size() != source.size()) return false; return memory::icompare(data(), source.data(), source.size()) == 0; } -auto string::beginsWith(rstring source) const -> bool { +auto string::beginsWith(string_view source) const -> bool { if(source.size() > size()) return false; return memory::compare(data(), source.data(), source.size()) == 0; } -auto string::ibeginsWith(rstring source) const -> bool { +auto string::ibeginsWith(string_view source) const -> bool { if(source.size() > size()) return false; return memory::icompare(data(), source.data(), source.size()) == 0; } -auto string::endsWith(rstring source) const -> bool { +auto string::endsWith(string_view source) const -> bool { if(source.size() > size()) return false; return memory::compare(data() + size() - source.size(), source.data(), source.size()) == 0; } -auto string::iendsWith(rstring source) const -> bool { +auto string::iendsWith(string_view source) const -> bool { if(source.size() > size()) return false; return memory::icompare(data() + size() - source.size(), source.data(), source.size()) == 0; } diff --git a/string/convert.hpp b/string/convert.hpp index 2b177f4..4c7d4ab 100644 --- a/string/convert.hpp +++ b/string/convert.hpp @@ -4,7 +4,7 @@ namespace nall { auto string::downcase() -> string& { char* p = get(); - for(unsigned n = 0; n < size(); n++) { + for(uint n = 0; n < size(); n++) { if(p[n] >= 'A' && p[n] <= 'Z') p[n] += 0x20; } return *this; @@ -12,7 +12,7 @@ auto string::downcase() -> string& { auto string::qdowncase() -> string& { char* p = get(); - for(unsigned n = 0, quoted = 0; n < size(); n++) { + for(uint n = 0, quoted = 0; n < size(); n++) { if(p[n] == '\"') quoted ^= 1; if(!quoted && p[n] >= 'A' && p[n] <= 'Z') p[n] += 0x20; } @@ -21,7 +21,7 @@ auto string::qdowncase() -> string& { auto string::upcase() -> string& { char* p = get(); - for(unsigned n = 0; n < size(); n++) { + for(uint n = 0; n < size(); n++) { if(p[n] >= 'a' && p[n] <= 'z') p[n] -= 0x20; } return *this; @@ -29,18 +29,18 @@ auto string::upcase() -> string& { auto string::qupcase() -> string& { char* p = get(); - for(unsigned n = 0, quoted = 0; n < size(); n++) { + for(uint n = 0, quoted = 0; n < size(); n++) { if(p[n] == '\"') quoted ^= 1; if(!quoted && p[n] >= 'a' && p[n] <= 'z') p[n] -= 0x20; } return *this; } -auto string::transform(rstring from, rstring to) -> string& { +auto string::transform(string_view from, string_view to) -> string& { if(from.size() != to.size() || from.size() == 0) return *this; //patterns must be the same length char* p = get(); - for(unsigned n = 0; n < size(); n++) { - for(unsigned s = 0; s < from.size(); s++) { + for(uint n = 0; n < size(); n++) { + for(uint s = 0; s < from.size(); s++) { if(p[n] == from[s]) { p[n] = to[s]; break; diff --git a/string/core.hpp b/string/core.hpp index da8c166..7122c5f 100644 --- a/string/core.hpp +++ b/string/core.hpp @@ -16,7 +16,7 @@ namespace nall { auto string::operator[](int position) const -> const char& { - if(position > size() + 1) throw exception_out_of_bounds{}; +//if(position > size() + 1) throw; return data()[position]; } @@ -45,10 +45,6 @@ template auto string::_append(const stringify& source) -> string& return *this; } -auto string::empty() const -> bool { - return size() == 0; -} - auto string::length() const -> uint { return strlen(data()); } diff --git a/string/eval/evaluator.hpp b/string/eval/evaluator.hpp index 60fc2d1..184f8eb 100644 --- a/string/eval/evaluator.hpp +++ b/string/eval/evaluator.hpp @@ -28,7 +28,7 @@ inline auto evaluateExpression(Node* node) -> string { for(auto& link : node->link) { result.append(evaluateExpression(link), ", "); } - return result.rtrim(", ", 1L).append(")"); + return result.trimRight(", ", 1L).append(")"); } } #undef p diff --git a/string/eval/literal.hpp b/string/eval/literal.hpp index f56078a..4efd94a 100644 --- a/string/eval/literal.hpp +++ b/string/eval/literal.hpp @@ -16,7 +16,7 @@ inline auto literalNumber(const char*& s) -> string { //binary if(p[0] == '%' || (p[0] == '0' && p[1] == 'b')) { - unsigned prefix = 1 + (p[0] == '0'); + uint prefix = 1 + (p[0] == '0'); p += prefix; while(p[0] == '\'' || p[0] == '0' || p[0] == '1') p++; if(p - s <= prefix) throw "invalid binary literal"; @@ -27,7 +27,7 @@ inline auto literalNumber(const char*& s) -> string { //octal if(p[0] == '0' && p[1] == 'o') { - unsigned prefix = 1 + (p[0] == '0'); + uint prefix = 1 + (p[0] == '0'); p += prefix; while(p[0] == '\'' || (p[0] >= '0' && p[0] <= '7')) p++; if(p - s <= prefix) throw "invalid octal literal"; @@ -38,7 +38,7 @@ inline auto literalNumber(const char*& s) -> string { //hex if(p[0] == '$' || (p[0] == '0' && p[1] == 'x')) { - unsigned prefix = 1 + (p[0] == '0'); + uint prefix = 1 + (p[0] == '0'); p += prefix; while(p[0] == '\'' || (p[0] >= '0' && p[0] <= '9') || (p[0] >= 'A' && p[0] <= 'F') || (p[0] >= 'a' && p[0] <= 'f')) p++; if(p - s <= prefix) throw "invalid hex literal"; diff --git a/string/eval/parser.hpp b/string/eval/parser.hpp index 1cae0d9..5e8ebe5 100644 --- a/string/eval/parser.hpp +++ b/string/eval/parser.hpp @@ -45,7 +45,7 @@ inline auto parse(Node*& node, const char*& s, uint depth) -> void { while(whitespace(s[0])) s++; if(!s[0]) return; - if(s[0] == '(' && node->link.empty()) { + if(s[0] == '(' && !node->link) { parse(node, s += 1, 1); if(*s++ != ')') throw "mismatched group"; } @@ -55,7 +55,7 @@ inline auto parse(Node*& node, const char*& s, uint depth) -> void { node->literal = literal(s); } - #define p() (node->literal.empty() && node->link.empty()) + #define p() (!node->literal && !node->link) while(true) { while(whitespace(s[0])) s++; if(!s[0]) return; diff --git a/string/find.hpp b/string/find.hpp index 872fece..d8d9a48 100644 --- a/string/find.hpp +++ b/string/find.hpp @@ -2,7 +2,7 @@ namespace nall { -template auto string::_find(int offset, rstring source) const -> maybe { +template auto string::_find(int offset, string_view source) const -> maybe { if(source.size() == 0) return nothing; auto p = data(); @@ -15,12 +15,12 @@ template auto string::_find(int offset, rstring s return nothing; } -auto string::find(rstring source) const -> maybe { return _find<0, 0>(0, source); } -auto string::ifind(rstring source) const -> maybe { return _find<1, 0>(0, source); } -auto string::qfind(rstring source) const -> maybe { return _find<0, 1>(0, source); } -auto string::iqfind(rstring source) const -> maybe { return _find<1, 1>(0, source); } +auto string::find(string_view source) const -> maybe { return _find<0, 0>(0, source); } +auto string::ifind(string_view source) const -> maybe { return _find<1, 0>(0, source); } +auto string::qfind(string_view source) const -> maybe { return _find<0, 1>(0, source); } +auto string::iqfind(string_view source) const -> maybe { return _find<1, 1>(0, source); } -auto string::findFrom(int offset, rstring source) const -> maybe { return _find<0, 0>(offset, source); } -auto string::ifindFrom(int offset, rstring source) const -> maybe { return _find<1, 0>(offset, source); } +auto string::findFrom(int offset, string_view source) const -> maybe { return _find<0, 0>(offset, source); } +auto string::ifindFrom(int offset, string_view source) const -> maybe { return _find<1, 0>(offset, source); } } diff --git a/string/format.hpp b/string/format.hpp index 8f8c463..71c8a1a 100644 --- a/string/format.hpp +++ b/string/format.hpp @@ -10,11 +10,11 @@ auto string::format(const nall::format& params) -> type& { auto data = (char*)memory::allocate(size); memory::copy(data, this->data(), size); - signed x = 0; + int x = 0; while(x < size - 2) { //2 = minimum tag length if(data[x] != '{') { x++; continue; } - signed y = x + 1; + int y = x + 1; while(y < size - 1) { //-1 avoids going out of bounds on test after this loop if(data[y] != '}') { y++; continue; } break; @@ -70,7 +70,12 @@ auto format::append() -> format& { template auto print(P&&... p) -> void { string s{forward

(p)...}; - fputs(s.data(), stdout); + fwrite(s.data(), 1, s.size(), stdout); +} + +template auto print(FILE* fp, P&&... p) -> void { + string s{forward

(p)...}; + fwrite(s.data(), 1, s.size(), fp); } auto integer(intmax value, long precision, char padchar) -> string { diff --git a/string/hash.hpp b/string/hash.hpp deleted file mode 100644 index 11371a3..0000000 --- a/string/hash.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -namespace nall { - -namespace Hash { - auto CRC16::digest() -> string { - return hex(value(), 4L); - } - - auto CRC32::digest() -> string { - return hex(value(), 8L); - } - - auto SHA256::digest() const -> string { - string result; - for(auto n : value()) result.append(hex(n, 2L)); - return result; - } -} - -auto crc16(rstring self) -> string { - return Hash::CRC16(self.data(), self.size()).digest(); -} - -auto crc32(rstring self) -> string { - return Hash::CRC32(self.data(), self.size()).digest(); -} - -auto sha256(rstring self) -> string { - return Hash::SHA256(self.data(), self.size()).digest(); -} - -} diff --git a/string/list.hpp b/string/list.hpp index cbdc375..ae74172 100644 --- a/string/list.hpp +++ b/string/list.hpp @@ -16,7 +16,7 @@ auto lstring::operator!=(const lstring& source) const -> bool { } auto lstring::isort() -> lstring& { - nall::sort(pool, objectsize, [](const string& x, const string& y) { + sort([](const string& x, const string& y) { return memory::icompare(x.data(), x.size(), y.data(), y.size()) < 0; }); return *this; @@ -32,21 +32,21 @@ auto lstring::append() -> lstring& { return *this; } -auto lstring::find(rstring source) const -> maybe { +auto lstring::find(string_view source) const -> maybe { for(uint n = 0; n < size(); n++) { if(operator[](n).equals(source)) return n; } return nothing; } -auto lstring::ifind(rstring source) const -> maybe { +auto lstring::ifind(string_view source) const -> maybe { for(uint n = 0; n < size(); n++) { if(operator[](n).iequals(source)) return n; } return nothing; } -auto lstring::match(rstring pattern) const -> lstring { +auto lstring::match(string_view pattern) const -> lstring { lstring result; for(uint n = 0; n < size(); n++) { if(operator[](n).match(pattern)) result.append(operator[](n)); @@ -54,7 +54,7 @@ auto lstring::match(rstring pattern) const -> lstring { return result; } -auto lstring::merge(rstring separator) const -> string { +auto lstring::merge(string_view separator) const -> string { string output; for(uint n = 0; n < size(); n++) { output.append(operator[](n)); diff --git a/string/markup/bml.hpp b/string/markup/bml.hpp index d170d19..550f3e0 100644 --- a/string/markup/bml.hpp +++ b/string/markup/bml.hpp @@ -74,7 +74,7 @@ protected: if(length == 0) throw "Invalid attribute name"; node->_name = slice(p, 0, length); node->parseData(p += length); - node->_value.rtrim("\n", 1L); + node->_value.trimRight("\n", 1L); _children.append(node); } } @@ -101,7 +101,7 @@ protected: _children.append(node); } - _value.rtrim("\n", 1L); + _value.trimRight("\n", 1L); } //read top-level nodes @@ -127,7 +127,7 @@ protected: memory::move(output, origin, p - origin); output += p - origin; } - document.resize(document.size() - (p - output)).rtrim("\n"); + document.resize(document.size() - (p - output)).trimRight("\n"); if(document.size() == 0) return; //empty document auto text = document.split("\n"); diff --git a/string/markup/find.hpp b/string/markup/find.hpp index 9767bfd..f4016ba 100644 --- a/string/markup/find.hpp +++ b/string/markup/find.hpp @@ -31,7 +31,7 @@ auto ManagedNode::_evaluate(string query) const -> bool { } string data = string{_value}.strip(); - if(side(0).empty() == false) { + if(side(0)) { auto result = _find(side(0)); if(result.size() == 0) return false; data = result[0].value(); @@ -60,19 +60,19 @@ auto ManagedNode::_find(const string& query) const -> vector { uint lo = 0u, hi = ~0u; if(name.match("*[*]")) { - auto p = name.rtrim("]", 1L).split("[", 1L); + auto p = name.trimRight("]", 1L).split("[", 1L); name = p(0); if(p(1).find("-")) { p = p(1).split("-", 1L); - lo = p(0).empty() ? 0u : p(0).natural(); - hi = p(1).empty() ? ~0u : p(1).natural(); + lo = !p(0) ? 0u : p(0).natural(); + hi = !p(1) ? ~0u : p(1).natural(); } else { lo = hi = p(1).natural(); } } if(name.match("*(*)")) { - auto p = name.rtrim(")", 1L).split("(", 1L); + auto p = name.trimRight(")", 1L).split("(", 1L); name = p(0); rule = p(1); } @@ -119,13 +119,13 @@ auto ManagedNode::_create(const string& path) -> Node { } } _children.append(new ManagedNode(name)); - return _children.last()->_create(slice(path, *position + 1)); + return _children.right()->_create(slice(path, *position + 1)); } for(auto& node : _children) { if(path == node->_name) return node; } _children.append(new ManagedNode(path)); - return _children.last(); + return _children.right(); } }} diff --git a/string/markup/xml.hpp b/string/markup/xml.hpp index f53090e..b0d946a 100644 --- a/string/markup/xml.hpp +++ b/string/markup/xml.hpp @@ -125,7 +125,7 @@ protected: while(isName(*p)) p++; const char* nameEnd = p; copy(_name, nameStart, nameEnd - nameStart); - if(_name.empty()) throw "missing element name"; + if(!_name) throw "missing element name"; //parse attributes while(*p) { @@ -141,7 +141,7 @@ protected: while(isName(*p)) p++; const char* nameEnd = p; copy(attribute->_name, nameStart, nameEnd - nameStart); - if(attribute->_name.empty()) throw "missing attribute name"; + if(!attribute->_name) throw "missing attribute name"; //parse attribute data if(*p++ != '=') throw "missing attribute value"; diff --git a/string/match.hpp b/string/match.hpp index 80ff7c1..3d1bebb 100644 --- a/string/match.hpp +++ b/string/match.hpp @@ -4,7 +4,7 @@ namespace nall { //todo: these functions are not binary-safe -auto string::match(rstring source) const -> bool { +auto string::match(string_view source) const -> bool { const char* s = data(); const char* p = source.data(); @@ -28,7 +28,7 @@ auto string::match(rstring source) const -> bool { return !*p; } -auto string::imatch(rstring source) const -> bool { +auto string::imatch(string_view source) const -> bool { static auto chrlower = [](char c) -> char { return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; }; diff --git a/string/path.hpp b/string/path.hpp index b5903d5..eac881b 100644 --- a/string/path.hpp +++ b/string/path.hpp @@ -4,7 +4,7 @@ namespace nall { // (/parent/child.type/) // (/parent/child.type/)name.type -auto pathname(rstring self) -> string { +auto pathname(string_view self) -> string { const char* p = self.data() + self.size() - 1; for(int offset = self.size() - 1; offset >= 0; offset--, p--) { if(*p == '/') return slice(self, 0, offset + 1); @@ -14,7 +14,7 @@ auto pathname(rstring self) -> string { // /parent/child.type/() // /parent/child.type/(name.type) -auto filename(rstring self) -> string { +auto filename(string_view self) -> string { const char* p = self.data() + self.size() - 1; for(int offset = self.size() - 1; offset >= 0; offset--, p--) { if(*p == '/') return slice(self, offset + 1); @@ -24,18 +24,18 @@ auto filename(rstring self) -> string { // (/parent/)child.type/ // (/parent/child.type/)name.type -auto dirname(rstring self) -> string { +auto dirname(string_view self) -> string { const char* p = self.data() + self.size() - 1, *last = p; for(int offset = self.size() - 1; offset >= 0; offset--, p--) { if(*p == '/' && p == last) continue; if(*p == '/') return slice(self, 0, offset + 1); } - return rootpath(); //technically, directory is unknown; must return something + return ""; //no path found } // /parent/(child.type/) // /parent/child.type/(name.type) -auto basename(rstring self) -> string { +auto basename(string_view self) -> string { const char* p = self.data() + self.size() - 1, *last = p; for(int offset = self.size() - 1; offset >= 0; offset--, p--) { if(*p == '/' && p == last) continue; @@ -46,25 +46,25 @@ auto basename(rstring self) -> string { // /parent/(child).type/ // /parent/child.type/(name).type -auto prefixname(rstring self) -> string { +auto prefixname(string_view self) -> string { const char* p = self.data() + self.size() - 1, *last = p; for(int offset = self.size() - 1, suffix = -1; offset >= 0; offset--, p--) { if(*p == '/' && p == last) continue; - if(*p == '/') return slice(self, offset + 1, suffix >= 0 ? suffix - offset - 1 : 0).rtrim("/"); + if(*p == '/') return slice(self, offset + 1, suffix >= 0 ? suffix - offset - 1 : 0).trimRight("/"); if(*p == '.' && suffix == -1) { suffix = offset; continue; } - if(offset == 0) return slice(self, offset, suffix).rtrim("/"); + if(offset == 0) return slice(self, offset, suffix).trimRight("/"); } return ""; //no prefix found } // /parent/child(.type)/ // /parent/child.type/name(.type) -auto suffixname(rstring self) -> string { +auto suffixname(string_view self) -> string { const char* p = self.data() + self.size() - 1, *last = p; for(int offset = self.size() - 1; offset >= 0; offset--, p--) { if(*p == '/' && p == last) continue; if(*p == '/') break; - if(*p == '.') return slice(self, offset).rtrim("/"); + if(*p == '.') return slice(self, offset).trimRight("/"); } return ""; //no suffix found } diff --git a/string/replace.hpp b/string/replace.hpp index 0744caf..d8143a1 100644 --- a/string/replace.hpp +++ b/string/replace.hpp @@ -3,17 +3,17 @@ namespace nall { template -auto string::_replace(rstring from, rstring to, long limit) -> string& { +auto string::_replace(string_view from, string_view to, long limit) -> string& { if(limit <= 0 || from.size() == 0) return *this; - signed size = this->size(); - signed matches = 0; - signed quoted = 0; + int size = this->size(); + int matches = 0; + int quoted = 0; //count matches first, so that we only need to reallocate memory once //(recording matches would also require memory allocation, so this is not done) { const char* p = data(); - for(signed n = 0; n <= size - (signed)from.size();) { + for(int n = 0; n <= size - (int)from.size();) { 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; } @@ -27,7 +27,7 @@ auto string::_replace(rstring from, rstring to, long limit) -> string& { if(to.size() == from.size()) { char* p = get(); - for(signed n = 0, remaining = matches, quoted = 0; n <= size - (signed)from.size();) { + for(int n = 0, remaining = matches, quoted = 0; n <= size - (int)from.size();) { 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; } @@ -41,10 +41,10 @@ auto string::_replace(rstring from, rstring to, long limit) -> string& { //left-to-right shrink else if(to.size() < from.size()) { char* p = get(); - signed offset = 0; - signed base = 0; + int offset = 0; + int base = 0; - for(signed n = 0, remaining = matches, quoted = 0; n <= size - (signed)from.size();) { + for(int n = 0, remaining = matches, quoted = 0; n <= size - (int)from.size();) { 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; } @@ -66,10 +66,10 @@ auto string::_replace(rstring from, rstring to, long limit) -> string& { resize(size + matches * (to.size() - from.size())); char* p = get(); - signed offset = this->size(); - signed base = size; + int offset = this->size(); + int base = size; - for(signed n = size, remaining = matches; n >= (signed)from.size();) { //quoted reused from parent scope since we are iterating backward + for(int n = size, remaining = matches; n >= (int)from.size();) { //quoted reused from parent scope since we are iterating backward if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n--; continue; } if(quoted) { n--; continue; } } if(_compare(p + n - from.size(), size - n + from.size(), from.data(), from.size())) { n--; continue; } @@ -86,9 +86,9 @@ auto string::_replace(rstring from, rstring to, long limit) -> string& { return *this; } -auto string::replace(rstring from, rstring to, long limit) -> string& { return _replace<0, 0>(from, to, limit); } -auto string::ireplace(rstring from, rstring to, long limit) -> string& { return _replace<1, 0>(from, to, limit); } -auto string::qreplace(rstring from, rstring to, long limit) -> string& { return _replace<0, 1>(from, to, limit); } -auto string::iqreplace(rstring from, rstring to, long limit) -> string& { return _replace<1, 1>(from, to, limit); } +auto string::replace(string_view from, string_view to, long limit) -> string& { return _replace<0, 0>(from, to, limit); } +auto string::ireplace(string_view from, string_view to, long limit) -> string& { return _replace<1, 0>(from, to, limit); } +auto string::qreplace(string_view from, string_view to, long limit) -> string& { return _replace<0, 1>(from, to, limit); } +auto string::iqreplace(string_view from, string_view to, long limit) -> string& { return _replace<1, 1>(from, to, limit); } }; diff --git a/string/split.hpp b/string/split.hpp index b236e37..ef5b8f3 100644 --- a/string/split.hpp +++ b/string/split.hpp @@ -3,16 +3,16 @@ namespace nall { template -auto lstring::_split(rstring source, rstring find, long limit) -> lstring& { +auto lstring::_split(string_view source, string_view find, long limit) -> lstring& { reset(); if(limit <= 0 || find.size() == 0) return *this; const char* p = source.data(); - signed size = source.size(); - signed base = 0; - signed matches = 0; + int size = source.size(); + int base = 0; + int matches = 0; - for(signed n = 0, quoted = 0; n <= size - (signed)find.size();) { + for(int n = 0, quoted = 0; n <= size - (int)find.size();) { if(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } } if(string::_compare(p + n, size - n, find.data(), find.size())) { n++; continue; } if(matches >= limit) break; @@ -33,9 +33,9 @@ auto lstring::_split(rstring source, rstring find, long limit) -> lstring& { return *this; } -auto string::split(rstring on, long limit) const -> lstring { return lstring()._split<0, 0>(*this, on, limit); } -auto string::isplit(rstring on, long limit) const -> lstring { return lstring()._split<1, 0>(*this, on, limit); } -auto string::qsplit(rstring on, long limit) const -> lstring { return lstring()._split<0, 1>(*this, on, limit); } -auto string::iqsplit(rstring on, long limit) const -> lstring { return lstring()._split<1, 1>(*this, on, limit); } +auto string::split(string_view on, long limit) const -> lstring { return lstring()._split<0, 0>(*this, on, limit); } +auto string::isplit(string_view on, long limit) const -> lstring { return lstring()._split<1, 0>(*this, on, limit); } +auto string::qsplit(string_view on, long limit) const -> lstring { return lstring()._split<0, 1>(*this, on, limit); } +auto string::iqsplit(string_view on, long limit) const -> lstring { return lstring()._split<1, 1>(*this, on, limit); } } diff --git a/string/transform/cml.hpp b/string/transform/cml.hpp index 0b99669..c0e9733 100644 --- a/string/transform/cml.hpp +++ b/string/transform/cml.hpp @@ -54,11 +54,11 @@ auto CML::parseDocument(const string& filedata, const string& pathname, uint dep }; for(auto& block : filedata.split("\n\n")) { - lstring lines = block.rstrip().split("\n"); - string name = lines.takeFirst(); + lstring lines = block.stripRight().split("\n"); + string name = lines.takeLeft(); if(name.beginsWith("include ")) { - name.ltrim("include ", 1L); + name.trimLeft("include ", 1L); string filename{pathname, name}; string document = settings.reader ? settings.reader(filename) : string::read(filename); parseDocument(document, nall::pathname(filename), depth + 1); diff --git a/string/transform/dml.hpp b/string/transform/dml.hpp index 9c6f915..32dcf1d 100644 --- a/string/transform/dml.hpp +++ b/string/transform/dml.hpp @@ -61,7 +61,7 @@ auto DML::parseDocument(const string& filedata, const string& pathname, uint dep } auto DML::parseBlock(string& block, const string& pathname, uint depth) -> bool { - if(block.rstrip().empty()) return true; + if(!block.stripRight()) return true; auto lines = block.split("\n"); //include @@ -75,7 +75,7 @@ auto DML::parseBlock(string& block, const string& pathname, uint depth) -> bool 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"); + state.output.append(lines[n].trimLeft(" ", 1L), "\n"); } } @@ -85,22 +85,22 @@ auto DML::parseBlock(string& block, const string& pathname, uint depth) -> bool if(state.sections++) state.output.append(""); state.output.append("

"); } - auto content = lines.takeFirst().ltrim("# ", 1L).split(" => ", 1L); + auto content = lines.takeLeft().trimLeft("# ", 1L).split(" => ", 1L); auto data = markup(content[0]); - auto name = escape(content(1, crc32(data))); + auto name = escape(content(1, data.hash())); state.output.append("
", data); for(auto& line : lines) { if(!line.beginsWith("# ")) continue; - state.output.append("", line.ltrim("# ", 1L), ""); + state.output.append("", line.trimLeft("# ", 1L), ""); } state.output.append("
\n"); } //header else if(auto depth = count(block, '=')) { - auto content = slice(lines.takeFirst(), depth + 1).split(" => ", 1L); + auto content = slice(lines.takeLeft(), depth + 1).split(" => ", 1L); auto data = markup(content[0]); - auto name = escape(content(1, crc32(data))); + auto name = escape(content(1, data.hash())); if(depth <= 6) { state.output.append("", data); for(auto& line : lines) { @@ -121,7 +121,7 @@ auto DML::parseBlock(string& block, const string& pathname, uint depth) -> bool while(level > depth) level--, state.output.append("\n"); auto content = slice(line, depth + 1).split(" => ", 1L); auto data = markup(content[0]); - auto name = escape(content(1, crc32(data))); + auto name = escape(content(1, data.hash())); state.output.append("
  • ", data, "
  • \n"); } } @@ -162,9 +162,9 @@ auto DML::parseBlock(string& block, const string& pathname, uint depth) -> bool state.output.append("
    ");
         for(auto& line : lines) {
           if(!line.beginsWith("  ")) continue;
    -      state.output.append(escape(line.ltrim("  ", 1L)), "\n");
    +      state.output.append(escape(line.trimLeft("  ", 1L)), "\n");
         }
    -    state.output.rtrim("\n", 1L).append("
    \n"); + state.output.trimRight("\n", 1L).append("\n"); } //divider diff --git a/string/trim.hpp b/string/trim.hpp index 35c5ece..17823a7 100644 --- a/string/trim.hpp +++ b/string/trim.hpp @@ -2,19 +2,19 @@ namespace nall { -auto string::trim(rstring lhs, rstring rhs, long limit) -> string& { - rtrim(rhs, limit); - ltrim(lhs, limit); +auto string::trim(string_view lhs, string_view rhs, long limit) -> string& { + trimRight(rhs, limit); + trimLeft(lhs, limit); return *this; } -auto string::ltrim(rstring lhs, long limit) -> string& { +auto string::trimLeft(string_view lhs, long limit) -> string& { if(lhs.size() == 0) return *this; long matches = 0; while(matches < limit) { - signed offset = lhs.size() * matches; - signed length = (signed)size() - offset; - if(length < (signed)lhs.size()) break; + int offset = lhs.size() * matches; + int length = (int)size() - offset; + if(length < (int)lhs.size()) break; if(memory::compare(data() + offset, lhs.data(), lhs.size()) != 0) break; matches++; } @@ -22,13 +22,13 @@ auto string::ltrim(rstring lhs, long limit) -> string& { return *this; } -auto string::rtrim(rstring rhs, long limit) -> string& { +auto string::trimRight(string_view rhs, long limit) -> string& { if(rhs.size() == 0) return *this; long matches = 0; while(matches < limit) { - signed offset = (signed)size() - rhs.size() * (matches + 1); - signed length = (signed)size() - offset; - if(offset < 0 || length < (signed)rhs.size()) break; + int offset = (int)size() - rhs.size() * (matches + 1); + int length = (int)size() - offset; + if(offset < 0 || length < (int)rhs.size()) break; if(memory::compare(data() + offset, rhs.data(), rhs.size()) != 0) break; matches++; } @@ -36,19 +36,19 @@ auto string::rtrim(rstring rhs, long limit) -> string& { return *this; } -auto string::itrim(rstring lhs, rstring rhs, long limit) -> string& { - irtrim(rhs, limit); - iltrim(lhs, limit); +auto string::itrim(string_view lhs, string_view rhs, long limit) -> string& { + itrimRight(rhs, limit); + itrimLeft(lhs, limit); return *this; } -auto string::iltrim(rstring lhs, long limit) -> string& { +auto string::itrimLeft(string_view lhs, long limit) -> string& { if(lhs.size() == 0) return *this; long matches = 0; while(matches < limit) { - signed offset = lhs.size() * matches; - signed length = (signed)size() - offset; - if(length < (signed)lhs.size()) break; + int offset = lhs.size() * matches; + int length = (int)size() - offset; + if(length < (int)lhs.size()) break; if(memory::icompare(data() + offset, lhs.data(), lhs.size()) != 0) break; matches++; } @@ -56,13 +56,13 @@ auto string::iltrim(rstring lhs, long limit) -> string& { return *this; } -auto string::irtrim(rstring rhs, long limit) -> string& { +auto string::itrimRight(string_view rhs, long limit) -> string& { if(rhs.size() == 0) return *this; long matches = 0; while(matches < limit) { - signed offset = (signed)size() - rhs.size() * (matches + 1); - signed length = (signed)size() - offset; - if(offset < 0 || length < (signed)rhs.size()) break; + int offset = (int)size() - rhs.size() * (matches + 1); + int length = (int)size() - offset; + if(offset < 0 || length < (int)rhs.size()) break; if(memory::icompare(data() + offset, rhs.data(), rhs.size()) != 0) break; matches++; } @@ -71,13 +71,13 @@ auto string::irtrim(rstring rhs, long limit) -> string& { } auto string::strip() -> string& { - rstrip(); - lstrip(); + stripRight(); + stripLeft(); return *this; } -auto string::lstrip() -> string& { - unsigned length = 0; +auto string::stripLeft() -> string& { + uint length = 0; while(length < size()) { char input = operator[](length); if(input != ' ' && input != '\t' && input != '\r' && input != '\n') break; @@ -87,8 +87,8 @@ auto string::lstrip() -> string& { return *this; } -auto string::rstrip() -> string& { - unsigned length = 0; +auto string::stripRight() -> string& { + uint length = 0; while(length < size()) { bool matched = false; char input = operator[](size() - length - 1); diff --git a/string/utility.hpp b/string/utility.hpp index 0faa2be..00a5296 100644 --- a/string/utility.hpp +++ b/string/utility.hpp @@ -2,7 +2,7 @@ namespace nall { -auto string::read(rstring filename) -> string { +auto string::read(string_view filename) -> string { #if !defined(_WIN32) FILE* fp = fopen(filename, "rb"); #else @@ -22,7 +22,7 @@ auto string::read(rstring filename) -> string { return fclose(fp), result; } -auto string::repeat(rstring pattern, uint times) -> string { +auto string::repeat(string_view pattern, uint times) -> string { string result; while(times--) result.append(pattern.data()); return result; @@ -33,7 +33,7 @@ auto string::fill(char fill) -> string& { return *this; } -auto string::hash() const -> unsigned { +auto string::hash() const -> uint { const char* p = data(); uint length = size(); uint result = 5381; @@ -82,7 +82,7 @@ auto string::size(int length, char fill) -> string& { return *this; } -auto slice(rstring self, int offset, int length) -> string { +auto slice(string_view self, int offset, int length) -> string { string result; if(offset < self.size()) { if(length < 0) length = self.size() - offset; diff --git a/string/view.hpp b/string/view.hpp index 2f72337..0c8a175 100644 --- a/string/view.hpp +++ b/string/view.hpp @@ -2,87 +2,84 @@ namespace nall { -struct string_view { - string_view() { - _string = nullptr; - _data = ""; - _size = 0; - } +string_view::string_view() { + _string = nullptr; + _data = ""; + _size = 0; +} - string_view(const char* data) { - _string = nullptr; - _data = data; - _size = -1; //defer length calculation, as it is often unnecessary - } +string_view::string_view(const string_view& source) { + if(this == &source) return; + _string = nullptr; + _data = source._data; + _size = source._size; +} - string_view(const char* data, unsigned size) { - _string = nullptr; - _data = data; - _size = size; - } +string_view::string_view(string_view&& source) { + if(this == &source) return; + _string = source._string; + _data = source._data; + _size = source._size; + source._string = nullptr; +} - string_view(const string& source) { - _string = nullptr; - _data = source.data(); - _size = source.size(); - } +string_view::string_view(const char* data) { + _string = nullptr; + _data = data; + _size = -1; //defer length calculation, as it is often unnecessary +} - template - string_view(P&&... p) { - _string = new string{forward

    (p)...}; - _data = _string->data(); - _size = _string->size(); - } +string_view::string_view(const char* data, uint size) { + _string = nullptr; + _data = data; + _size = size; +} - ~string_view() { - if(_string) delete _string; - } +string_view::string_view(const string& source) { + _string = nullptr; + _data = source.data(); + _size = source.size(); +} - string_view(const string_view& source) { - _string = nullptr; - _data = source._data; - _size = source._size; - } +template +string_view::string_view(P&&... p) { + _string = new string{forward

    (p)...}; + _data = _string->data(); + _size = _string->size(); +} - string_view(string_view&& source) { - _string = source._string; - _data = source._data; - _size = source._size; - source._string = nullptr; - } +string_view::~string_view() { + if(_string) delete _string; +} - auto operator=(const string_view& source) -> string_view& { - _string = nullptr; - _data = source._data; - _size = source._size; - return *this; - }; - - auto operator=(string_view&& source) -> string_view& { - _string = source._string; - _data = source._data; - _size = source._size; - source._string = nullptr; - return *this; - }; - - operator const char*() const { - return _data; - } - - auto data() const -> const char* { - return _data; - } - - auto size() const -> unsigned { - if(_size < 0) _size = strlen(_data); - return _size; - } - -protected: - string* _string; - const char* _data; - mutable signed _size; +auto string_view::operator=(const string_view& source) -> string_view& { + if(this == &source) return *this; + _string = nullptr; + _data = source._data; + _size = source._size; + return *this; }; +auto string_view::operator=(string_view&& source) -> string_view& { + if(this == &source) return *this; + _string = source._string; + _data = source._data; + _size = source._size; + source._string = nullptr; + return *this; +}; + +string_view::operator const char*() const { + return _data; +} + +auto string_view::data() const -> const char* { + return _data; +} + +auto string_view::size() const -> uint { + if(_size < 0) _size = strlen(_data); + return _size; +} + } diff --git a/thread.hpp b/thread.hpp index a01624b..fd33e2d 100644 --- a/thread.hpp +++ b/thread.hpp @@ -19,13 +19,13 @@ namespace nall { struct thread { inline auto join() -> void; - static inline auto create(const function& callback, uintptr_t parameter = 0, unsigned stacksize = 0) -> thread; + static inline auto create(const function& callback, uintptr parameter = 0, uint stacksize = 0) -> thread; static inline auto detach() -> void; static inline auto exit() -> void; struct context { - function callback; - uintptr_t parameter = 0; + function void> callback; + uintptr parameter = 0; }; private: @@ -43,7 +43,7 @@ auto thread::join() -> void { pthread_join(handle, nullptr); } -auto thread::create(const function& callback, uintptr_t parameter, unsigned stacksize) -> thread { +auto thread::create(const function& callback, uintptr parameter, uint stacksize) -> thread { thread instance; auto context = new thread::context; @@ -76,13 +76,13 @@ struct thread { inline ~thread(); inline auto join() -> void; - static inline auto create(const function& callback, uintptr_t parameter = 0, unsigned stacksize = 0) -> thread; + static inline auto create(const function& callback, uintptr parameter = 0, uint stacksize = 0) -> thread; static inline auto detach() -> void; static inline auto exit() -> void; struct context { - function callback; - uintptr_t parameter = 0; + function void> callback; + uintptr parameter = 0; }; private: @@ -111,7 +111,7 @@ auto thread::join() -> void { } } -auto thread::create(const function& callback, uintptr_t parameter, unsigned stacksize) -> thread { +auto thread::create(const function& callback, uintptr parameter, uint stacksize) -> thread { thread instance; auto context = new thread::context; diff --git a/utility.hpp b/utility.hpp index ac1d13e..23abcc8 100644 --- a/utility.hpp +++ b/utility.hpp @@ -9,9 +9,9 @@ template struct base_from_member { T value; }; -template inline auto allocate(unsigned size, const T& value) -> T* { +template inline auto allocate(uint size, const T& value) -> T* { T* array = new T[size]; - for(unsigned i = 0; i < size; i++) array[i] = value; + for(uint i = 0; i < size; i++) array[i] = value; return array; } diff --git a/varint.hpp b/varint.hpp index f684bf4..ee18a03 100644 --- a/varint.hpp +++ b/varint.hpp @@ -10,8 +10,8 @@ struct varint { virtual auto read() -> uint8_t = 0; virtual auto write(uint8_t) -> void = 0; - auto readvu() -> uintmax_t { - uintmax_t data = 0, shift = 1; + auto readvu() -> uintmax { + uintmax data = 0, shift = 1; while(true) { uint8_t x = read(); data += (x & 0x7f) * shift; @@ -22,15 +22,15 @@ struct varint { return data; } - auto readvs() -> intmax_t { - uintmax_t data = readvu(); + auto readvs() -> intmax { + uintmax data = readvu(); bool negate = data & 1; data >>= 1; if(negate) data = ~data; return data; } - auto writevu(uintmax_t data) -> void { + auto writevu(uintmax data) -> void { while(true) { uint8_t x = data & 0x7f; data >>= 7; @@ -40,7 +40,7 @@ struct varint { } } - auto writevs(intmax_t data) -> void { + auto writevs(intmax data) -> void { bool negate = data < 0; if(negate) data = ~data; data = (data << 1) | negate; diff --git a/vector.hpp b/vector.hpp index 73c7d36..ad3d0ed 100644 --- a/vector.hpp +++ b/vector.hpp @@ -1,282 +1,109 @@ #pragma once -#include -#include #include -#include -#include + #include +#include #include #include +#include #include -#include +#include namespace nall { -template struct vector { - struct exception_out_of_bounds{}; +template struct vector_iterator; +template struct vector_iterator_const; - explicit operator bool() const { return objectsize; } - auto data() -> T* { return pool + poolbase; } - auto data() const -> const T* { return pool + poolbase; } - - auto empty() const -> bool { return objectsize == 0; } - auto size() const -> unsigned { return objectsize; } - auto capacity() const -> unsigned { return poolsize; } - - auto release() -> T* { - T* result = pool + poolbase; - pool = nullptr; - poolbase = 0; - poolsize = 0; - objectsize = 0; - return result; - } - - auto reset() -> void { - if(pool) { - for(unsigned n = 0; n < objectsize; n++) pool[poolbase + n].~T(); - memory::free(pool); - } - pool = nullptr; - poolbase = 0; - poolsize = 0; - objectsize = 0; - } - - auto reserve(unsigned size) -> void { - if(size <= poolsize) return; - size = bit::round(size); //amortize growth - - T* copy = (T*)memory::allocate(size * sizeof(T)); - for(unsigned n = 0; n < objectsize; n++) new(copy + n) T(move(pool[poolbase + n])); - free(pool); - pool = copy; - poolbase = 0; - poolsize = size; - } - - auto resize(unsigned size, T value = T()) -> void { - T* copy = (T*)memory::allocate(size * sizeof(T)); - for(unsigned n = 0; n < size && n < objectsize; n++) new(copy + n) T(move(pool[poolbase + n])); - for(unsigned n = objectsize; n < size; n++) new(copy + n) T(value); - reset(); - pool = copy; - poolbase = 0; - poolsize = size; - objectsize = size; - } - - auto reallocate(unsigned size, T value = T()) -> void { - reset(); - resize(size, value); - } - - template auto prepend(const T& data, Args&&... args) -> void { - prepend(forward(args)...); - prepend(data); - } - - auto prepend(const T& data) -> T& { - reserve(objectsize + 1); - if(poolbase == 0) { - unsigned available = poolsize - objectsize; - poolbase = max(1u, available >> 1); - for(signed n = objectsize - 1; n >= 0; n--) { - pool[poolbase + n] = move(pool[n]); - } - } - new(pool + --poolbase) T(data); - objectsize++; - return first(); - } - - template auto append(const T& data, Args&&... args) -> void { - append(data); - append(forward(args)...); - } - - auto append(const T& data) -> T& { - reserve(poolbase + objectsize + 1); - new(pool + poolbase + objectsize++) T(data); - return last(); - } - - auto appendOnce(const T& data) -> bool { - if(find(data)) return false; - return append(data), true; - } - - auto insert(unsigned position, const T& data) -> void { - if(position == 0) { - prepend(data); - return; - } - append(data); - if(position == ~0u) return; - for(signed n = objectsize - 1; n > position; n--) { - pool[poolbase + n] = move(pool[poolbase + n - 1]); - } - pool[poolbase + position] = data; - } - - auto remove(unsigned position = ~0u, unsigned length = 1) -> void { - if(position == ~0u) position = objectsize - 1; - if(position + length > objectsize) throw exception_out_of_bounds{}; - - if(position == 0) { - for(unsigned n = 0; n < length; n++) pool[poolbase + n].~T(); - poolbase += length; - } else { - for(unsigned n = position; n < objectsize; n++) { - if(n + length < objectsize) { - pool[poolbase + n] = move(pool[poolbase + n + length]); - } else { - pool[poolbase + n].~T(); - } - } - } - objectsize -= length; - } - - auto removeFirst() -> void { return remove(0); } - auto removeLast() -> void { return remove(~0u); } - - auto take(unsigned position = ~0u) -> T { - if(position == ~0u) position = objectsize - 1; - T object = pool[poolbase + position]; - remove(position); - return object; - } - - auto takeFirst() -> T { return take(0); } - auto takeLast() -> T { return take(~0u); } - - auto reverse() -> void { - unsigned pivot = size() / 2; - for(unsigned l = 0, r = size() - 1; l < pivot; l++, r--) { - swap(pool[poolbase + l], pool[poolbase + r]); - } - } - - auto sort(const function& comparator = [](const T& lhs, const T& rhs) -> bool { - return lhs < rhs; - }) -> void { - nall::sort(pool + poolbase, objectsize, comparator); - } - - auto find(const T& data) const -> maybe { - for(unsigned n = 0; n < objectsize; n++) if(pool[poolbase + n] == data) return n; - return nothing; - } - - auto first() -> T& { - if(objectsize == 0) throw exception_out_of_bounds(); - return pool[poolbase]; - } - - auto first() const -> const T& { - if(objectsize == 0) throw exception_out_of_bounds(); - return pool[poolbase]; - } - - auto last() -> T& { - if(objectsize == 0) throw exception_out_of_bounds(); - return pool[poolbase + objectsize - 1]; - } - - auto last() const -> const T& { - if(objectsize == 0) throw exception_out_of_bounds(); - return pool[poolbase + objectsize - 1]; - } - - //access - inline auto operator[](unsigned position) -> T& { - if(position >= objectsize) throw exception_out_of_bounds(); - return pool[poolbase + position]; - } - - inline auto operator[](unsigned position) const -> const T& { - if(position >= objectsize) throw exception_out_of_bounds(); - return pool[poolbase + position]; - } - - inline auto operator()(unsigned position) -> T& { - if(position >= poolsize) reserve(position + 1); - while(position >= objectsize) append(T()); - return pool[poolbase + position]; - } - - inline auto operator()(unsigned position, const T& data) const -> const T& { - if(position >= objectsize) return data; - return pool[poolbase + position]; - } - - //iteration - struct iterator { - iterator(vector& source, unsigned position) : source(source), position(position) {} - auto operator*() -> T& { return source.operator[](position); } - auto operator!=(const iterator& source) const -> bool { return position != source.position; } - auto operator++() -> iterator& { position++; return *this; } - - private: - vector& source; - unsigned position; - }; - - auto begin() -> iterator { return iterator(*this, 0); } - auto end() -> iterator { return iterator(*this, size()); } - - struct constIterator { - constIterator(const vector& source, unsigned position) : source(source), position(position) {} - auto operator*() const -> const T& { return source.operator[](position); } - auto operator!=(const constIterator& source) const -> bool { return position != source.position; } - auto operator++() -> constIterator& { position++; return *this; } - - private: - const vector& source; - unsigned position; - }; - - auto begin() const -> const constIterator { return constIterator(*this, 0); } - auto end() const -> const constIterator { return constIterator(*this, size()); } - - //copy - inline auto operator=(const vector& source) -> vector& { - if(this == &source) return *this; - reset(); - reserve(source.size()); - for(auto& data : source) append(data); - return *this; - } - - //move - inline auto operator=(vector&& source) -> vector& { - if(this == &source) return *this; - reset(); - pool = source.pool; - poolbase = source.poolbase; - poolsize = source.poolsize; - objectsize = source.objectsize; - source.pool = nullptr; - source.poolbase = 0; - source.poolsize = 0; - source.objectsize = 0; - return *this; - } - - //construction and destruction +template +struct vector { + //core.hpp vector() = default; - vector(initializer_list list) { for(auto& data : list) append(data); } - vector(const vector& source) { operator=(source); } - vector(vector&& source) { operator=(move(source)); } - ~vector() { reset(); } + vector(const initializer_list& values); + vector(const vector& source); + vector(vector&& source); + ~vector(); -protected: - T* pool = nullptr; - unsigned poolbase = 0; - unsigned poolsize = 0; - unsigned objectsize = 0; + explicit operator bool() const; + auto capacity() const -> uint; + auto size() const -> uint; + auto data() -> T*; + auto data() const -> const T*; + + //assign.hpp + auto operator=(const vector& source) -> vector&; + auto operator=(vector&& source) -> vector&; + + //memory.hpp + auto reset() -> void; + auto release() -> T*; + + auto reserveLeft(uint capacity) -> bool; + auto reserveRight(uint capacity) -> bool; + auto reserve(uint capacity) -> bool { return reserveRight(capacity); } + + auto resizeLeft(uint size, const T& value = T()) -> bool; + auto resizeRight(uint size, const T& value = T()) -> bool; + auto resize(uint size, const T& value = T()) -> bool { return resizeRight(size, value); } + + //access.hpp + alwaysinline auto operator[](uint offset) -> T&; + alwaysinline auto operator[](uint offset) const -> const T&; + + alwaysinline auto operator()(uint offset) -> T&; + alwaysinline auto operator()(uint offset, const T& value) const -> const T&; + + alwaysinline auto left() -> T&; + alwaysinline auto left() const -> const T&; + + alwaysinline auto right() -> T&; + alwaysinline auto right() const -> const T&; + + //modify.hpp + auto prepend(const T& value) -> void; + auto prepend(T&& value) -> void; + auto prepend(const vector& values) -> void; + auto prepend(vector&& values) -> void; + + auto append(const T& value) -> void; + auto append(T&& value) -> void; + auto append(const vector& values) -> void; + auto append(vector&& values) -> void; + + auto insert(uint offset, const T& value) -> void; + + auto removeLeft(uint length = 1) -> void; + auto removeRight(uint length = 1) -> void; + auto remove(uint offset, uint length = 1) -> void; + + auto takeLeft() -> T; + auto takeRight() -> T; + auto take(uint offset) -> T; + + //iterator.hpp + auto begin() { return vector_iterator{*this, 0}; } + auto end() { return vector_iterator{*this, size()}; } + + auto begin() const { return vector_iterator_const{*this, 0}; } + auto end() const { return vector_iterator_const{*this, size()}; } + + //utility.hpp + auto sort(const function& comparator = [](auto& lhs, auto& rhs) { return lhs < rhs; }) -> void; + auto find(const T& value) const -> maybe; + +private: + T* _pool = nullptr; //pointer to first initialized element in pool + uint _size = 0; //number of initialized elements in pool + uint _left = 0; //number of allocated elements free on the left of pool + uint _right = 0; //number of allocated elements free on the right of pool }; } + +#include +#include +#include +#include +#include +#include +#include diff --git a/vector/access.hpp b/vector/access.hpp new file mode 100644 index 0000000..4867c1b --- /dev/null +++ b/vector/access.hpp @@ -0,0 +1,39 @@ +#pragma once + +namespace nall { + +template auto vector::operator[](uint offset) -> T& { + return _pool[offset]; +} + +template auto vector::operator[](uint offset) const -> const T& { + return _pool[offset]; +} + +template auto vector::operator()(uint offset) -> T& { + while(offset >= size()) append(T()); + return _pool[offset]; +} + +template auto vector::operator()(uint offset, const T& value) const -> const T& { + if(offset >= size()) return value; + return _pool[offset]; +} + +template auto vector::left() -> T& { + return _pool[0]; +} + +template auto vector::left() const -> const T& { + return _pool[0]; +} + +template auto vector::right() -> T& { + return _pool[_size - 1]; +} + +template auto vector::right() const -> const T& { + return _pool[_size - 1]; +} + +} diff --git a/vector/assign.hpp b/vector/assign.hpp new file mode 100644 index 0000000..d13eca5 --- /dev/null +++ b/vector/assign.hpp @@ -0,0 +1,28 @@ +#pragma once + +namespace nall { + +template auto vector::operator=(const vector& source) -> vector& { + if(this == &source) return *this; + _pool = (T*)memory::allocate(sizeof(T) * source._size); + _size = source._size; + _left = 0; + _right = 0; + for(uint n : range(_size)) new(_pool + n) T(source._pool[n]); + return *this; +} + +template auto vector::operator=(vector&& source) -> vector& { + if(this == &source) return *this; + _pool = source._pool; + _size = source._size; + _left = source._left; + _right = source._right; + source._pool = nullptr; + source._size = 0; + source._left = 0; + source._right = 0; + return *this; +} + +} diff --git a/vector/core.hpp b/vector/core.hpp new file mode 100644 index 0000000..0073b89 --- /dev/null +++ b/vector/core.hpp @@ -0,0 +1,42 @@ +#pragma once + +namespace nall { + +template vector::vector(const initializer_list& values) { + reserveRight(values.size()); + for(auto& value : values) append(value); +} + +template vector::vector(const vector& source) { + operator=(source); +} + +template vector::vector(vector&& source) { + operator=(move(source)); +} + +template vector::~vector() { + reset(); +} + +template vector::operator bool() const { + return _size; +} + +template auto vector::capacity() const -> uint { + return _left + _size + _right; +} + +template auto vector::size() const -> uint { + return _size; +} + +template auto vector::data() -> T* { + return _pool; +} + +template auto vector::data() const -> const T* { + return _pool; +} + +} diff --git a/vector/iterator.hpp b/vector/iterator.hpp new file mode 100644 index 0000000..641a1c5 --- /dev/null +++ b/vector/iterator.hpp @@ -0,0 +1,37 @@ +#pragma once + +namespace nall { + +template +struct vector_iterator { + vector_iterator(vector& self, uint offset) : self(self), offset(offset) {} + auto operator*() -> T& { return self.operator[](offset); } + auto operator!=(const vector_iterator& source) const -> bool { return offset != source.offset; } + auto operator++() -> vector_iterator& { return offset++, *this; } + +private: + vector& self; + uint offset; +}; + +template +struct vector_iterator_const { + vector_iterator_const(const vector& self, uint offset) : self(self), offset(offset) {} + auto operator*() -> const T& { return self.operator[](offset); } + auto operator!=(const vector_iterator_const& source) const -> bool { return offset != source.offset; } + auto operator++() -> vector_iterator_const& { return offset++, *this; } + +private: + const vector& self; + uint offset; +}; + +template inline auto range(const vector& container) { + return range_t{0, (int)container.size(), 1}; +} + +template inline auto rrange(const vector& container) { + return range_t{(int)container.size() - 1, -1, -1}; +} + +} diff --git a/vector/memory.hpp b/vector/memory.hpp new file mode 100644 index 0000000..e177787 --- /dev/null +++ b/vector/memory.hpp @@ -0,0 +1,90 @@ +#pragma once + +namespace nall { + +template auto vector::reset() -> void { + if(!_pool) return; + + for(uint n : range(_size)) _pool[n].~T(); + memory::free(_pool - _left); + + _pool = nullptr; + _size = 0; + _left = 0; + _right = 0; +} + +template auto vector::release() -> T* { + auto pool = _pool; + _pool = nullptr; + _size = 0; + _left = 0; + _right = 0; + return pool; +} + +template auto vector::reserveLeft(uint capacity) -> bool { + if(_size + _left >= capacity) return false; + + uint left = bit::round(capacity); + auto pool = (T*)memory::allocate(sizeof(T) * (left + _right)) + (left - _size); + for(uint n : range(_size)) new(pool + n) T(move(_pool[n])); + memory::free(_pool - _left); + + _pool = pool; + _left = left - _size; + + return true; +} + +template auto vector::reserveRight(uint capacity) -> bool { + if(_size + _right >= capacity) return false; + + uint right = bit::round(capacity); + auto pool = (T*)memory::allocate(sizeof(T) * (_left + right)) + _left; + for(uint n : range(_size)) new(pool + n) T(move(_pool[n])); + memory::free(_pool - _left); + + _pool = pool; + _right = right - _size; + + return true; +} + +template auto vector::resizeLeft(uint size, const T& value) -> bool { + if(size < _size) { //shrink + for(uint n : range(_size - size)) _pool[n].~T(); + _pool += _size - size; + _left += _size - size; + _size = size; + return true; + } + if(size > _size) { //grow + reserveLeft(size); + _pool -= size - _size; + for(uint n : rrange(size - _size)) new(_pool + n) T(value); + _left -= size - _size; + _size = size; + return true; + } + return false; +} + +template auto vector::resizeRight(uint size, const T& value) -> bool { + if(size < _size) { //shrink + for(uint n : range(size, _size)) _pool[n].~T(); + _right += _size - size; + _size = size; + return true; + } + if(size > _size) { //grow + reserveRight(size); + for(uint n : range(_size, size)) new(_pool + n) T(value); + _right -= size - _size; + _size = size; + return true; + } + return false; +} + +} diff --git a/vector/modify.hpp b/vector/modify.hpp new file mode 100644 index 0000000..402429b --- /dev/null +++ b/vector/modify.hpp @@ -0,0 +1,127 @@ +#pragma once + +namespace nall { + +template auto vector::prepend(const T& value) -> void { + reserveLeft(size() + 1); + new(--_pool) T(value); + _left--; + _size++; +} + +template auto vector::prepend(T&& value) -> void { + reserveLeft(size() + 1); + new(--_pool) T(move(value)); + _left--; + _size++; +} + +template auto vector::prepend(const vector& values) -> void { + reserveLeft(size() + values.size()); + _pool -= values.size(); + for(uint n : range(values)) new(_pool + n) T(values[n]); + _left -= values.size(); + _size += values.size(); +} + +template auto vector::prepend(vector&& values) -> void { + reserveLeft(size() + values.size()); + _pool -= values.size(); + for(uint n : range(values)) new(_pool + n) T(move(values[n])); + _left -= values.size(); + _size += values.size(); +} + +// + +template auto vector::append(const T& value) -> void { + reserveRight(size() + 1); + new(_pool + _size) T(value); + _right--; + _size++; +} + +template auto vector::append(T&& value) -> void { + reserveRight(size() + 1); + new(_pool + _size) T(move(value)); + _right--; + _size++; +} + +template auto vector::append(const vector& values) -> void { + reserveRight(size() + values.size()); + for(uint n : range(values)) new(_pool + _size + n) T(values[n]); + _right -= values.size(); + _size += values.size(); +} + +template auto vector::append(vector&& values) -> void { + reserveRight(size() + values.size()); + for(uint n : range(values)) new(_pool + _size + n) T(move(values[n])); + _right -= values.size(); + _size += values.size(); +} + +// + +template auto vector::insert(uint offset, const T& value) -> void { + if(offset == 0) return prepend(value); + if(offset == size() - 1) return append(value); + reserveRight(size() + 1); + _size++; + for(int n = size() - 1; n > offset; n--) { + _pool[n] = move(_pool[n - 1]); + } + new(_pool + offset) T(value); +} + +// + +template auto vector::removeLeft(uint length) -> void { + if(length > size()) length = size(); + resizeLeft(size() - length); +} + +template auto vector::removeRight(uint length) -> void { + if(length > size()) length = size(); + resizeRight(size() - length); +} + +template auto vector::remove(uint offset, uint length) -> void { + if(offset == 0) return removeLeft(length); + if(offset == size() - 1) return removeRight(length); + + for(uint n = offset; n < size(); n++) { + if(n + length < size()) { + _pool[n] = move(_pool[n + length]); + } else { + _pool[n].~T(); + } + } + _size -= length; +} + +// + +template auto vector::takeLeft() -> T { + T value = move(_pool[0]); + removeLeft(); + return value; +} + +template auto vector::takeRight() -> T { + T value = move(_pool[size() - 1]); + removeRight(); + return value; +} + +template auto vector::take(uint offset) -> T { + if(offset == 0) return takeLeft(); + if(offset == size() - 1) return takeRight(); + + T value = move(_pool[offset]); + remove(offset); + return value; +} + +} diff --git a/vector/utility.hpp b/vector/utility.hpp new file mode 100644 index 0000000..1cb2b6e --- /dev/null +++ b/vector/utility.hpp @@ -0,0 +1,14 @@ +#pragma once + +namespace nall { + +template auto vector::sort(const function& comparator) -> void { + nall::sort(_pool, _size, comparator); +} + +template auto vector::find(const T& value) const -> maybe { + for(uint n : range(size())) if(_pool[n] == value) return n; + return nothing; +} + +} diff --git a/vfs.hpp b/vfs.hpp new file mode 100644 index 0000000..8039678 --- /dev/null +++ b/vfs.hpp @@ -0,0 +1,3 @@ +#pragma once + +#include diff --git a/vfs/fs/file.hpp b/vfs/fs/file.hpp new file mode 100644 index 0000000..d899a43 --- /dev/null +++ b/vfs/fs/file.hpp @@ -0,0 +1,51 @@ +#pragma once + +#include + +namespace nall { namespace vfs { namespace fs { + +struct file : vfs::file { + static auto open(string location_, mode mode_) -> vfs::shared::file { + auto instance = shared_pointer{new file}; + if(!instance->_open(location_, mode_)) return {}; + return instance; + } + + auto size() const -> uintmax override { + return _fp.size(); + } + + auto offset() const -> uintmax override { + return _fp.offset(); + } + + auto seek(intmax offset_, index index_) -> void override { + _fp.seek(offset_, (nall::file::index)index_); + } + + auto read() -> uint8_t override { + return _fp.read(); + } + + auto write(uint8_t data_) -> void override { + _fp.write(data_); + } + + auto flush() -> void override { + _fp.flush(); + } + +private: + file() = default; + file(const file&) = delete; + auto operator=(const file&) -> file& = delete; + + auto _open(string location_, mode mode_) -> bool { + if(!_fp.open(location_, (nall::file::mode)mode_)) return false; + return true; + } + + nall::file _fp; +}; + +}}} diff --git a/vfs/memory/file.hpp b/vfs/memory/file.hpp new file mode 100644 index 0000000..4f9afa2 --- /dev/null +++ b/vfs/memory/file.hpp @@ -0,0 +1,48 @@ +#pragma once + +namespace nall { namespace vfs { namespace memory { + +struct file : vfs::file { + ~file() { delete[] _data; } + + static auto open(const uint8_t* data, uintmax size) -> vfs::shared::file { + auto instance = shared_pointer{new file}; + instance->_open(data, size); + return instance; + } + + auto size() const -> uintmax override { return _size; } + auto offset() const -> uintmax override { return _offset; } + + auto seek(intmax offset, index mode) -> void override { + if(mode == index::absolute) _offset = (uintmax)offset; + if(mode == index::relative) _offset += (intmax)offset; + } + + auto read() -> uint8_t override { + if(_offset >= _size) return 0x00; + return _data[_offset++]; + } + + auto write(uint8_t data) -> void override { + if(_offset >= _size) return; + _data[_offset++] = data; + } + +private: + file() = default; + file(const file&) = delete; + auto operator=(const file&) -> file& = delete; + + auto _open(const uint8_t* data, uintmax size) -> void { + _size = size; + _data = new uint8_t[size]; + nall::memory::copy(_data, data, size); + } + + uint8_t* _data = nullptr; + uintmax _size = 0; + uintmax _offset = 0; +}; + +}}} diff --git a/vfs/vfs.hpp b/vfs/vfs.hpp new file mode 100644 index 0000000..b1589bb --- /dev/null +++ b/vfs/vfs.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include +#include + +namespace nall { namespace vfs { + +struct file { + enum class mode : uint { read, write, modify, create }; + enum class index : uint { absolute, relative }; + + virtual ~file() = default; + + virtual auto size() const -> uintmax = 0; + virtual auto offset() const -> uintmax = 0; + + virtual auto seek(intmax offset, index = index::absolute) -> void = 0; + virtual auto read() -> uint8_t = 0; + virtual auto write(uint8_t data) -> void = 0; + virtual auto flush() -> void {} + + auto end() const -> bool { + return offset() >= size(); + } + + auto read(void* vdata, uintmax bytes) -> void { + auto data = (uint8_t*)vdata; + while(bytes--) *data++ = read(); + } + + auto readl(uint bytes) -> uintmax { + uintmax data = 0; + for(auto n : range(bytes)) data |= (uintmax)read() << n * 8; + return data; + } + + auto readm(uint bytes) -> uintmax { + uintmax data = 0; + for(auto n : range(bytes)) data = data << 8 | read(); + return data; + } + + auto reads() -> string { + string s; + s.resize(size()); + read(s.get(), s.size()); + return s; + } + + auto write(const void* vdata, uintmax bytes) -> void { + auto data = (const uint8_t*)vdata; + while(bytes--) write(*data++); + } + + auto writel(uintmax data, uint bytes) -> void { + for(auto n : range(bytes)) write(data), data >>= 8; + } + + auto writem(uintmax data, uint bytes) -> void { + for(auto n : rrange(bytes)) write(data >> n * 8); + } + + auto writes(const string& s) -> void { + write(s.data(), s.size()); + } +}; + +}} + +namespace nall { namespace vfs { namespace shared { + using file = shared_pointer; +}}} + +#include +#include diff --git a/windows/detour.hpp b/windows/detour.hpp index 6e57a59..bedb190 100644 --- a/windows/detour.hpp +++ b/windows/detour.hpp @@ -74,7 +74,7 @@ auto detour::insert(const string& moduleName, const string& functionName, void*& #if 1 string output = {"detour::insert(", moduleName, "::", functionName, ") failed: "}; for(uint n = 0; n < 16; n++) output.append(hex<2>(sourceData[n]), " "); - output.rtrim(" ", 1L); + output.trimRight(" ", 1L); MessageBoxA(0, output, "nall::detour", MB_OK); #endif return false; diff --git a/windows/guid.hpp b/windows/guid.hpp index 056c7ae..314683d 100644 --- a/windows/guid.hpp +++ b/windows/guid.hpp @@ -1,27 +1,17 @@ #pragma once -#include #include namespace nall { -//generate unique GUID inline auto guid() -> string { - LinearFeedbackShiftRegisterGenerator lfsr; - lfsr.seed(time(nullptr)); - for(uint n = 0; n < 256; n++) lfsr(); + GUID guidInstance; + CoCreateGuid(&guidInstance); - string output; - for(uint n = 0; n < 4; n++) output.append(hex(lfsr(), 2L)); - output.append("-"); - for(uint n = 0; n < 2; n++) output.append(hex(lfsr(), 2L)); - output.append("-"); - for(uint n = 0; n < 2; n++) output.append(hex(lfsr(), 2L)); - output.append("-"); - for(uint n = 0; n < 2; n++) output.append(hex(lfsr(), 2L)); - output.append("-"); - for(uint n = 0; n < 6; n++) output.append(hex(lfsr(), 2L)); - return {"{", output, "}"}; + wchar_t guidString[39]; + StringFromGUID2(guidInstance, guidString, 39); + + return (char*)utf8_t(guidString); } } diff --git a/windows/registry.hpp b/windows/registry.hpp index cd5767d..97f3f35 100644 --- a/windows/registry.hpp +++ b/windows/registry.hpp @@ -25,8 +25,8 @@ namespace nall { struct registry { static auto exists(const string& name) -> bool { lstring part = name.split("/"); - HKEY handle, rootKey = root(part.take(0)); - string node = part.take(); + HKEY handle, rootKey = root(part.takeLeft()); + string node = part.takeRight(); string path = part.merge("\\"); if(RegOpenKeyExW(rootKey, utf16_t(path), 0, NWR_FLAGS | KEY_READ, &handle) == ERROR_SUCCESS) { wchar_t data[NWR_SIZE] = L""; @@ -40,8 +40,8 @@ struct registry { static auto read(const string& name) -> string { lstring part = name.split("/"); - HKEY handle, rootKey = root(part.take(0)); - string node = part.take(); + HKEY handle, rootKey = root(part.takeLeft()); + string node = part.takeRight(); string path = part.merge("\\"); if(RegOpenKeyExW(rootKey, utf16_t(path), 0, NWR_FLAGS | KEY_READ, &handle) == ERROR_SUCCESS) { wchar_t data[NWR_SIZE] = L""; @@ -55,8 +55,8 @@ struct registry { static auto write(const string& name, const string& data = "") -> void { lstring part = name.split("/"); - HKEY handle, rootKey = root(part.take(0)); - string node = part.take(), path; + HKEY handle, rootKey = root(part.takeLeft()); + string node = part.takeRight(), path; DWORD disposition; for(uint n = 0; n < part.size(); n++) { path.append(part[n]); @@ -72,17 +72,17 @@ struct registry { static auto remove(const string& name) -> bool { lstring part = name.split("/"); - HKEY rootKey = root(part.take(0)); - string node = part.take(); + HKEY rootKey = root(part.takeLeft()); + string node = part.takeRight(); string path = part.merge("\\"); - if(node.empty()) return SHDeleteKeyW(rootKey, utf16_t(path)) == ERROR_SUCCESS; + if(!node) return SHDeleteKeyW(rootKey, utf16_t(path)) == ERROR_SUCCESS; return SHDeleteValueW(rootKey, utf16_t(path), utf16_t(node)) == ERROR_SUCCESS; } static auto contents(const string& name) -> lstring { lstring part = name.split("/"), result; - HKEY handle, rootKey = root(part.take(0)); - part.remove(); + HKEY handle, rootKey = root(part.takeLeft()); + part.removeRight(); string path = part.merge("\\"); if(RegOpenKeyExW(rootKey, utf16_t(path), 0, NWR_FLAGS | KEY_READ, &handle) == ERROR_SUCCESS) { DWORD folders, nodes; diff --git a/windows/utf8.hpp b/windows/utf8.hpp index 9944a23..8ee26ac 100644 --- a/windows/utf8.hpp +++ b/windows/utf8.hpp @@ -77,7 +77,7 @@ namespace nall { inline auto utf8_args(int& argc, char**& argv) -> void { wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc); - argv = new char*[argc]; + argv = new char*[argc + 1](); for(uint i = 0; i < argc; i++) { argv[i] = new char[PATH_MAX]; strcpy(argv[i], nall::utf8_t(wargv[i]));