Update to bsnes v107.1 release.

byuu says:

Don't let the point release fool you, there are many significant changes in this
release. I will be keeping bsnes releases using a point system until the new
higan release is ready.

Changelog:

  - GUI: added high DPI support
  - GUI: fixed the state manager image preview
  - Windows: added a new waveOut driver with support for dynamic rate control
  - Windows: corrected the XAudio 2.1 dynamic rate control support [BearOso]
  - Windows: corrected the Direct3D 9.0 fullscreen exclusive window centering
  - Windows: fixed XInput controller support on Windows 10
  - SFC: added high-level emulation for the DSP1, DSP2, DSP4, ST010, and Cx4
    coprocessors
  - SFC: fixed a slight rendering glitch in the intro to Megalomania

If the coprocessor firmware is missing, bsnes will fallback on HLE where it is
supported, which is everything other than SD Gundam GX and the two Hayazashi
Nidan Morita Shougi games.

The Windows dynamic rate control works best with Direct3D in fullscreen
exclusive mode. I recommend the waveOut driver over the XAudio 2.1 driver, as it
is not possible to target a single XAudio2 version on all Windows OS releases.
The waveOut driver should work everywhere out of the box.

Note that with DRC, the synchronization source is your monitor, so you will
want to be running at 60hz (NTSC) or 50hz (PAL). If you have an adaptive sync
monitor, you should instead use the WASAPI (exclusive) or ASIO audio driver.
This commit is contained in:
Tim Allen
2019-04-09 11:16:30 +10:00
parent 7786206a4f
commit 4d7bb510f2
223 changed files with 9895 additions and 3116 deletions

View File

@@ -139,8 +139,6 @@ ifeq ($(threaded),true)
endif
# paths
prefix := $(HOME)/.local
ifeq ($(object.path),)
object.path := obj
endif
@@ -227,3 +225,10 @@ streq = $(if $(filter-out xx,x$(subst $1,,$2)$(subst $2,,$1)x),,1)
# function strne(source)
strne = $(if $(filter-out xx,x$(subst $1,,$2)$(subst $2,,$1)x),1,)
# prefix
ifeq ($(platform),windows)
prefix := $(subst $([space]),\$([space]),$(strip $(call strtr,$(LOCALAPPDATA),\,/)))
else
prefix := $(HOME)/.local
endif

View File

@@ -7,19 +7,19 @@
namespace nall {
template<typename T, typename U> auto min(const T& t, const U& u) -> T {
template<typename T, typename U> constexpr auto min(const T& t, const U& u) -> T {
return t < u ? t : (T)u;
}
template<typename T, typename U, typename... P> auto min(const T& t, const U& u, P&&... p) -> T {
template<typename T, typename U, typename... P> constexpr auto min(const T& t, const U& u, P&&... p) -> T {
return t < u ? min(t, forward<P>(p)...) : min(u, forward<P>(p)...);
}
template<typename T, typename U> auto max(const T& t, const U& u) -> T {
template<typename T, typename U> constexpr auto max(const T& t, const U& u) -> T {
return t > u ? t : (T)u;
}
template<typename T, typename U, typename... P> auto max(const T& t, const U& u, P&&... p) -> T {
template<typename T, typename U, typename... P> constexpr auto max(const T& t, const U& u, P&&... p) -> T {
return t > u ? max(t, forward<P>(p)...) : max(u, forward<P>(p)...);
}

View File

@@ -137,7 +137,7 @@ inline auto Arguments::take(string_view name) -> bool {
inline auto Arguments::take(string_view name, bool& argument) -> bool {
for(uint index : range(arguments.size())) {
if(arguments[index].match(name) && arguments.size() >= index
if(arguments[index].match(name) && arguments.size() > index + 1
&& (arguments[index + 1] == "true" || arguments[index + 1] == "false")) {
arguments.remove(index);
argument = arguments.take(index) == "true";
@@ -149,7 +149,7 @@ inline auto Arguments::take(string_view name, bool& argument) -> bool {
inline auto Arguments::take(string_view name, string& argument) -> bool {
for(uint index : range(arguments.size())) {
if(arguments[index].match(name) && arguments.size() >= index) {
if(arguments[index].match(name) && arguments.size() > index + 1) {
arguments.remove(index);
argument = arguments.take(index);
return true;

View File

@@ -21,6 +21,7 @@ namespace nall {
struct directory : inode {
directory() = delete;
static auto copy(const string& source, const string& target) -> bool; //recursive
static auto create(const string& pathname, uint permissions = 0755) -> bool; //recursive
static auto remove(const string& pathname) -> bool; //recursive
static auto exists(const string& pathname) -> bool;
@@ -28,6 +29,7 @@ struct directory : inode {
static auto folders(const string& pathname, const string& pattern = "*") -> vector<string> {
auto folders = directory::ufolders(pathname, pattern);
folders.sort();
for(auto& folder : folders) folder.append("/"); //must append after sorting
return folders;
}
@@ -39,8 +41,9 @@ struct directory : inode {
static auto contents(const string& pathname, const string& pattern = "*") -> vector<string> {
auto folders = directory::ufolders(pathname); //pattern search of contents should only filter files
auto files = directory::ufiles(pathname, pattern);
folders.sort();
for(auto& folder : folders) folder.append("/"); //must append after sorting
auto files = directory::ufiles(pathname, pattern);
files.sort();
for(auto& file : files) folders.append(file);
return folders;
@@ -49,6 +52,7 @@ struct directory : inode {
static auto ifolders(const string& pathname, const string& pattern = "*") -> vector<string> {
auto folders = ufolders(pathname, pattern);
folders.isort();
for(auto& folder : folders) folder.append("/"); //must append after sorting
return folders;
}
@@ -60,8 +64,9 @@ struct directory : inode {
static auto icontents(const string& pathname, const string& pattern = "*") -> vector<string> {
auto folders = directory::ufolders(pathname); //pattern search of contents should only filter files
auto files = directory::ufiles(pathname, pattern);
folders.isort();
for(auto& folder : folders) folder.append("/"); //must append after sorting
auto files = directory::ufiles(pathname, pattern);
files.isort();
for(auto& file : files) folders.append(file);
return folders;
@@ -151,6 +156,18 @@ private:
static auto ufiles(const string& pathname, const string& pattern = "*") -> vector<string>;
};
inline auto directory::copy(const string& source, const string& target) -> bool {
bool result = true;
if(!directory::create(target)) return result = false;
for(auto& name : directory::folders(source)) {
if(!directory::copy({source, name}, {target, name})) result = false;
}
for(auto& name : directory::files(source)) {
if(!file::copy({source, name}, {target, name})) result = false;
}
return result;
}
#if defined(PLATFORM_WINDOWS)
inline auto directory::create(const string& pathname, uint permissions) -> bool {
string path;
@@ -219,7 +236,6 @@ private:
}
FindClose(handle);
}
for(auto& name : list) name.append("/"); //must append after sorting
return list;
}
@@ -305,7 +321,6 @@ private:
}
closedir(dp);
}
for(auto& name : list) name.append("/"); //must append after sorting
return list;
}

View File

@@ -121,7 +121,7 @@ auto Response::body(const function<bool (const uint8_t*, uint)>& callback) const
} else if(hasData()) {
if(!callback(data().data(), data().size())) return false;
} else if(hasFile()) {
filemap map(file(), filemap::mode::read);
file_map map(file(), file_map::mode::read);
if(!callback(map.data(), map.size())) return false;
} else if(hasText()) {
if(!callback(text().data<uint8_t>(), text().size())) return false;

View File

@@ -86,6 +86,7 @@ struct image {
inline auto impose(blend mode, uint targetX, uint targetY, image source, uint x, uint y, uint width, uint height) -> void;
//utility.hpp
inline auto shrink(uint64_t transparentColor = 0) -> void;
inline auto crop(uint x, uint y, uint width, uint height) -> bool;
inline auto alphaBlend(uint64_t alphaColor) -> void;
inline auto alphaMultiply() -> void;

View File

@@ -5,7 +5,6 @@ namespace nall {
auto image::impose(blend mode, unsigned targetX, unsigned targetY, image source, unsigned sourceX, unsigned sourceY, unsigned sourceWidth, unsigned sourceHeight) -> void {
source.transform(_endian, _depth, _alpha.mask(), _red.mask(), _green.mask(), _blue.mask());
#pragma omp parallel for
for(unsigned y = 0; y < sourceHeight; y++) {
const uint8_t* sp = source._data + source.pitch() * (sourceY + y) + source.stride() * sourceX;
uint8_t* dp = _data + pitch() * (targetY + y) + stride() * targetX;

View File

@@ -27,7 +27,6 @@ auto image::scaleLinearWidth(unsigned outputWidth) -> void {
unsigned outputPitch = outputWidth * stride();
uint64_t xstride = ((uint64_t)(_width - 1) << 32) / max(1u, outputWidth - 1);
#pragma omp parallel for
for(unsigned y = 0; y < _height; y++) {
uint64_t xfraction = 0;
@@ -63,7 +62,6 @@ auto image::scaleLinearHeight(unsigned outputHeight) -> void {
uint8_t* outputData = allocate(_width, outputHeight, stride());
uint64_t ystride = ((uint64_t)(_height - 1) << 32) / max(1u, outputHeight - 1);
#pragma omp parallel for
for(unsigned x = 0; x < _width; x++) {
uint64_t yfraction = 0;
@@ -102,7 +100,6 @@ auto image::scaleLinear(unsigned outputWidth, unsigned outputHeight) -> void {
uint64_t xstride = ((uint64_t)(_width - 1) << 32) / max(1u, outputWidth - 1);
uint64_t ystride = ((uint64_t)(_height - 1) << 32) / max(1u, outputHeight - 1);
#pragma omp parallel for
for(unsigned y = 0; y < outputHeight; y++) {
uint64_t yfraction = ystride * y;
uint64_t xfraction = 0;
@@ -147,7 +144,6 @@ auto image::scaleNearest(unsigned outputWidth, unsigned outputHeight) -> void {
uint64_t xstride = ((uint64_t)_width << 32) / outputWidth;
uint64_t ystride = ((uint64_t)_height << 32) / outputHeight;
#pragma omp parallel for
for(unsigned y = 0; y < outputHeight; y++) {
uint64_t yfraction = ystride * y;
uint64_t xfraction = 0;

View File

@@ -2,6 +2,71 @@
namespace nall {
//scan all four sides of the image for fully transparent pixels, and then crop them
//imagine an icon centered on a transparent background: this function removes the bordering
//this certainly won't win any speed awards, but nall::image is meant to be correct and simple, not fast
auto image::shrink(uint64_t transparentColor) -> void {
//top
{ uint padding = 0;
for(uint y : range(_height)) {
const uint8_t* sp = _data + pitch() * y;
bool found = false;
for(uint x : range(_width)) {
if(read(sp) != transparentColor) { found = true; break; }
sp += stride();
}
if(found) break;
padding++;
}
crop(0, padding, _width, _height - padding);
}
//bottom
{ uint padding = 0;
for(uint y : reverse(range(_height))) {
const uint8_t* sp = _data + pitch() * y;
bool found = false;
for(uint x : range(_width)) {
if(read(sp) != transparentColor) { found = true; break; }
sp += stride();
}
if(found) break;
padding++;
}
crop(0, 0, _width, _height - padding);
}
//left
{ uint padding = 0;
for(uint x : range(_width)) {
const uint8_t* sp = _data + stride() * x;
bool found = false;
for(uint y : range(_height)) {
if(read(sp) != transparentColor) { found = true; break; }
sp += pitch();
}
if(found) break;
padding++;
}
crop(padding, 0, _width - padding, _height);
}
//right
{ uint padding = 0;
for(uint x : reverse(range(_width))) {
const uint8_t* sp = _data + stride() * x;
bool found = false;
for(uint y : range(_height)) {
if(read(sp) != transparentColor) { found = true; break; }
sp += pitch();
}
if(found) break;
padding++;
}
crop(0, 0, _width - padding, _height);
}
}
auto image::crop(unsigned outputX, unsigned outputY, unsigned outputWidth, unsigned outputHeight) -> bool {
if(outputX + outputWidth > _width) return false;
if(outputY + outputHeight > _height) return false;
@@ -9,7 +74,6 @@ auto image::crop(unsigned outputX, unsigned outputY, unsigned outputWidth, unsig
uint8_t* outputData = allocate(outputWidth, outputHeight, stride());
unsigned outputPitch = outputWidth * stride();
#pragma omp parallel for
for(unsigned y = 0; y < outputHeight; y++) {
const uint8_t* sp = _data + pitch() * (outputY + y) + stride() * outputX;
uint8_t* dp = outputData + outputPitch * y;
@@ -32,7 +96,6 @@ auto image::alphaBlend(uint64_t alphaColor) -> void {
uint64_t alphaG = (alphaColor & _green.mask()) >> _green.shift();
uint64_t alphaB = (alphaColor & _blue.mask() ) >> _blue.shift();
#pragma omp parallel for
for(unsigned y = 0; y < _height; y++) {
uint8_t* dp = _data + pitch() * y;
for(unsigned x = 0; x < _width; x++) {
@@ -58,7 +121,6 @@ auto image::alphaBlend(uint64_t alphaColor) -> void {
auto image::alphaMultiply() -> void {
unsigned divisor = (1 << _alpha.depth()) - 1;
#pragma omp parallel for
for(unsigned y = 0; y < _height; y++) {
uint8_t* dp = _data + pitch() * y;
for(unsigned x = 0; x < _width; x++) {
@@ -89,7 +151,6 @@ auto image::transform(bool outputEndian, unsigned outputDepth, uint64_t outputAl
image output(outputEndian, outputDepth, outputAlphaMask, outputRedMask, outputGreenMask, outputBlueMask);
output.allocate(_width, _height);
#pragma omp parallel for
for(unsigned y = 0; y < _height; y++) {
const uint8_t* sp = _data + pitch() * y;
uint8_t* dp = output._data + output.pitch() * y;

View File

@@ -31,6 +31,16 @@ struct inode {
return access(name, X_OK) == 0;
}
static auto hidden(const string& name) -> bool {
#if defined(PLATFORM_WINDOWS)
auto attributes = GetFileAttributes(utf16_t(name));
return attributes & FILE_ATTRIBUTE_HIDDEN;
#else
//todo: is this really the best way to do this? stat doesn't have S_ISHIDDEN ...
return name.split("/").last().beginsWith(".");
#endif
}
static auto mode(const string& name) -> uint {
struct stat data{};
stat(name, &data);

39
nall/instance.hpp Normal file
View File

@@ -0,0 +1,39 @@
#pragma once
namespace nall {
template<typename T>
struct Instance {
~Instance() {
destruct();
}
auto operator()() -> T& {
return instance.object;
}
template<typename... P>
auto construct(P&&... p) {
if(constructed) return;
constructed = true;
new((void*)(&instance.object)) T(forward<P>(p)...);
}
auto destruct() -> void {
if(!constructed) return;
constructed = false;
instance.object.~T();
}
private:
bool constructed = false;
union Union {
Union() {}
~Union() {}
T object;
char storage[sizeof(T)];
} instance;
};
}

View File

@@ -3,47 +3,51 @@
namespace nall {
template<typename T> struct iterator {
iterator(T* self, uint64_t offset) : self(self), offset(offset) {}
auto operator*() -> T& { return self[offset]; }
auto operator!=(const iterator& source) const -> bool { return offset != source.offset; }
auto operator++() -> iterator& { return offset++, *this; }
iterator(T* self, uint64_t offset) : _self(self), _offset(offset) {}
auto operator*() -> T& { return _self[_offset]; }
auto operator!=(const iterator& source) const -> bool { return _offset != source._offset; }
auto operator++() -> iterator& { return _offset++, *this; }
auto offset() const -> uint64_t { return _offset; }
private:
T* self;
uint64_t offset;
T* _self;
uint64_t _offset;
};
template<typename T> struct iterator_const {
iterator_const(const T* self, uint64_t offset) : self(self), offset(offset) {}
auto operator*() -> const T& { return self[offset]; }
auto operator!=(const iterator_const& source) const -> bool { return offset != source.offset; }
auto operator++() -> iterator_const& { return offset++, *this; }
iterator_const(const T* self, uint64_t offset) : _self(self), _offset(offset) {}
auto operator*() -> const T& { return _self[_offset]; }
auto operator!=(const iterator_const& source) const -> bool { return _offset != source._offset; }
auto operator++() -> iterator_const& { return _offset++, *this; }
auto offset() const -> uint64_t { return _offset; }
private:
const T* self;
uint64_t offset;
const T* _self;
uint64_t _offset;
};
template<typename T> struct reverse_iterator {
reverse_iterator(T* self, uint64_t offset) : self(self), offset(offset) {}
auto operator*() -> T& { return self[offset]; }
auto operator!=(const reverse_iterator& source) const -> bool { return offset != source.offset; }
auto operator++() -> reverse_iterator& { return offset--, *this; }
reverse_iterator(T* self, uint64_t offset) : _self(self), _offset(offset) {}
auto operator*() -> T& { return _self[_offset]; }
auto operator!=(const reverse_iterator& source) const -> bool { return _offset != source._offset; }
auto operator++() -> reverse_iterator& { return _offset--, *this; }
auto offset() const -> uint64_t { return _offset; }
private:
T* self;
uint64_t offset;
T* _self;
uint64_t _offset;
};
template<typename T> struct reverse_iterator_const {
reverse_iterator_const(const T* self, uint64_t offset) : self(self), offset(offset) {}
auto operator*() -> const T& { return self[offset]; }
auto operator!=(const reverse_iterator_const& source) const -> bool { return offset != source.offset; }
auto operator++() -> reverse_iterator_const& { return offset--, *this; }
reverse_iterator_const(const T* self, uint64_t offset) : _self(self), _offset(offset) {}
auto operator*() -> const T& { return _self[_offset]; }
auto operator!=(const reverse_iterator_const& source) const -> bool { return _offset != source._offset; }
auto operator++() -> reverse_iterator_const& { return _offset--, *this; }
auto offset() const -> uint64_t { return _offset; }
private:
const T* self;
uint64_t offset;
const T* _self;
uint64_t _offset;
};
//std::rbegin(), std::rend() is missing from GCC 4.9; which I still target
@@ -55,13 +59,13 @@ template<typename T> auto rbegin(T& self) { return self.rbegin(); }
template<typename T> auto rend(T& self) { return self.rend(); }
template<typename T> struct reverse_wrapper {
T self;
auto begin() { return rbegin(_self); }
auto end() { return rend(_self); }
auto begin() { return rbegin(self); }
auto end() { return rend(self); }
auto begin() const { return rbegin(_self); }
auto end() const { return rend(_self); }
auto begin() const { return rbegin(self); }
auto end() const { return rend(self); }
T _self;
};
template<typename T> auto reverse(T& object) -> reverse_wrapper<T&> {

View File

@@ -12,11 +12,28 @@ namespace nall {
CoInitialize(0);
WSAData wsaData{0};
WSAStartup(MAKEWORD(2, 2), &wsaData);
_setmode(_fileno(stdin), O_BINARY);
_setmode(_fileno(stdin ), O_BINARY);
_setmode(_fileno(stdout), O_BINARY);
_setmode(_fileno(stderr), O_BINARY);
#endif
return main(move(Arguments{argc, argv})), EXIT_SUCCESS;
main(move(Arguments{argc, argv}));
//when a program is running, input on the terminal queues in stdin
//when terminating the program, the shell proceeds to try and execute all stdin data
//this is annoying behavior: this code tries to minimize the impact as much as it can
//we can flush all of stdin up to the last line feed, preventing spurious commands from executing
//however, even with setvbuf(_IONBF), we can't stop the last line from echoing to the terminal
#if !defined(PLATFORM_WINDOWS)
auto flags = fcntl(fileno(stdin), F_GETFL, 0);
fcntl(fileno(stdin), F_SETFL, flags | O_NONBLOCK); //don't allow read() to block when empty
char buffer[4096], data = false;
while(read(fileno(stdin), buffer, sizeof(buffer)) > 0) data = true;
fcntl(fileno(stdin), F_SETFL, flags); //restore original flags for the terminal
if(data) putchar('\r'); //ensures PS1 is printed at the start of the line
#endif
return EXIT_SUCCESS;
}
}

View File

@@ -36,6 +36,7 @@
#include <nall/hid.hpp>
#include <nall/image.hpp>
#include <nall/inode.hpp>
#include <nall/instance.hpp>
#include <nall/interpolation.hpp>
#include <nall/intrinsics.hpp>
#include <nall/iterator.hpp>
@@ -50,7 +51,6 @@
#include <nall/path.hpp>
#include <nall/pointer.hpp>
#include <nall/primitives.hpp>
#include <nall/property.hpp>
#include <nall/queue.hpp>
#include <nall/random.hpp>
#include <nall/range.hpp>
@@ -66,6 +66,7 @@
#include <nall/traits.hpp>
#include <nall/unique-pointer.hpp>
#include <nall/utility.hpp>
#include <nall/variant.hpp>
#include <nall/varint.hpp>
#include <nall/vector.hpp>
#include <nall/view.hpp>

View File

@@ -75,10 +75,13 @@ inline auto desktop(string_view name = {}) -> string {
return {user(), "Desktop/", name};
}
// /home/username/.local/share/
//todo: MacOS uses the same location for userData() and userSettings()
//... is there a better option here?
// /home/username/.config/
// ~/Library/Application Support/
// c:/users/username/appdata/roaming/
inline auto userData() -> string {
inline auto userSettings() -> string {
#if defined(PLATFORM_WINDOWS)
wchar_t path[PATH_MAX] = L"";
SHGetFolderPathW(nullptr, CSIDL_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path);
@@ -87,6 +90,25 @@ inline auto userData() -> string {
#elif defined(PLATFORM_MACOS)
string result = {Path::user(), "Library/Application Support/"};
#else
string result = {Path::user(), ".config/"};
#endif
if(!result) result = ".";
if(!result.endsWith("/")) result.append("/");
return result;
}
// /home/username/.local/share/
// ~/Library/Application Support/
// c:/users/username/appdata/local/
inline auto userData() -> string {
#if defined(PLATFORM_WINDOWS)
wchar_t path[PATH_MAX] = L"";
SHGetFolderPathW(nullptr, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path);
string result = (const char*)utf8_t(path);
result.transform("\\", "/");
#elif defined(PLATFORM_MACOS)
string result = {Path::user(), "Library/Application Support/"};
#else
string result = {Path::user(), ".local/share/"};
#endif
if(!result) result = ".";

View File

@@ -120,4 +120,5 @@ namespace Math {
#define unreachable throw
#endif
#define export $export
#define register $register

View File

@@ -1,5 +1,6 @@
#pragma once
#include <nall/atoi.hpp>
#include <nall/serializer.hpp>
#include <nall/traits.hpp>

View File

@@ -8,6 +8,7 @@ struct Boolean {
inline Boolean() : data(false) {}
template<typename T> inline Boolean(const T& value) : data(value) {}
explicit inline Boolean(const char* value) { data = !strcmp(value, "true"); }
inline operator bool() const { return data; }
template<typename T> inline auto& operator=(const T& value) { data = value; return *this; }

View File

@@ -18,6 +18,7 @@ template<uint Precision> struct Integer {
inline Integer() : data(0) {}
template<uint Bits> inline Integer(Integer<Bits> value) { data = mask(value); }
template<typename T> inline Integer(const T& value) { data = mask(value); }
explicit inline Integer(const char* value) { data = mask(toInteger(value)); }
inline operator stype() const { return data; }
@@ -43,7 +44,7 @@ template<uint Precision> struct Integer {
inline auto bit(int index) -> BitRange<Precision> { return {(utype&)data, index, index}; }
inline auto byte(int index) -> BitRange<Precision> { return {(utype&)data, index * 8 + 0, index * 8 + 7}; }
inline auto bits(int lo, int hi) const -> const BitRange<Precision> { return {(utype&)*this, lo, lo}; }
inline auto bits(int lo, int hi) const -> const BitRange<Precision> { return {(utype&)*this, lo, hi}; }
inline auto bit(int index) const -> const BitRange<Precision> { return {(utype&)*this, index, index}; }
inline auto byte(int index) const -> const BitRange<Precision> { return {(utype&)*this, index * 8 + 0, index * 8 + 7}; }

View File

@@ -16,6 +16,7 @@ template<uint Precision> struct Natural {
inline Natural() : data(0) {}
template<uint Bits> inline Natural(Natural<Bits> value) { data = mask(value); }
template<typename T> inline Natural(const T& value) { data = mask(value); }
explicit inline Natural(const char* value) { data = mask(toNatural(value)); }
inline operator utype() const { return data; }

View File

@@ -13,6 +13,7 @@ template<uint Precision> struct Real {
inline Real() : data(0.0) {}
template<int Bits> inline Real(Real<Bits> value) : data((ftype)value) {}
template<typename T> inline Real(const T& value) : data((ftype)value) {}
explicit inline Real(const char* value) : data((ftype)toReal(value)) {}
inline operator ftype() const { return data; }

View File

@@ -1,67 +0,0 @@
#pragma once
namespace nall {
template<typename T> struct property {
property() = default;
property(const T& value) : value(value) {}
operator T&() { return value; } //direct assignment
auto operator->() -> T* { return &value; } //class-member access
operator const T&() const { return value; }
auto operator()() const -> const T& { return value; }
auto get() const -> const T& { return value; }
auto operator=(const T& value) -> T& { return this->value = value; }
auto set(const T& value) -> T& { return this->value = value; }
T value;
};
template<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;
};
}

View File

@@ -35,6 +35,7 @@ template<typename T> struct set {
~set() { reset(); }
auto operator=(const set& source) -> set& {
if(this == &source) return *this;
reset();
copy(root, source.root);
nodes = source.nodes;
@@ -42,6 +43,7 @@ template<typename T> struct set {
}
auto operator=(set&& source) -> set& {
if(this == &source) return *this;
root = source.root;
nodes = source.nodes;
source.root = nullptr;

View File

@@ -21,9 +21,15 @@ struct shared_pointer_manager {
template<typename T> struct shared_pointer;
template<typename T> struct shared_pointer_weak;
template<typename T> struct shared_pointer_this;
struct shared_pointer_this_base{};
template<typename T>
struct shared_pointer {
template<typename... P> static auto create(P&&... p) {
return shared_pointer<T>{new T{forward<P>(p)...}};
}
using type = T;
shared_pointer_manager* manager = nullptr;
@@ -86,6 +92,9 @@ struct shared_pointer {
if(source) {
manager = new shared_pointer_manager((void*)source);
manager->strong++;
if constexpr(is_base_of_v<shared_pointer_this_base, T>) {
source->weak = *this;
}
}
return *this;
}
@@ -257,11 +266,22 @@ struct shared_pointer_weak {
}
};
template<typename T>
struct shared_pointer_this : shared_pointer_this_base {
shared_pointer_weak<T> weak;
auto shared() -> shared_pointer<T> { return weak; }
auto shared() const -> shared_pointer<T const> { return weak; }
};
template<typename T, typename... P>
auto shared_pointer_make(P&&... p) -> shared_pointer<T> {
return shared_pointer<T>{new T{forward<P>(p)...}};
}
template<typename T>
struct shared_pointer_new : shared_pointer<T> {
template<typename... P>
shared_pointer_new(P&&... p) : shared_pointer<T>(new T(forward<P>(p)...)) {
}
shared_pointer_new(const shared_pointer<T>& source) : shared_pointer<T>(source) {}
template<typename... P> shared_pointer_new(P&&... p) : shared_pointer<T>(new T(forward<P>(p)...)) {}
};
}

View File

@@ -18,6 +18,7 @@
#include <nall/primitives.hpp>
#include <nall/shared-pointer.hpp>
#include <nall/stdint.hpp>
#include <nall/unique-pointer.hpp>
#include <nall/utility.hpp>
#include <nall/varint.hpp>
#include <nall/vector.hpp>
@@ -133,6 +134,9 @@ protected:
public:
inline string();
inline string(string& source) : string() { operator=(source); }
inline string(const string& source) : string() { operator=(source); }
inline string(string&& source) : string() { operator=(move(source)); }
template<typename T = char> inline auto get() -> T*;
template<typename T = char> inline auto data() const -> const T*;
template<typename T = char> auto size() const -> uint { return _size / sizeof(T); }
@@ -172,15 +176,13 @@ public:
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 boolean() const -> bool;
inline auto integer() const -> intmax;
inline auto natural() const -> uintmax;
inline auto hex() const -> uintmax;
@@ -193,11 +195,11 @@ public:
template<typename T, typename... P> inline auto prepend(const T&, P&&...) -> type&;
template<typename... P> inline auto prepend(const nall::string_format&, P&&...) -> type&;
inline auto prepend() -> type&;
template<typename T> inline auto _prepend(const stringify<T>&) -> string&;
template<typename T> inline auto _prepend(const stringify<T>&) -> type&;
template<typename T, typename... P> inline auto append(const T&, P&&...) -> type&;
template<typename... P> inline auto append(const nall::string_format&, P&&...) -> type&;
inline auto append() -> type&;
template<typename T> inline auto _append(const stringify<T>&) -> string&;
template<typename T> inline auto _append(const stringify<T>&) -> type&;
inline auto length() const -> uint;
//find.hpp

View File

@@ -2,6 +2,10 @@
namespace nall {
auto string::boolean() const -> bool {
return equals("true");
}
auto string::integer() const -> intmax {
return toInteger(data());
}

View File

@@ -5,7 +5,7 @@ namespace nall::Markup {
auto ManagedNode::_evaluate(string query) const -> bool {
if(!query) return true;
for(auto& rule : query.replace(" ", "").split(",")) {
for(auto& rule : query.split(",")) {
enum class Comparator : uint { ID, EQ, NE, LT, LE, GT, GE };
auto comparator = Comparator::ID;
if(rule.match("*!=*")) comparator = Comparator::NE;

View File

@@ -46,31 +46,39 @@ protected:
struct Node {
Node() : shared(new ManagedNode) {}
Node(const SharedNode& source) : shared(source ? source : new ManagedNode) {}
Node(const string& name) : shared(new ManagedNode(name)) {}
Node(const string& name, const string& value) : shared(new ManagedNode(name, value)) {}
Node(const nall::string& name) : shared(new ManagedNode(name)) {}
Node(const nall::string& name, const nall::string& value) : shared(new ManagedNode(name, value)) {}
auto unique() const -> bool { return shared.unique(); }
auto clone() const -> Node { return shared->clone(); }
auto copy(Node source) -> void { return shared->copy(source.shared); }
explicit operator bool() const { return shared->_name || shared->_children; }
auto name() const -> string { return shared->_name; }
auto value() const -> string { return shared->_value; }
auto name() const -> nall::string { return shared->_name; }
auto value() const -> nall::string { return shared->_value; }
auto text() const -> string { return value().strip(); }
auto value(nall::string& target) const -> bool { if(shared) target = string(); return (bool)shared; }
auto value(bool& target) const -> bool { if(shared) target = boolean(); return (bool)shared; }
auto value(int& target) const -> bool { if(shared) target = integer(); return (bool)shared; }
auto value(uint& target) const -> bool { if(shared) target = natural(); return (bool)shared; }
auto value(double& target) const -> bool { if(shared) target = real(); return (bool)shared; }
auto text() const -> nall::string { return value().strip(); }
auto string() const -> nall::string { return value().strip(); }
auto boolean() const -> bool { return text() == "true"; }
auto integer() const -> intmax { return text().integer(); }
auto natural() const -> uintmax { return text().natural(); }
auto real() const -> double { return text().real(); }
auto text(const string& fallback) const -> string { return bool(*this) ? text() : fallback; }
auto text(const nall::string& fallback) const -> nall::string { return bool(*this) ? text() : fallback; }
auto string(const nall::string& fallback) const -> nall::string { return bool(*this) ? string() : fallback; }
auto boolean(bool fallback) const -> bool { return bool(*this) ? boolean() : fallback; }
auto integer(intmax fallback) const -> intmax { return bool(*this) ? integer() : fallback; }
auto natural(uintmax fallback) const -> uintmax { return bool(*this) ? natural() : fallback; }
auto real(double fallback) const -> double { return bool(*this) ? real() : fallback; }
auto setName(const string& name = "") -> Node& { shared->_name = name; return *this; }
auto setValue(const string& value = "") -> Node& { shared->_value = value; return *this; }
auto setName(const nall::string& name = "") -> Node& { shared->_name = name; return *this; }
auto setValue(const nall::string& value = "") -> Node& { shared->_value = value; return *this; }
auto reset() -> void { shared->_children.reset(); }
auto size() const -> uint { return shared->_children.size(); }
@@ -102,7 +110,7 @@ struct Node {
}
auto sort(function<bool (Node, Node)> comparator = [](auto x, auto y) {
return string::compare(x.shared->_name, y.shared->_name) < 0;
return nall::string::compare(x.shared->_name, y.shared->_name) < 0;
}) -> void {
nall::sort(shared->_children.data(), shared->_children.size(), [&](auto x, auto y) {
return comparator(x, y); //this call converts SharedNode objects to Node objects
@@ -114,9 +122,9 @@ struct Node {
return shared->_children[position];
}
auto operator[](const string& path) const -> Node { return shared->_lookup(path); }
auto operator()(const string& path) -> Node { return shared->_create(path); }
auto find(const string& query) const -> vector<Node> { return shared->_find(query); }
auto operator[](const nall::string& path) const -> Node { return shared->_lookup(path); }
auto operator()(const nall::string& path) -> Node { return shared->_create(path); }
auto find(const nall::string& query) const -> vector<Node> { return shared->_find(query); }
struct iterator {
auto operator*() -> Node { return {source.shared->_children[position]}; }

View File

@@ -213,8 +213,8 @@ inline auto DML::markup(const string& s) -> string {
boolean deletion;
boolean code;
uint link, linkBase;
uint embed, embedBase;
natural link, linkBase;
natural embed, embedBase;
for(uint n = 0; n < s.size();) {
char a = s[n];

View File

@@ -21,6 +21,7 @@ namespace nall {
using std::initializer_list;
using std::is_array;
using std::is_base_of;
using std::is_base_of_v;
using std::is_function;
using std::is_integral;
using std::is_integral_v;

View File

@@ -4,9 +4,13 @@ namespace nall {
template<typename T>
struct unique_pointer {
template<typename... P> static auto create(P&&... p) {
return unique_pointer<T>{new T{forward<P>(p)...}};
}
using type = T;
T* pointer = nullptr;
function<auto (T*) -> void> deleter;
function<void (T*)> deleter;
unique_pointer(const unique_pointer&) = delete;
auto operator=(const unique_pointer&) -> unique_pointer& = delete;

148
nall/variant.hpp Normal file
View File

@@ -0,0 +1,148 @@
#pragma once
namespace nall {
template<typename T, typename... P> struct variant_size {
static constexpr uint size = max(sizeof(T), variant_size<P...>::size);
};
template<typename T> struct variant_size<T> {
static constexpr uint size = sizeof(T);
};
template<uint Index, typename F, typename T, typename... P> struct variant_index {
static constexpr uint index = is_same_v<F, T> ? Index : variant_index<Index + 1, F, P...>::index;
};
template<uint Index, typename F, typename T> struct variant_index<Index, F, T> {
static constexpr uint index = is_same_v<F, T> ? Index : 0;
};
template<typename T, typename... P> struct variant_copy {
constexpr variant_copy(uint index, uint assigned, void* target, void* source) {
if(index == assigned) new(target) T(*((T*)source));
else variant_copy<P...>(index + 1, assigned, target, source);
}
};
template<typename T> struct variant_copy<T> {
constexpr variant_copy(uint index, uint assigned, void* target, void* source) {
if(index == assigned) new(target) T(*((T*)source));
}
};
template<typename T, typename... P> struct variant_move {
constexpr variant_move(uint index, uint assigned, void* target, void* source) {
if(index == assigned) new(target) T(move(*((T*)source)));
else variant_move<P...>(index + 1, assigned, target, source);
}
};
template<typename T> struct variant_move<T> {
constexpr variant_move(uint index, uint assigned, void* target, void* source) {
if(index == assigned) new(target) T(move(*((T*)source)));
}
};
template<typename T, typename... P> struct variant_destruct {
constexpr variant_destruct(uint index, uint assigned, void* data) {
if(index == assigned) ((T*)data)->~T();
else variant_destruct<P...>(index + 1, assigned, data);
}
};
template<typename T> struct variant_destruct<T> {
constexpr variant_destruct(uint index, uint assigned, void* data) {
if(index == assigned) ((T*)data)->~T();
}
};
template<typename F, typename T, typename... P> struct variant_equals {
constexpr auto operator()(uint index, uint assigned) const -> bool {
if(index == assigned) return is_same_v<F, T>;
return variant_equals<F, P...>()(index + 1, assigned);
}
};
template<typename F, typename T> struct variant_equals<F, T> {
constexpr auto operator()(uint index, uint assigned) const -> bool {
if(index == assigned) return is_same_v<F, T>;
return false;
}
};
template<typename... P> struct variant final { //final as destructor is not virtual
variant() : assigned(0) {}
variant(const variant& source) { operator=(source); }
variant(variant&& source) { operator=(move(source)); }
template<typename T> variant(const T& value) { operator=(value); }
template<typename T> variant(T&& value) { operator=(move(value)); }
~variant() { reset(); }
explicit operator bool() const { return assigned; }
template<typename T> explicit constexpr operator T&() { return get<T>(); }
template<typename T> explicit constexpr operator const T&() const { return get<T>(); }
template<typename T> constexpr auto is() const -> bool {
return variant_equals<T, P...>()(1, assigned);
}
template<typename T> constexpr auto get() -> T& {
static_assert(variant_index<1, T, P...>::index, "type not in variant");
struct variant_bad_cast{};
if(!is<T>()) throw variant_bad_cast{};
return *((T*)data);
}
template<typename T> constexpr auto get() const -> const T& {
static_assert(variant_index<1, T, P...>::index, "type not in variant");
struct variant_bad_cast{};
if(!is<T>()) throw variant_bad_cast{};
return *((const T*)data);
}
template<typename T> constexpr auto get(const T& fallback) const -> const T& {
if(!is<T>()) return fallback;
return *((const T*)data);
}
auto reset() -> void {
if(assigned) variant_destruct<P...>(1, assigned, (void*)data);
assigned = 0;
}
auto& operator=(const variant& source) {
reset();
if(assigned = source.assigned) variant_copy<P...>(1, source.assigned, (void*)data, (void*)source.data);
return *this;
}
auto& operator=(variant&& source) {
reset();
if(assigned = source.assigned) variant_move<P...>(1, source.assigned, (void*)data, (void*)source.data);
source.assigned = 0;
return *this;
}
template<typename T> auto& operator=(const T& value) {
static_assert(variant_index<1, T, P...>::index, "type not in variant");
reset();
new((void*)&data) T(value);
assigned = variant_index<1, T, P...>::index;
return *this;
}
template<typename T> auto& operator=(T&& value) {
static_assert(variant_index<1, T, P...>::index, "type not in variant");
reset();
new((void*)&data) T(move(value));
assigned = variant_index<1, T, P...>::index;
return *this;
}
private:
alignas(P...) char data[variant_size<P...>::size];
uint assigned;
};
}

View File

@@ -16,11 +16,6 @@
namespace nall {
template<typename T> struct vector_iterator;
template<typename T> struct vector_iterator_const;
template<typename T> struct vector_reverse_iterator;
template<typename T> struct vector_reverse_iterator_const;
template<typename T>
struct vector_base {
using type = vector_base;
@@ -100,6 +95,19 @@ struct vector_base {
auto removeRight(uint64_t length = 1) -> void;
auto removeLast(uint64_t length = 1) -> void { return removeRight(length); }
auto remove(uint64_t offset, uint64_t length = 1) -> void;
struct RemoveWhere {
RemoveWhere(type& source) : self(source) {}
auto operator==(const T& value) -> type&;
auto operator!=(const T& value) -> type&;
auto operator< (const T& value) -> type&;
auto operator<=(const T& value) -> type&;
auto operator> (const T& value) -> type&;
auto operator>=(const T& value) -> type&;
private:
type& self;
template<typename Compare> auto remove(const T& value) -> type&;
};
auto removeWhere() -> RemoveWhere { return RemoveWhere{*this}; }
auto takeLeft() -> T;
auto takeFirst() -> T { return move(takeLeft()); }
@@ -127,6 +135,32 @@ struct vector_base {
auto find(const function<bool (const T& lhs)>& comparator) -> maybe<uint64_t>;
auto find(const T& value) const -> maybe<uint64_t>;
auto findSorted(const T& value) const -> maybe<uint64_t>;
struct FindWhere {
FindWhere(type& source) : self(source) {}
auto operator==(const T& value) -> vector_base<iterator<T>>;
auto operator!=(const T& value) -> vector_base<iterator<T>>;
auto operator< (const T& value) -> vector_base<iterator<T>>;
auto operator<=(const T& value) -> vector_base<iterator<T>>;
auto operator> (const T& value) -> vector_base<iterator<T>>;
auto operator>=(const T& value) -> vector_base<iterator<T>>;
private:
type& self;
template<typename Compare> auto find(const T& value) -> vector_base<iterator<T>>;
};
auto findWhere() { return FindWhere{*this}; }
struct FindWhereConst {
FindWhereConst(const type& source) : self(source) {}
auto operator==(const T& value) const -> vector_base<iterator_const<T>>;
auto operator!=(const T& value) const -> vector_base<iterator_const<T>>;
auto operator< (const T& value) const -> vector_base<iterator_const<T>>;
auto operator<=(const T& value) const -> vector_base<iterator_const<T>>;
auto operator> (const T& value) const -> vector_base<iterator_const<T>>;
auto operator>=(const T& value) const -> vector_base<iterator_const<T>>;
private:
const type& self;
template<typename Compare> auto find(const T& value) const -> vector_base<iterator_const<T>>;
};
auto findWhere() const { return FindWhereConst{*this}; }
auto foreach(const function<void (const T&)>& callback) -> void;
auto foreach(const function<void (uint, const T&)>& callback) -> void;
@@ -137,6 +171,10 @@ protected:
uint64_t _right = 0; //number of allocated elements free on the right of pool
};
template<typename T> auto removeWhere(vector_base<T>& source) { return source.removeWhere(); }
template<typename T> auto findWhere(vector_base<T>& source) { return source.findWhere(); }
template<typename T> auto findWhere(const vector_base<T>& source) { return source.findWhere(); }
}
#define vector vector_base

View File

@@ -6,6 +6,7 @@ template<typename T>
struct vector_iterator {
vector_iterator(vector<T>& self, uint64_t offset) : self(self), offset(offset) {}
auto operator*() -> T& { return self.operator[](offset); }
auto operator->() -> T* { return self.operator[](offset); }
auto operator!=(const vector_iterator& source) const -> bool { return offset != source.offset; }
auto operator++() -> vector_iterator& { return offset++, *this; }
@@ -18,6 +19,7 @@ template<typename T>
struct vector_iterator_const {
vector_iterator_const(const vector<T>& self, uint64_t offset) : self(self), offset(offset) {}
auto operator*() -> const T& { return self.operator[](offset); }
auto operator->() -> T* { return self.operator[](offset); }
auto operator!=(const vector_iterator_const& source) const -> bool { return offset != source.offset; }
auto operator++() -> vector_iterator_const& { return offset++, *this; }
@@ -30,6 +32,7 @@ template<typename T>
struct vector_reverse_iterator {
vector_reverse_iterator(vector<T>& self, uint64_t offset) : self(self), offset(offset) {}
auto operator*() -> T& { return self.operator[](offset); }
auto operator->() -> T* { return self.operator[](offset); }
auto operator!=(const vector_reverse_iterator& source) const -> bool { return offset != source.offset; }
auto operator++() -> vector_reverse_iterator& { return offset--, *this; }
@@ -42,6 +45,7 @@ template<typename T>
struct vector_reverse_iterator_const {
vector_reverse_iterator_const(const vector<T>& self, uint64_t offset) : self(self), offset(offset) {}
auto operator*() -> const T& { return self.operator[](offset); }
auto operator->() -> T* { return self.operator[](offset); }
auto operator!=(const vector_reverse_iterator_const& source) const -> bool { return offset != source.offset; }
auto operator++() -> vector_reverse_iterator_const& { return offset--, *this; }

View File

@@ -101,6 +101,25 @@ template<typename T> auto vector<T>::remove(uint64_t offset, uint64_t length) ->
_size -= length;
}
template<typename T> auto vector<T>::RemoveWhere::operator==(const T& value) -> type& { return remove<std::equal_to<T>>(value); }
template<typename T> auto vector<T>::RemoveWhere::operator!=(const T& value) -> type& { return remove<std::not_equal_to<T>>(value); }
template<typename T> auto vector<T>::RemoveWhere::operator< (const T& value) -> type& { return remove<std::less<T>>(value); }
template<typename T> auto vector<T>::RemoveWhere::operator<=(const T& value) -> type& { return remove<std::less_equal<T>>(value); }
template<typename T> auto vector<T>::RemoveWhere::operator> (const T& value) -> type& { return remove<std::greater<T>>(value); }
template<typename T> auto vector<T>::RemoveWhere::operator>=(const T& value) -> type& { return remove<std::greater_equal<T>>(value); }
template<typename T> template<typename Compare> auto vector<T>::RemoveWhere::remove(const T& value) -> type& {
auto source = self.begin();
auto target = self.begin();
while(source != self.end()) {
if(source != target) *target = move(*source);
if(!Compare()(*target, value)) ++target;
++source;
}
self.resize(target.offset());
return self;
}
//
template<typename T> auto vector<T>::takeLeft() -> T {

View File

@@ -36,6 +36,36 @@ template<typename T> auto vector<T>::findSorted(const T& value) const -> maybe<u
return nothing;
}
template<typename T> auto vector<T>::FindWhere::operator==(const T& value) -> vector<iterator<T>> { return move(find<std::equal_to<T>>(value)); }
template<typename T> auto vector<T>::FindWhere::operator!=(const T& value) -> vector<iterator<T>> { return move(find<std::not_equal_to<T>>(value)); }
template<typename T> auto vector<T>::FindWhere::operator< (const T& value) -> vector<iterator<T>> { return move(find<std::less<T>>(value)); }
template<typename T> auto vector<T>::FindWhere::operator<=(const T& value) -> vector<iterator<T>> { return move(find<std::less_equal<T>>(value)); }
template<typename T> auto vector<T>::FindWhere::operator> (const T& value) -> vector<iterator<T>> { return move(find<std::greater<T>>(value)); }
template<typename T> auto vector<T>::FindWhere::operator>=(const T& value) -> vector<iterator<T>> { return move(find<std::greater_equal<T>>(value)); }
template<typename T> template<typename Compare> auto vector<T>::FindWhere::find(const T& value) -> vector<iterator<T>> {
vector<iterator<T>> found;
for(auto iterator = self.begin(); iterator != self.end(); ++iterator) {
if(Compare()(*iterator, value)) found.append(iterator);
}
return move(found);
}
template<typename T> auto vector<T>::FindWhereConst::operator==(const T& value) const -> vector<iterator_const<T>> { return move(find<std::equal_to<T>>(value)); }
template<typename T> auto vector<T>::FindWhereConst::operator!=(const T& value) const -> vector<iterator_const<T>> { return move(find<std::not_equal_to<T>>(value)); }
template<typename T> auto vector<T>::FindWhereConst::operator< (const T& value) const -> vector<iterator_const<T>> { return move(find<std::less<T>>(value)); }
template<typename T> auto vector<T>::FindWhereConst::operator<=(const T& value) const -> vector<iterator_const<T>> { return move(find<std::less_equal<T>>(value)); }
template<typename T> auto vector<T>::FindWhereConst::operator> (const T& value) const -> vector<iterator_const<T>> { return move(find<std::greater<T>>(value)); }
template<typename T> auto vector<T>::FindWhereConst::operator>=(const T& value) const -> vector<iterator_const<T>> { return move(find<std::greater_equal<T>>(value)); }
template<typename T> template<typename Compare> auto vector<T>::FindWhereConst::find(const T& value) const -> vector<iterator_const<T>> {
vector<iterator_const<T>> found;
for(auto iterator = self.begin(); iterator != self.end(); ++iterator) {
if(Compare()(*iterator, value)) found.append(iterator);
}
return move(found);
}
template<typename T> auto vector<T>::foreach(const function<void (const T&)>& callback) -> void {
for(uint64_t n : range(size())) callback(_pool[n]);
}

View File

@@ -1,5 +1,8 @@
#pragma once
#include <nall/file.hpp>
#include <nall/decode/zip.hpp>
namespace nall::vfs::memory {
struct file : vfs::file {
@@ -11,6 +14,22 @@ struct file : vfs::file {
return instance;
}
static auto open(string location, bool decompress = false) -> shared_pointer<file> {
auto instance = shared_pointer<file>{new file};
if(decompress && location.iendsWith(".zip")) {
Decode::ZIP archive;
if(archive.open(location) && archive.file.size() == 1) {
auto memory = archive.extract(archive.file.first());
instance->_open(memory.data(), memory.size());
return instance;
}
}
auto memory = nall::file::read(location);
instance->_open(memory.data(), memory.size());
return instance;
}
auto data() const -> const uint8_t* { return _data; }
auto size() const -> uintmax override { return _size; }
auto offset() const -> uintmax override { return _offset; }

View File

@@ -6,6 +6,8 @@
#define Display XlibDisplay
#define Screen XlibScreen
#define Window XlibWindow
#define Above XlibAbove
#define Below XlibBelow
#else
#undef NALL_XORG_GUARD_HPP
@@ -15,6 +17,8 @@
#undef Display
#undef Screen
#undef Window
#undef Above
#undef Below
#ifndef NALL_XORG_GUARD_CONSTANTS
#define NALL_XORG_GUARD_CONSTANTS