updated to higan v099r13 release
This commit is contained in:
parent
ec42524237
commit
285fc3a7f6
116 changed files with 2424 additions and 3193 deletions
1
any.hpp
1
any.hpp
|
@ -13,7 +13,6 @@ struct any {
|
||||||
~any() { reset(); }
|
~any() { reset(); }
|
||||||
|
|
||||||
explicit operator bool() const { return container; }
|
explicit operator bool() const { return container; }
|
||||||
auto empty() const -> bool { return !container; }
|
|
||||||
auto reset() -> void { if(container) { delete container; container = nullptr; } }
|
auto reset() -> void { if(container) { delete container; container = nullptr; } }
|
||||||
|
|
||||||
auto type() const -> const std::type_info& {
|
auto type() const -> const std::type_info& {
|
||||||
|
|
|
@ -31,7 +31,7 @@ auto Archive::create(const string& beatname, const string& pathname, const strin
|
||||||
bool directory = name.endsWith("/");
|
bool directory = name.endsWith("/");
|
||||||
bool writable = inode::writable(location);
|
bool writable = inode::writable(location);
|
||||||
bool executable = inode::executable(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.writevu(info);
|
||||||
beat.writes(name);
|
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 {
|
auto Archive::scan(lstring& result, const string& basename, const string& pathname) -> void {
|
||||||
for(auto& name : directory::contents(pathname)) {
|
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});
|
if(name.endsWith("/")) scan(result, basename, {pathname, name});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <nall/filemap.hpp>
|
#include <nall/filemap.hpp>
|
||||||
#include <nall/stdint.hpp>
|
#include <nall/stdint.hpp>
|
||||||
#include <nall/string.hpp>
|
#include <nall/string.hpp>
|
||||||
|
#include <nall/hash/crc32.hpp>
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ struct bpsmulti {
|
||||||
|
|
||||||
for(auto& targetName : targetList) {
|
for(auto& targetName : targetList) {
|
||||||
if(targetName.endsWith("/")) {
|
if(targetName.endsWith("/")) {
|
||||||
targetName.rtrim("/");
|
targetName.trimRight("/");
|
||||||
writeNumber(CreatePath | ((targetName.length() - 1) << 2));
|
writeNumber(CreatePath | ((targetName.length() - 1) << 2));
|
||||||
writeString(targetName);
|
writeString(targetName);
|
||||||
} else if(auto position = sourceList.find(targetName)) { //if sourceName == targetName
|
} else if(auto position = sourceList.find(targetName)) { //if sourceName == targetName
|
||||||
|
@ -65,15 +65,15 @@ struct bpsmulti {
|
||||||
bpslinear patch;
|
bpslinear patch;
|
||||||
patch.source({sourcePath, targetName});
|
patch.source({sourcePath, targetName});
|
||||||
patch.target({targetPath, targetName});
|
patch.target({targetPath, targetName});
|
||||||
patch.create({temppath(), "temp.bps"});
|
patch.create({Path::temp(), "temp.bps"});
|
||||||
} else {
|
} else {
|
||||||
bpsdelta patch;
|
bpsdelta patch;
|
||||||
patch.source({sourcePath, targetName});
|
patch.source({sourcePath, targetName});
|
||||||
patch.target({targetPath, 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());
|
writeNumber(buffer.size());
|
||||||
for(auto &byte : buffer) write(byte);
|
for(auto &byte : buffer) write(byte);
|
||||||
}
|
}
|
||||||
|
@ -159,13 +159,13 @@ protected:
|
||||||
auto ls(lstring& list, const string& path, const string& basepath) -> void {
|
auto ls(lstring& list, const string& path, const string& basepath) -> void {
|
||||||
lstring paths = directory::folders(path);
|
lstring paths = directory::folders(path);
|
||||||
for(auto& pathname : paths) {
|
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);
|
ls(list, {path, pathname}, basepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
lstring files = directory::files(path);
|
lstring files = directory::files(path);
|
||||||
for(auto& filename : files) {
|
for(auto& filename : files) {
|
||||||
list.append(string{path, filename}.ltrim(basepath, 1L));
|
list.append(string{path, filename}.trimLeft(basepath, 1L));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
85
bit-field.hpp
Normal file
85
bit-field.hpp
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace nall {
|
||||||
|
|
||||||
|
template<typename type, uint Lo, uint Hi> 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<typename T> 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<typename T> 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<typename type, uint Bit> 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<typename T> 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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -27,7 +27,6 @@ struct bitvector {
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit operator bool() const { return bits > 0; }
|
explicit operator bool() const { return bits > 0; }
|
||||||
auto empty() const -> bool { return bits == 0; }
|
|
||||||
auto size() const -> uint { return bits; }
|
auto size() const -> uint { return bits; }
|
||||||
auto bytes() const -> uint { return (bits + 7) / 8; }
|
auto bytes() const -> uint { return (bits + 7) / 8; }
|
||||||
auto data() -> uint8_t* { return pool; }
|
auto data() -> uint8_t* { return pool; }
|
36
bit.hpp
36
bit.hpp
|
@ -4,28 +4,28 @@
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
template<unsigned bits> inline auto uclamp(const uintmax_t x) -> uintmax_t {
|
template<uint bits> inline auto uclamp(const uintmax x) -> uintmax {
|
||||||
enum : uintmax_t { b = 1ull << (bits - 1), y = b * 2 - 1 };
|
enum : uintmax { b = 1ull << (bits - 1), y = b * 2 - 1 };
|
||||||
return y + ((x - y) & -(x < y)); //min(x, y);
|
return y + ((x - y) & -(x < y)); //min(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned bits> inline auto uclip(const uintmax_t x) -> uintmax_t {
|
template<uint bits> inline auto uclip(const uintmax x) -> uintmax {
|
||||||
enum : uintmax_t { b = 1ull << (bits - 1), m = b * 2 - 1 };
|
enum : uintmax { b = 1ull << (bits - 1), m = b * 2 - 1 };
|
||||||
return (x & m);
|
return (x & m);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned bits> inline auto sclamp(const intmax_t x) -> intmax_t {
|
template<uint bits> inline auto sclamp(const intmax x) -> intmax {
|
||||||
enum : intmax_t { b = 1ull << (bits - 1), m = b - 1 };
|
enum : intmax { b = 1ull << (bits - 1), m = b - 1 };
|
||||||
return (x > m) ? m : (x < -b) ? -b : x;
|
return (x > m) ? m : (x < -b) ? -b : x;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<unsigned bits> inline auto sclip(const intmax_t x) -> intmax_t {
|
template<uint bits> inline auto sclip(const intmax x) -> intmax {
|
||||||
enum : uintmax_t { b = 1ull << (bits - 1), m = b * 2 - 1 };
|
enum : uintmax { b = 1ull << (bits - 1), m = b * 2 - 1 };
|
||||||
return ((x & m) ^ b) - b;
|
return ((x & m) ^ b) - b;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace bit {
|
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 (
|
return (
|
||||||
*s == '0' || *s == '1' ? mask(s + 1, (sum << 1) | 1) :
|
*s == '0' || *s == '1' ? mask(s + 1, (sum << 1) | 1) :
|
||||||
*s == ' ' || *s == '_' ? mask(s + 1, sum) :
|
*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 (
|
return (
|
||||||
*s == '0' || *s == '1' ? test(s + 1, (sum << 1) | (*s - '0')) :
|
*s == '0' || *s == '1' ? test(s + 1, (sum << 1) | (*s - '0')) :
|
||||||
*s == ' ' || *s == '_' ? test(s + 1, sum) :
|
*s == ' ' || *s == '_' ? test(s + 1, sum) :
|
||||||
|
@ -44,38 +44,38 @@ namespace bit {
|
||||||
}
|
}
|
||||||
|
|
||||||
//lowest(0b1110) == 0b0010
|
//lowest(0b1110) == 0b0010
|
||||||
constexpr inline auto lowest(const uintmax_t x) -> uintmax_t {
|
constexpr inline auto lowest(const uintmax x) -> uintmax {
|
||||||
return x & -x;
|
return x & -x;
|
||||||
}
|
}
|
||||||
|
|
||||||
//clear_lowest(0b1110) == 0b1100
|
//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);
|
return x & (x - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//set_lowest(0b0101) == 0b0111
|
//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);
|
return x | (x + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//count number of bits set in a byte
|
//count number of bits set in a byte
|
||||||
inline auto count(uintmax_t x) -> unsigned {
|
inline auto count(uintmax x) -> uint {
|
||||||
unsigned count = 0;
|
uint count = 0;
|
||||||
do count += x & 1; while(x >>= 1);
|
do count += x & 1; while(x >>= 1);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
//return index of the first bit set (or zero of no bits are set)
|
//return index of the first bit set (or zero of no bits are set)
|
||||||
//first(0b1000) == 3
|
//first(0b1000) == 3
|
||||||
inline auto first(uintmax_t x) -> unsigned {
|
inline auto first(uintmax x) -> uint {
|
||||||
unsigned first = 0;
|
uint first = 0;
|
||||||
while(x) { if(x & 1) break; x >>= 1; first++; }
|
while(x) { if(x & 1) break; x >>= 1; first++; }
|
||||||
return first;
|
return first;
|
||||||
}
|
}
|
||||||
|
|
||||||
//round up to next highest single bit:
|
//round up to next highest single bit:
|
||||||
//round(15) == 16, round(16) == 16, round(17) == 32
|
//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;
|
if((x & (x - 1)) == 0) return x;
|
||||||
while(x & (x - 1)) x &= x - 1;
|
while(x & (x - 1)) x &= x - 1;
|
||||||
return x << 1;
|
return x << 1;
|
||||||
|
|
14
config.hpp
14
config.hpp
|
@ -10,13 +10,11 @@ namespace Configuration {
|
||||||
struct Node {
|
struct Node {
|
||||||
string name;
|
string name;
|
||||||
string desc;
|
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;
|
void* data = nullptr;
|
||||||
vector<Node> children;
|
vector<Node> children;
|
||||||
|
|
||||||
auto empty() const -> bool {
|
explicit operator bool() const { return data; }
|
||||||
return data == nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto get() const -> string {
|
auto get() const -> string {
|
||||||
switch(type) {
|
switch(type) {
|
||||||
|
@ -57,7 +55,7 @@ struct Node {
|
||||||
|
|
||||||
auto find(const string& path) -> maybe<Node&> {
|
auto find(const string& path) -> maybe<Node&> {
|
||||||
auto p = path.split("/");
|
auto p = path.split("/");
|
||||||
auto name = p.takeFirst();
|
auto name = p.takeLeft();
|
||||||
for(auto& child : children) {
|
for(auto& child : children) {
|
||||||
if(child.name == name) {
|
if(child.name == name) {
|
||||||
if(p.size() == 0) return child;
|
if(p.size() == 0) return child;
|
||||||
|
@ -70,13 +68,13 @@ struct Node {
|
||||||
auto load(Markup::Node path) -> void {
|
auto load(Markup::Node path) -> void {
|
||||||
for(auto& child : children) {
|
for(auto& child : children) {
|
||||||
if(auto leaf = path[child.name]) {
|
if(auto leaf = path[child.name]) {
|
||||||
if(!child.empty()) child.set(leaf.text());
|
if(child) child.set(leaf.text());
|
||||||
child.load(leaf);
|
child.load(leaf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto save(file& fp, unsigned depth = 0) -> void {
|
auto save(file& fp, uint depth = 0) -> void {
|
||||||
for(auto& child : children) {
|
for(auto& child : children) {
|
||||||
if(child.desc) {
|
if(child.desc) {
|
||||||
for(auto n : range(depth)) fp.print(" ");
|
for(auto n : range(depth)) fp.print(" ");
|
||||||
|
@ -84,7 +82,7 @@ struct Node {
|
||||||
}
|
}
|
||||||
for(auto n : range(depth)) fp.print(" ");
|
for(auto n : range(depth)) fp.print(" ");
|
||||||
fp.print(child.name);
|
fp.print(child.name);
|
||||||
if(!child.empty()) fp.print(": ", child.get());
|
if(child) fp.print(": ", child.get());
|
||||||
fp.print("\n");
|
fp.print("\n");
|
||||||
child.save(fp, depth + 1);
|
child.save(fp, depth + 1);
|
||||||
if(depth == 0) fp.print("\n");
|
if(depth == 0) fp.print("\n");
|
||||||
|
|
|
@ -73,7 +73,7 @@ private:
|
||||||
#if defined(PLATFORM_WINDOWS)
|
#if defined(PLATFORM_WINDOWS)
|
||||||
inline auto directory::create(const string& pathname, unsigned permissions) -> bool {
|
inline auto directory::create(const string& pathname, unsigned permissions) -> bool {
|
||||||
string path;
|
string path;
|
||||||
lstring list = string{pathname}.transform("\\", "/").rtrim("/").split("/");
|
lstring list = string{pathname}.transform("\\", "/").trimRight("/").split("/");
|
||||||
bool result = true;
|
bool result = true;
|
||||||
for(auto& part : list) {
|
for(auto& part : list) {
|
||||||
path.append(part, "/");
|
path.append(part, "/");
|
||||||
|
@ -168,7 +168,7 @@ private:
|
||||||
|
|
||||||
inline auto directory::create(const string& pathname, unsigned permissions) -> bool {
|
inline auto directory::create(const string& pathname, unsigned permissions) -> bool {
|
||||||
string path;
|
string path;
|
||||||
lstring list = string{pathname}.rtrim("/").split("/");
|
lstring list = string{pathname}.trimRight("/").split("/");
|
||||||
bool result = true;
|
bool result = true;
|
||||||
for(auto& part : list) {
|
for(auto& part : list) {
|
||||||
path.append(part, "/");
|
path.append(part, "/");
|
||||||
|
|
5
dl.hpp
5
dl.hpp
|
@ -3,6 +3,7 @@
|
||||||
//dynamic linking support
|
//dynamic linking support
|
||||||
|
|
||||||
#include <nall/intrinsics.hpp>
|
#include <nall/intrinsics.hpp>
|
||||||
|
#include <nall/path.hpp>
|
||||||
#include <nall/stdint.hpp>
|
#include <nall/stdint.hpp>
|
||||||
#include <nall/string.hpp>
|
#include <nall/string.hpp>
|
||||||
#include <nall/utility.hpp>
|
#include <nall/utility.hpp>
|
||||||
|
@ -38,7 +39,7 @@ private:
|
||||||
inline auto library::open(const string& name, const string& path) -> bool {
|
inline auto library::open(const string& name, const string& path) -> bool {
|
||||||
if(handle) close();
|
if(handle) close();
|
||||||
if(path) handle = (uintptr_t)dlopen(string(path, "lib", name, ".so"), RTLD_LAZY);
|
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("/usr/local/lib/lib", name, ".so"), RTLD_LAZY);
|
||||||
if(!handle) handle = (uintptr_t)dlopen(string("lib", name, ".so"), RTLD_LAZY);
|
if(!handle) handle = (uintptr_t)dlopen(string("lib", name, ".so"), RTLD_LAZY);
|
||||||
return handle;
|
return handle;
|
||||||
|
@ -64,7 +65,7 @@ inline auto library::close() -> void {
|
||||||
inline auto library::open(const string& name, const string& path) -> bool {
|
inline auto library::open(const string& name, const string& path) -> bool {
|
||||||
if(handle) close();
|
if(handle) close();
|
||||||
if(path) handle = (uintptr_t)dlopen(string(path, "lib", name, ".dylib"), RTLD_LAZY);
|
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("/usr/local/lib/lib", name, ".dylib"), RTLD_LAZY);
|
||||||
if(!handle) handle = (uintptr_t)dlopen(string("lib", name, ".dylib"), RTLD_LAZY);
|
if(!handle) handle = (uintptr_t)dlopen(string("lib", name, ".dylib"), RTLD_LAZY);
|
||||||
return handle;
|
return handle;
|
||||||
|
|
10
dsp.hpp
10
dsp.hpp
|
@ -1,10 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <nall/bit.hpp>
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#ifdef __SSE__
|
|
||||||
#include <xmmintrin.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <nall/dsp/core.hpp>
|
|
|
@ -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;
|
|
||||||
};
|
|
164
dsp/core.hpp
164
dsp/core.hpp
|
@ -1,164 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
#include <vector>
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
153
dsp/iir/biquad.hpp
Normal file
153
dsp/iir/biquad.hpp
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}}}
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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<unsigned char> coeffs_mem;
|
|
||||||
|
|
||||||
// second half of ringbuffer should be copy of first half.
|
|
||||||
resample_samp_t *rb;
|
|
||||||
std::vector<unsigned char> 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<resample_coeff_t *> coeffs; // Pointers into coeff_mem.
|
|
||||||
std::vector<unsigned char> coeff_mem;
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<resample_samp_t> 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<double> 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<double> 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<unsigned>(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;
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
56
dsp/resampler/cubic.hpp
Normal file
56
dsp/resampler/cubic.hpp
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <nall/queue.hpp>
|
||||||
|
|
||||||
|
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<double> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}}}
|
|
@ -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();
|
|
||||||
}
|
|
134
emulation/21fx.hpp
Normal file
134
emulation/21fx.hpp
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <nall/nall.hpp>
|
||||||
|
#include <nall/serial.hpp>
|
||||||
|
using namespace nall;
|
||||||
|
|
||||||
|
struct FX {
|
||||||
|
auto open(lstring& args) -> bool;
|
||||||
|
auto close() -> void;
|
||||||
|
auto readable() -> bool;
|
||||||
|
auto read() -> uint8_t;
|
||||||
|
auto writable() -> bool;
|
||||||
|
auto write(uint8_t data) -> void;
|
||||||
|
|
||||||
|
auto read(uint offset, uint length) -> vector<uint8_t>;
|
||||||
|
auto write(uint offset, const void* buffer, uint length) -> void;
|
||||||
|
auto write(uint offset, const vector<uint8_t>& 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<uint8_t> {
|
||||||
|
write(0x21);
|
||||||
|
write(0x66);
|
||||||
|
write(0x78);
|
||||||
|
write(offset >> 16);
|
||||||
|
write(offset >> 8);
|
||||||
|
write(offset >> 0);
|
||||||
|
write(0x01);
|
||||||
|
write(length >> 8);
|
||||||
|
write(length >> 0);
|
||||||
|
write(0x00);
|
||||||
|
|
||||||
|
vector<uint8_t> buffer;
|
||||||
|
while(length--) buffer.append(read());
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto FX::write(uint offset, const 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<uint8_t> buffer = {data};
|
||||||
|
write(offset, buffer);
|
||||||
|
}
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
namespace nall { namespace Encode {
|
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<uint8_t> result;
|
vector<uint8_t> result;
|
||||||
|
|
||||||
char lookup[65];
|
char lookup[65];
|
||||||
|
@ -34,14 +35,14 @@ inline auto Base64(const uint8_t* data, unsigned size, const string& format = "M
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
buffer |= data[i] >> 4;
|
buffer |= data[i] >> 4;
|
||||||
result.last() = lookup[buffer];
|
result.right() = lookup[buffer];
|
||||||
buffer = (data[i] & 15) << 2;
|
buffer = (data[i] & 15) << 2;
|
||||||
result.append(lookup[buffer]);
|
result.append(lookup[buffer]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
buffer |= data[i] >> 6;
|
buffer |= data[i] >> 6;
|
||||||
result.last() = lookup[buffer];
|
result.right() = lookup[buffer];
|
||||||
buffer = (data[i] & 63);
|
buffer = (data[i] & 63);
|
||||||
result.append(lookup[buffer]);
|
result.append(lookup[buffer]);
|
||||||
break;
|
break;
|
||||||
|
@ -61,7 +62,7 @@ inline auto Base64(const vector<uint8_t>& buffer, const string& format = "MIME")
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto Base64(const string& text, const string& format = "MIME") -> string {
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|
3
file.hpp
3
file.hpp
|
@ -7,7 +7,6 @@
|
||||||
#include <nall/utility.hpp>
|
#include <nall/utility.hpp>
|
||||||
#include <nall/varint.hpp>
|
#include <nall/varint.hpp>
|
||||||
#include <nall/hash/sha256.hpp>
|
#include <nall/hash/sha256.hpp>
|
||||||
#include <nall/stream/memory.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
|
@ -239,7 +238,7 @@ struct file : inode, varint {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
auto end() -> bool {
|
auto end() const -> bool {
|
||||||
if(!fp) return true; //file not open
|
if(!fp) return true; //file not open
|
||||||
return file_offset >= file_size;
|
return file_offset >= file_size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,39 +1,64 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <nall/range.hpp>
|
#include <nall/range.hpp>
|
||||||
|
#include <nall/string.hpp>
|
||||||
|
|
||||||
namespace nall {
|
namespace nall { namespace Hash {
|
||||||
struct string;
|
|
||||||
namespace Hash {
|
|
||||||
|
|
||||||
struct CRC16 {
|
struct CRC16 {
|
||||||
CRC16() { reset(); }
|
CRC16() { reset(); }
|
||||||
CRC16(const void* values, unsigned size) : CRC16() { data(values, size); }
|
CRC16(const void* values, uint size) : CRC16() { data(values, size); }
|
||||||
|
CRC16(const vector<uint8_t>& values) : CRC16() { data(values); }
|
||||||
|
CRC16(const string& values) : CRC16() { data(values); }
|
||||||
|
|
||||||
auto reset() -> void {
|
auto reset() -> void {
|
||||||
checksum = ~0;
|
checksum = ~0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto data(uint8_t value) -> void {
|
auto data(uint8_t value) -> void {
|
||||||
for(auto n : range(8)) {
|
checksum = (checksum >> 8) ^ table(checksum ^ value);
|
||||||
if((checksum & 1) ^ (value & 1)) checksum = (checksum >> 1) ^ 0x8408;
|
|
||||||
else checksum >>= 1;
|
|
||||||
value >>= 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto data(const void* values, unsigned size) -> void {
|
auto data(const void* values, uint size) -> void {
|
||||||
auto p = (const uint8_t*)values;
|
auto p = (const uint8_t*)values;
|
||||||
while(size--) data(*p++);
|
while(size--) data(*p++);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto value() -> uint16_t {
|
auto data(const vector<uint8_t>& values) -> void {
|
||||||
|
for(auto value : values) data(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto data(const string& values) -> void {
|
||||||
|
for(auto value : values) data(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto value() const -> uint16_t {
|
||||||
return ~checksum;
|
return ~checksum;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto digest() -> string;
|
inline auto digest() const -> string {
|
||||||
|
return hex(value(), 4L);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static auto table(uint8_t index) -> uint16_t {
|
||||||
|
static uint16_t table[256] = {0};
|
||||||
|
static bool initialized = false;
|
||||||
|
|
||||||
|
if(!initialized) {
|
||||||
|
initialized = true;
|
||||||
|
for(auto index : range(256)) {
|
||||||
|
uint16_t crc = index;
|
||||||
|
for(auto bit : range(8)) {
|
||||||
|
crc = (crc >> 1) ^ (crc & 1 ? 0x8408 : 0);
|
||||||
|
}
|
||||||
|
table[index] = crc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return table[index];
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t checksum;
|
uint16_t checksum;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,81 +1,64 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <nall/range.hpp>
|
#include <nall/range.hpp>
|
||||||
|
#include <nall/string.hpp>
|
||||||
|
|
||||||
namespace nall {
|
namespace nall { namespace Hash {
|
||||||
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,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CRC32 {
|
struct CRC32 {
|
||||||
CRC32() { reset(); }
|
CRC32() { reset(); }
|
||||||
CRC32(const void* values, unsigned size) : CRC32() { data(values, size); }
|
CRC32(const void* values, uint size) : CRC32() { data(values, size); }
|
||||||
|
CRC32(const vector<uint8_t>& values) : CRC32() { data(values); }
|
||||||
|
CRC32(const string& values) : CRC32() { data(values); }
|
||||||
|
|
||||||
auto reset() -> void {
|
auto reset() -> void {
|
||||||
checksum = ~0;
|
checksum = ~0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto data(uint8_t value) -> void {
|
auto data(uint8_t value) -> void {
|
||||||
checksum = ((checksum >> 8) & 0xffffff) ^ _crc32_table[(checksum ^ value) & 0xff];
|
checksum = (checksum >> 8) ^ table(checksum ^ value);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto data(const void* values, unsigned size) -> void {
|
auto data(const void* values, uint size) -> void {
|
||||||
auto p = (const uint8_t*)values;
|
auto p = (const uint8_t*)values;
|
||||||
while(size--) data(*p++);
|
while(size--) data(*p++);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto data(const vector<uint8_t>& values) -> void {
|
||||||
|
for(auto value : values) data(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto data(const string& values) -> void {
|
||||||
|
for(auto value : values) data(value);
|
||||||
|
}
|
||||||
|
|
||||||
auto value() const -> uint32_t {
|
auto value() const -> uint32_t {
|
||||||
return ~checksum;
|
return ~checksum;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto digest() -> string;
|
inline auto digest() const -> string {
|
||||||
|
return hex(value(), 8L);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static auto table(uint8_t index) -> uint32_t {
|
||||||
|
static uint32_t table[256] = {0};
|
||||||
|
static bool initialized = false;
|
||||||
|
|
||||||
|
if(!initialized) {
|
||||||
|
initialized = true;
|
||||||
|
for(auto index : range(256)) {
|
||||||
|
uint32_t crc = index;
|
||||||
|
for(auto bit : range(8)) {
|
||||||
|
crc = (crc >> 1) ^ (crc & 1 ? 0xedb8'8320 : 0);
|
||||||
|
}
|
||||||
|
table[index] = crc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return table[index];
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t checksum;
|
uint32_t checksum;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
65
hash/crc64.hpp
Normal file
65
hash/crc64.hpp
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <nall/range.hpp>
|
||||||
|
#include <nall/string.hpp>
|
||||||
|
|
||||||
|
namespace nall { namespace Hash {
|
||||||
|
|
||||||
|
struct CRC64 {
|
||||||
|
CRC64() { reset(); }
|
||||||
|
CRC64(const void* values, uint size) : CRC64() { data(values, size); }
|
||||||
|
CRC64(const vector<uint8_t>& values) : CRC64() { data(values); }
|
||||||
|
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<uint8_t>& 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
}}
|
|
@ -1,14 +1,15 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <nall/range.hpp>
|
#include <nall/range.hpp>
|
||||||
|
#include <nall/string.hpp>
|
||||||
|
|
||||||
namespace nall {
|
namespace nall { namespace Hash {
|
||||||
struct string;
|
|
||||||
namespace Hash {
|
|
||||||
|
|
||||||
struct SHA256 {
|
struct SHA256 {
|
||||||
SHA256() { reset(); }
|
SHA256() { reset(); }
|
||||||
SHA256(const void* values, unsigned size) : SHA256() { data(values, size); }
|
SHA256(const void* values, uint size) : SHA256() { data(values, size); }
|
||||||
|
SHA256(const vector<uint8_t>& values) : SHA256() { data(values); }
|
||||||
|
SHA256(const string& values) : SHA256() { data(values); }
|
||||||
|
|
||||||
auto reset() -> void {
|
auto reset() -> void {
|
||||||
for(auto n : input) n = 0;
|
for(auto n : input) n = 0;
|
||||||
|
@ -22,12 +23,20 @@ struct SHA256 {
|
||||||
length++;
|
length++;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto data(const void* values, unsigned size) -> void {
|
auto data(const void* values, uint size) -> void {
|
||||||
length += size;
|
length += size;
|
||||||
auto p = (const uint8_t*)values;
|
auto p = (const uint8_t*)values;
|
||||||
while(size--) byte(*p++);
|
while(size--) byte(*p++);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto data(const vector<uint8_t>& values) -> void {
|
||||||
|
for(auto value : values) data(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto data(const string& values) -> void {
|
||||||
|
for(auto value : values) data(value);
|
||||||
|
}
|
||||||
|
|
||||||
auto value() const -> vector<uint8_t> {
|
auto value() const -> vector<uint8_t> {
|
||||||
SHA256 self(*this);
|
SHA256 self(*this);
|
||||||
self.finish();
|
self.finish();
|
||||||
|
@ -36,7 +45,11 @@ struct SHA256 {
|
||||||
return result;
|
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:
|
private:
|
||||||
auto byte(uint8_t value) -> void {
|
auto byte(uint8_t value) -> void {
|
||||||
|
@ -77,14 +90,14 @@ private:
|
||||||
return (x >> n) | (x << 32 - n);
|
return (x >> n) | (x << 32 - n);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto square(unsigned n) -> uint32_t {
|
auto square(uint n) -> uint32_t {
|
||||||
static const uint32_t value[8] = {
|
static const uint32_t value[8] = {
|
||||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
|
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
|
||||||
};
|
};
|
||||||
return value[n];
|
return value[n];
|
||||||
}
|
}
|
||||||
|
|
||||||
auto cube(unsigned n) -> uint32_t {
|
auto cube(uint n) -> uint32_t {
|
||||||
static const uint32_t value[64] = {
|
static const uint32_t value[64] = {
|
||||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||||
|
|
30
hashset.hpp
30
hashset.hpp
|
@ -7,7 +7,7 @@
|
||||||
//remove: O(1) average; O(n) worst
|
//remove: O(1) average; O(n) worst
|
||||||
//
|
//
|
||||||
//requirements:
|
//requirements:
|
||||||
// auto T::hash() const -> unsigned;
|
// auto T::hash() const -> uint;
|
||||||
// auto T::operator==(const T&) const -> bool;
|
// auto T::operator==(const T&) const -> bool;
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
@ -15,7 +15,7 @@ namespace nall {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct hashset {
|
struct hashset {
|
||||||
hashset() = default;
|
hashset() = default;
|
||||||
hashset(unsigned length) : length(bit::round(length)) {}
|
hashset(uint length) : length(bit::round(length)) {}
|
||||||
hashset(const hashset& source) { operator=(source); }
|
hashset(const hashset& source) { operator=(source); }
|
||||||
hashset(hashset&& source) { operator=(move(source)); }
|
hashset(hashset&& source) { operator=(move(source)); }
|
||||||
~hashset() { reset(); }
|
~hashset() { reset(); }
|
||||||
|
@ -23,7 +23,7 @@ struct hashset {
|
||||||
auto operator=(const hashset& source) -> hashset& {
|
auto operator=(const hashset& source) -> hashset& {
|
||||||
reset();
|
reset();
|
||||||
if(source.pool) {
|
if(source.pool) {
|
||||||
for(unsigned n = 0; n < source.count; n++) {
|
for(uint n : range(source.count)) {
|
||||||
insert(*source.pool[n]);
|
insert(*source.pool[n]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,13 +41,13 @@ struct hashset {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto capacity() const -> unsigned { return length; }
|
explicit operator bool() const { return count; }
|
||||||
auto size() const -> unsigned { return count; }
|
auto capacity() const -> uint { return length; }
|
||||||
auto empty() const -> bool { return count == 0; }
|
auto size() const -> uint { return count; }
|
||||||
|
|
||||||
auto reset() -> void {
|
auto reset() -> void {
|
||||||
if(pool) {
|
if(pool) {
|
||||||
for(unsigned n = 0; n < length; n++) {
|
for(uint n : range(length)) {
|
||||||
if(pool[n]) {
|
if(pool[n]) {
|
||||||
delete pool[n];
|
delete pool[n];
|
||||||
pool[n] = nullptr;
|
pool[n] = nullptr;
|
||||||
|
@ -60,15 +60,15 @@ struct hashset {
|
||||||
count = 0;
|
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
|
//ensure all items will fit into pool (with <= 50% load) and amortize growth
|
||||||
size = bit::round(max(size, count << 1));
|
size = bit::round(max(size, count << 1));
|
||||||
T** copy = new T*[size]();
|
T** copy = new T*[size]();
|
||||||
|
|
||||||
if(pool) {
|
if(pool) {
|
||||||
for(unsigned n = 0; n < length; n++) {
|
for(uint n : range(length)) {
|
||||||
if(pool[n]) {
|
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;
|
while(copy[hash]) if(++hash >= size) hash = 0;
|
||||||
copy[hash] = pool[n];
|
copy[hash] = pool[n];
|
||||||
pool[n] = nullptr;
|
pool[n] = nullptr;
|
||||||
|
@ -84,7 +84,7 @@ struct hashset {
|
||||||
auto find(const T& value) -> maybe<T&> {
|
auto find(const T& value) -> maybe<T&> {
|
||||||
if(!pool) return nothing;
|
if(!pool) return nothing;
|
||||||
|
|
||||||
unsigned hash = value.hash() & (length - 1);
|
uint hash = value.hash() & (length - 1);
|
||||||
while(pool[hash]) {
|
while(pool[hash]) {
|
||||||
if(value == *pool[hash]) return *pool[hash];
|
if(value == *pool[hash]) return *pool[hash];
|
||||||
if(++hash >= length) hash = 0;
|
if(++hash >= length) hash = 0;
|
||||||
|
@ -100,7 +100,7 @@ struct hashset {
|
||||||
if(count >= (length >> 1)) reserve(length << 1);
|
if(count >= (length >> 1)) reserve(length << 1);
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
unsigned hash = value.hash() & (length - 1);
|
uint hash = value.hash() & (length - 1);
|
||||||
while(pool[hash]) if(++hash >= length) hash = 0;
|
while(pool[hash]) if(++hash >= length) hash = 0;
|
||||||
pool[hash] = new T(value);
|
pool[hash] = new T(value);
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ struct hashset {
|
||||||
auto remove(const T& value) -> bool {
|
auto remove(const T& value) -> bool {
|
||||||
if(!pool) return false;
|
if(!pool) return false;
|
||||||
|
|
||||||
unsigned hash = value.hash() & (length - 1);
|
uint hash = value.hash() & (length - 1);
|
||||||
while(pool[hash]) {
|
while(pool[hash]) {
|
||||||
if(value == *pool[hash]) {
|
if(value == *pool[hash]) {
|
||||||
delete pool[hash];
|
delete pool[hash];
|
||||||
|
@ -126,8 +126,8 @@ struct hashset {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
T** pool = nullptr;
|
T** pool = nullptr;
|
||||||
unsigned length = 8; //length of pool
|
uint length = 8; //length of pool
|
||||||
unsigned count = 0; //number of objects inside of the pool
|
uint count = 0; //number of objects inside of the pool
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
18
hid.hpp
18
hid.hpp
|
@ -19,10 +19,10 @@ struct Group : vector<Input> {
|
||||||
Group(const string& name) : _name(name) {}
|
Group(const string& name) : _name(name) {}
|
||||||
|
|
||||||
auto name() const -> string { return _name; }
|
auto name() const -> string { return _name; }
|
||||||
auto input(unsigned id) -> Input& { return operator[](id); }
|
auto input(uint id) -> Input& { return operator[](id); }
|
||||||
auto append(const string& name) -> void { vector::append({name}); }
|
auto append(const string& name) -> void { vector::append(Input{name}); }
|
||||||
|
|
||||||
auto find(const string& name) const -> maybe<unsigned> {
|
auto find(const string& name) const -> maybe<uint> {
|
||||||
for(auto id : range(size())) {
|
for(auto id : range(size())) {
|
||||||
if(operator[](id)._name == name) return id;
|
if(operator[](id)._name == name) return id;
|
||||||
}
|
}
|
||||||
|
@ -50,10 +50,10 @@ struct Device : vector<Group> {
|
||||||
auto name() const -> string { return _name; }
|
auto name() const -> string { return _name; }
|
||||||
auto id() const -> uint64_t { return _id; }
|
auto id() const -> uint64_t { return _id; }
|
||||||
auto setID(uint64_t id) -> void { _id = id; }
|
auto setID(uint64_t id) -> void { _id = id; }
|
||||||
auto group(unsigned id) -> Group& { return operator[](id); }
|
auto group(uint id) -> Group& { return operator[](id); }
|
||||||
auto append(const string& name) -> void { vector::append({name}); }
|
auto append(const string& name) -> void { vector::append(Group{name}); }
|
||||||
|
|
||||||
auto find(const string& name) const -> maybe<unsigned> {
|
auto find(const string& name) const -> maybe<uint> {
|
||||||
for(auto id : range(size())) {
|
for(auto id : range(size())) {
|
||||||
if(operator[](id)._name == name) return id;
|
if(operator[](id)._name == name) return id;
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ struct Null : Device {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Keyboard : Device {
|
struct Keyboard : Device {
|
||||||
enum GroupID : unsigned { Button };
|
enum GroupID : uint { Button };
|
||||||
|
|
||||||
Keyboard() : Device("Keyboard") { append("Button"); }
|
Keyboard() : Device("Keyboard") { append("Button"); }
|
||||||
auto isKeyboard() const -> bool { return true; }
|
auto isKeyboard() const -> bool { return true; }
|
||||||
|
@ -79,7 +79,7 @@ struct Keyboard : Device {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Mouse : Device {
|
struct Mouse : Device {
|
||||||
enum GroupID : unsigned { Axis, Button };
|
enum GroupID : uint { Axis, Button };
|
||||||
|
|
||||||
Mouse() : Device("Mouse") { append("Axis"), append("Button"); }
|
Mouse() : Device("Mouse") { append("Axis"), append("Button"); }
|
||||||
auto isMouse() const -> bool { return true; }
|
auto isMouse() const -> bool { return true; }
|
||||||
|
@ -88,7 +88,7 @@ struct Mouse : Device {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Joypad : 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"); }
|
Joypad() : Device("Joypad") { append("Axis"), append("Hat"), append("Trigger"), append("Button"); }
|
||||||
auto isJoypad() const -> bool { return true; }
|
auto isJoypad() const -> bool { return true; }
|
||||||
|
|
|
@ -50,7 +50,7 @@ auto Request::head(const function<bool (const uint8_t*, unsigned)>& callback) co
|
||||||
for(auto& variable : get) {
|
for(auto& variable : get) {
|
||||||
request.append(Encode::URL(variable.name()), "=", Encode::URL(variable.value()), "&");
|
request.append(Encode::URL(variable.name()), "=", Encode::URL(variable.value()), "&");
|
||||||
}
|
}
|
||||||
request.rtrim("&", 1L);
|
request.trimRight("&", 1L);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(requestType()) {
|
switch(requestType()) {
|
||||||
|
@ -65,25 +65,25 @@ auto Request::head(const function<bool (const uint8_t*, unsigned)>& callback) co
|
||||||
}
|
}
|
||||||
output.append("\r\n");
|
output.append("\r\n");
|
||||||
|
|
||||||
return callback(output.binary(), output.size());
|
return callback(output.data<uint8_t>(), output.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Request::setHead() -> bool {
|
auto Request::setHead() -> bool {
|
||||||
lstring headers = _head.split("\n");
|
lstring headers = _head.split("\n");
|
||||||
string request = headers.takeFirst().rtrim("\r", 1L);
|
string request = headers.takeLeft().trimRight("\r", 1L);
|
||||||
string requestHost;
|
string requestHost;
|
||||||
|
|
||||||
if(request.iendsWith(" HTTP/1.0")) request.irtrim(" HTTP/1.0", 1L);
|
if(request.iendsWith(" HTTP/1.0")) request.itrimRight(" HTTP/1.0", 1L);
|
||||||
else if(request.iendsWith(" HTTP/1.1")) request.irtrim(" HTTP/1.1", 1L);
|
else if(request.iendsWith(" HTTP/1.1")) request.itrimRight(" HTTP/1.1", 1L);
|
||||||
else return false;
|
else return false;
|
||||||
|
|
||||||
if(request.ibeginsWith("HEAD ")) request.iltrim("HEAD ", 1L), setRequestType(RequestType::Head);
|
if(request.ibeginsWith("HEAD ")) request.itrimLeft("HEAD ", 1L), setRequestType(RequestType::Head);
|
||||||
else if(request.ibeginsWith("GET " )) request.iltrim("GET ", 1L), setRequestType(RequestType::Get );
|
else if(request.ibeginsWith("GET " )) request.itrimLeft("GET ", 1L), setRequestType(RequestType::Get );
|
||||||
else if(request.ibeginsWith("POST ")) request.iltrim("POST ", 1L), setRequestType(RequestType::Post);
|
else if(request.ibeginsWith("POST ")) request.itrimLeft("POST ", 1L), setRequestType(RequestType::Post);
|
||||||
else return false;
|
else return false;
|
||||||
|
|
||||||
//decode absolute URIs
|
//decode absolute URIs
|
||||||
request.strip().iltrim("http://", 1L);
|
request.strip().itrimLeft("http://", 1L);
|
||||||
if(!request.beginsWith("/")) {
|
if(!request.beginsWith("/")) {
|
||||||
lstring components = request.split("/", 1L);
|
lstring components = request.split("/", 1L);
|
||||||
requestHost = components(0);
|
requestHost = components(0);
|
||||||
|
@ -126,7 +126,7 @@ auto Request::body(const function<bool (const uint8_t*, unsigned)>& callback) co
|
||||||
if(!callback) return false;
|
if(!callback) return false;
|
||||||
|
|
||||||
if(_body) {
|
if(_body) {
|
||||||
return callback(_body.binary(), _body.size());
|
return callback(_body.data<uint8_t>(), _body.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -137,16 +137,16 @@ auto Request::setBody() -> bool {
|
||||||
auto contentType = header["Content-Type"].value();
|
auto contentType = header["Content-Type"].value();
|
||||||
if(contentType.iequals("application/x-www-form-urlencoded")) {
|
if(contentType.iequals("application/x-www-form-urlencoded")) {
|
||||||
for(auto& block : _body.split("&")) {
|
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 name = Decode::URL(p(0));
|
||||||
auto value = Decode::URL(p(1));
|
auto value = Decode::URL(p(1));
|
||||||
if(name) post.append(name, value);
|
if(name) post.append(name, value);
|
||||||
}
|
}
|
||||||
} else if(contentType.imatch("multipart/form-data; boundary=?*")) {
|
} 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
|
auto blocks = _body.split({"--", boundary}, 1024L); //limit blocks to prevent memory exhaustion
|
||||||
for(auto& block : blocks) block.trim("\r\n", "\r\n", 1L);
|
for(auto& block : blocks) block.trim("\r\n", "\r\n", 1L);
|
||||||
if(blocks.size() < 2 || (blocks.takeFirst(), !blocks.takeLast().beginsWith("--"))) return false;
|
if(blocks.size() < 2 || (blocks.takeLeft(), !blocks.takeRight().beginsWith("--"))) return false;
|
||||||
for(auto& block : blocks) {
|
for(auto& block : blocks) {
|
||||||
string name;
|
string name;
|
||||||
string filename;
|
string filename;
|
||||||
|
|
|
@ -61,7 +61,7 @@ auto Response::head(const function<bool (const uint8_t*, unsigned)>& callback) c
|
||||||
output.append("HTTP/1.1 304 Not Modified\r\n");
|
output.append("HTTP/1.1 304 Not Modified\r\n");
|
||||||
output.append("Connection: close\r\n");
|
output.append("Connection: close\r\n");
|
||||||
output.append("\r\n");
|
output.append("\r\n");
|
||||||
return callback(output.binary(), output.size());
|
return callback(output.data<uint8_t>(), output.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,15 +83,15 @@ auto Response::head(const function<bool (const uint8_t*, unsigned)>& callback) c
|
||||||
}
|
}
|
||||||
output.append("\r\n");
|
output.append("\r\n");
|
||||||
|
|
||||||
return callback(output.binary(), output.size());
|
return callback(output.data<uint8_t>(), output.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Response::setHead() -> bool {
|
auto Response::setHead() -> bool {
|
||||||
lstring headers = _head.split("\n");
|
lstring headers = _head.split("\n");
|
||||||
string response = headers.takeFirst().rtrim("\r");
|
string response = headers.takeLeft().trimRight("\r");
|
||||||
|
|
||||||
if(response.ibeginsWith("HTTP/1.0 ")) response.iltrim("HTTP/1.0 ", 1L);
|
if(response.ibeginsWith("HTTP/1.0 ")) response.itrimLeft("HTTP/1.0 ", 1L);
|
||||||
else if(response.ibeginsWith("HTTP/1.1 ")) response.iltrim("HTTP/1.1 ", 1L);
|
else if(response.ibeginsWith("HTTP/1.1 ")) response.itrimLeft("HTTP/1.1 ", 1L);
|
||||||
else return false;
|
else return false;
|
||||||
|
|
||||||
setResponseType(natural(response));
|
setResponseType(natural(response));
|
||||||
|
@ -113,26 +113,26 @@ auto Response::body(const function<bool (const uint8_t*, unsigned)>& callback) c
|
||||||
|
|
||||||
if(chunked) {
|
if(chunked) {
|
||||||
string prefix = {hex(findContentLength()), "\r\n"};
|
string prefix = {hex(findContentLength()), "\r\n"};
|
||||||
if(!callback(prefix.binary(), prefix.size())) return false;
|
if(!callback(prefix.data<uint8_t>(), prefix.size())) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_body) {
|
if(_body) {
|
||||||
if(!callback(_body.binary(), _body.size())) return false;
|
if(!callback(_body.data<uint8_t>(), _body.size())) return false;
|
||||||
} else if(hasData()) {
|
} else if(hasData()) {
|
||||||
if(!callback(data().data(), data().size())) return false;
|
if(!callback(data().data(), data().size())) return false;
|
||||||
} else if(hasFile()) {
|
} else if(hasFile()) {
|
||||||
filemap map(file(), filemap::mode::read);
|
filemap map(file(), filemap::mode::read);
|
||||||
if(!callback(map.data(), map.size())) return false;
|
if(!callback(map.data(), map.size())) return false;
|
||||||
} else if(hasText()) {
|
} else if(hasText()) {
|
||||||
if(!callback(text().binary(), text().size())) return false;
|
if(!callback(text().data<uint8_t>(), text().size())) return false;
|
||||||
} else {
|
} else {
|
||||||
string response = findResponseType();
|
string response = findResponseType();
|
||||||
if(!callback(response.binary(), response.size())) return false;
|
if(!callback(response.data<uint8_t>(), response.size())) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(chunked) {
|
if(chunked) {
|
||||||
string suffix = {"\r\n0\r\n\r\n"};
|
string suffix = {"\r\n0\r\n\r\n"};
|
||||||
if(!callback(suffix.binary(), suffix.size())) return false;
|
if(!callback(suffix.data<uint8_t>(), suffix.size())) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -54,7 +54,6 @@ struct image {
|
||||||
inline auto write(uint8_t* data, uint64_t value) const -> void;
|
inline auto write(uint8_t* data, uint64_t value) const -> void;
|
||||||
|
|
||||||
inline auto free() -> void;
|
inline auto free() -> void;
|
||||||
inline auto empty() const -> bool;
|
|
||||||
inline auto load(const string& filename) -> bool;
|
inline auto load(const string& filename) -> bool;
|
||||||
inline auto allocate(unsigned width, unsigned height) -> void;
|
inline auto allocate(unsigned width, unsigned height) -> void;
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ auto image::operator=(image&& source) -> image& {
|
||||||
}
|
}
|
||||||
|
|
||||||
image::operator bool() const {
|
image::operator bool() const {
|
||||||
return !empty();
|
return _data && _width && _height;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto image::operator==(const image& source) const -> bool {
|
auto image::operator==(const image& source) const -> bool {
|
||||||
|
@ -137,10 +137,6 @@ auto image::free() -> void {
|
||||||
_data = nullptr;
|
_data = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto image::empty() const -> bool {
|
|
||||||
return !_data || !_width || !_height;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto image::load(const string& filename) -> bool {
|
auto image::load(const string& filename) -> bool {
|
||||||
if(loadBMP(filename) == true) return true;
|
if(loadBMP(filename) == true) return true;
|
||||||
if(loadPNG(filename) == true) return true;
|
if(loadPNG(filename) == true) return true;
|
||||||
|
|
10
inode.hpp
10
inode.hpp
|
@ -9,7 +9,7 @@
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
struct inode {
|
struct inode {
|
||||||
enum class time : unsigned { access, modify };
|
enum class time : uint { access, modify };
|
||||||
|
|
||||||
static auto exists(const string& name) -> bool {
|
static auto exists(const string& name) -> bool {
|
||||||
return access(name, F_OK) == 0;
|
return access(name, F_OK) == 0;
|
||||||
|
@ -27,19 +27,19 @@ struct inode {
|
||||||
return access(name, X_OK) == 0;
|
return access(name, X_OK) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static auto uid(const string& name) -> unsigned {
|
static auto uid(const string& name) -> uint {
|
||||||
struct stat data{0};
|
struct stat data{0};
|
||||||
stat(name, &data);
|
stat(name, &data);
|
||||||
return data.st_uid;
|
return data.st_uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
static auto gid(const string& name) -> unsigned {
|
static auto gid(const string& name) -> uint {
|
||||||
struct stat data{0};
|
struct stat data{0};
|
||||||
stat(name, &data);
|
stat(name, &data);
|
||||||
return data.st_gid;
|
return data.st_gid;
|
||||||
}
|
}
|
||||||
|
|
||||||
static auto mode(const string& name) -> unsigned {
|
static auto mode(const string& name) -> uint {
|
||||||
struct stat data{0};
|
struct stat data{0};
|
||||||
stat(name, &data);
|
stat(name, &data);
|
||||||
return data.st_mode;
|
return data.st_mode;
|
||||||
|
@ -55,7 +55,7 @@ struct inode {
|
||||||
}
|
}
|
||||||
|
|
||||||
//returns true if 'name' already exists
|
//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(exists(name)) return true;
|
||||||
if(name.endsWith("/")) return mkdir(name, permissions) == 0;
|
if(name.endsWith("/")) return mkdir(name, permissions) == 0;
|
||||||
int fd = open(name, O_CREAT | O_EXCL, permissions);
|
int fd = open(name, O_CREAT | O_EXCL, permissions);
|
||||||
|
|
|
@ -19,7 +19,7 @@ struct Interpolation {
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline auto Cosine(double mu, double a, double b, double c, double d) -> double {
|
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;
|
return b * (1.0 - mu) + c * mu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
using uint = unsigned;
|
||||||
|
|
||||||
struct Intrinsics {
|
struct Intrinsics {
|
||||||
enum class Compiler : unsigned { Clang, GCC, VisualCPP, Unknown };
|
enum class Compiler : uint { Clang, GCC, VisualCPP, Unknown };
|
||||||
enum class Platform : unsigned { Windows, MacOSX, Linux, BSD, Unknown };
|
enum class Platform : uint { Windows, MacOSX, Linux, BSD, Unknown };
|
||||||
enum class API : unsigned { Windows, Posix, Unknown };
|
enum class API : uint { Windows, Posix, Unknown };
|
||||||
enum class Display : unsigned { Windows, Quartz, Xorg, Unknown };
|
enum class Display : uint { Windows, Quartz, Xorg, Unknown };
|
||||||
enum class Processor : unsigned { x86, amd64, ARM, PPC32, PPC64, Unknown };
|
enum class Processor : uint { x86, amd64, ARM, PPC32, PPC64, Unknown };
|
||||||
enum class Endian : unsigned { LSB, MSB, Unknown };
|
enum class Endian : uint { LSB, MSB, Unknown };
|
||||||
|
|
||||||
static inline auto compiler() -> Compiler;
|
static inline auto compiler() -> Compiler;
|
||||||
static inline auto platform() -> Platform;
|
static inline auto platform() -> Platform;
|
||||||
|
|
3
main.hpp
3
main.hpp
|
@ -11,6 +11,9 @@ namespace nall {
|
||||||
CoInitialize(0);
|
CoInitialize(0);
|
||||||
WSAData wsaData{0};
|
WSAData wsaData{0};
|
||||||
WSAStartup(MAKEWORD(2, 2), &wsaData);
|
WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||||
|
_setmode(_fileno(stdin), O_BINARY);
|
||||||
|
_setmode(_fileno(stdout), O_BINARY);
|
||||||
|
_setmode(_fileno(stderr), O_BINARY);
|
||||||
utf8_args(argc, argv);
|
utf8_args(argc, argv);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
10
matrix.hpp
10
matrix.hpp
|
@ -4,13 +4,13 @@ namespace nall {
|
||||||
|
|
||||||
namespace Matrix {
|
namespace Matrix {
|
||||||
|
|
||||||
template<typename T> inline auto Multiply(T* output, const T* xdata, unsigned xrows, unsigned xcols, const T* ydata, unsigned yrows, unsigned ycols) -> void {
|
template<typename T> inline auto Multiply(T* output, const T* xdata, uint xrows, uint xcols, const T* ydata, uint yrows, uint ycols) -> void {
|
||||||
if(xcols != yrows) return;
|
if(xcols != yrows) return;
|
||||||
|
|
||||||
for(unsigned y = 0; y < xrows; y++) {
|
for(uint y : range(xrows)) {
|
||||||
for(unsigned x = 0; x < ycols; x++) {
|
for(uint x : range(ycols)) {
|
||||||
T sum = 0;
|
T sum = 0;
|
||||||
for(unsigned z = 0; z < xcols; z++) {
|
for(uint z : range(xcols)) {
|
||||||
sum += xdata[y * xcols + z] * ydata[z * ycols + x];
|
sum += xdata[y * xcols + z] * ydata[z * ycols + x];
|
||||||
}
|
}
|
||||||
*output++ = sum;
|
*output++ = sum;
|
||||||
|
@ -18,7 +18,7 @@ template<typename T> inline auto Multiply(T* output, const T* xdata, unsigned xr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> inline auto Multiply(const T* xdata, unsigned xrows, unsigned xcols, const T* ydata, unsigned yrows, unsigned ycols) -> vector<T> {
|
template<typename T> inline auto Multiply(const T* xdata, uint xrows, uint xcols, const T* ydata, uint yrows, uint ycols) -> vector<T> {
|
||||||
vector<T> output;
|
vector<T> output;
|
||||||
output.resize(xrows * ycols);
|
output.resize(xrows * ycols);
|
||||||
Multiply(output.data(), xdata, xrows, xcols, ydata, yrows, ycols);
|
Multiply(output.data(), xdata, xrows, xcols, ydata, yrows, ycols);
|
||||||
|
|
|
@ -30,7 +30,6 @@ struct maybe {
|
||||||
if(this == &source) return *this;
|
if(this == &source) return *this;
|
||||||
reset();
|
reset();
|
||||||
if(_valid = source._valid) new(&_value.t) T(move(source.get()));
|
if(_valid = source._valid) new(&_value.t) T(move(source.get()));
|
||||||
source._valid = false;
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
132
memory.hpp
132
memory.hpp
|
@ -1,3 +1,133 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <nall/memory/memory.hpp>
|
#include <nall/algorithm.hpp>
|
||||||
|
#include <nall/stdint.hpp>
|
||||||
|
|
||||||
|
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<typename T> inline auto assign(T* target) -> void {}
|
||||||
|
template<typename T, typename U, typename... P> 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<typename T, typename U, typename... P>
|
||||||
|
auto memory::assign(T* target, const U& value, P&&... p) -> void {
|
||||||
|
*target++ = value;
|
||||||
|
assign(target, forward<P>(p)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,129 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <nall/algorithm.hpp>
|
|
||||||
|
|
||||||
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 <nall/memory/pool.hpp>
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
namespace memory {
|
|
||||||
|
|
||||||
template<unsigned Capacity, unsigned Size>
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -69,7 +69,7 @@ struct context {
|
||||||
for(auto& item : list) {
|
for(auto& item : list) {
|
||||||
item.strip();
|
item.strip();
|
||||||
if(item.match("f(?*) ?*")) {
|
if(item.match("f(?*) ?*")) {
|
||||||
item.ltrim("f(", 1L);
|
item.trimLeft("f(", 1L);
|
||||||
lstring part = item.split(") ", 1L);
|
lstring part = item.split(") ", 1L);
|
||||||
lstring args = part[0].split(";", 3L).strip();
|
lstring args = part[0].split(";", 3L).strip();
|
||||||
|
|
||||||
|
@ -90,9 +90,9 @@ struct context {
|
||||||
}
|
}
|
||||||
} else if(item.match("base64*")) {
|
} else if(item.match("base64*")) {
|
||||||
uint offset = 0;
|
uint offset = 0;
|
||||||
item.ltrim("base64", 1L);
|
item.trimLeft("base64", 1L);
|
||||||
if(item.match("(?*) *")) {
|
if(item.match("(?*) *")) {
|
||||||
item.ltrim("(", 1L);
|
item.trimLeft("(", 1L);
|
||||||
lstring part = item.split(") ", 1L);
|
lstring part = item.split(") ", 1L);
|
||||||
offset = eval(part[0]);
|
offset = eval(part[0]);
|
||||||
item = part(1, "");
|
item = part(1, "");
|
||||||
|
@ -106,10 +106,10 @@ struct context {
|
||||||
if(c == '_') buffer.append(offset + 63);
|
if(c == '_') buffer.append(offset + 63);
|
||||||
}
|
}
|
||||||
} else if(item.match("file *")) {
|
} else if(item.match("file *")) {
|
||||||
item.ltrim("file ", 1L);
|
item.trimLeft("file ", 1L);
|
||||||
item.strip();
|
item.strip();
|
||||||
//...
|
//...
|
||||||
} else if(item.empty() == false) {
|
} else if(item) {
|
||||||
buffer.append(eval(item));
|
buffer.append(eval(item));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
7
nall.hpp
7
nall.hpp
|
@ -17,7 +17,8 @@
|
||||||
#include <nall/any.hpp>
|
#include <nall/any.hpp>
|
||||||
#include <nall/atoi.hpp>
|
#include <nall/atoi.hpp>
|
||||||
#include <nall/bit.hpp>
|
#include <nall/bit.hpp>
|
||||||
#include <nall/bitvector.hpp>
|
#include <nall/bit-field.hpp>
|
||||||
|
#include <nall/bit-vector.hpp>
|
||||||
#include <nall/config.hpp>
|
#include <nall/config.hpp>
|
||||||
#include <nall/directory.hpp>
|
#include <nall/directory.hpp>
|
||||||
#include <nall/dl.hpp>
|
#include <nall/dl.hpp>
|
||||||
|
@ -35,8 +36,10 @@
|
||||||
#include <nall/matrix.hpp>
|
#include <nall/matrix.hpp>
|
||||||
#include <nall/maybe.hpp>
|
#include <nall/maybe.hpp>
|
||||||
#include <nall/memory.hpp>
|
#include <nall/memory.hpp>
|
||||||
|
#include <nall/path.hpp>
|
||||||
#include <nall/primitives.hpp>
|
#include <nall/primitives.hpp>
|
||||||
#include <nall/property.hpp>
|
#include <nall/property.hpp>
|
||||||
|
#include <nall/queue.hpp>
|
||||||
#include <nall/random.hpp>
|
#include <nall/random.hpp>
|
||||||
#include <nall/range.hpp>
|
#include <nall/range.hpp>
|
||||||
#include <nall/run.hpp>
|
#include <nall/run.hpp>
|
||||||
|
@ -45,7 +48,6 @@
|
||||||
#include <nall/shared-pointer.hpp>
|
#include <nall/shared-pointer.hpp>
|
||||||
#include <nall/sort.hpp>
|
#include <nall/sort.hpp>
|
||||||
#include <nall/stdint.hpp>
|
#include <nall/stdint.hpp>
|
||||||
#include <nall/stream.hpp>
|
|
||||||
#include <nall/string.hpp>
|
#include <nall/string.hpp>
|
||||||
#include <nall/thread.hpp>
|
#include <nall/thread.hpp>
|
||||||
#include <nall/traits.hpp>
|
#include <nall/traits.hpp>
|
||||||
|
@ -64,6 +66,7 @@
|
||||||
#include <nall/encode/url.hpp>
|
#include <nall/encode/url.hpp>
|
||||||
#include <nall/hash/crc16.hpp>
|
#include <nall/hash/crc16.hpp>
|
||||||
#include <nall/hash/crc32.hpp>
|
#include <nall/hash/crc32.hpp>
|
||||||
|
#include <nall/hash/crc64.hpp>
|
||||||
#include <nall/hash/sha256.hpp>
|
#include <nall/hash/sha256.hpp>
|
||||||
|
|
||||||
#if defined(PLATFORM_WINDOWS)
|
#if defined(PLATFORM_WINDOWS)
|
||||||
|
|
|
@ -1,44 +1,46 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace nall {
|
#include <nall/string.hpp>
|
||||||
|
|
||||||
auto activepath() -> string {
|
namespace nall { namespace Path {
|
||||||
|
|
||||||
|
inline auto active() -> string {
|
||||||
char path[PATH_MAX] = "";
|
char path[PATH_MAX] = "";
|
||||||
auto unused = getcwd(path, PATH_MAX);
|
auto unused = getcwd(path, PATH_MAX);
|
||||||
string result = path;
|
string result = path;
|
||||||
if(!result) result = ".";
|
if(!result) result = ".";
|
||||||
result.transform("\\", "/");
|
result.transform("\\", "/");
|
||||||
if(result.endsWith("/") == false) result.append("/");
|
if(!result.endsWith("/")) result.append("/");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto realpath(rstring name) -> string {
|
inline auto real(string_view name) -> string {
|
||||||
string result;
|
string result;
|
||||||
char path[PATH_MAX] = "";
|
char path[PATH_MAX] = "";
|
||||||
if(::realpath(name, path)) result = pathname(string{path}.transform("\\", "/"));
|
if(::realpath(name, path)) result = pathname(string{path}.transform("\\", "/"));
|
||||||
if(!result) return activepath();
|
if(!result) return active();
|
||||||
result.transform("\\", "/");
|
result.transform("\\", "/");
|
||||||
if(result.endsWith("/") == false) result.append("/");
|
if(!result.endsWith("/")) result.append("/");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto programpath() -> string {
|
inline auto program() -> string {
|
||||||
#if defined(PLATFORM_WINDOWS)
|
#if defined(PLATFORM_WINDOWS)
|
||||||
wchar_t path[PATH_MAX] = L"";
|
wchar_t path[PATH_MAX] = L"";
|
||||||
GetModuleFileName(nullptr, path, PATH_MAX);
|
GetModuleFileName(nullptr, path, PATH_MAX);
|
||||||
string result = (const char*)utf8_t(path);
|
string result = (const char*)utf8_t(path);
|
||||||
result.transform("\\", "/");
|
result.transform("\\", "/");
|
||||||
return realpath(result);
|
return Path::real(result);
|
||||||
#else
|
#else
|
||||||
Dl_info info;
|
Dl_info info;
|
||||||
dladdr((void*)&programpath, &info);
|
dladdr((void*)&program, &info);
|
||||||
return realpath(info.dli_fname);
|
return Path::real(info.dli_fname);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// /
|
// /
|
||||||
// c:/
|
// c:/
|
||||||
auto rootpath() -> string {
|
inline auto root() -> string {
|
||||||
#if defined(PLATFORM_WINDOWS)
|
#if defined(PLATFORM_WINDOWS)
|
||||||
wchar_t path[PATH_MAX] = L"";
|
wchar_t path[PATH_MAX] = L"";
|
||||||
SHGetFolderPathW(nullptr, CSIDL_WINDOWS | CSIDL_FLAG_CREATE, nullptr, 0, path);
|
SHGetFolderPathW(nullptr, CSIDL_WINDOWS | CSIDL_FLAG_CREATE, nullptr, 0, path);
|
||||||
|
@ -52,7 +54,7 @@ auto rootpath() -> string {
|
||||||
|
|
||||||
// /home/username/
|
// /home/username/
|
||||||
// c:/users/username/
|
// c:/users/username/
|
||||||
auto userpath() -> string {
|
inline auto user() -> string {
|
||||||
#if defined(PLATFORM_WINDOWS)
|
#if defined(PLATFORM_WINDOWS)
|
||||||
wchar_t path[PATH_MAX] = L"";
|
wchar_t path[PATH_MAX] = L"";
|
||||||
SHGetFolderPathW(nullptr, CSIDL_PROFILE | CSIDL_FLAG_CREATE, nullptr, 0, path);
|
SHGetFolderPathW(nullptr, CSIDL_PROFILE | CSIDL_FLAG_CREATE, nullptr, 0, path);
|
||||||
|
@ -63,50 +65,50 @@ auto userpath() -> string {
|
||||||
string result = userinfo->pw_dir;
|
string result = userinfo->pw_dir;
|
||||||
#endif
|
#endif
|
||||||
if(!result) result = ".";
|
if(!result) result = ".";
|
||||||
if(result.endsWith("/") == false) result.append("/");
|
if(!result.endsWith("/")) result.append("/");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// /home/username/.config/
|
// /home/username/.config/
|
||||||
// c:/users/username/appdata/roaming/
|
// c:/users/username/appdata/roaming/
|
||||||
auto configpath() -> string {
|
inline auto config() -> string {
|
||||||
#if defined(PLATFORM_WINDOWS)
|
#if defined(PLATFORM_WINDOWS)
|
||||||
wchar_t path[PATH_MAX] = L"";
|
wchar_t path[PATH_MAX] = L"";
|
||||||
SHGetFolderPathW(nullptr, CSIDL_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path);
|
SHGetFolderPathW(nullptr, CSIDL_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path);
|
||||||
string result = (const char*)utf8_t(path);
|
string result = (const char*)utf8_t(path);
|
||||||
result.transform("\\", "/");
|
result.transform("\\", "/");
|
||||||
#elif defined(PLATFORM_MACOSX)
|
#elif defined(PLATFORM_MACOSX)
|
||||||
string result = {userpath(), "Library/Application Support/"};
|
string result = {Path::user(), "Library/Application Support/"};
|
||||||
#else
|
#else
|
||||||
string result = {userpath(), ".config/"};
|
string result = {Path::user(), ".config/"};
|
||||||
#endif
|
#endif
|
||||||
if(!result) result = ".";
|
if(!result) result = ".";
|
||||||
if(result.endsWith("/") == false) result.append("/");
|
if(!result.endsWith("/")) result.append("/");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// /home/username/.local/share/
|
// /home/username/.local/share/
|
||||||
// c:/users/username/appdata/local/
|
// c:/users/username/appdata/local/
|
||||||
auto localpath() -> string {
|
inline auto local() -> string {
|
||||||
#if defined(PLATFORM_WINDOWS)
|
#if defined(PLATFORM_WINDOWS)
|
||||||
wchar_t path[PATH_MAX] = L"";
|
wchar_t path[PATH_MAX] = L"";
|
||||||
SHGetFolderPathW(nullptr, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path);
|
SHGetFolderPathW(nullptr, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path);
|
||||||
string result = (const char*)utf8_t(path);
|
string result = (const char*)utf8_t(path);
|
||||||
result.transform("\\", "/");
|
result.transform("\\", "/");
|
||||||
#elif defined(PLATFORM_MACOSX)
|
#elif defined(PLATFORM_MACOSX)
|
||||||
string result = {userpath(), "Library/Application Support/"};
|
string result = {Path::user(), "Library/Application Support/"};
|
||||||
#else
|
#else
|
||||||
string result = {userpath(), ".local/share/"};
|
string result = {Path::user(), ".local/share/"};
|
||||||
#endif
|
#endif
|
||||||
if(!result) result = ".";
|
if(!result) result = ".";
|
||||||
if(result.endsWith("/") == false) result.append("/");
|
if(!result.endsWith("/")) result.append("/");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// /usr/share
|
// /usr/share
|
||||||
// /Library/Application Support/
|
// /Library/Application Support/
|
||||||
// c:/ProgramData/
|
// c:/ProgramData/
|
||||||
auto sharedpath() -> string {
|
inline auto shared() -> string {
|
||||||
#if defined(PLATFORM_WINDOWS)
|
#if defined(PLATFORM_WINDOWS)
|
||||||
wchar_t path[PATH_MAX] = L"";
|
wchar_t path[PATH_MAX] = L"";
|
||||||
SHGetFolderPathW(nullptr, CSIDL_COMMON_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path);
|
SHGetFolderPathW(nullptr, CSIDL_COMMON_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path);
|
||||||
|
@ -118,13 +120,13 @@ auto sharedpath() -> string {
|
||||||
string result = "/usr/share/";
|
string result = "/usr/share/";
|
||||||
#endif
|
#endif
|
||||||
if(!result) result = ".";
|
if(!result) result = ".";
|
||||||
if(result.endsWith("/") == false) result.append("/");
|
if(!result.endsWith("/")) result.append("/");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// /tmp
|
// /tmp
|
||||||
// c:/users/username/AppData/Local/Temp/
|
// c:/users/username/AppData/Local/Temp/
|
||||||
auto temppath() -> string {
|
inline auto temp() -> string {
|
||||||
#if defined(PLATFORM_WINDOWS)
|
#if defined(PLATFORM_WINDOWS)
|
||||||
wchar_t path[PATH_MAX] = L"";
|
wchar_t path[PATH_MAX] = L"";
|
||||||
GetTempPathW(PATH_MAX, path);
|
GetTempPathW(PATH_MAX, path);
|
||||||
|
@ -135,8 +137,8 @@ auto temppath() -> string {
|
||||||
#else
|
#else
|
||||||
string result = "/tmp/";
|
string result = "/tmp/";
|
||||||
#endif
|
#endif
|
||||||
if(result.endsWith("/") == false) result.append("/");
|
if(!result.endsWith("/")) result.append("/");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}}
|
|
@ -18,10 +18,6 @@ struct shared_memory {
|
||||||
return _mode != mode::inactive;
|
return _mode != mode::inactive;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto empty() const -> bool {
|
|
||||||
return _mode == mode::inactive;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto size() const -> unsigned {
|
auto size() const -> unsigned {
|
||||||
return _size;
|
return _size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,27 +29,27 @@ template<uint Bits> struct Natural {
|
||||||
enum : type { Mask = ~0ull >> (64 - Bits) };
|
enum : type { Mask = ~0ull >> (64 - Bits) };
|
||||||
|
|
||||||
inline Natural() : data(0) {}
|
inline Natural() : data(0) {}
|
||||||
template<typename T> inline Natural(const T& value) { assign(value); }
|
template<typename T> inline Natural(const T& value) { set(value); }
|
||||||
|
|
||||||
inline operator type() const { return data; }
|
inline operator type() const { return data; }
|
||||||
template<typename T> inline auto& operator=(const T& value) { assign(value); return *this; }
|
template<typename T> 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; set(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++() { assign(data + 1); return *this; }
|
inline auto& operator++() { set(data + 1); return *this; }
|
||||||
inline auto& operator--() { assign(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) { set(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) { assign(data ^ value); return *this; }
|
inline auto& operator ^=(const type value) { set(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) { assign(data >> value); return *this; }
|
inline auto& operator>>=(const type value) { set(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) { assign(data - value); return *this; }
|
inline auto& operator -=(const type value) { set(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) { assign(data / value); return *this; }
|
inline auto& operator /=(const type value) { set(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 serialize(serializer& s) { s(data); }
|
inline auto serialize(serializer& s) { s(data); }
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ template<uint Bits> struct Natural {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto assign(type value) -> void {
|
auto set(type value) -> void {
|
||||||
data = value & Mask;
|
data = value & Mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,27 +111,27 @@ template<uint Bits> struct Integer {
|
||||||
enum : utype { Mask = ~0ull >> (64 - Bits), Sign = 1ull << (Bits - 1) };
|
enum : utype { Mask = ~0ull >> (64 - Bits), Sign = 1ull << (Bits - 1) };
|
||||||
|
|
||||||
inline Integer() : data(0) {}
|
inline Integer() : data(0) {}
|
||||||
template<typename T> inline Integer(const T& value) { assign(value); }
|
template<typename T> inline Integer(const T& value) { set(value); }
|
||||||
|
|
||||||
inline operator type() const { return data; }
|
inline operator type() const { return data; }
|
||||||
template<typename T> inline auto& operator=(const T& value) { assign(value); return *this; }
|
template<typename T> 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; set(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++() { assign(data + 1); return *this; }
|
inline auto& operator++() { set(data + 1); return *this; }
|
||||||
inline auto& operator--() { assign(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) { set(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) { assign(data ^ value); return *this; }
|
inline auto& operator ^=(const type value) { set(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) { assign(data >> value); return *this; }
|
inline auto& operator>>=(const type value) { set(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) { assign(data - value); return *this; }
|
inline auto& operator -=(const type value) { set(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) { assign(data / value); return *this; }
|
inline auto& operator /=(const type value) { set(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 serialize(serializer& s) { s(data); }
|
inline auto serialize(serializer& s) { s(data); }
|
||||||
|
|
||||||
|
@ -174,7 +174,7 @@ template<uint Bits> struct Integer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto assign(type value) -> void {
|
auto set(type value) -> void {
|
||||||
data = ((value & Mask) ^ Sign) - Sign;
|
data = ((value & Mask) ^ Sign) - Sign;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,12 +208,16 @@ template<uint Bits> struct Real {
|
||||||
|
|
||||||
inline auto serialize(serializer& s) { s(data); }
|
inline auto serialize(serializer& s) { s(data); }
|
||||||
|
|
||||||
|
private:
|
||||||
type data;
|
type data;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
using boolean = nall::Boolean;
|
using boolean = nall::Boolean;
|
||||||
|
//note: these conflict with nall/atoi.hpp functions
|
||||||
|
//using integer = nall::Integer<sizeof( int) * 8>;
|
||||||
|
//using natural = nall::Natural<sizeof(uint) * 8>;
|
||||||
|
|
||||||
using int1 = nall::Integer< 1>;
|
using int1 = nall::Integer< 1>;
|
||||||
using int2 = nall::Integer< 2>;
|
using int2 = nall::Integer< 2>;
|
||||||
|
|
|
@ -1,106 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <limits>
|
|
||||||
#include <nall/function.hpp>
|
|
||||||
#include <nall/serializer.hpp>
|
|
||||||
#include <nall/utility.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
template<typename type_t> 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<typename type_t> struct priority_queue {
|
|
||||||
priority_queue(unsigned size, function<void (type_t)> callback = &priority_queue_nocallback<type_t>) : 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<unsigned>::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<void (type_t)> 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<unsigned>::max() >> 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
90
property.hpp
90
property.hpp
|
@ -2,40 +2,66 @@
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
template<typename C> struct property {
|
template<typename T> struct property {
|
||||||
template<typename T> struct readonly {
|
property() = default;
|
||||||
auto operator->() const -> const T* { return &value; }
|
property(const T& value) : value(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<typename T> struct writeonly {
|
operator T&() { return value; } //direct assignment
|
||||||
auto operator=(const T& value_) -> void { value = value_; }
|
auto operator->() -> T* { return &value; } //class-member access
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T> struct readwrite {
|
operator const T&() const { return value; }
|
||||||
auto operator->() const -> const T* { return &value; }
|
auto operator()() const -> const T& { return value; }
|
||||||
auto operator()() const -> const T& { return value; }
|
auto get() const -> const T& { return value; }
|
||||||
operator const T&() const { return value; }
|
|
||||||
auto operator->() -> T* { return &value; }
|
auto operator=(const T& value) -> T& { return this->value = value; }
|
||||||
operator T&() { return value; }
|
auto set(const T& value) -> T& { return this->value = value; }
|
||||||
auto operator=(const T& value_) -> const T& { return value = value_; }
|
|
||||||
T value;
|
T value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T, typename R = T> struct functional_property {
|
||||||
|
functional_property(
|
||||||
|
const function<R (const T&)>& getter = {},
|
||||||
|
const function<R (T&, const T&)>& 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<R (const T&)> getter;
|
||||||
|
function<R (T&, const T&)> setter;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename R = T> struct virtual_property {
|
||||||
|
virtual_property(
|
||||||
|
const function<R ()>& getter = {},
|
||||||
|
const function<R (const T&)>& 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<R ()> getter;
|
||||||
|
function<R (const T&)> setter;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
101
queue.hpp
Normal file
101
queue.hpp
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//simple circular ring buffer
|
||||||
|
|
||||||
|
namespace nall {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -15,11 +15,11 @@ struct RandomNumberGenerator {
|
||||||
struct LinearFeedbackShiftRegisterGenerator : RandomNumberGenerator {
|
struct LinearFeedbackShiftRegisterGenerator : RandomNumberGenerator {
|
||||||
auto seed(uint64_t seed) -> void {
|
auto seed(uint64_t seed) -> void {
|
||||||
lfsr = seed;
|
lfsr = seed;
|
||||||
for(unsigned n = 0; n < 8; n++) operator()();
|
for(uint n = 0; n < 8; n++) operator()();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operator()() -> uint64_t {
|
auto operator()() -> uint64_t {
|
||||||
return lfsr = (lfsr >> 1) ^ (-(lfsr & 1) & crc64jones);
|
return lfsr = (lfsr >> 1) ^ (-(lfsr & 1) & crc64);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto serialize(serializer& s) -> void {
|
auto serialize(serializer& s) -> void {
|
||||||
|
@ -27,9 +27,8 @@ struct LinearFeedbackShiftRegisterGenerator : RandomNumberGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const uint64_t crc64ecma = 0x42f0e1eba9ea3693;
|
static const uint64_t crc64 = 0xc96c'5795'd787'0f42;
|
||||||
static const uint64_t crc64jones = 0xad93d23594c935a9;
|
uint64_t lfsr = crc64;
|
||||||
uint64_t lfsr = crc64ecma;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline auto random() -> uint64_t {
|
inline auto random() -> uint64_t {
|
||||||
|
|
|
@ -39,12 +39,4 @@ inline auto rrange(int size) {
|
||||||
return range_t{size - 1, -1, -1};
|
return range_t{size - 1, -1, -1};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> inline auto range(const vector<T>& container) {
|
|
||||||
return range_t{0, (int)container.size(), 1};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T> inline auto rrange(const vector<T>& container) {
|
|
||||||
return range_t{(int)container.size() - 1, -1, -1};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
112
run.hpp
112
run.hpp
|
@ -16,11 +16,21 @@
|
||||||
|
|
||||||
namespace nall {
|
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)
|
#if defined(PLATFORM_MACOSX) || defined(PLATFORM_LINUX) || defined(PLATFORM_BSD)
|
||||||
|
|
||||||
template<typename... P> inline auto execute(const string& name, P&&... p) -> string {
|
template<typename... P> inline auto execute(const string& name, P&&... p) -> execute_result_t {
|
||||||
int fd[2];
|
int fdout[2];
|
||||||
if(pipe(fd) == -1) return "";
|
int fderr[2];
|
||||||
|
if(pipe(fdout) == -1) return {};
|
||||||
|
if(pipe(fderr) == -1) return {};
|
||||||
|
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
if(pid == 0) {
|
if(pid == 0) {
|
||||||
|
@ -31,28 +41,48 @@ template<typename... P> inline auto execute(const string& name, P&&... p) -> str
|
||||||
for(auto& arg : argl) *argp++ = (const char*)arg;
|
for(auto& arg : argl) *argp++ = (const char*)arg;
|
||||||
*argp++ = nullptr;
|
*argp++ = nullptr;
|
||||||
|
|
||||||
dup2(fd[1], STDOUT_FILENO);
|
dup2(fdout[1], STDOUT_FILENO);
|
||||||
dup2(fd[1], STDERR_FILENO);
|
dup2(fderr[1], STDERR_FILENO);
|
||||||
close(fd[0]);
|
close(fdout[0]);
|
||||||
close(fd[1]);
|
close(fderr[0]);
|
||||||
|
close(fdout[1]);
|
||||||
|
close(fderr[1]);
|
||||||
execvp(name, (char* const*)argv);
|
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 {
|
} else {
|
||||||
close(fd[1]);
|
close(fdout[1]);
|
||||||
|
close(fderr[1]);
|
||||||
|
|
||||||
|
char buffer[256];
|
||||||
|
execute_result_t result;
|
||||||
|
|
||||||
string result;
|
|
||||||
while(true) {
|
while(true) {
|
||||||
char buffer[256];
|
auto size = read(fdout[0], buffer, sizeof(buffer));
|
||||||
auto size = read(fd[0], buffer, sizeof(buffer));
|
|
||||||
if(size <= 0) break;
|
if(size <= 0) break;
|
||||||
|
|
||||||
auto offset = result.size();
|
auto offset = result.output.size();
|
||||||
result.resize(offset + size);
|
result.output.resize(offset + size);
|
||||||
memory::copy(result.get() + offset, buffer, size);
|
memory::copy(result.output.get() + offset, buffer, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd[0]);
|
while(true) {
|
||||||
wait(nullptr);
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,7 +106,7 @@ template<typename... P> inline auto invoke(const string& name, P&&... p) -> void
|
||||||
|
|
||||||
#elif defined(PLATFORM_WINDOWS)
|
#elif defined(PLATFORM_WINDOWS)
|
||||||
|
|
||||||
template<typename... P> inline auto execute(const string& name, P&&... p) -> string {
|
template<typename... P> inline auto execute(const string& name, P&&... p) -> execute_result_t {
|
||||||
lstring argl(name, forward<P>(p)...);
|
lstring argl(name, forward<P>(p)...);
|
||||||
for(auto& arg : argl) if(arg.find(" ")) arg = {"\"", arg, "\""};
|
for(auto& arg : argl) if(arg.find(" ")) arg = {"\"", arg, "\""};
|
||||||
string arguments = argl.merge(" ");
|
string arguments = argl.merge(" ");
|
||||||
|
@ -89,19 +119,24 @@ template<typename... P> inline auto execute(const string& name, P&&... p) -> str
|
||||||
|
|
||||||
HANDLE stdoutRead;
|
HANDLE stdoutRead;
|
||||||
HANDLE stdoutWrite;
|
HANDLE stdoutWrite;
|
||||||
if(!CreatePipe(&stdoutRead, &stdoutWrite, &sa, 0)) return "";
|
if(!CreatePipe(&stdoutRead, &stdoutWrite, &sa, 0)) return {};
|
||||||
if(!SetHandleInformation(stdoutRead, HANDLE_FLAG_INHERIT, 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 stdinRead;
|
||||||
HANDLE stdinWrite;
|
HANDLE stdinWrite;
|
||||||
if(!CreatePipe(&stdinRead, &stdinWrite, &sa, 0)) return "";
|
if(!CreatePipe(&stdinRead, &stdinWrite, &sa, 0)) return {};
|
||||||
if(!SetHandleInformation(stdinWrite, HANDLE_FLAG_INHERIT, 0)) return "";
|
if(!SetHandleInformation(stdinWrite, HANDLE_FLAG_INHERIT, 0)) return {};
|
||||||
|
|
||||||
STARTUPINFO si;
|
STARTUPINFO si;
|
||||||
ZeroMemory(&si, sizeof(STARTUPINFO));
|
ZeroMemory(&si, sizeof(STARTUPINFO));
|
||||||
si.cb = sizeof(STARTUPINFO);
|
si.cb = sizeof(STARTUPINFO);
|
||||||
si.hStdError = stdoutWrite;
|
|
||||||
si.hStdOutput = stdoutWrite;
|
si.hStdOutput = stdoutWrite;
|
||||||
|
si.hStdError = stderrWrite;
|
||||||
si.hStdInput = stdinRead;
|
si.hStdInput = stdinRead;
|
||||||
si.dwFlags = STARTF_USESTDHANDLES;
|
si.dwFlags = STARTF_USESTDHANDLES;
|
||||||
|
|
||||||
|
@ -112,15 +147,19 @@ template<typename... P> inline auto execute(const string& name, P&&... p) -> str
|
||||||
nullptr, utf16_t(arguments),
|
nullptr, utf16_t(arguments),
|
||||||
nullptr, nullptr, true, CREATE_NO_WINDOW,
|
nullptr, nullptr, true, CREATE_NO_WINDOW,
|
||||||
nullptr, nullptr, &si, &pi
|
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.hThread);
|
||||||
CloseHandle(pi.hProcess);
|
CloseHandle(pi.hProcess);
|
||||||
|
|
||||||
string result;
|
char buffer[256];
|
||||||
|
execute_result_t result;
|
||||||
|
result.code = exitCode;
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
char buffer[256];
|
|
||||||
DWORD read, available, remaining;
|
DWORD read, available, remaining;
|
||||||
if(!PeekNamedPipe(stdoutRead, nullptr, sizeof(buffer), &read, &available, &remaining)) break;
|
if(!PeekNamedPipe(stdoutRead, nullptr, sizeof(buffer), &read, &available, &remaining)) break;
|
||||||
if(read == 0) break;
|
if(read == 0) break;
|
||||||
|
@ -128,9 +167,22 @@ template<typename... P> inline auto execute(const string& name, P&&... p) -> str
|
||||||
if(!ReadFile(stdoutRead, buffer, sizeof(buffer), &read, nullptr)) break;
|
if(!ReadFile(stdoutRead, buffer, sizeof(buffer), &read, nullptr)) break;
|
||||||
if(read == 0) break;
|
if(read == 0) break;
|
||||||
|
|
||||||
auto offset = result.size();
|
auto offset = result.output.size();
|
||||||
result.resize(offset + read);
|
result.output.resize(offset + read);
|
||||||
memory::copy(result.get() + offset, buffer, 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;
|
return result;
|
||||||
|
|
34
serial.hpp
34
serial.hpp
|
@ -16,17 +16,12 @@
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
struct serial {
|
struct serial {
|
||||||
serial() {
|
|
||||||
port = -1;
|
|
||||||
port_open = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
~serial() {
|
~serial() {
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto readable() -> bool {
|
auto readable() -> bool {
|
||||||
if(port_open == false) return false;
|
if(!opened) return false;
|
||||||
fd_set fdset;
|
fd_set fdset;
|
||||||
FD_ZERO(&fdset);
|
FD_ZERO(&fdset);
|
||||||
FD_SET(port, &fdset);
|
FD_SET(port, &fdset);
|
||||||
|
@ -40,12 +35,12 @@ struct serial {
|
||||||
|
|
||||||
//-1 on error, otherwise return bytes read
|
//-1 on error, otherwise return bytes read
|
||||||
auto read(uint8_t* data, uint length) -> int {
|
auto read(uint8_t* data, uint length) -> int {
|
||||||
if(port_open == false) return -1;
|
if(!opened) return -1;
|
||||||
return ::read(port, (void*)data, length);
|
return ::read(port, (void*)data, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto writable() -> bool {
|
auto writable() -> bool {
|
||||||
if(port_open == false) return false;
|
if(!opened) return false;
|
||||||
fd_set fdset;
|
fd_set fdset;
|
||||||
FD_ZERO(&fdset);
|
FD_ZERO(&fdset);
|
||||||
FD_SET(port, &fdset);
|
FD_SET(port, &fdset);
|
||||||
|
@ -59,14 +54,17 @@ struct serial {
|
||||||
|
|
||||||
//-1 on error, otherwise return bytes written
|
//-1 on error, otherwise return bytes written
|
||||||
auto write(const uint8_t* data, uint length) -> int {
|
auto write(const uint8_t* data, uint length) -> int {
|
||||||
if(port_open == false) return -1;
|
if(!opened) return -1;
|
||||||
return ::write(port, (void*)data, length);
|
return ::write(port, (void*)data, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto open(const string& portname, uint rate, bool flowcontrol) -> bool {
|
//rate==0: use flow control (synchronous mode)
|
||||||
|
//rate!=0: baud-rate (asynchronous mode)
|
||||||
|
auto open(string device, uint rate = 0) -> bool {
|
||||||
close();
|
close();
|
||||||
|
|
||||||
port = ::open(portname, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
|
if(!device) device = "/dev/ttyU0"; //note: default device name is for FreeBSD 10+
|
||||||
|
port = ::open(device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
|
||||||
if(port == -1) return false;
|
if(port == -1) return false;
|
||||||
|
|
||||||
if(ioctl(port, TIOCEXCL) == -1) { close(); return false; }
|
if(ioctl(port, TIOCEXCL) == -1) { close(); return false; }
|
||||||
|
@ -75,7 +73,7 @@ struct serial {
|
||||||
|
|
||||||
termios attr = original_attr;
|
termios attr = original_attr;
|
||||||
cfmakeraw(&attr);
|
cfmakeraw(&attr);
|
||||||
cfsetspeed(&attr, rate);
|
cfsetspeed(&attr, rate ? rate : 57600); //rate value has no effect in synchronous mode
|
||||||
|
|
||||||
attr.c_lflag &=~ (ECHO | ECHONL | ISIG | ICANON | IEXTEN);
|
attr.c_lflag &=~ (ECHO | ECHONL | ISIG | ICANON | IEXTEN);
|
||||||
attr.c_iflag &=~ (BRKINT | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY);
|
attr.c_iflag &=~ (BRKINT | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY);
|
||||||
|
@ -83,7 +81,7 @@ struct serial {
|
||||||
attr.c_oflag &=~ (OPOST);
|
attr.c_oflag &=~ (OPOST);
|
||||||
attr.c_cflag &=~ (CSIZE | CSTOPB | PARENB | CLOCAL);
|
attr.c_cflag &=~ (CSIZE | CSTOPB | PARENB | CLOCAL);
|
||||||
attr.c_cflag |= (CS8 | CREAD);
|
attr.c_cflag |= (CS8 | CREAD);
|
||||||
if(flowcontrol == false) {
|
if(rate) {
|
||||||
attr.c_cflag &= ~CRTSCTS;
|
attr.c_cflag &= ~CRTSCTS;
|
||||||
} else {
|
} else {
|
||||||
attr.c_cflag |= CRTSCTS;
|
attr.c_cflag |= CRTSCTS;
|
||||||
|
@ -91,15 +89,15 @@ struct serial {
|
||||||
attr.c_cc[VTIME] = attr.c_cc[VMIN] = 0;
|
attr.c_cc[VTIME] = attr.c_cc[VMIN] = 0;
|
||||||
|
|
||||||
if(tcsetattr(port, TCSANOW, &attr) == -1) { close(); return false; }
|
if(tcsetattr(port, TCSANOW, &attr) == -1) { close(); return false; }
|
||||||
return port_open = true;
|
return opened = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto close() -> void {
|
auto close() -> void {
|
||||||
if(port != -1) {
|
if(port != -1) {
|
||||||
tcdrain(port);
|
tcdrain(port);
|
||||||
if(port_open == true) {
|
if(opened) {
|
||||||
tcsetattr(port, TCSANOW, &original_attr);
|
tcsetattr(port, TCSANOW, &original_attr);
|
||||||
port_open = false;
|
opened = false;
|
||||||
}
|
}
|
||||||
::close(port);
|
::close(port);
|
||||||
port = -1;
|
port = -1;
|
||||||
|
@ -107,8 +105,8 @@ struct serial {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int port;
|
int port = -1;
|
||||||
bool port_open;
|
bool opened = false;
|
||||||
termios original_attr;
|
termios original_attr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
32
set.hpp
32
set.hpp
|
@ -26,7 +26,7 @@ template<typename T> struct set {
|
||||||
};
|
};
|
||||||
|
|
||||||
node_t* root = nullptr;
|
node_t* root = nullptr;
|
||||||
unsigned nodes = 0;
|
uint nodes = 0;
|
||||||
|
|
||||||
set() = default;
|
set() = default;
|
||||||
set(const set& source) { operator=(source); }
|
set(const set& source) { operator=(source); }
|
||||||
|
@ -49,8 +49,8 @@ template<typename T> struct set {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto size() const -> unsigned { return nodes; }
|
explicit operator bool() const { return nodes; }
|
||||||
auto empty() const -> bool { return nodes == 0; }
|
auto size() const -> uint { return nodes; }
|
||||||
|
|
||||||
auto reset() -> void {
|
auto reset() -> void {
|
||||||
reset(root);
|
reset(root);
|
||||||
|
@ -68,7 +68,7 @@ template<typename T> struct set {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto insert(const T& value) -> maybe<T&> {
|
auto insert(const T& value) -> maybe<T&> {
|
||||||
unsigned count = size();
|
uint count = size();
|
||||||
node_t* v = insert(root, value);
|
node_t* v = insert(root, value);
|
||||||
root->red = 0;
|
root->red = 0;
|
||||||
if(size() == count) return nothing;
|
if(size() == count) return nothing;
|
||||||
|
@ -82,7 +82,7 @@ template<typename T> struct set {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto remove(const T& value) -> bool {
|
auto remove(const T& value) -> bool {
|
||||||
unsigned count = size();
|
uint count = size();
|
||||||
bool done = 0;
|
bool done = 0;
|
||||||
remove(root, &value, done);
|
remove(root, &value, done);
|
||||||
if(root) root->red = 0;
|
if(root) root->red = 0;
|
||||||
|
@ -100,19 +100,19 @@ template<typename T> struct set {
|
||||||
auto operator++() -> base_iterator& {
|
auto operator++() -> base_iterator& {
|
||||||
if(++position >= source.size()) { position = source.size(); return *this; }
|
if(++position >= source.size()) { position = source.size(); return *this; }
|
||||||
|
|
||||||
if(stack.last()->link[1]) {
|
if(stack.right()->link[1]) {
|
||||||
stack.append(stack.last()->link[1]);
|
stack.append(stack.right()->link[1]);
|
||||||
while(stack.last()->link[0]) stack.append(stack.last()->link[0]);
|
while(stack.right()->link[0]) stack.append(stack.right()->link[0]);
|
||||||
} else {
|
} else {
|
||||||
node_t* child;
|
node_t* child;
|
||||||
do child = stack.take();
|
do child = stack.takeRight();
|
||||||
while(child == stack.last()->link[1]);
|
while(child == stack.right()->link[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
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;
|
node_t* node = source.root;
|
||||||
while(node) {
|
while(node) {
|
||||||
stack.append(node);
|
stack.append(node);
|
||||||
|
@ -122,21 +122,21 @@ template<typename T> struct set {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const set& source;
|
const set& source;
|
||||||
unsigned position;
|
uint position;
|
||||||
vector<node_t*> stack;
|
vector<node_t*> stack;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct iterator : base_iterator {
|
struct iterator : base_iterator {
|
||||||
iterator(const set& source, unsigned position) : base_iterator(source, position) {}
|
iterator(const set& source, uint position) : base_iterator(source, position) {}
|
||||||
auto operator*() const -> T& { return base_iterator::stack.last()->value; }
|
auto operator*() const -> T& { return base_iterator::stack.right()->value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
auto begin() -> iterator { return iterator(*this, 0); }
|
auto begin() -> iterator { return iterator(*this, 0); }
|
||||||
auto end() -> iterator { return iterator(*this, size()); }
|
auto end() -> iterator { return iterator(*this, size()); }
|
||||||
|
|
||||||
struct const_iterator : base_iterator {
|
struct const_iterator : base_iterator {
|
||||||
const_iterator(const set& source, unsigned position) : base_iterator(source, position) {}
|
const_iterator(const set& source, uint position) : base_iterator(source, position) {}
|
||||||
auto operator*() const -> const T& { return base_iterator::stack.last()->value; }
|
auto operator*() const -> const T& { return base_iterator::stack.right()->value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
auto begin() const -> const const_iterator { return const_iterator(*this, 0); }
|
auto begin() const -> const const_iterator { return const_iterator(*this, 0); }
|
||||||
|
|
|
@ -170,11 +170,7 @@ struct shared_pointer {
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit operator bool() const {
|
explicit operator bool() const {
|
||||||
return !empty();
|
return manager && manager->strong;
|
||||||
}
|
|
||||||
|
|
||||||
auto empty() const -> bool {
|
|
||||||
return !manager || !manager->strong;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto unique() const -> bool {
|
auto unique() const -> bool {
|
||||||
|
@ -242,11 +238,7 @@ struct shared_pointer_weak {
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit operator bool() const {
|
explicit operator bool() const {
|
||||||
return !empty();
|
return manager && manager->strong;
|
||||||
}
|
|
||||||
|
|
||||||
auto empty() const -> bool {
|
|
||||||
return !manager || !manager->strong;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto acquire() const -> shared_pointer<T> {
|
auto acquire() const -> shared_pointer<T> {
|
||||||
|
|
16
smtp.hpp
16
smtp.hpp
|
@ -18,14 +18,14 @@
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
struct SMTP {
|
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 server(string server, uint16_t port = 25) -> void;
|
||||||
inline auto from(string mail, string name = "") -> void;
|
inline auto from(string mail, string name = "") -> void;
|
||||||
inline auto to(string mail, string name = "") -> void;
|
inline auto to(string mail, string name = "") -> void;
|
||||||
inline auto cc(string mail, string name = "") -> void;
|
inline auto cc(string mail, string name = "") -> void;
|
||||||
inline auto bcc(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 attachment(string filename, string name = "") -> bool;
|
||||||
inline auto subject(string subject) -> void;
|
inline auto subject(string subject) -> void;
|
||||||
inline auto body(string body, Format format = Format::Plain) -> 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});
|
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<uint8_t> buffer;
|
vector<uint8_t> buffer;
|
||||||
buffer.resize(size);
|
buffer.resize(size);
|
||||||
memcpy(buffer.data(), data, size);
|
memcpy(buffer.data(), data, size);
|
||||||
|
@ -223,7 +223,7 @@ auto SMTP::response() -> string {
|
||||||
|
|
||||||
auto SMTP::send(int sock, const string& text) -> bool {
|
auto SMTP::send(int sock, const string& text) -> bool {
|
||||||
const char* data = text.data();
|
const char* data = text.data();
|
||||||
unsigned size = text.size();
|
uint size = text.size();
|
||||||
while(size) {
|
while(size) {
|
||||||
int length = ::send(sock, (const char*)data, size, 0);
|
int length = ::send(sock, (const char*)data, size, 0);
|
||||||
if(length == -1) return false;
|
if(length == -1) return false;
|
||||||
|
@ -249,7 +249,7 @@ auto SMTP::boundary() -> string {
|
||||||
random_lfsr random;
|
random_lfsr random;
|
||||||
random.seed(time(0));
|
random.seed(time(0));
|
||||||
string boundary;
|
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;
|
return boundary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,16 +272,16 @@ auto SMTP::contacts(const vector<Information::Contact>& contacts) -> string {
|
||||||
for(auto& contact : contacts) {
|
for(auto& contact : contacts) {
|
||||||
result.append(this->contact(contact), "; ");
|
result.append(this->contact(contact), "; ");
|
||||||
}
|
}
|
||||||
result.rtrim("; ", 1L);
|
result.trimRight("; ", 1L);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SMTP::split(const string& text) -> string {
|
auto SMTP::split(const string& text) -> string {
|
||||||
string result;
|
string result;
|
||||||
|
|
||||||
unsigned offset = 0;
|
uint offset = 0;
|
||||||
while(offset < text.size()) {
|
while(offset < text.size()) {
|
||||||
unsigned length = min(76, text.size() - offset);
|
uint length = min(76, text.size() - offset);
|
||||||
if(length < 76) {
|
if(length < 76) {
|
||||||
result.append(text.slice(offset));
|
result.append(text.slice(offset));
|
||||||
} else {
|
} else {
|
||||||
|
|
18
sort.hpp
18
sort.hpp
|
@ -19,13 +19,13 @@
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
template<typename T, typename Comparator> auto sort(T list[], unsigned size, const Comparator& lessthan) -> void {
|
template<typename T, typename Comparator> auto sort(T list[], uint size, const Comparator& lessthan) -> void {
|
||||||
if(size <= 1) return; //nothing to sort
|
if(size <= 1) return; //nothing to sort
|
||||||
|
|
||||||
//use insertion sort to quickly sort smaller blocks
|
//use insertion sort to quickly sort smaller blocks
|
||||||
if(size < 64) {
|
if(size < 64) {
|
||||||
#if defined(NALL_SORT_INSERTION)
|
#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]);
|
T copy = std::move(list[i]);
|
||||||
for(j = i - 1; j >= 0; j--) {
|
for(j = i - 1; j >= 0; j--) {
|
||||||
if(!lessthan(copy, list[j])) break;
|
if(!lessthan(copy, list[j])) break;
|
||||||
|
@ -34,9 +34,9 @@ template<typename T, typename Comparator> auto sort(T list[], unsigned size, con
|
||||||
list[j + 1] = std::move(copy);
|
list[j + 1] = std::move(copy);
|
||||||
}
|
}
|
||||||
#elif defined(NALL_SORT_SELECTION)
|
#elif defined(NALL_SORT_SELECTION)
|
||||||
for(unsigned i = 0; i < size; i++) {
|
for(uint i = 0; i < size; i++) {
|
||||||
unsigned min = i;
|
uint min = i;
|
||||||
for(unsigned j = i + 1; j < size; j++) {
|
for(uint j = i + 1; j < size; j++) {
|
||||||
if(lessthan(list[j], list[min])) min = j;
|
if(lessthan(list[j], list[min])) min = j;
|
||||||
}
|
}
|
||||||
if(min != i) std::swap(list[i], list[min]);
|
if(min != i) std::swap(list[i], list[min]);
|
||||||
|
@ -46,13 +46,13 @@ template<typename T, typename Comparator> auto sort(T list[], unsigned size, con
|
||||||
}
|
}
|
||||||
|
|
||||||
//split list in half and recursively sort both
|
//split list in half and recursively sort both
|
||||||
unsigned middle = size / 2;
|
uint middle = size / 2;
|
||||||
sort(list, middle, lessthan);
|
sort(list, middle, lessthan);
|
||||||
sort(list + middle, size - middle, lessthan);
|
sort(list + middle, size - middle, lessthan);
|
||||||
|
|
||||||
//left and right are sorted here; perform merge sort
|
//left and right are sorted here; perform merge sort
|
||||||
T* buffer = new T[size];
|
T* buffer = new T[size];
|
||||||
unsigned offset = 0, left = 0, right = middle;
|
uint offset = 0, left = 0, right = middle;
|
||||||
while(left < middle && right < size) {
|
while(left < middle && right < size) {
|
||||||
if(!lessthan(list[right], list[left])) {
|
if(!lessthan(list[right], list[left])) {
|
||||||
buffer[offset++] = std::move(list[left++]);
|
buffer[offset++] = std::move(list[left++]);
|
||||||
|
@ -63,11 +63,11 @@ template<typename T, typename Comparator> auto sort(T list[], unsigned size, con
|
||||||
while(left < middle) buffer[offset++] = std::move(list[left++]);
|
while(left < middle) buffer[offset++] = std::move(list[left++]);
|
||||||
while(right < size) buffer[offset++] = std::move(list[right++]);
|
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;
|
delete[] buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> auto sort(T list[], unsigned size) -> void {
|
template<typename T> auto sort(T list[], uint size) -> void {
|
||||||
return sort(list, size, [](const T& l, const T& r) { return l < r; });
|
return sort(list, size, [](const T& l, const T& r) { return l < r; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
19
stream.hpp
19
stream.hpp
|
@ -1,19 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <nall/file.hpp>
|
|
||||||
#include <nall/filemap.hpp>
|
|
||||||
#include <nall/stdint.hpp>
|
|
||||||
#include <nall/string.hpp>
|
|
||||||
#include <nall/decode/gzip.hpp>
|
|
||||||
#include <nall/decode/zip.hpp>
|
|
||||||
|
|
||||||
#include <nall/stream/stream.hpp>
|
|
||||||
#include <nall/stream/memory.hpp>
|
|
||||||
#include <nall/stream/mmap.hpp>
|
|
||||||
#include <nall/stream/file.hpp>
|
|
||||||
#include <nall/stream/gzip.hpp>
|
|
||||||
#include <nall/stream/zip.hpp>
|
|
||||||
#include <nall/stream/auto.hpp>
|
|
|
@ -1,21 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
#define autostream(...) (*makestream(__VA_ARGS__))
|
|
||||||
|
|
||||||
inline auto makestream(const string& path) -> std::unique_ptr<stream> {
|
|
||||||
if(path.iendsWith(".gz")) return std::unique_ptr<stream>(new gzipstream(filestream{path}));
|
|
||||||
if(path.iendsWith(".zip")) return std::unique_ptr<stream>(new zipstream(filestream{path}));
|
|
||||||
return std::unique_ptr<stream>(new mmapstream(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto makestream(uint8_t* data, uint size) -> std::unique_ptr<stream> {
|
|
||||||
return std::unique_ptr<stream>(new memorystream(data, size));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto makestream(const uint8_t* data, uint size) -> std::unique_ptr<stream> {
|
|
||||||
return std::unique_ptr<stream>(new memorystream(data, size));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <nall/file.hpp>
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <nall/decode/gzip.hpp>
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <nall/stream/stream.hpp>
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <nall/filemap.hpp>
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <nall/stream/stream.hpp>
|
|
||||||
#include <nall/vector.hpp>
|
|
||||||
|
|
||||||
namespace nall {
|
|
||||||
|
|
||||||
struct vectorstream : stream {
|
|
||||||
using stream::read;
|
|
||||||
using stream::write;
|
|
||||||
|
|
||||||
vectorstream(vector<uint8_t>& memory) : memory(memory), pwritable(true) {}
|
|
||||||
vectorstream(const vector<uint8_t>& memory) : memory((vector<uint8_t>&)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<uint8_t>& memory;
|
|
||||||
mutable uint poffset = 0;
|
|
||||||
mutable bool pwritable = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <nall/decode/zip.hpp>
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
304
string.hpp
304
string.hpp
|
@ -20,11 +20,305 @@
|
||||||
#include <nall/utility.hpp>
|
#include <nall/utility.hpp>
|
||||||
#include <nall/varint.hpp>
|
#include <nall/varint.hpp>
|
||||||
#include <nall/vector.hpp>
|
#include <nall/vector.hpp>
|
||||||
#include <nall/hash/crc16.hpp>
|
|
||||||
#include <nall/hash/crc32.hpp>
|
|
||||||
#include <nall/hash/sha256.hpp>
|
|
||||||
|
|
||||||
#include <nall/string/base.hpp>
|
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<typename... P> 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<typename T> struct stringify;
|
||||||
|
|
||||||
|
//format.hpp
|
||||||
|
template<typename... P> inline auto print(P&&...) -> void;
|
||||||
|
template<typename... P> 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<typename T> 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<typename T = char> inline auto get() -> T*;
|
||||||
|
template<typename T = char> 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<typename T, typename... P> string(T&& s, P&&... p) : string() {
|
||||||
|
append(forward<T>(s), forward<P>(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<typename... P> inline auto assign(P&&...) -> type&;
|
||||||
|
template<typename T, typename... P> inline auto append(const T&, P&&...) -> type&;
|
||||||
|
template<typename... P> inline auto append(const nall::format&, P&&...) -> type&;
|
||||||
|
inline auto append() -> type&;
|
||||||
|
template<typename T> inline auto _append(const stringify<T>&) -> 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<bool, bool> inline auto _find(int, string_view) const -> maybe<uint>;
|
||||||
|
|
||||||
|
inline auto find(string_view source) const -> maybe<uint>;
|
||||||
|
inline auto ifind(string_view source) const -> maybe<uint>;
|
||||||
|
inline auto qfind(string_view source) const -> maybe<uint>;
|
||||||
|
inline auto iqfind(string_view source) const -> maybe<uint>;
|
||||||
|
|
||||||
|
inline auto findFrom(int offset, string_view source) const -> maybe<uint>;
|
||||||
|
inline auto ifindFrom(int offset, string_view source) const -> maybe<uint>;
|
||||||
|
|
||||||
|
//format.hpp
|
||||||
|
inline auto format(const nall::format& params) -> type&;
|
||||||
|
|
||||||
|
//compare.hpp
|
||||||
|
template<bool> 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<bool, bool> 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<string> {
|
||||||
|
using type = lstring;
|
||||||
|
|
||||||
|
lstring(const lstring& source) { vector::operator=(source); }
|
||||||
|
lstring(lstring& source) { vector::operator=(source); }
|
||||||
|
lstring(lstring&& source) { vector::operator=(move(source)); }
|
||||||
|
template<typename... P> lstring(P&&... p) { append(forward<P>(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<typename... P> inline auto append(const string&, P&&...) -> type&;
|
||||||
|
inline auto append() -> type&;
|
||||||
|
|
||||||
|
inline auto find(string_view source) const -> maybe<uint>;
|
||||||
|
inline auto ifind(string_view source) const -> maybe<uint>;
|
||||||
|
inline auto match(string_view pattern) const -> lstring;
|
||||||
|
inline auto merge(string_view separator) const -> string;
|
||||||
|
inline auto strip() -> type&;
|
||||||
|
|
||||||
|
//split.hpp
|
||||||
|
template<bool, bool> inline auto _split(string_view, string_view, long) -> lstring&;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct format : vector<string> {
|
||||||
|
using type = format;
|
||||||
|
|
||||||
|
template<typename... P> format(P&&... p) { reserve(sizeof...(p)); append(forward<P>(p)...); }
|
||||||
|
template<typename T, typename... P> inline auto append(const T&, P&&... p) -> type&;
|
||||||
|
inline auto append() -> type&;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#include <nall/string/view.hpp>
|
#include <nall/string/view.hpp>
|
||||||
#include <nall/string/atoi.hpp>
|
#include <nall/string/atoi.hpp>
|
||||||
#include <nall/string/cast.hpp>
|
#include <nall/string/cast.hpp>
|
||||||
|
@ -34,11 +328,9 @@
|
||||||
#include <nall/string/datetime.hpp>
|
#include <nall/string/datetime.hpp>
|
||||||
#include <nall/string/find.hpp>
|
#include <nall/string/find.hpp>
|
||||||
#include <nall/string/format.hpp>
|
#include <nall/string/format.hpp>
|
||||||
#include <nall/string/hash.hpp>
|
|
||||||
#include <nall/string/list.hpp>
|
#include <nall/string/list.hpp>
|
||||||
#include <nall/string/match.hpp>
|
#include <nall/string/match.hpp>
|
||||||
#include <nall/string/path.hpp>
|
#include <nall/string/path.hpp>
|
||||||
#include <nall/string/platform.hpp>
|
|
||||||
#include <nall/string/replace.hpp>
|
#include <nall/string/replace.hpp>
|
||||||
#include <nall/string/split.hpp>
|
#include <nall/string/split.hpp>
|
||||||
#include <nall/string/trim.hpp>
|
#include <nall/string/trim.hpp>
|
||||||
|
|
|
@ -22,15 +22,17 @@ namespace nall {
|
||||||
string::string() : _data(nullptr), _capacity(SSO - 1), _size(0) {
|
string::string() : _data(nullptr), _capacity(SSO - 1), _size(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto string::get() -> char* {
|
template<typename T>
|
||||||
if(_capacity < SSO) return _text;
|
auto string::get() -> T* {
|
||||||
|
if(_capacity < SSO) return (T*)_text;
|
||||||
if(*_refs > 1) _copy();
|
if(*_refs > 1) _copy();
|
||||||
return _data;
|
return (T*)_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto string::data() const -> const char* {
|
template<typename T>
|
||||||
if(_capacity < SSO) return _text;
|
auto string::data() const -> const T* {
|
||||||
return _data;
|
if(_capacity < SSO) return (const T*)_text;
|
||||||
|
return (const T*)_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto string::reset() -> type& {
|
auto string::reset() -> type& {
|
||||||
|
|
293
string/base.hpp
293
string/base.hpp
|
@ -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<typename T> struct stringify;
|
|
||||||
|
|
||||||
//format.hpp
|
|
||||||
template<typename... P> 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<typename T> 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<typename T, typename... P> string(T&& s, P&&... p) : string() { append(forward<T>(s), forward<P>(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<typename... P> inline auto assign(P&&...) -> type&;
|
|
||||||
template<typename T, typename... P> inline auto append(const T&, P&&...) -> type&;
|
|
||||||
template<typename... P> inline auto append(const nall::format&, P&&...) -> type&;
|
|
||||||
inline auto append() -> type&;
|
|
||||||
template<typename T> inline auto _append(const stringify<T>&) -> 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<bool, bool> inline auto _find(int, rstring) const -> maybe<uint>;
|
|
||||||
|
|
||||||
inline auto find(rstring source) const -> maybe<unsigned>;
|
|
||||||
inline auto ifind(rstring source) const -> maybe<unsigned>;
|
|
||||||
inline auto qfind(rstring source) const -> maybe<unsigned>;
|
|
||||||
inline auto iqfind(rstring source) const -> maybe<unsigned>;
|
|
||||||
|
|
||||||
inline auto findFrom(int offset, rstring source) const -> maybe<uint>;
|
|
||||||
inline auto ifindFrom(int offset, rstring source) const -> maybe<uint>;
|
|
||||||
|
|
||||||
//format.hpp
|
|
||||||
inline auto format(const nall::format& params) -> type&;
|
|
||||||
|
|
||||||
//compare.hpp
|
|
||||||
template<bool> 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<bool, bool> 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<string> {
|
|
||||||
using type = lstring;
|
|
||||||
|
|
||||||
lstring(const lstring& source) { vector::operator=(source); }
|
|
||||||
lstring(lstring& source) { vector::operator=(source); }
|
|
||||||
lstring(lstring&& source) { vector::operator=(move(source)); }
|
|
||||||
template<typename... P> lstring(P&&... p) { append(forward<P>(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<typename... P> inline auto append(const string&, P&&...) -> type&;
|
|
||||||
inline auto append() -> type&;
|
|
||||||
|
|
||||||
inline auto find(rstring source) const -> maybe<uint>;
|
|
||||||
inline auto ifind(rstring source) const -> maybe<uint>;
|
|
||||||
inline auto match(rstring pattern) const -> lstring;
|
|
||||||
inline auto merge(rstring separator) const -> string;
|
|
||||||
inline auto strip() -> type&;
|
|
||||||
|
|
||||||
//split.hpp
|
|
||||||
template<bool, bool> inline auto _split(rstring, rstring, long) -> lstring&;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct format : vector<string> {
|
|
||||||
using type = format;
|
|
||||||
|
|
||||||
template<typename... P> format(P&&... p) { reserve(sizeof...(p)); append(forward<P>(p)...); }
|
|
||||||
template<typename T, typename... P> inline auto append(const T&, P&&... p) -> type&;
|
|
||||||
inline auto append() -> type&;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -10,7 +10,7 @@ namespace nall {
|
||||||
template<> struct stringify<bool> {
|
template<> struct stringify<bool> {
|
||||||
stringify(bool value) : _value(value) {}
|
stringify(bool value) : _value(value) {}
|
||||||
auto data() const -> const char* { return _value ? "true" : "false"; }
|
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;
|
bool _value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ template<> struct stringify<Boolean> {
|
||||||
template<> struct stringify<char> {
|
template<> struct stringify<char> {
|
||||||
stringify(char source) { _data[0] = source; _data[1] = 0; }
|
stringify(char source) { _data[0] = source; _data[1] = 0; }
|
||||||
auto data() const -> const char* { return _data; }
|
auto data() const -> const char* { return _data; }
|
||||||
auto size() const -> unsigned { return 1; }
|
auto size() const -> uint { return 1; }
|
||||||
char _data[2];
|
char _data[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -35,35 +35,35 @@ template<> struct stringify<char> {
|
||||||
template<> struct stringify<signed char> {
|
template<> struct stringify<signed char> {
|
||||||
stringify(signed char source) { integer(_data, source); }
|
stringify(signed char source) { integer(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
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];
|
char _data[2 + sizeof(signed char) * 3];
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct stringify<signed short> {
|
template<> struct stringify<signed short> {
|
||||||
stringify(signed short source) { integer(_data, source); }
|
stringify(signed short source) { integer(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
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];
|
char _data[2 + sizeof(signed short) * 3];
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct stringify<signed int> {
|
template<> struct stringify<signed int> {
|
||||||
stringify(signed int source) { integer(_data, source); }
|
stringify(signed int source) { integer(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
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];
|
char _data[2 + sizeof(signed int) * 3];
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct stringify<signed long> {
|
template<> struct stringify<signed long> {
|
||||||
stringify(signed long source) { integer(_data, source); }
|
stringify(signed long source) { integer(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
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];
|
char _data[2 + sizeof(signed long) * 3];
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct stringify<signed long long> {
|
template<> struct stringify<signed long long> {
|
||||||
stringify(signed long long source) { integer(_data, source); }
|
stringify(signed long long source) { integer(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
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];
|
char _data[2 + sizeof(signed long long) * 3];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -79,35 +79,35 @@ template<uint Bits> struct stringify<Integer<Bits>> {
|
||||||
template<> struct stringify<unsigned char> {
|
template<> struct stringify<unsigned char> {
|
||||||
stringify(unsigned char source) { natural(_data, source); }
|
stringify(unsigned char source) { natural(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
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];
|
char _data[1 + sizeof(unsigned char) * 3];
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct stringify<unsigned short> {
|
template<> struct stringify<unsigned short> {
|
||||||
stringify(unsigned short source) { natural(_data, source); }
|
stringify(unsigned short source) { natural(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
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];
|
char _data[1 + sizeof(unsigned short) * 3];
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct stringify<unsigned int> {
|
template<> struct stringify<unsigned int> {
|
||||||
stringify(unsigned int source) { natural(_data, source); }
|
stringify(unsigned int source) { natural(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
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];
|
char _data[1 + sizeof(unsigned int) * 3];
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct stringify<unsigned long> {
|
template<> struct stringify<unsigned long> {
|
||||||
stringify(unsigned long source) { natural(_data, source); }
|
stringify(unsigned long source) { natural(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
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];
|
char _data[1 + sizeof(unsigned long) * 3];
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct stringify<unsigned long long> {
|
template<> struct stringify<unsigned long long> {
|
||||||
stringify(unsigned long long source) { natural(_data, source); }
|
stringify(unsigned long long source) { natural(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
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];
|
char _data[1 + sizeof(unsigned long long) * 3];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -123,21 +123,21 @@ template<uint Bits> struct stringify<Natural<Bits>> {
|
||||||
template<> struct stringify<float> {
|
template<> struct stringify<float> {
|
||||||
stringify(float source) { real(_data, source); }
|
stringify(float source) { real(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
auto data() const -> const char* { return _data; }
|
||||||
auto size() const -> unsigned { return strlen(_data); }
|
auto size() const -> uint { return strlen(_data); }
|
||||||
char _data[256];
|
char _data[256];
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct stringify<double> {
|
template<> struct stringify<double> {
|
||||||
stringify(double source) { real(_data, source); }
|
stringify(double source) { real(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
auto data() const -> const char* { return _data; }
|
||||||
auto size() const -> unsigned { return strlen(_data); }
|
auto size() const -> uint { return strlen(_data); }
|
||||||
char _data[256];
|
char _data[256];
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct stringify<long double> {
|
template<> struct stringify<long double> {
|
||||||
stringify(long double source) { real(_data, source); }
|
stringify(long double source) { real(_data, source); }
|
||||||
auto data() const -> const char* { return _data; }
|
auto data() const -> const char* { return _data; }
|
||||||
auto size() const -> unsigned { return strlen(_data); }
|
auto size() const -> uint { return strlen(_data); }
|
||||||
char _data[256];
|
char _data[256];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ template<> struct stringify<vector<uint8_t>> {
|
||||||
memory::copy(_text.data(), source.data(), source.size());
|
memory::copy(_text.data(), source.data(), source.size());
|
||||||
}
|
}
|
||||||
auto data() const -> const char* { return _text.data(); }
|
auto data() const -> const char* { return _text.data(); }
|
||||||
auto size() const -> unsigned { return _text.size(); }
|
auto size() const -> uint { return _text.size(); }
|
||||||
vector<char> _text;
|
vector<char> _text;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -166,7 +166,7 @@ template<> struct stringify<const vector<uint8_t>&> {
|
||||||
memory::copy(_text.data(), source.data(), source.size());
|
memory::copy(_text.data(), source.data(), source.size());
|
||||||
}
|
}
|
||||||
auto data() const -> const char* { return _text.data(); }
|
auto data() const -> const char* { return _text.data(); }
|
||||||
auto size() const -> unsigned { return _text.size(); }
|
auto size() const -> uint { return _text.size(); }
|
||||||
vector<char> _text;
|
vector<char> _text;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -175,14 +175,14 @@ template<> struct stringify<const vector<uint8_t>&> {
|
||||||
template<> struct stringify<char*> {
|
template<> struct stringify<char*> {
|
||||||
stringify(char* source) : _data(source ? source : "") {}
|
stringify(char* source) : _data(source ? source : "") {}
|
||||||
auto data() const -> const char* { return _data; }
|
auto data() const -> const char* { return _data; }
|
||||||
auto size() const -> unsigned { return strlen(_data); }
|
auto size() const -> uint { return strlen(_data); }
|
||||||
const char* _data;
|
const char* _data;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct stringify<const char*> {
|
template<> struct stringify<const char*> {
|
||||||
stringify(const char* source) : _data(source ? source : "") {}
|
stringify(const char* source) : _data(source ? source : "") {}
|
||||||
auto data() const -> const char* { return _data; }
|
auto data() const -> const char* { return _data; }
|
||||||
auto size() const -> unsigned { return strlen(_data); }
|
auto size() const -> uint { return strlen(_data); }
|
||||||
const char* _data;
|
const char* _data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -191,28 +191,28 @@ template<> struct stringify<const char*> {
|
||||||
template<> struct stringify<string> {
|
template<> struct stringify<string> {
|
||||||
stringify(const string& source) : _text(source) {}
|
stringify(const string& source) : _text(source) {}
|
||||||
auto data() const -> const char* { return _text.data(); }
|
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;
|
const string& _text;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct stringify<const string&> {
|
template<> struct stringify<const string&> {
|
||||||
stringify(const string& source) : _text(source) {}
|
stringify(const string& source) : _text(source) {}
|
||||||
auto data() const -> const char* { return _text.data(); }
|
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;
|
const string& _text;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct stringify<string_view> {
|
template<> struct stringify<string_view> {
|
||||||
stringify(const string_view& source) : _view(source) {}
|
stringify(const string_view& source) : _view(source) {}
|
||||||
auto data() const -> const char* { return _view.data(); }
|
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;
|
const string_view& _view;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> struct stringify<const string_view&> {
|
template<> struct stringify<const string_view&> {
|
||||||
stringify(const string_view& source) : _view(source) {}
|
stringify(const string_view& source) : _view(source) {}
|
||||||
auto data() const -> const char* { return _view.data(); }
|
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;
|
const string_view& _view;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,54 +3,54 @@
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
template<bool Insensitive>
|
template<bool Insensitive>
|
||||||
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);
|
if(Insensitive) return memory::icompare(target, capacity, source, size);
|
||||||
return memory::compare(target, capacity, source, size);
|
return memory::compare(target, capacity, source, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
//size() + 1 includes null-terminator; required to properly compare strings of differing lengths
|
//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);
|
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);
|
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);
|
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);
|
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;
|
if(size() != source.size()) return false;
|
||||||
return memory::compare(data(), source.data(), source.size()) == 0;
|
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;
|
if(size() != source.size()) return false;
|
||||||
return memory::icompare(data(), source.data(), source.size()) == 0;
|
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;
|
if(source.size() > size()) return false;
|
||||||
return memory::compare(data(), source.data(), source.size()) == 0;
|
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;
|
if(source.size() > size()) return false;
|
||||||
return memory::icompare(data(), source.data(), source.size()) == 0;
|
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;
|
if(source.size() > size()) return false;
|
||||||
return memory::compare(data() + size() - source.size(), source.data(), source.size()) == 0;
|
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;
|
if(source.size() > size()) return false;
|
||||||
return memory::icompare(data() + size() - source.size(), source.data(), source.size()) == 0;
|
return memory::icompare(data() + size() - source.size(), source.data(), source.size()) == 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ namespace nall {
|
||||||
|
|
||||||
auto string::downcase() -> string& {
|
auto string::downcase() -> string& {
|
||||||
char* p = get();
|
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;
|
if(p[n] >= 'A' && p[n] <= 'Z') p[n] += 0x20;
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -12,7 +12,7 @@ auto string::downcase() -> string& {
|
||||||
|
|
||||||
auto string::qdowncase() -> string& {
|
auto string::qdowncase() -> string& {
|
||||||
char* p = get();
|
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(p[n] == '\"') quoted ^= 1;
|
||||||
if(!quoted && p[n] >= 'A' && p[n] <= 'Z') p[n] += 0x20;
|
if(!quoted && p[n] >= 'A' && p[n] <= 'Z') p[n] += 0x20;
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ auto string::qdowncase() -> string& {
|
||||||
|
|
||||||
auto string::upcase() -> string& {
|
auto string::upcase() -> string& {
|
||||||
char* p = get();
|
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;
|
if(p[n] >= 'a' && p[n] <= 'z') p[n] -= 0x20;
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -29,18 +29,18 @@ auto string::upcase() -> string& {
|
||||||
|
|
||||||
auto string::qupcase() -> string& {
|
auto string::qupcase() -> string& {
|
||||||
char* p = get();
|
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(p[n] == '\"') quoted ^= 1;
|
||||||
if(!quoted && p[n] >= 'a' && p[n] <= 'z') p[n] -= 0x20;
|
if(!quoted && p[n] >= 'a' && p[n] <= 'z') p[n] -= 0x20;
|
||||||
}
|
}
|
||||||
return *this;
|
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
|
if(from.size() != to.size() || from.size() == 0) return *this; //patterns must be the same length
|
||||||
char* p = get();
|
char* p = get();
|
||||||
for(unsigned n = 0; n < size(); n++) {
|
for(uint n = 0; n < size(); n++) {
|
||||||
for(unsigned s = 0; s < from.size(); s++) {
|
for(uint s = 0; s < from.size(); s++) {
|
||||||
if(p[n] == from[s]) {
|
if(p[n] == from[s]) {
|
||||||
p[n] = to[s];
|
p[n] = to[s];
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
auto string::operator[](int position) const -> const char& {
|
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];
|
return data()[position];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,10 +45,6 @@ template<typename T> auto string::_append(const stringify<T>& source) -> string&
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto string::empty() const -> bool {
|
|
||||||
return size() == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto string::length() const -> uint {
|
auto string::length() const -> uint {
|
||||||
return strlen(data());
|
return strlen(data());
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ inline auto evaluateExpression(Node* node) -> string {
|
||||||
for(auto& link : node->link) {
|
for(auto& link : node->link) {
|
||||||
result.append(evaluateExpression(link), ", ");
|
result.append(evaluateExpression(link), ", ");
|
||||||
}
|
}
|
||||||
return result.rtrim(", ", 1L).append(")");
|
return result.trimRight(", ", 1L).append(")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#undef p
|
#undef p
|
||||||
|
|
|
@ -16,7 +16,7 @@ inline auto literalNumber(const char*& s) -> string {
|
||||||
|
|
||||||
//binary
|
//binary
|
||||||
if(p[0] == '%' || (p[0] == '0' && p[1] == 'b')) {
|
if(p[0] == '%' || (p[0] == '0' && p[1] == 'b')) {
|
||||||
unsigned prefix = 1 + (p[0] == '0');
|
uint prefix = 1 + (p[0] == '0');
|
||||||
p += prefix;
|
p += prefix;
|
||||||
while(p[0] == '\'' || p[0] == '0' || p[0] == '1') p++;
|
while(p[0] == '\'' || p[0] == '0' || p[0] == '1') p++;
|
||||||
if(p - s <= prefix) throw "invalid binary literal";
|
if(p - s <= prefix) throw "invalid binary literal";
|
||||||
|
@ -27,7 +27,7 @@ inline auto literalNumber(const char*& s) -> string {
|
||||||
|
|
||||||
//octal
|
//octal
|
||||||
if(p[0] == '0' && p[1] == 'o') {
|
if(p[0] == '0' && p[1] == 'o') {
|
||||||
unsigned prefix = 1 + (p[0] == '0');
|
uint prefix = 1 + (p[0] == '0');
|
||||||
p += prefix;
|
p += prefix;
|
||||||
while(p[0] == '\'' || (p[0] >= '0' && p[0] <= '7')) p++;
|
while(p[0] == '\'' || (p[0] >= '0' && p[0] <= '7')) p++;
|
||||||
if(p - s <= prefix) throw "invalid octal literal";
|
if(p - s <= prefix) throw "invalid octal literal";
|
||||||
|
@ -38,7 +38,7 @@ inline auto literalNumber(const char*& s) -> string {
|
||||||
|
|
||||||
//hex
|
//hex
|
||||||
if(p[0] == '$' || (p[0] == '0' && p[1] == 'x')) {
|
if(p[0] == '$' || (p[0] == '0' && p[1] == 'x')) {
|
||||||
unsigned prefix = 1 + (p[0] == '0');
|
uint prefix = 1 + (p[0] == '0');
|
||||||
p += prefix;
|
p += prefix;
|
||||||
while(p[0] == '\'' || (p[0] >= '0' && p[0] <= '9') || (p[0] >= 'A' && p[0] <= 'F') || (p[0] >= 'a' && p[0] <= 'f')) p++;
|
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";
|
if(p - s <= prefix) throw "invalid hex literal";
|
||||||
|
|
|
@ -45,7 +45,7 @@ inline auto parse(Node*& node, const char*& s, uint depth) -> void {
|
||||||
while(whitespace(s[0])) s++;
|
while(whitespace(s[0])) s++;
|
||||||
if(!s[0]) return;
|
if(!s[0]) return;
|
||||||
|
|
||||||
if(s[0] == '(' && node->link.empty()) {
|
if(s[0] == '(' && !node->link) {
|
||||||
parse(node, s += 1, 1);
|
parse(node, s += 1, 1);
|
||||||
if(*s++ != ')') throw "mismatched group";
|
if(*s++ != ')') throw "mismatched group";
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ inline auto parse(Node*& node, const char*& s, uint depth) -> void {
|
||||||
node->literal = literal(s);
|
node->literal = literal(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define p() (node->literal.empty() && node->link.empty())
|
#define p() (!node->literal && !node->link)
|
||||||
while(true) {
|
while(true) {
|
||||||
while(whitespace(s[0])) s++;
|
while(whitespace(s[0])) s++;
|
||||||
if(!s[0]) return;
|
if(!s[0]) return;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
template<bool Insensitive, bool Quoted> auto string::_find(int offset, rstring source) const -> maybe<uint> {
|
template<bool Insensitive, bool Quoted> auto string::_find(int offset, string_view source) const -> maybe<uint> {
|
||||||
if(source.size() == 0) return nothing;
|
if(source.size() == 0) return nothing;
|
||||||
|
|
||||||
auto p = data();
|
auto p = data();
|
||||||
|
@ -15,12 +15,12 @@ template<bool Insensitive, bool Quoted> auto string::_find(int offset, rstring s
|
||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto string::find(rstring source) const -> maybe<uint> { return _find<0, 0>(0, source); }
|
auto string::find(string_view source) const -> maybe<uint> { return _find<0, 0>(0, source); }
|
||||||
auto string::ifind(rstring source) const -> maybe<uint> { return _find<1, 0>(0, source); }
|
auto string::ifind(string_view source) const -> maybe<uint> { return _find<1, 0>(0, source); }
|
||||||
auto string::qfind(rstring source) const -> maybe<uint> { return _find<0, 1>(0, source); }
|
auto string::qfind(string_view source) const -> maybe<uint> { return _find<0, 1>(0, source); }
|
||||||
auto string::iqfind(rstring source) const -> maybe<uint> { return _find<1, 1>(0, source); }
|
auto string::iqfind(string_view source) const -> maybe<uint> { return _find<1, 1>(0, source); }
|
||||||
|
|
||||||
auto string::findFrom(int offset, rstring source) const -> maybe<uint> { return _find<0, 0>(offset, source); }
|
auto string::findFrom(int offset, string_view source) const -> maybe<uint> { return _find<0, 0>(offset, source); }
|
||||||
auto string::ifindFrom(int offset, rstring source) const -> maybe<uint> { return _find<1, 0>(offset, source); }
|
auto string::ifindFrom(int offset, string_view source) const -> maybe<uint> { return _find<1, 0>(offset, source); }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,11 @@ auto string::format(const nall::format& params) -> type& {
|
||||||
auto data = (char*)memory::allocate(size);
|
auto data = (char*)memory::allocate(size);
|
||||||
memory::copy(data, this->data(), size);
|
memory::copy(data, this->data(), size);
|
||||||
|
|
||||||
signed x = 0;
|
int x = 0;
|
||||||
while(x < size - 2) { //2 = minimum tag length
|
while(x < size - 2) { //2 = minimum tag length
|
||||||
if(data[x] != '{') { x++; continue; }
|
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
|
while(y < size - 1) { //-1 avoids going out of bounds on test after this loop
|
||||||
if(data[y] != '}') { y++; continue; }
|
if(data[y] != '}') { y++; continue; }
|
||||||
break;
|
break;
|
||||||
|
@ -70,7 +70,12 @@ auto format::append() -> format& {
|
||||||
|
|
||||||
template<typename... P> auto print(P&&... p) -> void {
|
template<typename... P> auto print(P&&... p) -> void {
|
||||||
string s{forward<P>(p)...};
|
string s{forward<P>(p)...};
|
||||||
fputs(s.data(), stdout);
|
fwrite(s.data(), 1, s.size(), stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... P> auto print(FILE* fp, P&&... p) -> void {
|
||||||
|
string s{forward<P>(p)...};
|
||||||
|
fwrite(s.data(), 1, s.size(), fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto integer(intmax value, long precision, char padchar) -> string {
|
auto integer(intmax value, long precision, char padchar) -> string {
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -16,7 +16,7 @@ auto lstring::operator!=(const lstring& source) const -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lstring::isort() -> lstring& {
|
auto lstring::isort() -> lstring& {
|
||||||
nall::sort(pool, objectsize, [](const string& x, const string& y) {
|
sort([](const string& x, const string& y) {
|
||||||
return memory::icompare(x.data(), x.size(), y.data(), y.size()) < 0;
|
return memory::icompare(x.data(), x.size(), y.data(), y.size()) < 0;
|
||||||
});
|
});
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -32,21 +32,21 @@ auto lstring::append() -> lstring& {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lstring::find(rstring source) const -> maybe<uint> {
|
auto lstring::find(string_view source) const -> maybe<uint> {
|
||||||
for(uint n = 0; n < size(); n++) {
|
for(uint n = 0; n < size(); n++) {
|
||||||
if(operator[](n).equals(source)) return n;
|
if(operator[](n).equals(source)) return n;
|
||||||
}
|
}
|
||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lstring::ifind(rstring source) const -> maybe<uint> {
|
auto lstring::ifind(string_view source) const -> maybe<uint> {
|
||||||
for(uint n = 0; n < size(); n++) {
|
for(uint n = 0; n < size(); n++) {
|
||||||
if(operator[](n).iequals(source)) return n;
|
if(operator[](n).iequals(source)) return n;
|
||||||
}
|
}
|
||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lstring::match(rstring pattern) const -> lstring {
|
auto lstring::match(string_view pattern) const -> lstring {
|
||||||
lstring result;
|
lstring result;
|
||||||
for(uint n = 0; n < size(); n++) {
|
for(uint n = 0; n < size(); n++) {
|
||||||
if(operator[](n).match(pattern)) result.append(operator[](n));
|
if(operator[](n).match(pattern)) result.append(operator[](n));
|
||||||
|
@ -54,7 +54,7 @@ auto lstring::match(rstring pattern) const -> lstring {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lstring::merge(rstring separator) const -> string {
|
auto lstring::merge(string_view separator) const -> string {
|
||||||
string output;
|
string output;
|
||||||
for(uint n = 0; n < size(); n++) {
|
for(uint n = 0; n < size(); n++) {
|
||||||
output.append(operator[](n));
|
output.append(operator[](n));
|
||||||
|
|
|
@ -74,7 +74,7 @@ protected:
|
||||||
if(length == 0) throw "Invalid attribute name";
|
if(length == 0) throw "Invalid attribute name";
|
||||||
node->_name = slice(p, 0, length);
|
node->_name = slice(p, 0, length);
|
||||||
node->parseData(p += length);
|
node->parseData(p += length);
|
||||||
node->_value.rtrim("\n", 1L);
|
node->_value.trimRight("\n", 1L);
|
||||||
_children.append(node);
|
_children.append(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ protected:
|
||||||
_children.append(node);
|
_children.append(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
_value.rtrim("\n", 1L);
|
_value.trimRight("\n", 1L);
|
||||||
}
|
}
|
||||||
|
|
||||||
//read top-level nodes
|
//read top-level nodes
|
||||||
|
@ -127,7 +127,7 @@ protected:
|
||||||
memory::move(output, origin, p - origin);
|
memory::move(output, origin, p - origin);
|
||||||
output += 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
|
if(document.size() == 0) return; //empty document
|
||||||
|
|
||||||
auto text = document.split("\n");
|
auto text = document.split("\n");
|
||||||
|
|
|
@ -31,7 +31,7 @@ auto ManagedNode::_evaluate(string query) const -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
string data = string{_value}.strip();
|
string data = string{_value}.strip();
|
||||||
if(side(0).empty() == false) {
|
if(side(0)) {
|
||||||
auto result = _find(side(0));
|
auto result = _find(side(0));
|
||||||
if(result.size() == 0) return false;
|
if(result.size() == 0) return false;
|
||||||
data = result[0].value();
|
data = result[0].value();
|
||||||
|
@ -60,19 +60,19 @@ auto ManagedNode::_find(const string& query) const -> vector<Node> {
|
||||||
uint lo = 0u, hi = ~0u;
|
uint lo = 0u, hi = ~0u;
|
||||||
|
|
||||||
if(name.match("*[*]")) {
|
if(name.match("*[*]")) {
|
||||||
auto p = name.rtrim("]", 1L).split("[", 1L);
|
auto p = name.trimRight("]", 1L).split("[", 1L);
|
||||||
name = p(0);
|
name = p(0);
|
||||||
if(p(1).find("-")) {
|
if(p(1).find("-")) {
|
||||||
p = p(1).split("-", 1L);
|
p = p(1).split("-", 1L);
|
||||||
lo = p(0).empty() ? 0u : p(0).natural();
|
lo = !p(0) ? 0u : p(0).natural();
|
||||||
hi = p(1).empty() ? ~0u : p(1).natural();
|
hi = !p(1) ? ~0u : p(1).natural();
|
||||||
} else {
|
} else {
|
||||||
lo = hi = p(1).natural();
|
lo = hi = p(1).natural();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(name.match("*(*)")) {
|
if(name.match("*(*)")) {
|
||||||
auto p = name.rtrim(")", 1L).split("(", 1L);
|
auto p = name.trimRight(")", 1L).split("(", 1L);
|
||||||
name = p(0);
|
name = p(0);
|
||||||
rule = p(1);
|
rule = p(1);
|
||||||
}
|
}
|
||||||
|
@ -119,13 +119,13 @@ auto ManagedNode::_create(const string& path) -> Node {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_children.append(new ManagedNode(name));
|
_children.append(new ManagedNode(name));
|
||||||
return _children.last()->_create(slice(path, *position + 1));
|
return _children.right()->_create(slice(path, *position + 1));
|
||||||
}
|
}
|
||||||
for(auto& node : _children) {
|
for(auto& node : _children) {
|
||||||
if(path == node->_name) return node;
|
if(path == node->_name) return node;
|
||||||
}
|
}
|
||||||
_children.append(new ManagedNode(path));
|
_children.append(new ManagedNode(path));
|
||||||
return _children.last();
|
return _children.right();
|
||||||
}
|
}
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -125,7 +125,7 @@ protected:
|
||||||
while(isName(*p)) p++;
|
while(isName(*p)) p++;
|
||||||
const char* nameEnd = p;
|
const char* nameEnd = p;
|
||||||
copy(_name, nameStart, nameEnd - nameStart);
|
copy(_name, nameStart, nameEnd - nameStart);
|
||||||
if(_name.empty()) throw "missing element name";
|
if(!_name) throw "missing element name";
|
||||||
|
|
||||||
//parse attributes
|
//parse attributes
|
||||||
while(*p) {
|
while(*p) {
|
||||||
|
@ -141,7 +141,7 @@ protected:
|
||||||
while(isName(*p)) p++;
|
while(isName(*p)) p++;
|
||||||
const char* nameEnd = p;
|
const char* nameEnd = p;
|
||||||
copy(attribute->_name, nameStart, nameEnd - nameStart);
|
copy(attribute->_name, nameStart, nameEnd - nameStart);
|
||||||
if(attribute->_name.empty()) throw "missing attribute name";
|
if(!attribute->_name) throw "missing attribute name";
|
||||||
|
|
||||||
//parse attribute data
|
//parse attribute data
|
||||||
if(*p++ != '=') throw "missing attribute value";
|
if(*p++ != '=') throw "missing attribute value";
|
||||||
|
|
|
@ -4,7 +4,7 @@ namespace nall {
|
||||||
|
|
||||||
//todo: these functions are not binary-safe
|
//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* s = data();
|
||||||
const char* p = source.data();
|
const char* p = source.data();
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ auto string::match(rstring source) const -> bool {
|
||||||
return !*p;
|
return !*p;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto string::imatch(rstring source) const -> bool {
|
auto string::imatch(string_view source) const -> bool {
|
||||||
static auto chrlower = [](char c) -> char {
|
static auto chrlower = [](char c) -> char {
|
||||||
return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c;
|
return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c;
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,7 +4,7 @@ namespace nall {
|
||||||
|
|
||||||
// (/parent/child.type/)
|
// (/parent/child.type/)
|
||||||
// (/parent/child.type/)name.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;
|
const char* p = self.data() + self.size() - 1;
|
||||||
for(int offset = self.size() - 1; offset >= 0; offset--, p--) {
|
for(int offset = self.size() - 1; offset >= 0; offset--, p--) {
|
||||||
if(*p == '/') return slice(self, 0, offset + 1);
|
if(*p == '/') return slice(self, 0, offset + 1);
|
||||||
|
@ -14,7 +14,7 @@ auto pathname(rstring self) -> string {
|
||||||
|
|
||||||
// /parent/child.type/()
|
// /parent/child.type/()
|
||||||
// /parent/child.type/(name.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;
|
const char* p = self.data() + self.size() - 1;
|
||||||
for(int offset = self.size() - 1; offset >= 0; offset--, p--) {
|
for(int offset = self.size() - 1; offset >= 0; offset--, p--) {
|
||||||
if(*p == '/') return slice(self, offset + 1);
|
if(*p == '/') return slice(self, offset + 1);
|
||||||
|
@ -24,18 +24,18 @@ auto filename(rstring self) -> string {
|
||||||
|
|
||||||
// (/parent/)child.type/
|
// (/parent/)child.type/
|
||||||
// (/parent/child.type/)name.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;
|
const char* p = self.data() + self.size() - 1, *last = p;
|
||||||
for(int offset = self.size() - 1; offset >= 0; offset--, p--) {
|
for(int offset = self.size() - 1; offset >= 0; offset--, p--) {
|
||||||
if(*p == '/' && p == last) continue;
|
if(*p == '/' && p == last) continue;
|
||||||
if(*p == '/') return slice(self, 0, offset + 1);
|
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/)
|
||||||
// /parent/child.type/(name.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;
|
const char* p = self.data() + self.size() - 1, *last = p;
|
||||||
for(int offset = self.size() - 1; offset >= 0; offset--, p--) {
|
for(int offset = self.size() - 1; offset >= 0; offset--, p--) {
|
||||||
if(*p == '/' && p == last) continue;
|
if(*p == '/' && p == last) continue;
|
||||||
|
@ -46,25 +46,25 @@ auto basename(rstring self) -> string {
|
||||||
|
|
||||||
// /parent/(child).type/
|
// /parent/(child).type/
|
||||||
// /parent/child.type/(name).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;
|
const char* p = self.data() + self.size() - 1, *last = p;
|
||||||
for(int offset = self.size() - 1, suffix = -1; offset >= 0; offset--, p--) {
|
for(int offset = self.size() - 1, suffix = -1; offset >= 0; offset--, p--) {
|
||||||
if(*p == '/' && p == last) continue;
|
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(*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
|
return ""; //no prefix found
|
||||||
}
|
}
|
||||||
|
|
||||||
// /parent/child(.type)/
|
// /parent/child(.type)/
|
||||||
// /parent/child.type/name(.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;
|
const char* p = self.data() + self.size() - 1, *last = p;
|
||||||
for(int offset = self.size() - 1; offset >= 0; offset--, p--) {
|
for(int offset = self.size() - 1; offset >= 0; offset--, p--) {
|
||||||
if(*p == '/' && p == last) continue;
|
if(*p == '/' && p == last) continue;
|
||||||
if(*p == '/') break;
|
if(*p == '/') break;
|
||||||
if(*p == '.') return slice(self, offset).rtrim("/");
|
if(*p == '.') return slice(self, offset).trimRight("/");
|
||||||
}
|
}
|
||||||
return ""; //no suffix found
|
return ""; //no suffix found
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,17 +3,17 @@
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
template<bool Insensitive, bool Quoted>
|
template<bool Insensitive, bool Quoted>
|
||||||
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;
|
if(limit <= 0 || from.size() == 0) return *this;
|
||||||
|
|
||||||
signed size = this->size();
|
int size = this->size();
|
||||||
signed matches = 0;
|
int matches = 0;
|
||||||
signed quoted = 0;
|
int quoted = 0;
|
||||||
|
|
||||||
//count matches first, so that we only need to reallocate memory once
|
//count matches first, so that we only need to reallocate memory once
|
||||||
//(recording matches would also require memory allocation, so this is not done)
|
//(recording matches would also require memory allocation, so this is not done)
|
||||||
{ const char* p = data();
|
{ 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(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } }
|
||||||
if(_compare<Insensitive>(p + n, size - n, from.data(), from.size())) { n++; continue; }
|
if(_compare<Insensitive>(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()) {
|
if(to.size() == from.size()) {
|
||||||
char* p = get();
|
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(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } }
|
||||||
if(_compare<Insensitive>(p + n, size - n, from.data(), from.size())) { n++; continue; }
|
if(_compare<Insensitive>(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
|
//left-to-right shrink
|
||||||
else if(to.size() < from.size()) {
|
else if(to.size() < from.size()) {
|
||||||
char* p = get();
|
char* p = get();
|
||||||
signed offset = 0;
|
int offset = 0;
|
||||||
signed base = 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(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } }
|
||||||
if(_compare<Insensitive>(p + n, size - n, from.data(), from.size())) { n++; continue; }
|
if(_compare<Insensitive>(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()));
|
resize(size + matches * (to.size() - from.size()));
|
||||||
char* p = get();
|
char* p = get();
|
||||||
|
|
||||||
signed offset = this->size();
|
int offset = this->size();
|
||||||
signed base = 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(Quoted) { if(p[n] == '\"') { quoted ^= 1; n--; continue; } if(quoted) { n--; continue; } }
|
||||||
if(_compare<Insensitive>(p + n - from.size(), size - n + from.size(), from.data(), from.size())) { n--; continue; }
|
if(_compare<Insensitive>(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;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto string::replace(rstring from, rstring to, long limit) -> string& { return _replace<0, 0>(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(rstring from, rstring to, long limit) -> string& { return _replace<1, 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(rstring from, rstring to, long limit) -> string& { return _replace<0, 1>(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(rstring from, rstring to, long limit) -> string& { return _replace<1, 1>(from, to, limit); }
|
auto string::iqreplace(string_view from, string_view to, long limit) -> string& { return _replace<1, 1>(from, to, limit); }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,16 +3,16 @@
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
template<bool Insensitive, bool Quoted>
|
template<bool Insensitive, bool Quoted>
|
||||||
auto lstring::_split(rstring source, rstring find, long limit) -> lstring& {
|
auto lstring::_split(string_view source, string_view find, long limit) -> lstring& {
|
||||||
reset();
|
reset();
|
||||||
if(limit <= 0 || find.size() == 0) return *this;
|
if(limit <= 0 || find.size() == 0) return *this;
|
||||||
|
|
||||||
const char* p = source.data();
|
const char* p = source.data();
|
||||||
signed size = source.size();
|
int size = source.size();
|
||||||
signed base = 0;
|
int base = 0;
|
||||||
signed matches = 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(Quoted) { if(p[n] == '\"') { quoted ^= 1; n++; continue; } if(quoted) { n++; continue; } }
|
||||||
if(string::_compare<Insensitive>(p + n, size - n, find.data(), find.size())) { n++; continue; }
|
if(string::_compare<Insensitive>(p + n, size - n, find.data(), find.size())) { n++; continue; }
|
||||||
if(matches >= limit) break;
|
if(matches >= limit) break;
|
||||||
|
@ -33,9 +33,9 @@ auto lstring::_split(rstring source, rstring find, long limit) -> lstring& {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto string::split(rstring on, long limit) const -> lstring { return lstring()._split<0, 0>(*this, on, limit); }
|
auto string::split(string_view 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::isplit(string_view 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::qsplit(string_view 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::iqsplit(string_view on, long limit) const -> lstring { return lstring()._split<1, 1>(*this, on, limit); }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,11 +54,11 @@ auto CML::parseDocument(const string& filedata, const string& pathname, uint dep
|
||||||
};
|
};
|
||||||
|
|
||||||
for(auto& block : filedata.split("\n\n")) {
|
for(auto& block : filedata.split("\n\n")) {
|
||||||
lstring lines = block.rstrip().split("\n");
|
lstring lines = block.stripRight().split("\n");
|
||||||
string name = lines.takeFirst();
|
string name = lines.takeLeft();
|
||||||
|
|
||||||
if(name.beginsWith("include ")) {
|
if(name.beginsWith("include ")) {
|
||||||
name.ltrim("include ", 1L);
|
name.trimLeft("include ", 1L);
|
||||||
string filename{pathname, name};
|
string filename{pathname, name};
|
||||||
string document = settings.reader ? settings.reader(filename) : string::read(filename);
|
string document = settings.reader ? settings.reader(filename) : string::read(filename);
|
||||||
parseDocument(document, nall::pathname(filename), depth + 1);
|
parseDocument(document, nall::pathname(filename), depth + 1);
|
||||||
|
|
|
@ -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 {
|
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");
|
auto lines = block.split("\n");
|
||||||
|
|
||||||
//include
|
//include
|
||||||
|
@ -75,7 +75,7 @@ auto DML::parseBlock(string& block, const string& pathname, uint depth) -> bool
|
||||||
else if(block.beginsWith("<html>\n") && settings.allowHTML) {
|
else if(block.beginsWith("<html>\n") && settings.allowHTML) {
|
||||||
for(auto n : range(lines)) {
|
for(auto n : range(lines)) {
|
||||||
if(n == 0 || !lines[n].beginsWith(" ")) continue;
|
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("</section>");
|
if(state.sections++) state.output.append("</section>");
|
||||||
state.output.append("<section>");
|
state.output.append("<section>");
|
||||||
}
|
}
|
||||||
auto content = lines.takeFirst().ltrim("# ", 1L).split(" => ", 1L);
|
auto content = lines.takeLeft().trimLeft("# ", 1L).split(" => ", 1L);
|
||||||
auto data = markup(content[0]);
|
auto data = markup(content[0]);
|
||||||
auto name = escape(content(1, crc32(data)));
|
auto name = escape(content(1, data.hash()));
|
||||||
state.output.append("<header id=\"", name, "\">", data);
|
state.output.append("<header id=\"", name, "\">", data);
|
||||||
for(auto& line : lines) {
|
for(auto& line : lines) {
|
||||||
if(!line.beginsWith("# ")) continue;
|
if(!line.beginsWith("# ")) continue;
|
||||||
state.output.append("<span>", line.ltrim("# ", 1L), "</span>");
|
state.output.append("<span>", line.trimLeft("# ", 1L), "</span>");
|
||||||
}
|
}
|
||||||
state.output.append("</header>\n");
|
state.output.append("</header>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
//header
|
//header
|
||||||
else if(auto depth = count(block, '=')) {
|
else if(auto depth = count(block, '=')) {
|
||||||
auto content = slice(lines.takeFirst(), depth + 1).split(" => ", 1L);
|
auto content = slice(lines.takeLeft(), depth + 1).split(" => ", 1L);
|
||||||
auto data = markup(content[0]);
|
auto data = markup(content[0]);
|
||||||
auto name = escape(content(1, crc32(data)));
|
auto name = escape(content(1, data.hash()));
|
||||||
if(depth <= 6) {
|
if(depth <= 6) {
|
||||||
state.output.append("<h", depth, " id=\"", name, "\">", data);
|
state.output.append("<h", depth, " id=\"", name, "\">", data);
|
||||||
for(auto& line : lines) {
|
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("</ul>\n");
|
while(level > depth) level--, state.output.append("</ul>\n");
|
||||||
auto content = slice(line, depth + 1).split(" => ", 1L);
|
auto content = slice(line, depth + 1).split(" => ", 1L);
|
||||||
auto data = markup(content[0]);
|
auto data = markup(content[0]);
|
||||||
auto name = escape(content(1, crc32(data)));
|
auto name = escape(content(1, data.hash()));
|
||||||
state.output.append("<li><a href=\"#", name, "\">", data, "</a></li>\n");
|
state.output.append("<li><a href=\"#", name, "\">", data, "</a></li>\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,9 +162,9 @@ auto DML::parseBlock(string& block, const string& pathname, uint depth) -> bool
|
||||||
state.output.append("<pre>");
|
state.output.append("<pre>");
|
||||||
for(auto& line : lines) {
|
for(auto& line : lines) {
|
||||||
if(!line.beginsWith(" ")) continue;
|
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("</pre>\n");
|
state.output.trimRight("\n", 1L).append("</pre>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
//divider
|
//divider
|
||||||
|
|
|
@ -2,19 +2,19 @@
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
auto string::trim(rstring lhs, rstring rhs, long limit) -> string& {
|
auto string::trim(string_view lhs, string_view rhs, long limit) -> string& {
|
||||||
rtrim(rhs, limit);
|
trimRight(rhs, limit);
|
||||||
ltrim(lhs, limit);
|
trimLeft(lhs, limit);
|
||||||
return *this;
|
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;
|
if(lhs.size() == 0) return *this;
|
||||||
long matches = 0;
|
long matches = 0;
|
||||||
while(matches < limit) {
|
while(matches < limit) {
|
||||||
signed offset = lhs.size() * matches;
|
int offset = lhs.size() * matches;
|
||||||
signed length = (signed)size() - offset;
|
int length = (int)size() - offset;
|
||||||
if(length < (signed)lhs.size()) break;
|
if(length < (int)lhs.size()) break;
|
||||||
if(memory::compare(data() + offset, lhs.data(), lhs.size()) != 0) break;
|
if(memory::compare(data() + offset, lhs.data(), lhs.size()) != 0) break;
|
||||||
matches++;
|
matches++;
|
||||||
}
|
}
|
||||||
|
@ -22,13 +22,13 @@ auto string::ltrim(rstring lhs, long limit) -> string& {
|
||||||
return *this;
|
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;
|
if(rhs.size() == 0) return *this;
|
||||||
long matches = 0;
|
long matches = 0;
|
||||||
while(matches < limit) {
|
while(matches < limit) {
|
||||||
signed offset = (signed)size() - rhs.size() * (matches + 1);
|
int offset = (int)size() - rhs.size() * (matches + 1);
|
||||||
signed length = (signed)size() - offset;
|
int length = (int)size() - offset;
|
||||||
if(offset < 0 || length < (signed)rhs.size()) break;
|
if(offset < 0 || length < (int)rhs.size()) break;
|
||||||
if(memory::compare(data() + offset, rhs.data(), rhs.size()) != 0) break;
|
if(memory::compare(data() + offset, rhs.data(), rhs.size()) != 0) break;
|
||||||
matches++;
|
matches++;
|
||||||
}
|
}
|
||||||
|
@ -36,19 +36,19 @@ auto string::rtrim(rstring rhs, long limit) -> string& {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto string::itrim(rstring lhs, rstring rhs, long limit) -> string& {
|
auto string::itrim(string_view lhs, string_view rhs, long limit) -> string& {
|
||||||
irtrim(rhs, limit);
|
itrimRight(rhs, limit);
|
||||||
iltrim(lhs, limit);
|
itrimLeft(lhs, limit);
|
||||||
return *this;
|
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;
|
if(lhs.size() == 0) return *this;
|
||||||
long matches = 0;
|
long matches = 0;
|
||||||
while(matches < limit) {
|
while(matches < limit) {
|
||||||
signed offset = lhs.size() * matches;
|
int offset = lhs.size() * matches;
|
||||||
signed length = (signed)size() - offset;
|
int length = (int)size() - offset;
|
||||||
if(length < (signed)lhs.size()) break;
|
if(length < (int)lhs.size()) break;
|
||||||
if(memory::icompare(data() + offset, lhs.data(), lhs.size()) != 0) break;
|
if(memory::icompare(data() + offset, lhs.data(), lhs.size()) != 0) break;
|
||||||
matches++;
|
matches++;
|
||||||
}
|
}
|
||||||
|
@ -56,13 +56,13 @@ auto string::iltrim(rstring lhs, long limit) -> string& {
|
||||||
return *this;
|
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;
|
if(rhs.size() == 0) return *this;
|
||||||
long matches = 0;
|
long matches = 0;
|
||||||
while(matches < limit) {
|
while(matches < limit) {
|
||||||
signed offset = (signed)size() - rhs.size() * (matches + 1);
|
int offset = (int)size() - rhs.size() * (matches + 1);
|
||||||
signed length = (signed)size() - offset;
|
int length = (int)size() - offset;
|
||||||
if(offset < 0 || length < (signed)rhs.size()) break;
|
if(offset < 0 || length < (int)rhs.size()) break;
|
||||||
if(memory::icompare(data() + offset, rhs.data(), rhs.size()) != 0) break;
|
if(memory::icompare(data() + offset, rhs.data(), rhs.size()) != 0) break;
|
||||||
matches++;
|
matches++;
|
||||||
}
|
}
|
||||||
|
@ -71,13 +71,13 @@ auto string::irtrim(rstring rhs, long limit) -> string& {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto string::strip() -> string& {
|
auto string::strip() -> string& {
|
||||||
rstrip();
|
stripRight();
|
||||||
lstrip();
|
stripLeft();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto string::lstrip() -> string& {
|
auto string::stripLeft() -> string& {
|
||||||
unsigned length = 0;
|
uint length = 0;
|
||||||
while(length < size()) {
|
while(length < size()) {
|
||||||
char input = operator[](length);
|
char input = operator[](length);
|
||||||
if(input != ' ' && input != '\t' && input != '\r' && input != '\n') break;
|
if(input != ' ' && input != '\t' && input != '\r' && input != '\n') break;
|
||||||
|
@ -87,8 +87,8 @@ auto string::lstrip() -> string& {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto string::rstrip() -> string& {
|
auto string::stripRight() -> string& {
|
||||||
unsigned length = 0;
|
uint length = 0;
|
||||||
while(length < size()) {
|
while(length < size()) {
|
||||||
bool matched = false;
|
bool matched = false;
|
||||||
char input = operator[](size() - length - 1);
|
char input = operator[](size() - length - 1);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
auto string::read(rstring filename) -> string {
|
auto string::read(string_view filename) -> string {
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
FILE* fp = fopen(filename, "rb");
|
FILE* fp = fopen(filename, "rb");
|
||||||
#else
|
#else
|
||||||
|
@ -22,7 +22,7 @@ auto string::read(rstring filename) -> string {
|
||||||
return fclose(fp), result;
|
return fclose(fp), result;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto string::repeat(rstring pattern, uint times) -> string {
|
auto string::repeat(string_view pattern, uint times) -> string {
|
||||||
string result;
|
string result;
|
||||||
while(times--) result.append(pattern.data());
|
while(times--) result.append(pattern.data());
|
||||||
return result;
|
return result;
|
||||||
|
@ -33,7 +33,7 @@ auto string::fill(char fill) -> string& {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto string::hash() const -> unsigned {
|
auto string::hash() const -> uint {
|
||||||
const char* p = data();
|
const char* p = data();
|
||||||
uint length = size();
|
uint length = size();
|
||||||
uint result = 5381;
|
uint result = 5381;
|
||||||
|
@ -82,7 +82,7 @@ auto string::size(int length, char fill) -> string& {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto slice(rstring self, int offset, int length) -> string {
|
auto slice(string_view self, int offset, int length) -> string {
|
||||||
string result;
|
string result;
|
||||||
if(offset < self.size()) {
|
if(offset < self.size()) {
|
||||||
if(length < 0) length = self.size() - offset;
|
if(length < 0) length = self.size() - offset;
|
||||||
|
|
143
string/view.hpp
143
string/view.hpp
|
@ -2,87 +2,84 @@
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
struct string_view {
|
string_view::string_view() {
|
||||||
string_view() {
|
_string = nullptr;
|
||||||
_string = nullptr;
|
_data = "";
|
||||||
_data = "";
|
_size = 0;
|
||||||
_size = 0;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
string_view(const char* data) {
|
string_view::string_view(const string_view& source) {
|
||||||
_string = nullptr;
|
if(this == &source) return;
|
||||||
_data = data;
|
_string = nullptr;
|
||||||
_size = -1; //defer length calculation, as it is often unnecessary
|
_data = source._data;
|
||||||
}
|
_size = source._size;
|
||||||
|
}
|
||||||
|
|
||||||
string_view(const char* data, unsigned size) {
|
string_view::string_view(string_view&& source) {
|
||||||
_string = nullptr;
|
if(this == &source) return;
|
||||||
_data = data;
|
_string = source._string;
|
||||||
_size = size;
|
_data = source._data;
|
||||||
}
|
_size = source._size;
|
||||||
|
source._string = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
string_view(const string& source) {
|
string_view::string_view(const char* data) {
|
||||||
_string = nullptr;
|
_string = nullptr;
|
||||||
_data = source.data();
|
_data = data;
|
||||||
_size = source.size();
|
_size = -1; //defer length calculation, as it is often unnecessary
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... P>
|
string_view::string_view(const char* data, uint size) {
|
||||||
string_view(P&&... p) {
|
_string = nullptr;
|
||||||
_string = new string{forward<P>(p)...};
|
_data = data;
|
||||||
_data = _string->data();
|
_size = size;
|
||||||
_size = _string->size();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
~string_view() {
|
string_view::string_view(const string& source) {
|
||||||
if(_string) delete _string;
|
_string = nullptr;
|
||||||
}
|
_data = source.data();
|
||||||
|
_size = source.size();
|
||||||
|
}
|
||||||
|
|
||||||
string_view(const string_view& source) {
|
template<typename... P>
|
||||||
_string = nullptr;
|
string_view::string_view(P&&... p) {
|
||||||
_data = source._data;
|
_string = new string{forward<P>(p)...};
|
||||||
_size = source._size;
|
_data = _string->data();
|
||||||
}
|
_size = _string->size();
|
||||||
|
}
|
||||||
|
|
||||||
string_view(string_view&& source) {
|
string_view::~string_view() {
|
||||||
_string = source._string;
|
if(_string) delete _string;
|
||||||
_data = source._data;
|
}
|
||||||
_size = source._size;
|
|
||||||
source._string = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto operator=(const string_view& source) -> string_view& {
|
auto string_view::operator=(const string_view& source) -> string_view& {
|
||||||
_string = nullptr;
|
if(this == &source) return *this;
|
||||||
_data = source._data;
|
_string = nullptr;
|
||||||
_size = source._size;
|
_data = source._data;
|
||||||
return *this;
|
_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=(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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
16
thread.hpp
16
thread.hpp
|
@ -19,13 +19,13 @@ namespace nall {
|
||||||
struct thread {
|
struct thread {
|
||||||
inline auto join() -> void;
|
inline auto join() -> void;
|
||||||
|
|
||||||
static inline auto create(const function<void (uintptr_t)>& callback, uintptr_t parameter = 0, unsigned stacksize = 0) -> thread;
|
static inline auto create(const function<void (uintptr)>& callback, uintptr parameter = 0, uint stacksize = 0) -> thread;
|
||||||
static inline auto detach() -> void;
|
static inline auto detach() -> void;
|
||||||
static inline auto exit() -> void;
|
static inline auto exit() -> void;
|
||||||
|
|
||||||
struct context {
|
struct context {
|
||||||
function<void (uintptr_t)> callback;
|
function<auto (uintptr) -> void> callback;
|
||||||
uintptr_t parameter = 0;
|
uintptr parameter = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -43,7 +43,7 @@ auto thread::join() -> void {
|
||||||
pthread_join(handle, nullptr);
|
pthread_join(handle, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto thread::create(const function<void (uintptr_t)>& callback, uintptr_t parameter, unsigned stacksize) -> thread {
|
auto thread::create(const function<void (uintptr)>& callback, uintptr parameter, uint stacksize) -> thread {
|
||||||
thread instance;
|
thread instance;
|
||||||
|
|
||||||
auto context = new thread::context;
|
auto context = new thread::context;
|
||||||
|
@ -76,13 +76,13 @@ struct thread {
|
||||||
inline ~thread();
|
inline ~thread();
|
||||||
inline auto join() -> void;
|
inline auto join() -> void;
|
||||||
|
|
||||||
static inline auto create(const function<void (uintptr_t)>& callback, uintptr_t parameter = 0, unsigned stacksize = 0) -> thread;
|
static inline auto create(const function<void (uintptr)>& callback, uintptr parameter = 0, uint stacksize = 0) -> thread;
|
||||||
static inline auto detach() -> void;
|
static inline auto detach() -> void;
|
||||||
static inline auto exit() -> void;
|
static inline auto exit() -> void;
|
||||||
|
|
||||||
struct context {
|
struct context {
|
||||||
function<void (uintptr_t)> callback;
|
function<auto (uintptr) -> void> callback;
|
||||||
uintptr_t parameter = 0;
|
uintptr parameter = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -111,7 +111,7 @@ auto thread::join() -> void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto thread::create(const function<void (uintptr_t)>& callback, uintptr_t parameter, unsigned stacksize) -> thread {
|
auto thread::create(const function<void (uintptr)>& callback, uintptr parameter, uint stacksize) -> thread {
|
||||||
thread instance;
|
thread instance;
|
||||||
|
|
||||||
auto context = new thread::context;
|
auto context = new thread::context;
|
||||||
|
|
|
@ -9,9 +9,9 @@ template<typename T> struct base_from_member {
|
||||||
T value;
|
T value;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T> inline auto allocate(unsigned size, const T& value) -> T* {
|
template<typename T> inline auto allocate(uint size, const T& value) -> T* {
|
||||||
T* array = new T[size];
|
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;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
12
varint.hpp
12
varint.hpp
|
@ -10,8 +10,8 @@ struct varint {
|
||||||
virtual auto read() -> uint8_t = 0;
|
virtual auto read() -> uint8_t = 0;
|
||||||
virtual auto write(uint8_t) -> void = 0;
|
virtual auto write(uint8_t) -> void = 0;
|
||||||
|
|
||||||
auto readvu() -> uintmax_t {
|
auto readvu() -> uintmax {
|
||||||
uintmax_t data = 0, shift = 1;
|
uintmax data = 0, shift = 1;
|
||||||
while(true) {
|
while(true) {
|
||||||
uint8_t x = read();
|
uint8_t x = read();
|
||||||
data += (x & 0x7f) * shift;
|
data += (x & 0x7f) * shift;
|
||||||
|
@ -22,15 +22,15 @@ struct varint {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto readvs() -> intmax_t {
|
auto readvs() -> intmax {
|
||||||
uintmax_t data = readvu();
|
uintmax data = readvu();
|
||||||
bool negate = data & 1;
|
bool negate = data & 1;
|
||||||
data >>= 1;
|
data >>= 1;
|
||||||
if(negate) data = ~data;
|
if(negate) data = ~data;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto writevu(uintmax_t data) -> void {
|
auto writevu(uintmax data) -> void {
|
||||||
while(true) {
|
while(true) {
|
||||||
uint8_t x = data & 0x7f;
|
uint8_t x = data & 0x7f;
|
||||||
data >>= 7;
|
data >>= 7;
|
||||||
|
@ -40,7 +40,7 @@ struct varint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto writevs(intmax_t data) -> void {
|
auto writevs(intmax data) -> void {
|
||||||
bool negate = data < 0;
|
bool negate = data < 0;
|
||||||
if(negate) data = ~data;
|
if(negate) data = ~data;
|
||||||
data = (data << 1) | negate;
|
data = (data << 1) | negate;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue