mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-01 03:42:03 +02:00
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:
@@ -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
|
||||
|
@@ -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)...);
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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
39
nall/instance.hpp
Normal 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;
|
||||
};
|
||||
|
||||
}
|
@@ -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&> {
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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>
|
||||
|
@@ -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 = ".";
|
||||
|
@@ -120,4 +120,5 @@ namespace Math {
|
||||
#define unreachable throw
|
||||
#endif
|
||||
|
||||
#define export $export
|
||||
#define register $register
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <nall/atoi.hpp>
|
||||
#include <nall/serializer.hpp>
|
||||
#include <nall/traits.hpp>
|
||||
|
||||
|
@@ -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; }
|
||||
|
@@ -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}; }
|
||||
|
||||
|
@@ -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; }
|
||||
|
||||
|
@@ -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; }
|
||||
|
||||
|
@@ -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;
|
||||
};
|
||||
|
||||
}
|
@@ -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;
|
||||
|
@@ -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)...)) {}
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -2,6 +2,10 @@
|
||||
|
||||
namespace nall {
|
||||
|
||||
auto string::boolean() const -> bool {
|
||||
return equals("true");
|
||||
}
|
||||
|
||||
auto string::integer() const -> intmax {
|
||||
return toInteger(data());
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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]}; }
|
||||
|
@@ -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];
|
||||
|
@@ -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;
|
||||
|
@@ -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
148
nall/variant.hpp
Normal 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;
|
||||
};
|
||||
|
||||
}
|
@@ -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
|
||||
|
@@ -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; }
|
||||
|
||||
|
@@ -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 {
|
||||
|
@@ -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]);
|
||||
}
|
||||
|
@@ -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; }
|
||||
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user