Update to v092r10 release.

byuu says:

Changelog:
- you can now drop game folders (not game files, sorry) onto higan's
  main window to load them
- audio buffer will clear on Windows when entering modal loop (entering
  menu, moving or resizing window)
  - this prevents DirectSound driver's audio repetition
- ruby defaults to the optimal driver for each platform, rather than the
  safest driver, now
- added Cydrak's gl_Position.zw change to ruby
- added fixes for all the changes to nall, ruby, phoenix over the past
  three months
This commit is contained in:
Tim Allen 2013-07-29 19:42:45 +10:00
parent 29ea5bd599
commit c74865e171
163 changed files with 2028 additions and 970 deletions

View File

@ -3,7 +3,7 @@
namespace Emulator {
static const char Name[] = "higan";
static const char Version[] = "092.09";
static const char Version[] = "092.10";
static const char Author[] = "byuu";
static const char License[] = "GPLv3";
static const char Website[] = "http://byuu.org/";

View File

@ -28,7 +28,7 @@ bool Cheat::decode(string code_, unsigned& addr, unsigned& data, unsigned& comp)
code.upper();
unsigned length = code.length(), bits = 0;
if(code.wildcard("????:??")) {
if(code.match("????:??")) {
code = {substr(code, 0, 4), substr(code, 5, 2)};
for(unsigned n = 0; n < 6; n++) if(mapProActionReplay[code[n]] > 15) return false;
bits = hex(code);
@ -38,7 +38,7 @@ bool Cheat::decode(string code_, unsigned& addr, unsigned& data, unsigned& comp)
return true;
}
if(code.wildcard("????:??:??")) {
if(code.match("????:??:??")) {
code = {substr(code, 0, 4), substr(code, 5, 2), substr(code, 8, 2)};
for(unsigned n = 0; n < 8; n++) if(mapProActionReplay[code[n]] > 15) return false;
bits = hex(code);

View File

@ -28,7 +28,7 @@ bool Cheat::decode(string code_, unsigned& addr, unsigned& data, unsigned& comp)
code.upper();
unsigned length = code.length(), bits = 0;
if(code.wildcard("????:??")) {
if(code.match("????:??")) {
code = {substr(code, 0, 4), substr(code, 5, 2)};
for(unsigned n = 0; n < 6; n++) if(mapProActionReplay[code[n]] > 15) return false;
bits = hex(code);
@ -38,7 +38,7 @@ bool Cheat::decode(string code_, unsigned& addr, unsigned& data, unsigned& comp)
return true;
}
if(code.wildcard("????:??:??")) {
if(code.match("????:??:??")) {
code = {substr(code, 0, 4), substr(code, 5, 2), substr(code, 8, 2)};
for(unsigned n = 0; n < 8; n++) if(mapProActionReplay[code[n]] > 15) return false;
bits = hex(code);
@ -48,7 +48,7 @@ bool Cheat::decode(string code_, unsigned& addr, unsigned& data, unsigned& comp)
return true;
}
if(code.wildcard("???" "-" "???")) {
if(code.match("???" "-" "???")) {
code = {substr(code, 0, 3), substr(code, 4, 3)};
for(unsigned n = 0; n < 6; n++) if(mapGameGenie[code[n]] > 15) return false;
for(unsigned n = 0; n < 6; n++) bits |= mapGameGenie[code[n]] << (20 - n * 4);
@ -62,7 +62,7 @@ bool Cheat::decode(string code_, unsigned& addr, unsigned& data, unsigned& comp)
return true;
}
if(code.wildcard("???" "-" "???" "-" "???")) {
if(code.match("???" "-" "???" "-" "???")) {
code = {substr(code, 0, 3), substr(code, 4, 3), substr(code, 8, 1), substr(code, 10, 1)};
for(unsigned n = 0; n < 8; n++) if(mapGameGenie[code[n]] > 15) return false;
for(unsigned n = 0; n < 8; n++) bits |= mapGameGenie[code[n]] << (28 - n * 4);

View File

@ -8,7 +8,11 @@ namespace nall {
struct any {
bool empty() const { return container; }
const std::type_info& type() const { return container ? container->type() : typeid(void); }
void reset() { if(container) { delete container; container = nullptr; } }
const std::type_info& type() const {
return container ? container->type() : typeid(void);
}
template<typename T> any& operator=(const T& value) {
typedef typename type_if<
@ -27,20 +31,37 @@ struct any {
return *this;
}
any& operator=(const any& source) {
if(container) { delete container; container = nullptr; }
if(source.container) container = source.container->copy();
return *this;
}
any& operator=(any&& source) {
if(container) delete container;
container = source.container;
source.container = nullptr;
return *this;
}
any() = default;
any(const any& source) { operator=(source); }
any(any&& source) { operator=(std::move(source)); }
template<typename T> any(const T& value) { operator=(value); }
~any() { if(container) delete container; }
~any() { reset(); }
private:
struct placeholder {
virtual const std::type_info& type() const = 0;
virtual placeholder* copy() const = 0;
virtual ~placeholder() {}
};
placeholder* container = nullptr;
template<typename T> struct holder : placeholder {
T value;
const std::type_info& type() const { return typeid(T); }
placeholder* copy() const { return new holder(value); }
holder(const T& value) : value(value) {}
};

View File

@ -48,6 +48,8 @@ constexpr inline uintmax_t binary(const char* s) {
constexpr inline uintmax_t octal(const char* s) {
return (
*s == '0' && *(s + 1) == 'O' ? octal_(s + 2) :
*s == '0' && *(s + 1) == 'o' ? octal_(s + 2) :
octal_(s)
);
}
@ -88,7 +90,7 @@ constexpr inline intmax_t numeral(const char* s) {
);
}
inline double fp(const char* s) {
inline double real(const char* s) {
return atof(s);
}

View File

@ -57,7 +57,7 @@ struct beatArchive : beatBase {
while(fp.offset() < fp.size() - 4) {
unsigned data = readNumber();
string name = readString((data >> 1) + 1);
if(name.position("\\") || name.position("../")) return false; //block path exploits
if(name.find("\\") || name.find("../")) return false; //block path exploits
if((data & 1) == 0) {
directory::create({pathname, name});

View File

@ -35,7 +35,7 @@ struct Node {
case Type::Bool: *(bool*)data = (value == "true"); break;
case Type::Signed: *(signed*)data = integer(value); break;
case Type::Unsigned: *(unsigned*)data = decimal(value); break;
case Type::Double: *(double*)data = fp(value); break;
case Type::Double: *(double*)data = real(value); break;
case Type::String: *(string*)data = value; break;
}
}

View File

@ -112,14 +112,14 @@ private:
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
string name = (const char*)utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(name);
if(name.match(pattern)) list.append(name);
}
}
while(FindNextFile(handle, &data) != false) {
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
string name = (const char*)utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(name);
if(name.match(pattern)) list.append(name);
}
}
}
@ -141,12 +141,12 @@ private:
if(handle != INVALID_HANDLE_VALUE) {
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
string name = (const char*)utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(name);
if(name.match(pattern)) list.append(name);
}
while(FindNextFile(handle, &data) != false) {
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
string name = (const char*)utf8_t(data.cFileName);
if(wildcard(name, pattern)) list.append(name);
if(name.match(pattern)) list.append(name);
}
}
FindClose(handle);
@ -190,8 +190,14 @@ private:
while(ep = readdir(dp)) {
if(!strcmp(ep->d_name, ".")) continue;
if(!strcmp(ep->d_name, "..")) continue;
if(ep->d_type & DT_DIR) {
if(wildcard(ep->d_name, pattern)) list.append(ep->d_name);
bool is_directory = ep->d_type & DT_DIR;
if(ep->d_type & DT_UNKNOWN) {
struct stat sp = {0};
stat(string{pathname, ep->d_name}, &sp);
is_directory = S_ISDIR(sp.st_mode);
}
if(is_directory) {
if(strmatch(ep->d_name, pattern)) list.append(ep->d_name);
}
}
closedir(dp);
@ -210,7 +216,7 @@ private:
if(!strcmp(ep->d_name, ".")) continue;
if(!strcmp(ep->d_name, "..")) continue;
if((ep->d_type & DT_DIR) == 0) {
if(wildcard(ep->d_name, pattern)) list.append(ep->d_name);
if(strmatch(ep->d_name, pattern)) list.append(ep->d_name);
}
}
closedir(dp);

137
higan/nall/hashset.hpp Normal file
View File

@ -0,0 +1,137 @@
#ifndef NALL_HASHSET_HPP
#define NALL_HASHSET_HPP
//hashset
//
//search: O(1) average; O(n) worst
//insert: O(1) average; O(n) worst
//remove: O(1) average; O(n) worst
//
//requirements:
// unsigned T::hash() const;
// bool T::operator==(const T&) const;
namespace nall {
template<typename T>
struct hashset {
protected:
T** pool = nullptr;
unsigned length = 8; //length of pool
unsigned count = 0; //number of objects inside of the pool
public:
hashset() {}
hashset(unsigned length) : length(bit::round(length)) {}
hashset(const hashset& source) { operator=(source); }
hashset(hashset&& source) { operator=(std::move(source)); }
~hashset() { reset(); }
hashset& operator=(const hashset& source) {
reset();
if(source.pool) {
for(unsigned n = 0; n < source.count; n++) {
insert(*source.pool[n]);
}
}
return *this;
}
hashset& operator=(hashset&& source) {
reset();
pool = source.pool;
length = source.length;
count = source.count;
source.pool = nullptr;
source.length = 8;
source.count = 0;
return *this;
}
unsigned capacity() const { return length; }
unsigned size() const { return count; }
bool empty() const { return count == 0; }
void reset() {
if(pool) {
for(unsigned n = 0; n < length; n++) {
if(pool[n]) {
delete pool[n];
pool[n] = nullptr;
}
}
delete pool;
pool = nullptr;
}
length = 8;
count = 0;
}
void reserve(unsigned size) {
//ensure all items will fit into pool (with <= 50% load) and amortize growth
size = bit::round(max(size, count << 1));
T** copy = new T*[size]();
if(pool) {
for(unsigned n = 0; n < length; n++) {
if(pool[n]) {
unsigned hash = (*pool[n]).hash() & (size - 1);
while(copy[hash]) if(++hash >= size) hash = 0;
copy[hash] = pool[n];
pool[n] = nullptr;
}
}
}
delete pool;
pool = copy;
length = size;
}
optional<T&> find(const T& value) {
if(!pool) return false;
unsigned hash = value.hash() & (length - 1);
while(pool[hash]) {
if(value == *pool[hash]) return {true, *pool[hash]};
if(++hash >= length) hash = 0;
}
return false;
}
optional<T&> insert(const T& value) {
if(!pool) pool = new T*[length]();
//double pool size when load is >= 50%
if(count >= (length >> 1)) reserve(length << 1);
count++;
unsigned hash = value.hash() & (length - 1);
while(pool[hash]) if(++hash >= length) hash = 0;
pool[hash] = new T(value);
return {true, *pool[hash]};
}
bool remove(const T& value) {
if(!pool) return false;
unsigned hash = value.hash() & (length - 1);
while(pool[hash]) {
if(value == *pool[hash]) {
delete pool[hash];
pool[hash] = nullptr;
count--;
return true;
}
if(++hash >= length) hash = 0;
}
return false;
}
};
}
#endif

View File

@ -100,7 +100,7 @@ struct http {
inline void downloadContent(uint8_t*& data, unsigned& size) {
unsigned capacity = 0;
if(header.iposition("\r\nTransfer-Encoding: chunked\r\n")) {
if(header.ifind("\r\nTransfer-Encoding: chunked\r\n")) {
while(true) {
unsigned length = hex(downloadChunkLength());
if(length == 0) break;
@ -116,7 +116,7 @@ struct http {
length -= packetlength;
}
}
} else if(auto position = header.iposition("\r\nContent-Length: ")) {
} else if(auto position = header.ifind("\r\nContent-Length: ")) {
unsigned length = decimal((const char*)header + position() + 18);
while(length) {
char buffer[256];

View File

@ -22,7 +22,7 @@ namespace nall {
template<typename... Args> inline void invoke(const string& name, Args&&... args) {
lstring argl(std::forward<Args>(args)...);
for(auto& arg : argl) if(arg.position(" ")) arg = {"\"", arg, "\""};
for(auto& arg : argl) if(arg.find(" ")) arg = {"\"", arg, "\""};
string arguments = argl.concatenate(" ");
ShellExecuteW(NULL, NULL, utf16_t(name), utf16_t(arguments), NULL, SW_SHOWNORMAL);
}

View File

@ -47,9 +47,8 @@ struct context {
}
unsigned eval(const string& expression) {
intmax_t result;
if(fixedpoint::eval(expression, result) == false) return 0u;
return result;
if(auto result = Eval::integer(expression)) return result();
return 0u;
}
void eval(vector<unsigned>& buffer, const string& expression_) {
@ -64,7 +63,7 @@ struct context {
lstring list = expression.split(",");
for(auto& item : list) {
item.trim();
if(item.wildcard("f(?*) ?*")) {
if(item.match("f(?*) ?*")) {
item.ltrim<1>("f(");
lstring part = item.split<1>(") ");
lstring args = part[0].split<3>(";");
@ -85,10 +84,10 @@ struct context {
buffer[offset] = eval(fn);
offset += stride;
}
} else if(item.wildcard("base64*")) {
} else if(item.match("base64*")) {
unsigned offset = 0;
item.ltrim<1>("base64");
if(item.wildcard("(?*) *")) {
if(item.match("(?*) *")) {
item.ltrim<1>("(");
lstring part = item.split<1>(") ");
offset = eval(part[0]);
@ -102,7 +101,7 @@ struct context {
if(c == '-') buffer.append(offset + 62);
if(c == '_') buffer.append(offset + 63);
}
} else if(item.wildcard("file *")) {
} else if(item.match("file *")) {
item.ltrim<1>("file ");
item.trim();
//...
@ -159,8 +158,8 @@ struct context {
}
bool load(const string& filename) {
string filedata;
if(filedata.readfile(filename) == false) return false;
string filedata = string::read(filename);
if(filedata.empty()) return false;
parse(filedata);
return true;
}

View File

@ -23,6 +23,7 @@
#include <nall/function.hpp>
#include <nall/group.hpp>
#include <nall/gzip.hpp>
#include <nall/hashset.hpp>
#include <nall/http.hpp>
#include <nall/image.hpp>
#include <nall/inflate.hpp>

View File

@ -13,6 +13,7 @@
//=========================
#include <limits>
#include <utility>
#include <assert.h>
#include <limits.h>

View File

@ -10,7 +10,7 @@
//
//caveats:
//- only plain-old-data can be stored. complex classes must provide serialize(serializer&);
//- floating-point usage is not portable across platforms
//- floating-point usage is not portable across different implementations
#include <type_traits>
#include <utility>
@ -19,122 +19,130 @@
namespace nall {
struct serializer;
template<typename T>
struct has_serialize {
template<typename C> static char test(decltype(std::declval<C>().serialize(std::declval<serializer&>()))*);
template<typename C> static long test(...);
static const bool value = sizeof(test<T>(0)) == sizeof(char);
};
struct serializer {
enum mode_t { Load, Save, Size };
mode_t mode() const {
return imode;
return _mode;
}
const uint8_t* data() const {
return idata;
return _data;
}
unsigned size() const {
return isize;
return _size;
}
unsigned capacity() const {
return icapacity;
return _capacity;
}
template<typename T> void floatingpoint(T& value) {
template<typename T> serializer& floatingpoint(T& value) {
enum { size = sizeof(T) };
//this is rather dangerous, and not cross-platform safe;
//but there is no standardized way to export FP-values
uint8_t* p = (uint8_t*)&value;
if(imode == Save) {
for(unsigned n = 0; n < size; n++) idata[isize++] = p[n];
} else if(imode == Load) {
for(unsigned n = 0; n < size; n++) p[n] = idata[isize++];
if(_mode == Save) {
for(unsigned n = 0; n < size; n++) _data[_size++] = p[n];
} else if(_mode == Load) {
for(unsigned n = 0; n < size; n++) p[n] = _data[_size++];
} else {
isize += size;
_size += size;
}
return *this;
}
template<typename T> void integer(T& value) {
template<typename T> serializer& integer(T& value) {
enum { size = std::is_same<bool, T>::value ? 1 : sizeof(T) };
if(imode == Save) {
for(unsigned n = 0; n < size; n++) idata[isize++] = (uintmax_t)value >> (n << 3);
} else if(imode == Load) {
if(_mode == Save) {
for(unsigned n = 0; n < size; n++) _data[_size++] = (uintmax_t)value >> (n << 3);
} else if(_mode == Load) {
value = 0;
for(unsigned n = 0; n < size; n++) value |= (uintmax_t)idata[isize++] << (n << 3);
} else if(imode == Size) {
isize += size;
for(unsigned n = 0; n < size; n++) value |= (uintmax_t)_data[_size++] << (n << 3);
} else if(_mode == Size) {
_size += size;
}
return *this;
}
template<typename T> void array(T& array) {
enum { size = sizeof(T) / sizeof(typename std::remove_extent<T>::type) };
for(unsigned n = 0; n < size; n++) integer(array[n]);
template<typename T, int N> serializer& array(T (&array)[N]) {
for(unsigned n = 0; n < N; n++) operator()(array[n]);
return *this;
}
template<typename T> void array(T array, unsigned size) {
for(unsigned n = 0; n < size; n++) integer(array[n]);
template<typename T> serializer& array(T array, unsigned size) {
for(unsigned n = 0; n < size; n++) operator()(array[n]);
return *this;
}
//copy
template<typename T> serializer& operator()(T& value, typename std::enable_if<has_serialize<T>::value>::type* = 0) { value.serialize(*this); return *this; }
template<typename T> serializer& operator()(T& value, typename std::enable_if<std::is_integral<T>::value>::type* = 0) { return integer(value); }
template<typename T> serializer& operator()(T& value, typename std::enable_if<std::is_floating_point<T>::value>::type* = 0) { return floatingpoint(value); }
template<typename T> serializer& operator()(T& value, typename std::enable_if<std::is_array<T>::value>::type* = 0) { return array(value); }
template<typename T> serializer& operator()(T& value, unsigned size, typename std::enable_if<std::is_pointer<T>::value>::type* = 0) { return array(value, size); }
serializer& operator=(const serializer& s) {
if(idata) delete[] idata;
if(_data) delete[] _data;
imode = s.imode;
idata = new uint8_t[s.icapacity];
isize = s.isize;
icapacity = s.icapacity;
_mode = s._mode;
_data = new uint8_t[s._capacity];
_size = s._size;
_capacity = s._capacity;
memcpy(idata, s.idata, s.icapacity);
memcpy(_data, s._data, s._capacity);
return *this;
}
serializer(const serializer& s) {
operator=(s);
}
//move
serializer& operator=(serializer&& s) {
if(idata) delete[] idata;
if(_data) delete[] _data;
imode = s.imode;
idata = s.idata;
isize = s.isize;
icapacity = s.icapacity;
_mode = s._mode;
_data = s._data;
_size = s._size;
_capacity = s._capacity;
s.idata = nullptr;
s._data = nullptr;
return *this;
}
serializer(serializer&& s) {
operator=(std::move(s));
}
//construction
serializer() = default;
serializer(const serializer& s) { operator=(s); }
serializer(serializer&& s) { operator=(std::move(s)); }
serializer(unsigned capacity) {
imode = Save;
idata = new uint8_t[capacity]();
isize = 0;
icapacity = capacity;
_mode = Save;
_data = new uint8_t[capacity]();
_size = 0;
_capacity = capacity;
}
serializer(const uint8_t* data, unsigned capacity) {
imode = Load;
idata = new uint8_t[capacity];
isize = 0;
icapacity = capacity;
memcpy(idata, data, capacity);
_mode = Load;
_data = new uint8_t[capacity];
_size = 0;
_capacity = capacity;
memcpy(_data, data, capacity);
}
//destruction
~serializer() {
if(idata) delete[] idata;
if(_data) delete[] _data;
}
private:
mode_t imode = Size;
uint8_t* idata = nullptr;
unsigned isize = 0;
unsigned icapacity = 0;
mode_t _mode = Size;
uint8_t* _data = nullptr;
unsigned _size = 0;
unsigned _capacity = 0;
};
};

View File

@ -3,9 +3,14 @@
//set
//implementation: red-black tree
//
//search: O(log n) average; O(log n) worst
//insert: O(log n) average; O(log n) worst
//remove: O(log n) average; O(log n) worst
//
//requirements:
// bool T::operator==(const T&) const;
// bool T::operator< (const T&) const;
#include <nall/utility.hpp>
#include <nall/vector.hpp>
@ -50,16 +55,18 @@ template<typename T> struct set {
return false;
}
bool insert(const T& value) {
optional<T&> insert(const T& value) {
unsigned count = size();
insert(root, value);
node_t* v = insert(root, value);
root->red = 0;
return size() > count;
if(size() == count) return false;
return {true, v->value};
}
template<typename... Args> bool insert(const T& value, Args&&... args) {
bool result = insert(value);
return insert(std::forward<Args>(args)...) | result;
insert(std::forward<Args>(args)...) | result;
return result;
}
bool remove(const T& value) {
@ -175,13 +182,13 @@ private:
rotate(node, dir);
}
void insert(node_t*& node, const T& value) {
if(!node) { nodes++; node = new node_t(value); return; }
if(node->value == value) { node->value = value; return; } //prevent duplicate entries
node_t* insert(node_t*& node, const T& value) {
if(!node) { nodes++; node = new node_t(value); return node; }
if(node->value == value) { node->value = value; return node; } //prevent duplicate entries
bool dir = node->value < value;
insert(node->link[dir], value);
if(black(node->link[dir])) return;
node_t* v = insert(node->link[dir], value);
if(black(node->link[dir])) return v;
if(red(node->link[!dir])) {
node->red = 1;
@ -192,6 +199,8 @@ private:
} else if(red(node->link[dir]->link[!dir])) {
rotateTwice(node, !dir);
}
return v;
}
void balance(node_t*& node, bool dir, bool& done) {

View File

@ -19,7 +19,7 @@ struct zipstream : memorystream {
delete[] data;
for(auto& file : archive.file) {
if(file.name.wildcard(filter)) {
if(file.name.match(filter)) {
auto buffer = archive.extract(file);
psize = buffer.size();
pdata = buffer.move();

View File

@ -12,6 +12,7 @@
#include <nall/platform.hpp>
#include <nall/atoi.hpp>
#include <nall/crc32.hpp>
#include <nall/function.hpp>
#include <nall/intrinsics.hpp>
#include <nall/sha256.hpp>
@ -39,6 +40,10 @@
#include <nall/string/utility.hpp>
#include <nall/string/variadic.hpp>
#include <nall/string/wrapper.hpp>
#include <nall/string/eval/node.hpp>
#include <nall/string/eval/literal.hpp>
#include <nall/string/eval/parser.hpp>
#include <nall/string/eval/evaluator.hpp>
#include <nall/string/markup/node.hpp>
#include <nall/string/markup/bml.hpp>
#include <nall/string/markup/xml.hpp>

View File

@ -0,0 +1,98 @@
#ifdef NALL_STRING_INTERNAL_HPP
/*
copy on write (COW) allocator
sizeof(string) == 24 (amd64)
utilizes a shared_ptr to reference count strings
allows string copies to execute as fast as string moves
requires extra computations, which will be slower for all string sizes
pros:
* lower memory usage
* pass-by-value does not require heap allocation; obviates pass-by-const-reference
cons:
* added overhead to fetch data()
* added heap allocation for reference-count pool
* no potential for in-place resize (always copies)
* larger sizeof(string)
*/
namespace nall {
char* string::data() {
if(!_data.unique()) _copy();
return _data.get();
}
const char* string::data() const {
if(!_data) return "";
return _data.get();
}
//copy _data (to make unique or to grow in size)
void string::_copy() {
auto copy = new char[_capacity + 1];
if(_data.get()) memcpy(copy, _data.get(), min(_capacity, _size));
copy[_size] = 0;
copy[_capacity] = 0;
_data.reset(copy);
}
//amortize growth to O(log n)
//allocate one extra byte to always store null-terminator for libc usage
void string::reserve(unsigned capacity) {
if(capacity > _capacity) {
_capacity = bit::round(capacity + 1) - 1;
_copy();
}
}
void string::resize(unsigned size) {
reserve(size);
data()[_size = size] = 0;
}
void string::reset() {
_data.reset();
_capacity = 0;
_size = 0;
}
string& string::operator=(const string& source) {
if(&source == this) return *this;
_data = source._data;
_capacity = source._capacity;
_size = source._size;
return *this;
}
string& string::operator=(string&& source) {
if(&source == this) return *this;
_data = std::move(source._data);
_capacity = source._capacity;
_size = source._size;
source._capacity = 0;
source._size = 0;
return *this;
}
template<typename T, typename... Args> string::string(T&& source, Args&&... args) {
_capacity = 0;
_size = 0;
sprint(*this, std::forward<T>(source), std::forward<Args>(args)...);
}
string::string() {
_capacity = 0;
_size = 0;
}
string::~string() {
}
}
#endif

View File

@ -0,0 +1,107 @@
#ifdef NALL_STRING_INTERNAL_HPP
/*
small string optimization (SSO) allocator
sizeof(string) == 16 (amd64)
utilizes a union to store small strings directly into text pointer
bypasses the need to allocate heap memory for small strings
requires extra computations, which can be slower for large strings
pros:
* potential for in-place resize
* no heap allocation when (capacity < 8)
cons:
* added overhead to fetch data()
* 32-bit platforms limited to (capacity < 4)
* pass-by-value requires heap allocation
*/
namespace nall {
char* string::data() {
if(_capacity < SSO) return _text;
return _data;
}
const char* string::data() const {
if(_capacity < SSO) return _text;
return _data;
}
void string::reserve(unsigned capacity) {
if(capacity > _capacity) {
if(capacity >= SSO) {
capacity = bit::round(capacity + 1) - 1;
if(_capacity < SSO) {
char temp[SSO];
memcpy(temp, _text, SSO);
_data = (char*)malloc(capacity + 1);
memcpy(_data, temp, SSO);
} else {
_data = (char*)realloc(_data, capacity + 1);
}
}
_capacity = capacity;
data()[_capacity] = 0;
}
}
void string::resize(unsigned size) {
reserve(size);
data()[_size = size] = 0;
}
void string::reset() {
if(_capacity >= SSO) free(_data);
_data = nullptr;
_capacity = SSO - 1;
_size = 0;
}
string& string::operator=(const string& source) {
if(&source == this) return *this;
if(source._capacity >= SSO) {
_data = (char*)malloc(source._capacity + 1);
_capacity = source._capacity;
_size = source._size;
memcpy(_data, source.data(), source.size() + 1);
} else {
memcpy(_text, source._text, SSO);
_capacity = SSO - 1;
_size = strlen(_text);
}
return *this;
}
string& string::operator=(string&& source) {
if(&source == this) return *this;
memcpy(this, &source, sizeof(string));
source._data = nullptr;
source._capacity = SSO - 1;
source._size = 0;
return *this;
}
template<typename T, typename... Args> string::string(T&& source, Args&&... args) {
_data = nullptr;
_capacity = SSO - 1;
_size = 0;
sprint(*this, std::forward<T>(source), std::forward<Args>(args)...);
}
string::string() {
_data = nullptr;
_capacity = SSO - 1;
_size = 0;
}
string::~string() {
if(_capacity >= SSO) free(_data);
}
}
#endif

View File

@ -0,0 +1,90 @@
#ifdef NALL_STRING_INTERNAL_HPP
/*
vector allocator
sizeof(string) == 16 (amd64)
utilizes a raw string pointer
always allocates memory onto the heap when string is not empty
pros:
* potential for in-place resize
* simplicity
cons:
* always allocates heap memory on (capacity > 0)
* pass-by-value requires heap allocation
*/
namespace nall {
char* string::data() {
if(_capacity == 0) reserve(1);
return _data;
}
const char* string::data() const {
if(_capacity == 0) return "";
return _data;
}
void string::reserve(unsigned capacity) {
if(capacity > _capacity) {
_capacity = bit::round(capacity + 1) - 1;
_data = (char*)realloc(_data, _capacity + 1);
_data[_capacity] = 0;
}
}
void string::resize(unsigned size) {
reserve(size);
data()[_size = size] = 0;
}
void string::reset() {
if(_data) { free(_data); _data = nullptr; }
_capacity = 0;
_size = 0;
}
string& string::operator=(const string& source) {
if(&source == this) return *this;
_data = (char*)malloc(source._size + 1);
_capacity = source._size;
_size = source._size;
memcpy(_data, source.data(), source.size() + 1);
return *this;
}
string& string::operator=(string&& source) {
if(&source == this) return *this;
_data = source._data;
_capacity = source._capacity;
_size = source._size;
source._data = nullptr;
source._capacity = 0;
source._size = 0;
return *this;
}
template<typename T, typename... Args> string::string(T&& source, Args&&... args) {
_data = nullptr;
_capacity = 0;
_size = 0;
sprint(*this, std::forward<T>(source), std::forward<Args>(args)...);
}
string::string() {
_data = nullptr;
_capacity = 0;
_size = 0;
}
string::~string() {
if(_data) free(_data);
}
}
#endif

View File

@ -7,9 +7,29 @@ struct stringref;
struct lstring;
typedef const stringref& rstring;
//#define NALL_STRING_ALLOCATOR_COPY_ON_WRITE
#define NALL_STRING_ALLOCATOR_SMALL_STRING_OPTIMIZATION
//#define NALL_STRING_ALLOCATOR_VECTOR
struct string {
protected:
#if defined(NALL_STRING_ALLOCATOR_COPY_ON_WRITE)
inline void _copy();
std::shared_ptr<char> _data;
#endif
#if defined(NALL_STRING_ALLOCATOR_SMALL_STRING_OPTIMIZATION)
enum : unsigned { SSO = 24 };
union {
char* _data;
char _text[SSO];
};
#endif
#if defined(NALL_STRING_ALLOCATOR_VECTOR)
char* _data;
#endif
unsigned _capacity;
unsigned _size;
@ -27,12 +47,13 @@ public:
inline void resize(unsigned);
inline void clear(char);
inline unsigned hash() const;
template<typename... Args> inline string& assign(Args&&... args);
template<typename... Args> inline string& append(Args&&... args);
//file.hpp
inline static string read(rstring filename);
inline bool readfile(rstring);
inline static string read(const string& filename);
//datetime.hpp
inline static string date();
@ -51,17 +72,22 @@ public:
template<unsigned Limit = 0> inline lstring qsplit(rstring) const;
template<unsigned Limit = 0> inline lstring iqsplit(rstring) const;
inline signed compare(rstring) const;
inline signed icompare(rstring) const;
inline bool equals(rstring) const;
inline bool iequals(rstring) const;
inline bool wildcard(rstring) const;
inline bool iwildcard(rstring) const;
inline bool match(rstring) const;
inline bool imatch(rstring) const;
inline bool beginswith(rstring) const;
inline bool ibeginswith(rstring) const;
inline bool endswith(rstring) const;
inline bool iendswith(rstring) const;
inline string slice(unsigned offset, unsigned length = ~0u) const;
inline string& lower();
inline string& upper();
inline string& qlower();
@ -69,21 +95,28 @@ public:
inline string& transform(rstring before, rstring after);
inline string& reverse();
template<unsigned limit = 0> inline string& ltrim(rstring key = " ");
template<unsigned limit = 0> inline string& rtrim(rstring key = " ");
template<unsigned limit = 0> inline string& trim(rstring key = " ", rstring rkey = "");
template<unsigned limit = 0> inline string& ltrim() { return ltrim<limit>(" "); }
template<unsigned limit = 0> inline string& ltrim(rstring key);
template<unsigned limit = 0> inline string& rtrim() { return rtrim<limit>(" "); }
template<unsigned limit = 0> inline string& rtrim(rstring key);
template<unsigned limit = 0> inline string& trim() { return trim<limit>(" "); }
template<unsigned limit = 0> inline string& trim(rstring key);
template<unsigned limit = 0> inline string& trim(rstring key, rstring rkey);
inline string& strip();
inline optional<unsigned> position(rstring key) const;
inline optional<unsigned> iposition(rstring key) const;
inline optional<unsigned> qposition(rstring key) const;
inline optional<unsigned> iqposition(rstring key) const;
inline optional<unsigned> find(rstring key) const;
inline optional<unsigned> ifind(rstring key) const;
inline optional<unsigned> qfind(rstring key) const;
inline optional<unsigned> iqfind(rstring key) const;
//core.hpp
inline explicit operator bool() const;
inline operator const char*() const;
inline char& operator[](unsigned);
inline const char& operator[](unsigned) const;
inline char& operator[](signed);
inline const char& operator[](signed) const;
inline bool operator==(const char*) const;
inline bool operator!=(const char*) const;
@ -109,8 +142,6 @@ public:
//protected:
struct exception_out_of_bounds{};
template<unsigned Limit, bool Insensitive, bool Quoted> inline string& ureplace(rstring, rstring);
inline void _unique();
inline void _copy();
inline string& _append(const char*);
#if defined(QSTRING_H)
@ -179,8 +210,8 @@ inline bool tokenize(lstring& list, const char* s, const char* p);
inline char* integer(char* result, intmax_t value);
inline char* decimal(char* result, uintmax_t value);
inline unsigned fp(char* str, long double value);
inline string fp(long double value);
inline unsigned real(char* str, long double value);
inline string real(long double value);
//variadic.hpp
inline void sprint(string& output);

View File

@ -101,19 +101,19 @@ template<unsigned bits> struct stringify<uint_t<bits>> {
template<> struct stringify<float> {
char data[256];
operator const char*() const { return data; }
stringify(float value) { fp(data, value); }
stringify(float value) { real(data, value); }
};
template<> struct stringify<double> {
char data[256];
operator const char*() const { return data; }
stringify(double value) { fp(data, value); }
stringify(double value) { real(data, value); }
};
template<> struct stringify<long double> {
char data[256];
operator const char*() const { return data; }
stringify(long double value) { fp(data, value); }
stringify(long double value) { real(data, value); }
};
// arrays

View File

@ -3,13 +3,11 @@
#include <nall/string/char/base.hpp>
#include <nall/string/char/compare.hpp>
#include <nall/string/char/convert.hpp>
#include <nall/string/char/math-fixed-point.hpp>
#include <nall/string/char/math-floating-point.hpp>
#include <nall/string/char/match.hpp>
#include <nall/string/char/strm.hpp>
#include <nall/string/char/strpos.hpp>
#include <nall/string/char/trim.hpp>
#include <nall/string/char/utf8.hpp>
#include <nall/string/char/utility.hpp>
#include <nall/string/char/wildcard.hpp>
#endif

View File

@ -23,21 +23,10 @@ inline char* qstrlower(char* str);
inline char* qstrupper(char* str);
inline char* strtr(char* dest, const char* before, const char* after);
//math-fixed-point.hpp
namespace fixedpoint {
inline intmax_t eval_integer(const char*& s);
inline intmax_t eval(const char*& s, int depth = 0);
inline bool eval(const char* s, intmax_t& result);
inline intmax_t parse(const char* s);
}
//math-floating-point.hpp
namespace floatingpoint {
inline double eval_integer(const char*& s);
inline double eval(const char*& s, int depth = 0);
inline bool eval(const char* s, double& result);
inline double parse(const char* s);
}
//match.hpp
inline bool strmatch(const char* str, const char* pattern);
inline bool istrmatch(const char* str, const char* pattern);
inline bool tokenize(const char* s, const char* p);
//strm.hpp
inline unsigned strmcpy(char* target, const char* source, unsigned length);
@ -56,7 +45,8 @@ template<bool Insensitive = false, bool Quoted = false> inline optional<unsigned
//trim.hpp
template<unsigned Limit = 0> inline char* ltrim(char* str, const char* key = " ");
template<unsigned Limit = 0> inline char* rtrim(char* str, const char* key = " ");
template<unsigned Limit = 0> inline char* trim(char* str, const char* key = " ", const char* rkey = nullptr);
template<unsigned Limit = 0> inline char* trim(char* str, const char* key = " ");
template<unsigned Limit = 0> inline char* trim(char* str, const char* lkey, const char* rkey);
inline char* strip(char* s);
//utf8.hpp
@ -73,11 +63,6 @@ template<bool Insensitive> alwaysinline bool chrequal(char x, char y);
template<bool Quoted, typename T> alwaysinline bool quoteskip(T*& p);
template<bool Quoted, typename T> alwaysinline bool quotecopy(char*& t, T*& p);
//wildcard.hpp
inline bool wildcard(const char* str, const char* pattern);
inline bool iwildcard(const char* str, const char* pattern);
inline bool tokenize(const char* s, const char* p);
}
#endif

View File

@ -2,7 +2,7 @@
namespace nall {
bool wildcard(const char* s, const char* p) {
bool strmatch(const char* s, const char* p) {
const char* cp = nullptr;
const char* mp = nullptr;
while(*s && *p != '*') {
@ -23,7 +23,7 @@ bool wildcard(const char* s, const char* p) {
return !*p;
}
bool iwildcard(const char* s, const char* p) {
bool istrmatch(const char* s, const char* p) {
const char* cp = nullptr;
const char* mp = nullptr;
while(*s && *p != '*') {

View File

@ -1,168 +0,0 @@
#ifdef NALL_STRING_INTERNAL_HPP
namespace nall {
namespace fixedpoint {
static nall::function<intmax_t (const char*&)> eval_fallback;
intmax_t eval_integer(const char*& s) {
if(!*s) throw "unrecognized integer";
intmax_t value = 0, x = *s, y = *(s + 1);
//hexadecimal
if(x == '0' && (y == 'X' || y == 'x')) {
s += 2;
while(true) {
if(*s >= '0' && *s <= '9') { value = value * 16 + (*s++ - '0'); continue; }
if(*s >= 'A' && *s <= 'F') { value = value * 16 + (*s++ - 'A' + 10); continue; }
if(*s >= 'a' && *s <= 'f') { value = value * 16 + (*s++ - 'a' + 10); continue; }
return value;
}
}
//binary
if(x == '0' && (y == 'B' || y == 'b')) {
s += 2;
while(true) {
if(*s == '0' || *s == '1') { value = value * 2 + (*s++ - '0'); continue; }
return value;
}
}
//octal (or decimal '0')
if(x == '0') {
s += 1;
while(true) {
if(*s >= '0' && *s <= '7') { value = value * 8 + (*s++ - '0'); continue; }
return value;
}
}
//decimal
if(x >= '0' && x <= '9') {
while(true) {
if(*s >= '0' && *s <= '9') { value = value * 10 + (*s++ - '0'); continue; }
return value;
}
}
//char
if(x == '\'' && y != '\'') {
s += 1;
while(true) {
value = value * 256 + *s++;
if(*s == '\'') { s += 1; return value; }
if(!*s) throw "mismatched char";
}
}
throw "unrecognized integer";
}
intmax_t eval(const char*& s, int depth) {
while(*s == ' ' || *s == '\t') s++; //trim whitespace
if(!*s) throw "unrecognized token";
intmax_t value = 0, x = *s, y = *(s + 1);
if(*s == '(') {
value = eval(++s, 1);
if(*s++ != ')') throw "mismatched group";
}
else if(x == '!') value = !eval(++s, 13);
else if(x == '~') value = ~eval(++s, 13);
else if(x == '+') value = +eval(++s, 13);
else if(x == '-') value = -eval(++s, 13);
else if((x >= '0' && x <= '9') || x == '\'') value = eval_integer(s);
else if(eval_fallback) value = eval_fallback(s); //optional user-defined syntax parsing
else throw "unrecognized token";
while(true) {
while(*s == ' ' || *s == '\t') s++; //trim whitespace
if(!*s) break;
x = *s, y = *(s + 1);
if(depth >= 13) break;
if(x == '*') { value *= eval(++s, 13); continue; }
if(x == '/') { intmax_t result = eval(++s, 13); if(result == 0) throw "division by zero"; value /= result; continue; }
if(x == '%') { intmax_t result = eval(++s, 13); if(result == 0) throw "division by zero"; value %= result; continue; }
if(depth >= 12) break;
if(x == '+') { value += eval(++s, 12); continue; }
if(x == '-') { value -= eval(++s, 12); continue; }
if(depth >= 11) break;
if(x == '<' && y == '<') { value <<= eval(++++s, 11); continue; }
if(x == '>' && y == '>') { value >>= eval(++++s, 11); continue; }
if(depth >= 10) break;
if(x == '<' && y == '=') { value = value <= eval(++++s, 10); continue; }
if(x == '>' && y == '=') { value = value >= eval(++++s, 10); continue; }
if(x == '<') { value = value < eval(++s, 10); continue; }
if(x == '>') { value = value > eval(++s, 10); continue; }
if(depth >= 9) break;
if(x == '=' && y == '=') { value = value == eval(++++s, 9); continue; }
if(x == '!' && y == '=') { value = value != eval(++++s, 9); continue; }
if(depth >= 8) break;
if(x == '&' && y != '&') { value = value & eval(++s, 8); continue; }
if(depth >= 7) break;
if(x == '^' && y != '^') { value = value ^ eval(++s, 7); continue; }
if(depth >= 6) break;
if(x == '|' && y != '|') { value = value | eval(++s, 6); continue; }
if(depth >= 5) break;
if(x == '&' && y == '&') { value = eval(++++s, 5) && value; continue; }
if(depth >= 4) break;
if(x == '^' && y == '^') { value = (!eval(++++s, 4) != !value); continue; }
if(depth >= 3) break;
if(x == '|' && y == '|') { value = eval(++++s, 3) || value; continue; }
if(x == '?') {
intmax_t lhs = eval(++s, 2);
if(*s != ':') throw "mismatched ternary";
intmax_t rhs = eval(++s, 2);
value = value ? lhs : rhs;
continue;
}
if(depth >= 2) break;
if(depth > 0 && x == ')') break;
throw "unrecognized token";
}
return value;
}
bool eval(const char* s, intmax_t& result) {
try {
result = eval(s);
return true;
} catch(const char*) {
result = 0;
return false;
}
}
intmax_t parse(const char* s) {
try {
intmax_t result = eval(s);
return result;
} catch(const char*) {
return 0;
}
}
}
}
#endif

View File

@ -1,160 +0,0 @@
#ifdef NALL_STRING_INTERNAL_HPP
namespace nall {
namespace floatingpoint {
static nall::function<double (const char*&)> eval_fallback;
double eval_integer(const char*& s) {
if(!*s) throw "unrecognized integer";
intmax_t value = 0, radix = 0, x = *s, y = *(s + 1);
//hexadecimal
if(x == '0' && (y == 'X' || y == 'x')) {
s += 2;
while(true) {
if(*s >= '0' && *s <= '9') { value = value * 16 + (*s++ - '0'); continue; }
if(*s >= 'A' && *s <= 'F') { value = value * 16 + (*s++ - 'A' + 10); continue; }
if(*s >= 'a' && *s <= 'f') { value = value * 16 + (*s++ - 'a' + 10); continue; }
return value;
}
}
//binary
if(x == '0' && (y == 'B' || y == 'b')) {
s += 2;
while(true) {
if(*s == '0' || *s == '1') { value = value * 2 + (*s++ - '0'); continue; }
return value;
}
}
//octal (or decimal '0')
if(x == '0' && y != '.') {
s += 1;
while(true) {
if(*s >= '0' && *s <= '7') { value = value * 8 + (*s++ - '0'); continue; }
return value;
}
}
//decimal
if(x >= '0' && x <= '9') {
while(true) {
if(*s >= '0' && *s <= '9') { value = value * 10 + (*s++ - '0'); continue; }
if(*s == '.') { s++; break; }
return value;
}
//floating-point
unsigned divisor = 1;
while(true) {
if(*s >= '0' && *s <= '9') { radix = radix * 10 + (*s++ - '0'); divisor *= 10; continue; }
return (double)value + (double)radix / (double)divisor;
}
}
//char
if(x == '\'' && y != '\'') {
s += 1;
while(true) {
value = value * 256 + *s++;
if(*s == '\'') { s += 1; return value; }
if(!*s) throw "mismatched char";
}
}
throw "unrecognized integer";
}
double eval(const char*& s, int depth) {
while(*s == ' ' || *s == '\t') s++; //trim whitespace
if(!*s) throw "unrecognized token";
double value = 0, x = *s, y = *(s + 1);
if(*s == '(') {
value = eval(++s, 1);
if(*s++ != ')') throw "mismatched group";
}
else if(x == '!') value = !eval(++s, 9);
else if(x == '+') value = +eval(++s, 9);
else if(x == '-') value = -eval(++s, 9);
else if((x >= '0' && x <= '9') || x == '\'') value = eval_integer(s);
else if(eval_fallback) value = eval_fallback(s); //optional user-defined syntax parsing
else throw "unrecognized token";
while(true) {
while(*s == ' ' || *s == '\t') s++; //trim whitespace
if(!*s) break;
x = *s, y = *(s + 1);
if(depth >= 9) break;
if(x == '*') { value *= eval(++s, 9); continue; }
if(x == '/') { double result = eval(++s, 9); if(result == 0.0) throw "division by zero"; value /= result; continue; }
if(depth >= 8) break;
if(x == '+') { value += eval(++s, 8); continue; }
if(x == '-') { value -= eval(++s, 8); continue; }
if(depth >= 7) break;
if(x == '<' && y == '=') { value = value <= eval(++++s, 7); continue; }
if(x == '>' && y == '=') { value = value >= eval(++++s, 7); continue; }
if(x == '<') { value = value < eval(++s, 7); continue; }
if(x == '>') { value = value > eval(++s, 7); continue; }
if(depth >= 6) break;
if(x == '=' && y == '=') { value = value == eval(++++s, 6); continue; }
if(x == '!' && y == '=') { value = value != eval(++++s, 6); continue; }
if(depth >= 5) break;
if(x == '&' && y == '&') { value = eval(++++s, 5) && value; continue; }
if(depth >= 4) break;
if(x == '^' && y == '^') { value = (!eval(++++s, 4) != !value); continue; }
if(depth >= 3) break;
if(x == '|' && y == '|') { value = eval(++++s, 3) || value; continue; }
if(x == '?') {
double lhs = eval(++s, 2);
if(*s != ':') throw "mismatched ternary";
double rhs = eval(++s, 2);
value = value ? lhs : rhs;
continue;
}
if(depth >= 2) break;
if(depth > 0 && x == ')') break;
throw "unrecognized token";
}
return value;
}
bool eval(const char* s, double& result) {
try {
result = eval(s);
return true;
} catch(const char*) {
result = 0;
return false;
}
}
double parse(const char* s) {
try {
double result = eval(s);
return result;
} catch(const char*) {
return 0;
}
}
}
}
#endif

View File

@ -29,11 +29,14 @@ template<unsigned Limit> char* rtrim(char* str, const char* key) {
return str;
}
template<unsigned limit> char* trim(char* str, const char* key, const char* rkey) {
if(rkey) return ltrim<limit>(rtrim<limit>(str, rkey), key);
template<unsigned limit> char* trim(char* str, const char* key) {
return ltrim<limit>(rtrim<limit>(str, key), key);
}
template<unsigned limit> char* trim(char* str, const char* lkey, const char* rkey) {
return ltrim<limit>(rtrim<limit>(str, rkey), lkey);
}
//remove whitespace characters from both left and right sides of string
char* strip(char* s) {
if(!s) return nullptr;

View File

@ -1,59 +1,36 @@
#ifdef NALL_STRING_INTERNAL_HPP
//core functionality
//only this header file may access _data, _size, _capacity directly
//all other headers must use data(), size(), capacity()
//only allocators may access _data or modify _size and _capacity
//all other functions must use data(), size(), capacity()
#if defined(NALL_STRING_ALLOCATOR_COPY_ON_WRITE)
#include <nall/string/allocator/copy-on-write.hpp>
#elif defined(NALL_STRING_ALLOCATOR_SMALL_STRING_OPTIMIZATION)
#include <nall/string/allocator/small-string-optimization.hpp>
#elif defined(NALL_STRING_ALLOCATOR_VECTOR)
#include <nall/string/allocator/vector.hpp>
#endif
namespace nall {
char* string::data() { _unique(); return _data.get(); }
const char* string::data() const { if(!_data) return ""; return _data.get(); }
unsigned string::length() const { return strlen(data()); }
unsigned string::size() const { return _size; }
unsigned string::capacity() const { return _capacity; }
bool string::empty() const { return size() == 0; }
//ensure _data is unique
void string::_unique() {
if(_data.unique()) return;
_copy();
}
//copy _data (to make unique or to grow in size)
void string::_copy() {
auto copy = new char[_capacity + 1];
if(_data.get()) memcpy(copy, _data.get(), min(_capacity, _size));
copy[_size] = 0;
copy[_capacity] = 0;
_data.reset(copy);
}
//amortize growth to O(log n)
//allocate one extra byte to always store null-terminator for libc usage
void string::reserve(unsigned capacity) {
if(capacity > _capacity) {
_capacity = bit::round(capacity + 1) - 1;
_copy();
}
}
void string::resize(unsigned size) {
reserve(size);
data()[_size = size] = 0;
}
void string::reset() {
_data.reset();
_capacity = 0;
_size = 0;
}
bool string::empty() const { return _size == 0; }
void string::clear(char c) {
for(unsigned n = 0; n < size(); n++) data()[n] = c;
}
unsigned string::hash() const {
const char* p = data();
unsigned result = 5381;
while(*p) result = (result << 5) + result + *p++;
return result;
}
template<typename... Args> string& string::assign(Args&&... args) {
reset();
resize(0);
sprint(*this, std::forward<Args>(args)...);
return *this;
}
@ -80,12 +57,12 @@ string::operator const char*() const {
return data();
}
char& string::operator[](unsigned position) {
char& string::operator[](signed position) {
if(position > size() + 1) throw exception_out_of_bounds{};
return data()[position];
}
const char& string::operator[](unsigned position) const {
const char& string::operator[](signed position) const {
if(position > size() + 1) throw exception_out_of_bounds{};
return data()[position];
}
@ -97,24 +74,6 @@ bool string::operator<=(const char* str) const { return strcmp(data(), str) <= 0
bool string::operator> (const char* str) const { return strcmp(data(), str) > 0; }
bool string::operator>=(const char* str) const { return strcmp(data(), str) >= 0; }
string& string::operator=(const string& source) {
if(&source == this) return *this;
_data = source._data;
_capacity = source._capacity;
_size = source._size;
return *this;
}
string& string::operator=(string&& source) {
if(&source == this) return *this;
_data = std::move(source._data);
_capacity = source._capacity;
_size = source._size;
source._capacity = 0;
source._size = 0;
return *this;
}
string::string(const string& source) {
operator=(source);
}
@ -123,20 +82,6 @@ string::string(string&& source) {
operator=(std::move(source));
}
template<typename T, typename... Args> string::string(T&& source, Args&&... args) {
_capacity = 0;
_size = 0;
sprint(*this, std::forward<T>(source), std::forward<Args>(args)...);
}
string::string() {
_capacity = 0;
_size = 0;
}
string::~string() {
}
}
#endif

View File

@ -0,0 +1,150 @@
#ifdef NALL_STRING_INTERNAL_HPP
namespace nall {
namespace Eval {
inline string evaluateExpression(Node* node) {
#define p(n) evaluateExpression(node->link[n])
switch(node->type) {
case Node::Type::Null: return "Null";
case Node::Type::Literal: return {"Literal:", node->literal};
case Node::Type::Function: return {"Function(0:", p(0), ", 1:", p(1), ")"};
case Node::Type::Subscript: return {"Subscript(0:", p(0), ", 1:", p(1), ")"};
case Node::Type::Member: return {"Member(0:", p(0), ", 1:", p(1), ")"};
case Node::Type::SuffixIncrement: return {"SuffixIncrement(0:", p(0), ")"};
case Node::Type::SuffixDecrement: return {"SuffixDecrement(0:", p(0), ")"};
case Node::Type::Reference: return {"Reference(0:", p(0), ")"};
case Node::Type::Dereference: return {"Dereference(0:", p(0), ")"};
case Node::Type::BitwiseNot: return {"Complement(0:", p(0), ")"};
case Node::Type::PrefixIncrement: return {"PrefixIncrement(0:", p(0), ")"};
case Node::Type::PrefixDecrement: return {"PrefixDecrement(0:", p(0), ")"};
case Node::Type::Add: return {"Add(0:", p(0), ", 1:", p(1), ")"};
case Node::Type::Multiply: return {"Multiply(0:", p(0), ", 1:", p(1), ")"};
case Node::Type::Concatenate: return {"Concatenate(0:", p(0), ", ", p(1), ")"};
case Node::Type::Coalesce: return {"Coalesce(0:", p(0), ", ", p(1), ")"};
case Node::Type::Condition: return {"Condition(0:", p(0), ", ", p(1), ", ", p(2), ")"};
case Node::Type::Assign: return {"Assign(0:", p(0), ", ", p(1), ")"};
case Node::Type::Separator: {
string result = "Separator(";
for(auto& link : node->link) {
result.append(evaluateExpression(link), ", ");
}
return result.rtrim<1>(", ").append(")");
}
}
#undef p
throw "invalid operator";
}
inline int64_t evaluateInteger(Node* node) {
if(node->type == Node::Type::Literal) return nall::integer(node->literal);
#define p(n) evaluateInteger(node->link[n])
switch(node->type) {
case Node::Type::SuffixIncrement: return p(0);
case Node::Type::SuffixDecrement: return p(0);
case Node::Type::LogicalNot: return !p(0);
case Node::Type::BitwiseNot: return ~p(0);
case Node::Type::Positive: return +p(0);
case Node::Type::Negative: return -p(0);
case Node::Type::PrefixIncrement: return p(0) + 1;
case Node::Type::PrefixDecrement: return p(0) - 1;
case Node::Type::Multiply: return p(0) * p(1);
case Node::Type::Divide: return p(0) / p(1);
case Node::Type::Modulo: return p(0) % p(1);
case Node::Type::Add: return p(0) + p(1);
case Node::Type::Subtract: return p(0) - p(1);
case Node::Type::ShiftLeft: return p(0) << p(1);
case Node::Type::ShiftRight: return p(0) >> p(1);
case Node::Type::BitwiseAnd: return p(0) & p(1);
case Node::Type::BitwiseOr: return p(0) | p(1);
case Node::Type::BitwiseXor: return p(0) ^ p(1);
case Node::Type::Equal: return p(0) == p(1);
case Node::Type::NotEqual: return p(0) != p(1);
case Node::Type::LessThanEqual: return p(0) <= p(1);
case Node::Type::GreaterThanEqual: return p(0) >= p(1);
case Node::Type::LessThan: return p(0) < p(1);
case Node::Type::GreaterThan: return p(0) > p(1);
case Node::Type::LogicalAnd: return p(0) && p(1);
case Node::Type::LogicalOr: return p(0) || p(1);
case Node::Type::Condition: return p(0) ? p(1) : p(2);
case Node::Type::Assign: return p(1);
case Node::Type::AssignMultiply: return p(0) * p(1);
case Node::Type::AssignDivide: return p(0) / p(1);
case Node::Type::AssignModulo: return p(0) % p(1);
case Node::Type::AssignAdd: return p(0) + p(1);
case Node::Type::AssignSubtract: return p(0) - p(1);
case Node::Type::AssignShiftLeft: return p(0) << p(1);
case Node::Type::AssignShiftRight: return p(0) >> p(1);
case Node::Type::AssignBitwiseAnd: return p(0) & p(1);
case Node::Type::AssignBitwiseOr: return p(0) | p(1);
case Node::Type::AssignBitwiseXor: return p(0) ^ p(1);
}
#undef p
throw "invalid operator";
}
inline optional<int64_t> integer(const string& expression) {
try {
auto tree = new Node;
const char* p = expression;
parse(tree, p, 0);
auto result = evaluateInteger(tree);
delete tree;
return {true, result};
} catch(const char*) {
return false;
}
}
inline long double evaluateReal(Node* node) {
if(node->type == Node::Type::Literal) return nall::real(node->literal);
#define p(n) evaluateReal(node->link[n])
switch(node->type) {
case Node::Type::LogicalNot: return !p(0);
case Node::Type::Positive: return +p(0);
case Node::Type::Negative: return -p(0);
case Node::Type::Multiply: return p(0) * p(1);
case Node::Type::Divide: return p(0) / p(1);
case Node::Type::Add: return p(0) + p(1);
case Node::Type::Subtract: return p(0) - p(1);
case Node::Type::Equal: return p(0) == p(1);
case Node::Type::NotEqual: return p(0) != p(1);
case Node::Type::LessThanEqual: return p(0) <= p(1);
case Node::Type::GreaterThanEqual: return p(0) >= p(1);
case Node::Type::LessThan: return p(0) < p(1);
case Node::Type::GreaterThan: return p(0) > p(1);
case Node::Type::LogicalAnd: return p(0) && p(1);
case Node::Type::LogicalOr: return p(0) || p(1);
case Node::Type::Condition: return p(0) ? p(1) : p(2);
case Node::Type::Assign: return p(1);
case Node::Type::AssignMultiply: return p(0) * p(1);
case Node::Type::AssignDivide: return p(0) / p(1);
case Node::Type::AssignAdd: return p(0) + p(1);
case Node::Type::AssignSubtract: return p(0) - p(1);
}
#undef p
throw "invalid operator";
}
inline optional<long double> real(const string& expression) {
try {
auto tree = new Node;
const char* p = expression;
parse(tree, p, 0);
auto result = evaluateReal(tree);
delete tree;
return {true, result};
} catch(const char*) {
return false;
}
}
}
}
#endif

View File

@ -0,0 +1,97 @@
#ifdef NALL_STRING_INTERNAL_HPP
namespace nall {
namespace Eval {
inline bool isLiteral(const char*& s) {
char n = s[0];
return (n >= 'A' && n <= 'Z')
|| (n >= 'a' && n <= 'z')
|| (n >= '0' && n <= '9')
|| n == '_' || n == '\"';
}
inline string literalNumber(const char*& s) {
const char* p = s;
//binary
if(p[0] == '0' && p[1] == 'b') {
p += 2;
while(p[0] == '0' || p[0] == '1') p++;
if(p - s < 3) throw "invalid binary literal";
string result = substr(s, 0, p - s);
s = p;
return result;
}
//octal
if(p[0] == '0' && p[1] == 'o') {
p += 2;
while(p[0] >= '0' && p[0] <= '7') p++;
if(p - s < 3) throw "invalid octal literal";
string result = substr(s, 0, p - s);
s = p;
return result;
}
//hex
if(p[0] == '0' && p[1] == 'x') {
p += 2;
while((p[0] >= '0' && p[0] <= '9') || (p[0] >= 'A' && p[0] <= 'F') || (p[0] >= 'a' && p[0] <= 'f')) p++;
if(p - s < 3) throw "invalid hex literal";
string result = substr(s, 0, p - s);
s = p;
return result;
}
//decimal
while(p[0] >= '0' && p[0] <= '9') p++;
if(p[0] != '.') {
string result = substr(s, 0, p - s);
s = p;
return result;
}
//floating-point
p++;
while(p[0] >= '0' && p[0] <= '9') p++;
string result = substr(s, 0, p - s);
s = p;
return result;
}
inline string literalString(const char*& s) {
const char* p = s + 1;
while(p[0] && p[0] != '\"') p++;
if(*p++ != '\"') throw "unclosed string literal";
string result = substr(s, 0, p - s);
s = p;
return result;
}
inline string literalVariable(const char*& s) {
const char* p = s;
while(p[0] == '_' || (p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z') || (p[0] >= '0' && p[0] <= '9')) p++;
string result = substr(s, 0, p - s);
s = p;
return result;
}
inline string literal(const char*& s) {
const char* p = s;
if(p[0] >= '0' && p[0] <= '9') return literalNumber(s);
if(p[0] == '\"') return literalString(s);
if(p[0] == '_' || (p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z')) return literalVariable(s);
throw "invalid literal";
}
}
}
#endif

View File

@ -0,0 +1,41 @@
#ifdef NALL_STRING_INTERNAL_HPP
namespace nall {
namespace Eval {
struct Node {
enum class Type : unsigned {
Null,
Literal,
Function, Subscript, Member, SuffixIncrement, SuffixDecrement,
Reference, Dereference, LogicalNot, BitwiseNot, Positive, Negative, PrefixIncrement, PrefixDecrement,
Multiply, Divide, Modulo,
Add, Subtract,
RotateLeft, RotateRight, ShiftLeft, ShiftRight,
BitwiseAnd, BitwiseOr, BitwiseXor,
Concatenate,
Equal, NotEqual, LessThanEqual, GreaterThanEqual, LessThan, GreaterThan,
LogicalAnd, LogicalOr,
Coalesce, Condition,
Assign, Create, //all assignment operators have the same precedence
AssignMultiply, AssignDivide, AssignModulo,
AssignAdd, AssignSubtract,
AssignRotateLeft, AssignRotateRight, AssignShiftLeft, AssignShiftRight,
AssignBitwiseAnd, AssignBitwiseOr, AssignBitwiseXor,
AssignConcatenate,
Separator,
};
Type type;
string literal;
vector<Node*> link;
Node() : type(Type::Null) {}
Node(Type type) : type(type) {}
~Node() { for(auto& node : link) delete node; }
};
}
}
#endif

View File

@ -0,0 +1,168 @@
#ifdef NALL_STRING_INTERNAL_HPP
namespace nall {
namespace Eval {
inline bool whitespace(char n) {
return n == ' ' || n == '\t' || n == '\r' || n == '\n';
}
inline void parse(Node*& node, const char*& s, unsigned depth) {
auto unaryPrefix = [&](Node::Type type, unsigned seek, unsigned depth) {
auto parent = new Node(type);
parse(parent->link(0) = new Node, s += seek, depth);
node = parent;
};
auto unarySuffix = [&](Node::Type type, unsigned seek, unsigned depth) {
auto parent = new Node(type);
parent->link(0) = node;
parse(parent, s += seek, depth);
node = parent;
};
auto binary = [&](Node::Type type, unsigned seek, unsigned depth) {
auto parent = new Node(type);
parent->link(0) = node;
parse(parent->link(1) = new Node, s += seek, depth);
node = parent;
};
auto ternary = [&](Node::Type type, unsigned seek, unsigned depth) {
auto parent = new Node(type);
parent->link(0) = node;
parse(parent->link(1) = new Node, s += seek, depth);
if(s[0] != ':') throw "mismatched ternary";
parse(parent->link(2) = new Node, s += seek, depth);
node = parent;
};
auto separator = [&](Node::Type type, unsigned seek, unsigned depth) {
if(node->type != Node::Type::Separator) return binary(type, seek, depth);
unsigned n = node->link.size();
parse(node->link(n) = new Node, s += seek, depth);
};
while(whitespace(s[0])) s++;
if(!s[0]) return;
if(s[0] == '(' && node->link.empty()) {
parse(node, s += 1, 1);
if(*s++ != ')') throw "mismatched group";
}
if(isLiteral(s)) {
node->type = Node::Type::Literal;
node->literal = literal(s);
}
#define p() (node->literal.empty() && node->link.empty())
while(true) {
while(whitespace(s[0])) s++;
if(!s[0]) return;
if(depth >= 13) break;
if(s[0] == '(' && !p()) {
binary(Node::Type::Function, 1, 1);
if(*s++ != ')') throw "mismatched function";
continue;
}
if(s[0] == '[') {
binary(Node::Type::Subscript, 1, 1);
if(*s++ != ']') throw "mismatched subscript";
continue;
}
if(s[0] == '.') { binary(Node::Type::Member, 1, 13); continue; }
if(s[0] == '+' && s[1] == '+' && !p()) { unarySuffix(Node::Type::SuffixIncrement, 2, 13); continue; }
if(s[0] == '-' && s[1] == '-' && !p()) { unarySuffix(Node::Type::SuffixDecrement, 2, 13); continue; }
if(s[0] == '&' && p()) { unaryPrefix(Node::Type::Reference, 1, 12); continue; }
if(s[0] == '*' && p()) { unaryPrefix(Node::Type::Dereference, 1, 12); continue; }
if(s[0] == '!' && p()) { unaryPrefix(Node::Type::LogicalNot, 1, 12); continue; }
if(s[0] == '~' && p()) { unaryPrefix(Node::Type::BitwiseNot, 1, 12); continue; }
if(s[0] == '+' && s[1] != '+' && p()) { unaryPrefix(Node::Type::Positive, 1, 12); continue; }
if(s[0] == '-' && s[1] != '-' && p()) { unaryPrefix(Node::Type::Negative, 1, 12); continue; }
if(s[0] == '+' && s[1] == '+' && p()) { unaryPrefix(Node::Type::PrefixIncrement, 2, 12); continue; }
if(s[0] == '-' && s[1] == '-' && p()) { unaryPrefix(Node::Type::PrefixDecrement, 2, 12); continue; }
if(depth >= 12) break;
if(depth >= 11) break;
if(s[0] == '*' && s[1] != '=') { binary(Node::Type::Multiply, 1, 11); continue; }
if(s[0] == '/' && s[1] != '=') { binary(Node::Type::Divide, 1, 11); continue; }
if(s[0] == '%' && s[1] != '=') { binary(Node::Type::Modulo, 1, 11); continue; }
if(depth >= 10) break;
if(s[0] == '+' && s[1] != '=') { binary(Node::Type::Add, 1, 10); continue; }
if(s[0] == '-' && s[1] != '=') { binary(Node::Type::Subtract, 1, 10); continue; }
if(depth >= 9) break;
if(s[0] == '<' && s[1] == '<' && s[2] == '<' && s[3] != '=') { binary(Node::Type::RotateLeft, 3, 9); continue; }
if(s[0] == '>' && s[1] == '>' && s[2] == '>' && s[3] != '=') { binary(Node::Type::RotateRight, 3, 9); continue; }
if(s[0] == '<' && s[1] == '<' && s[2] != '=') { binary(Node::Type::ShiftLeft, 2, 9); continue; }
if(s[0] == '>' && s[1] == '>' && s[2] != '=') { binary(Node::Type::ShiftRight, 2, 9); continue; }
if(depth >= 8) break;
if(s[0] == '&' && s[1] != '&' && s[1] != '=') { binary(Node::Type::BitwiseAnd, 1, 8); continue; }
if(s[0] == '|' && s[1] != '|' && s[1] != '=') { binary(Node::Type::BitwiseOr, 1, 8); continue; }
if(s[0] == '^' && s[1] != '^' && s[1] != '=') { binary(Node::Type::BitwiseXor, 1, 8); continue; }
if(depth >= 7) break;
if(s[0] == '~' && s[1] != '=') { binary(Node::Type::Concatenate, 1, 7); continue; }
if(depth >= 6) break;
if(s[0] == '=' && s[1] == '=') { binary(Node::Type::Equal, 2, 6); continue; }
if(s[0] == '!' && s[1] == '=') { binary(Node::Type::NotEqual, 2, 6); continue; }
if(s[0] == '<' && s[1] == '=') { binary(Node::Type::LessThanEqual, 2, 6); continue; }
if(s[0] == '>' && s[1] == '=') { binary(Node::Type::GreaterThanEqual, 2, 6); continue; }
if(s[0] == '<') { binary(Node::Type::LessThan, 1, 6); continue; }
if(s[0] == '>') { binary(Node::Type::GreaterThan, 1, 6); continue; }
if(depth >= 5) break;
if(s[0] == '&' && s[1] == '&') { binary(Node::Type::LogicalAnd, 2, 5); continue; }
if(s[0] == '|' && s[1] == '|') { binary(Node::Type::LogicalOr, 2, 5); continue; }
if(s[0] == '?' && s[1] == '?') { binary(Node::Type::Coalesce, 2, 4); continue; }
if(s[0] == '?' && s[1] != '?') { ternary(Node::Type::Condition, 1, 4); continue; }
if(depth >= 4) break;
if(s[0] == '=') { binary(Node::Type::Assign, 1, 3); continue; }
if(s[0] == ':' && s[1] == '=') { binary(Node::Type::Create, 2, 3); continue; }
if(s[0] == '*' && s[1] == '=') { binary(Node::Type::AssignMultiply, 2, 3); continue; }
if(s[0] == '/' && s[1] == '=') { binary(Node::Type::AssignDivide, 2, 3); continue; }
if(s[0] == '%' && s[1] == '=') { binary(Node::Type::AssignModulo, 2, 3); continue; }
if(s[0] == '+' && s[1] == '=') { binary(Node::Type::AssignAdd, 2, 3); continue; }
if(s[0] == '-' && s[1] == '=') { binary(Node::Type::AssignSubtract, 2, 3); continue; }
if(s[0] == '<' && s[1] == '<' && s[2] == '<' && s[3] == '=') { binary(Node::Type::AssignRotateLeft, 4, 3); continue; }
if(s[0] == '>' && s[1] == '>' && s[2] == '>' && s[3] == '=') { binary(Node::Type::AssignRotateRight, 4, 3); continue; }
if(s[0] == '<' && s[1] == '<' && s[2] == '=') { binary(Node::Type::AssignShiftLeft, 3, 3); continue; }
if(s[0] == '>' && s[1] == '>' && s[2] == '=') { binary(Node::Type::AssignShiftRight, 3, 3); continue; }
if(s[0] == '&' && s[1] == '=') { binary(Node::Type::AssignBitwiseAnd, 2, 3); continue; }
if(s[0] == '|' && s[1] == '=') { binary(Node::Type::AssignBitwiseOr, 2, 3); continue; }
if(s[0] == '^' && s[1] == '=') { binary(Node::Type::AssignBitwiseXor, 2, 3); continue; }
if(s[0] == '~' && s[1] == '=') { binary(Node::Type::AssignConcatenate, 2, 3); continue; }
if(depth >= 3) break;
if(depth >= 2) break;
if(s[0] == ',') { separator(Node::Type::Separator, 1, 2); continue; }
if(depth >= 1 && (s[0] == ')' || s[0] == ']')) break;
while(whitespace(s[0])) s++;
if(!s[0]) break;
throw "unrecognized terminal";
}
#undef p
}
inline Node* parse(const string& expression) {
auto result = new Node;
const char* p = expression;
parse(result, p, 0);
return result;
}
}
}
#endif

View File

@ -2,15 +2,15 @@
namespace nall {
bool string::readfile(rstring filename) {
reset();
string string::read(const string& filename) {
string result;
#if !defined(_WIN32)
FILE* fp = fopen(filename, "rb");
#else
FILE* fp = _wfopen(utf16_t(filename), L"rb");
#endif
if(!fp) return false;
if(!fp) return result;
fseek(fp, 0, SEEK_END);
unsigned fsize = ftell(fp);
@ -19,17 +19,11 @@ bool string::readfile(rstring filename) {
unsigned unused = fread(fdata, 1, fsize, fp);
fclose(fp);
fdata[fsize] = 0;
resize(fsize);
memcpy(data(), fdata, fsize);
result.resize(fsize);
memcpy(result.data(), fdata, fsize);
delete[] fdata;
return true;
}
string string::read(rstring filename) {
string data;
data.readfile(filename);
return data;
return result;
}
}

View File

@ -31,7 +31,7 @@ template<signed precision, char padchar> string hex(uintmax_t value) {
buffer[size++] = n < 10 ? '0' + n : 'a' + n - 10;
value >>= 4;
} while(value);
buffer[size] = 0;
buffer.resize(size);
buffer.reverse();
return format<precision, padchar>(buffer);
@ -46,7 +46,7 @@ template<signed precision, char padchar> string octal(uintmax_t value) {
buffer[size++] = '0' + (value & 7);
value >>= 3;
} while(value);
buffer[size] = 0;
buffer.resize(size);
buffer.reverse();
return format<precision, padchar>(buffer);
@ -61,7 +61,7 @@ template<signed precision, char padchar> string binary(uintmax_t value) {
buffer[size++] = '0' + (value & 1);
value >>= 1;
} while(value);
buffer[size] = 0;
buffer.resize(size);
buffer.reverse();
return format<precision, padchar>(buffer);

View File

@ -39,12 +39,12 @@ struct Node {
for(auto& rule : rules) {
enum class Comparator : unsigned { ID, EQ, NE, LT, LE, GT, GE };
auto comparator = Comparator::ID;
if(rule.wildcard("*!=*")) comparator = Comparator::NE;
else if(rule.wildcard("*<=*")) comparator = Comparator::LE;
else if(rule.wildcard("*>=*")) comparator = Comparator::GE;
else if(rule.wildcard ("*=*")) comparator = Comparator::EQ;
else if(rule.wildcard ("*<*")) comparator = Comparator::LT;
else if(rule.wildcard ("*>*")) comparator = Comparator::GT;
if(rule.match("*!=*")) comparator = Comparator::NE;
else if(rule.match("*<=*")) comparator = Comparator::LE;
else if(rule.match("*>=*")) comparator = Comparator::GE;
else if(rule.match ("*=*")) comparator = Comparator::EQ;
else if(rule.match ("*<*")) comparator = Comparator::LT;
else if(rule.match ("*>*")) comparator = Comparator::GT;
if(comparator == Comparator::ID) {
if(find(rule).size()) continue;
@ -69,8 +69,8 @@ struct Node {
}
switch(comparator) {
case Comparator::EQ: if(data.wildcard(side(1)) == true) continue; break;
case Comparator::NE: if(data.wildcard(side(1)) == false) continue; break;
case Comparator::EQ: if(data.match(side(1)) == true) continue; break;
case Comparator::NE: if(data.match(side(1)) == false) continue; break;
case Comparator::LT: if(numeral(data) < numeral(side(1))) continue; break;
case Comparator::LE: if(numeral(data) <= numeral(side(1))) continue; break;
case Comparator::GT: if(numeral(data) > numeral(side(1))) continue; break;
@ -90,7 +90,7 @@ struct Node {
string name = path.take(0), rule;
unsigned lo = 0u, hi = ~0u;
if(name.wildcard("*[*]")) {
if(name.match("*[*]")) {
lstring side = name.split<1>("[");
name = side(0);
side = side(1).rtrim<1>("]").split<1>("-");
@ -98,7 +98,7 @@ struct Node {
hi = side(1).empty() ? ~0u : numeral(side(1));
}
if(name.wildcard("*(*)")) {
if(name.match("*(*)")) {
lstring side = name.split<1>("(");
name = side(0);
rule = side(1).rtrim<1>(")");
@ -106,7 +106,7 @@ struct Node {
unsigned position = 0;
for(auto& node : children) {
if(node.name.wildcard(name) == false) continue;
if(node.name.match(name) == false) continue;
if(node.evaluate(rule) == false) continue;
bool inrange = position >= lo && position <= hi;

View File

@ -13,8 +13,8 @@ struct stringref {
unsigned size() const {
if(!_initialized) {
_initialized = true;
_size = strlen(_data);
_initialized = 1;
}
return _size;
}
@ -23,45 +23,21 @@ struct stringref {
stringref(const stringref& source) = delete;
stringref(stringref&& source) = delete;
template<typename T, typename... Args>
stringref(T&& source, Args&&... args) {
if(sizeof...(Args) == 0) { construct(std::forward<T>(source)); _string = nullptr; return; }
_string = new string(std::forward<T>(source), std::forward<Args>(args)...);
_data = _string->data();
_size = _string->size();
_initialized = 1;
stringref(const char* source) {
_data = source;
_initialized = false;
}
~stringref() {
if(_string) delete _string;
stringref(const string& source) {
_data = source.data();
_size = source.size();
_initialized = true;
}
protected:
const char* _data;
string* _string;
mutable unsigned _size;
mutable bool _initialized;
template<int size>
void construct(const char (&source)[size]) {
_data = source;
_size = size - 1;
_initialized = 1;
}
template<typename T, typename = typename std::enable_if<std::is_same<T, char>::value>::type>
void construct(const T* source) {
_data = source;
_size = 0;
_initialized = 0;
}
template<typename T, typename = typename std::enable_if<std::is_same<T, string>::value>::type>
void construct(const T& source) {
_data = source.data();
_size = source.size();
_initialized = 1;
}
};
}

View File

@ -79,7 +79,7 @@ char* decimal(char* result, uintmax_t value) {
//using sprintf is certainly not the most ideal method to convert
//a double to a string ... but attempting to parse a double by
//hand, digit-by-digit, results in subtle rounding errors.
unsigned fp(char* str, long double value) {
unsigned real(char* str, long double value) {
char buffer[256];
#ifdef _WIN32
//Windows C-runtime does not support long double via sprintf()
@ -105,10 +105,10 @@ unsigned fp(char* str, long double value) {
return length + 1;
}
string fp(long double value) {
string real(long double value) {
string temp;
temp.reserve(fp(nullptr, value));
fp(temp.data(), value);
temp.resize(real(nullptr, value));
real(temp.data(), value);
return temp;
}

View File

@ -7,17 +7,25 @@ template<unsigned limit> lstring string::isplit(rstring key) const { lstring res
template<unsigned limit> lstring string::qsplit(rstring key) const { lstring result; result.qsplit<limit>(key, data()); return result; }
template<unsigned limit> lstring string::iqsplit(rstring key) const { lstring result; result.iqsplit<limit>(key, data()); return result; }
bool string::wildcard(rstring source) const { return nall::wildcard(data(), source); }
bool string::iwildcard(rstring source) const { return nall::iwildcard(data(), source); }
bool string::match(rstring source) const { return nall::strmatch(data(), source); }
bool string::imatch(rstring source) const { return nall::istrmatch(data(), source); }
signed string::compare(rstring source) const {
return strcmp(data(), source.data());
}
signed string::icompare(rstring source) const {
return istrcmp(data(), source.data());
}
bool string::equals(rstring source) const {
if(size() != source.size()) return false;
return memcmp(data(), source.data(), source.size()) == 0;
return compare(source) == 0;
}
bool string::iequals(rstring source) const {
if(size() != source.size()) return false;
return imemcmp(data(), source.data(), source.size()) == 0;
return icompare(source) == 0;
}
bool string::beginswith(rstring source) const {
@ -40,6 +48,12 @@ bool string::iendswith(rstring source) const {
return imemcmp(data() + size() - source.size(), source.data(), source.size()) == 0;
}
string string::slice(unsigned offset, unsigned length) const {
if(offset >= size()) return "";
if(length == ~0u) length = size() - offset;
return substr(data(), offset, length);
}
string& string::lower() { nall::strlower(data()); return *this; }
string& string::upper() { nall::strupper(data()); return *this; }
string& string::qlower() { nall::qstrlower(data()); return *this; }
@ -82,9 +96,16 @@ template<unsigned Limit> string& string::rtrim(rstring key) {
return *this;
}
template<unsigned limit> string& string::trim(rstring key, rstring rkey) {
rtrim(rkey.size() ? rkey : key);
return ltrim(key);
template<unsigned Limit> string& string::trim(rstring key) {
rtrim<Limit>(key);
ltrim<Limit>(key);
return *this;
}
template<unsigned Limit> string& string::trim(rstring lkey, rstring rkey) {
rtrim<Limit>(rkey);
ltrim<Limit>(lkey);
return *this;
}
string& string::strip() {
@ -93,10 +114,10 @@ string& string::strip() {
return *this;
}
optional<unsigned> string::position(rstring key) const { return strpos(data(), key); }
optional<unsigned> string::iposition(rstring key) const { return istrpos(data(), key); }
optional<unsigned> string::qposition(rstring key) const { return qstrpos(data(), key); }
optional<unsigned> string::iqposition(rstring key) const { return iqstrpos(data(), key); }
optional<unsigned> string::find(rstring key) const { return strpos(data(), key); }
optional<unsigned> string::ifind(rstring key) const { return istrpos(data(), key); }
optional<unsigned> string::qfind(rstring key) const { return qstrpos(data(), key); }
optional<unsigned> string::iqfind(rstring key) const { return iqstrpos(data(), key); }
}

View File

@ -3,6 +3,7 @@
#include <type_traits>
#include <utility>
#include <nall/any.hpp>
namespace nall {
@ -11,6 +12,22 @@ template<typename T> struct base_from_member {
base_from_member(T value) : value(value) {}
};
template<typename T> struct ref {
T& operator*() {
if(type == Type::Reference) return *any_cast<T*>(value);
return any_cast<T&>(value);
}
operator T&() { return operator*(); }
ref(T& value) : type(Type::Reference), value(&value) {}
ref(T&& value) : type(Type::Temporary), value(value) {}
protected:
enum class Type : unsigned { Reference, Temporary } type;
any value;
};
template<typename TT> struct optional {
typedef typename std::remove_reference<TT>::type T;
static const bool isConst = std::is_const<TT>::value;
@ -30,12 +47,23 @@ template<typename TT> struct optional {
}
}
template<typename = typename std::enable_if<!isConst>::type>
T& operator*() {
if(!valid) throw optional_value_not_valid{};
return *value;
}
template<typename = typename std::enable_if<!isConst>::type>
T& operator()() {
if(!valid) throw optional_value_not_valid{};
return *value;
}
const T& operator*() const {
if(!valid) throw optional_value_not_valid{};
return *value;
}
const T& operator()() const {
if(!valid) throw optional_value_not_valid{};
return *value;

View File

@ -2,6 +2,7 @@
#define NALL_VARINT_HPP
#include <nall/bit.hpp>
#include <nall/serializer.hpp>
#include <nall/traits.hpp>
namespace nall {
@ -34,6 +35,8 @@ public:
template<unsigned s> inline type_t operator=(const uint_t<s> &i) { return data = uclip<bits>((type_t)i); }
template<unsigned s> inline uint_t(const uint_t<s> &i) : data(uclip<bits>(i)) {}
void serialize(serializer& s) { s(data); }
};
template<unsigned bits> struct int_t {
@ -64,6 +67,8 @@ public:
template<unsigned s> inline type_t operator=(const int_t<s> &i) { return data = sclip<bits>((type_t)i); }
template<unsigned s> inline int_t(const int_t<s> &i) : data(sclip<bits>(i)) {}
void serialize(serializer& s) { s(data); }
};
template<typename type_t> struct varuint_t {
@ -92,6 +97,8 @@ public:
inline void bits(type_t bits) { mask = (1ull << (bits - 1)) + ((1ull << (bits - 1)) - 1); data &= mask; }
inline varuint_t() : data(0ull), mask((type_t)~0ull) {}
inline varuint_t(const type_t i) : data(i), mask((type_t)~0ull) {}
void serialize(serializer& s) { s(data); s(mask); }
};
}

View File

@ -77,7 +77,7 @@ public:
prepend(data);
}
void prepend(const T& data) {
T& prepend(const T& data) {
reserve(objectsize + 1);
if(poolbase == 0) {
unsigned available = poolsize - objectsize;
@ -88,6 +88,7 @@ public:
}
new(pool + --poolbase) T(data);
objectsize++;
return first();
}
template<typename... Args> void append(const T& data, Args&&... args) {
@ -95,9 +96,10 @@ public:
append(std::forward<Args>(args)...);
}
void append(const T& data) {
T& append(const T& data) {
reserve(poolbase + objectsize + 1);
new(pool + poolbase + objectsize++) T(data);
return last();
}
bool appendonce(const T& data) {

View File

@ -33,7 +33,7 @@ void pCheckItem::setChecked(bool checked) {
}
}
void pCheckItem::setText(const string& text) {
void pCheckItem::setText(string text) {
@autoreleasepool {
[cocoaAction setTitle:[NSString stringWithUTF8String:text]];
}

View File

@ -14,7 +14,7 @@ struct pCheckItem : public pAction {
bool checked();
void setChecked(bool checked);
void setText(const string& text);
void setText(string text);
pCheckItem(CheckItem& checkItem) : pAction(checkItem), checkItem(checkItem) {}
void constructor();

View File

@ -24,7 +24,7 @@ void pItem::setImage(const image& image) {
}
}
void pItem::setText(const string& text) {
void pItem::setText(string text) {
@autoreleasepool {
[cocoaAction setTitle:[NSString stringWithUTF8String:text]];
}

View File

@ -13,7 +13,7 @@ struct pItem : public pAction {
CocoaItem* cocoaItem = nullptr;
void setImage(const image& image);
void setText(const string& text);
void setText(string text);
pItem(Item& item) : pAction(item), item(item) {}
void constructor();

View File

@ -37,7 +37,7 @@ void pMenu::setImage(const image& image) {
}
}
void pMenu::setText(const string& text) {
void pMenu::setText(string text) {
@autoreleasepool {
[[cocoaAction cocoaMenu] setTitle:[NSString stringWithUTF8String:text]];
[cocoaAction setTitle:[NSString stringWithUTF8String:text]];

View File

@ -16,7 +16,7 @@ struct pMenu : public pAction {
void append(Action& action);
void remove(Action& action);
void setImage(const image& image);
void setText(const string& text);
void setText(string text);
pMenu(Menu& menu) : pAction(menu), menu(menu) {}
void constructor();

View File

@ -37,7 +37,7 @@ void pRadioItem::setChecked() {
void pRadioItem::setGroup(const group<RadioItem>& group) {
}
void pRadioItem::setText(const string& text) {
void pRadioItem::setText(string text) {
@autoreleasepool {
[cocoaAction setTitle:[NSString stringWithUTF8String:text]];
}

View File

@ -15,7 +15,7 @@ struct pRadioItem : public pAction {
bool checked();
void setChecked();
void setGroup(const group<RadioItem>& group);
void setText(const string& text);
void setText(string text);
pRadioItem(RadioItem& radioItem) : pAction(radioItem), radioItem(radioItem) {}
void constructor();

View File

@ -50,7 +50,7 @@ string pBrowserWindow::save(BrowserWindow::State& state) {
NSMutableArray* filters = [[NSMutableArray alloc] init];
for(auto& rule : state.filters) {
string pattern = rule.split<1>("(")(1).rtrim<1>(")");
if(!pattern.empty()) [filters addObjects:[NSString stringWithUTF8String:pattern]];
if(!pattern.empty()) [filters addObject:[NSString stringWithUTF8String:pattern]];
}
NSSavePanel* panel = [NSSavePanel savePanel];
if(state.title) [panel setTitle:[NSString stringWithUTF8String:state.title]];

View File

@ -18,7 +18,7 @@ string pFont::monospace(unsigned size, string style) {
return {"Menlo, ", size, ", ", style};
}
Size pFont::size(const string& font, const string& text) {
Size pFont::size(string font, string text) {
@autoreleasepool {
if(NSFont* nsFont = cocoaFont(font)) {
return size(nsFont, text);
@ -27,27 +27,26 @@ Size pFont::size(const string& font, const string& text) {
return {0, 0};
}
NSFont* pFont::cocoaFont(const string& description) {
lstring part = description.split<2>(",");
for(auto& item : part) item.strip();
NSFont* pFont::cocoaFont(string description) {
lstring part = description.split<2>(",").strip();
NSString* family = @"Lucida Grande";
NSFontTraitMask traits = 0;
CGFloat size = 12;
if(!part(0).empty()) family = [NSString stringWithUTF8String:part(0)];
if(!part(1).empty()) size = fp(part(1));
if(part(2).iposition("bold")) traits |= NSBoldFontMask;
if(part(2).iposition("italic")) traits |= NSItalicFontMask;
if(part(2).iposition("narrow")) traits |= NSNarrowFontMask;
if(part(2).iposition("expanded")) traits |= NSExpandedFontMask;
if(part(2).iposition("condensed")) traits |= NSCondensedFontMask;
if(part(2).iposition("smallcaps")) traits |= NSSmallCapsFontMask;
if(!part(1).empty()) size = real(part(1));
if(part(2).ifind("bold")) traits |= NSBoldFontMask;
if(part(2).ifind("italic")) traits |= NSItalicFontMask;
if(part(2).ifind("narrow")) traits |= NSNarrowFontMask;
if(part(2).ifind("expanded")) traits |= NSExpandedFontMask;
if(part(2).ifind("condensed")) traits |= NSCondensedFontMask;
if(part(2).ifind("smallcaps")) traits |= NSSmallCapsFontMask;
return [[NSFontManager sharedFontManager] fontWithFamily:family traits:traits weight:5 size:size];
}
Size pFont::size(NSFont* font, const string& text) {
Size pFont::size(NSFont* font, string text) {
@autoreleasepool {
NSString* cocoaText = [NSString stringWithUTF8String:text];
NSDictionary* fontAttributes = [NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil];

View File

@ -4,10 +4,10 @@ struct pFont {
static string serif(unsigned size, string style);
static string sans(unsigned size, string style);
static string monospace(unsigned size, string style);
static Size size(const string& font, const string& text);
static Size size(string font, string text);
static NSFont* cocoaFont(const string& description);
static Size size(NSFont* font, const string& text);
static NSFont* cocoaFont(string description);
static Size size(NSFont* font, string text);
};
}

View File

@ -15,3 +15,27 @@ NSImage* NSMakeImage(nall::image image, unsigned width = 0, unsigned height = 0)
[cocoaImage addRepresentation:bitmap];
return cocoaImage;
}
NSDragOperation DropPathsOperation(id<NSDraggingInfo> sender) {
NSPasteboard* pboard = [sender draggingPasteboard];
if([[pboard types] containsObject:NSFilenamesPboardType]) {
if([sender draggingSourceOperationMask] & NSDragOperationGeneric) {
return NSDragOperationGeneric;
}
}
return NSDragOperationNone;
}
lstring DropPaths(id<NSDraggingInfo> sender) {
lstring paths;
NSPasteboard* pboard = [sender draggingPasteboard];
if([[pboard types] containsObject:NSFilenamesPboardType]) {
NSArray* files = [pboard propertyListForType:NSFilenamesPboardType];
for(unsigned n = 0; n < [files count]; n++) {
string path = [[files objectAtIndex:n] UTF8String];
if(directory::exists(path) && !path.endswith("/")) path.append("/");
paths.append(path);
}
}
return paths;
}

View File

@ -35,7 +35,7 @@ Size pButton::minimumSize() {
return {size.width + 20, size.height + 4};
}
void pButton::setGeometry(const Geometry& geometry) {
void pButton::setGeometry(Geometry geometry) {
pWidget::setGeometry({
geometry.x - 2, geometry.y - 2,
geometry.width + 4, geometry.height + 4
@ -56,7 +56,7 @@ void pButton::setImage(const image& image, Orientation orientation) {
}
}
void pButton::setText(const string& text) {
void pButton::setText(string text) {
@autoreleasepool {
[cocoaView setTitle:[NSString stringWithUTF8String:text]];
}

View File

@ -13,9 +13,9 @@ struct pButton : public pWidget {
CocoaButton* cocoaButton = nullptr;
Size minimumSize();
void setGeometry(const Geometry& geometry);
void setGeometry(Geometry geometry);
void setImage(const image& image, Orientation orientation);
void setText(const string& text);
void setText(string text);
pButton(Button& button) : pWidget(button), button(button) {}
void constructor();

View File

@ -13,6 +13,17 @@
return self;
}
-(NSDragOperation) draggingEntered:(id<NSDraggingInfo>)sender {
return DropPathsOperation(sender);
}
-(BOOL) performDragOperation:(id<NSDraggingInfo>)sender {
lstring paths = DropPaths(sender);
if(paths.empty()) return NO;
if(canvas->onDrop) canvas->onDrop(paths);
return YES;
}
-(void) mouseButton:(NSEvent*)event down:(BOOL)isDown {
if(auto &callback = isDown ? canvas->onMousePress : canvas->onMouseRelease) {
switch([event buttonNumber]) {
@ -73,7 +84,17 @@
namespace phoenix {
void pCanvas::setSize(const Size& size) {
void pCanvas::setDroppable(bool droppable) {
@autoreleasepool {
if(droppable) {
[cocoaCanvas registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
} else {
[cocoaCanvas unregisterDraggedTypes];
}
}
}
void pCanvas::setSize(Size size) {
@autoreleasepool {
NSImage* image = [[[NSImage alloc] initWithSize:NSMakeSize(size.width, size.height)] autorelease];
NSBitmapImageRep* bitmap = [[[NSBitmapImageRep alloc]

View File

@ -3,6 +3,8 @@
phoenix::Canvas* canvas;
}
-(id) initWith:(phoenix::Canvas&)canvas;
-(NSDragOperation) draggingEntered:(id<NSDraggingInfo>)sender;
-(BOOL) performDragOperation:(id<NSDraggingInfo>)sender;
-(void) mouseButton:(NSEvent*)event down:(BOOL)isDown;
-(void) mouseExited:(NSEvent*)event;
-(void) mouseMove:(NSEvent*)event;
@ -23,7 +25,8 @@ struct pCanvas : public pWidget {
Canvas& canvas;
CocoaCanvas* cocoaCanvas = nullptr;
void setSize(const Size& size);
void setDroppable(bool droppable);
void setSize(Size size);
void update();
pCanvas(Canvas& canvas) : pWidget(canvas), canvas(canvas) {}

View File

@ -37,14 +37,14 @@ void pCheckButton::setChecked(bool checked) {
}
}
void pCheckButton::setGeometry(const Geometry& geometry) {
void pCheckButton::setGeometry(Geometry geometry) {
pWidget::setGeometry({
geometry.x - 2, geometry.y,
geometry.width + 4, geometry.height
});
}
void pCheckButton::setText(const string& text) {
void pCheckButton::setText(string text) {
@autoreleasepool {
[cocoaView setTitle:[NSString stringWithUTF8String:text]];
}

View File

@ -15,8 +15,8 @@ struct pCheckButton : public pWidget {
bool checked();
Size minimumSize();
void setChecked(bool checked);
void setGeometry(const Geometry& geometry);
void setText(const string& text);
void setGeometry(Geometry geometry);
void setText(string text);
pCheckButton(CheckButton& checkButton) : pWidget(checkButton), checkButton(checkButton) {}
void constructor();

View File

@ -18,7 +18,7 @@
namespace phoenix {
void pComboButton::append(const string& text) {
void pComboButton::append(string text) {
@autoreleasepool {
[cocoaView addItemWithTitle:[NSString stringWithUTF8String:text]];
}
@ -31,7 +31,7 @@ Size pComboButton::minimumSize() {
return {maximumWidth + 36, size.height + 6};
}
void pComboButton::modify(unsigned row, const string& text) {
void pComboButton::modify(unsigned row, string text) {
@autoreleasepool {
[[cocoaView itemAtIndex:row] setTitle:[NSString stringWithUTF8String:text]];
}
@ -55,7 +55,7 @@ unsigned pComboButton::selection() {
}
}
void pComboButton::setGeometry(const Geometry& geometry) {
void pComboButton::setGeometry(Geometry geometry) {
pWidget::setGeometry({
geometry.x - 2, geometry.y,
geometry.width + 4, geometry.height

View File

@ -12,13 +12,13 @@ struct pComboButton : public pWidget {
ComboButton& comboButton;
CocoaComboButton* cocoaComboButton = nullptr;
void append(const string& text);
void append(string text);
Size minimumSize();
void modify(unsigned row, const string& text);
void modify(unsigned row, string text);
void remove(unsigned row);
void reset();
unsigned selection();
void setGeometry(const Geometry& geometry);
void setGeometry(Geometry geometry);
void setSelection(unsigned row);
pComboButton(ComboButton& comboButton) : pWidget(comboButton), comboButton(comboButton) {}

View File

@ -30,7 +30,7 @@ unsigned pHorizontalSlider::position() {
}
}
void pHorizontalSlider::setGeometry(const Geometry& geometry) {
void pHorizontalSlider::setGeometry(Geometry geometry) {
pWidget::setGeometry({
geometry.x - 2, geometry.y,
geometry.width + 4, geometry.height

View File

@ -14,7 +14,7 @@ struct pHorizontalSlider : public pWidget {
Size minimumSize();
unsigned position();
void setGeometry(const Geometry& geometry);
void setGeometry(Geometry geometry);
void setLength(unsigned length);
void setPosition(unsigned position);

View File

@ -21,7 +21,7 @@ Size pLabel::minimumSize() {
return {size.width, size.height};
}
void pLabel::setGeometry(const Geometry& geometry) {
void pLabel::setGeometry(Geometry geometry) {
//NSTextField does not support vertical text centering:
//simulate this by adjusting the geometry placement (reduce height, move view down)
unsigned height = Font::size(label.font(), " ").height;
@ -40,7 +40,7 @@ void pLabel::setGeometry(const Geometry& geometry) {
});
}
void pLabel::setText(const string& text) {
void pLabel::setText(string text) {
@autoreleasepool {
[cocoaView setStringValue:[NSString stringWithUTF8String:text]];
}

View File

@ -12,8 +12,8 @@ struct pLabel : public pWidget {
CocoaLabel* cocoaLabel = nullptr;
Size minimumSize();
void setGeometry(const Geometry& geometry);
void setText(const string& text);
void setGeometry(Geometry geometry);
void setText(string text);
pLabel(Label& label) : pWidget(label), label(label) {}
void constructor();

View File

@ -37,7 +37,7 @@ void pLineEdit::setEditable(bool editable) {
}
}
void pLineEdit::setText(const string& text) {
void pLineEdit::setText(string text) {
@autoreleasepool {
[cocoaView setStringValue:[NSString stringWithUTF8String:text]];
}

View File

@ -15,7 +15,7 @@ struct pLineEdit : public pWidget {
Size minimumSize();
void setEditable(bool editable);
void setText(const string& text);
void setText(string text);
string text();
pLineEdit(LineEdit& lineEdit) : pWidget(lineEdit), lineEdit(lineEdit) {}

View File

@ -285,7 +285,7 @@ void pListView::setChecked(unsigned row, bool checked) {
}
}
void pListView::setFont(const string& font) {
void pListView::setFont(string font) {
@autoreleasepool {
[cocoaView setFont:pFont::cocoaFont(font)];
}

View File

@ -50,7 +50,7 @@ struct pListView : public pWidget {
unsigned selection();
void setCheckable(bool checkable);
void setChecked(unsigned row, bool checked);
void setFont(const string& font);
void setFont(string font);
void setHeaderText(const lstring& text);
void setHeaderVisible(bool visible);
void setImage(unsigned row, unsigned column, const image& image);

View File

@ -40,7 +40,7 @@ void pRadioButton::setChecked() {
}
}
void pRadioButton::setGeometry(const Geometry& geometry) {
void pRadioButton::setGeometry(Geometry geometry) {
pWidget::setGeometry({
geometry.x - 1, geometry.y,
geometry.width + 2, geometry.height
@ -50,7 +50,7 @@ void pRadioButton::setGeometry(const Geometry& geometry) {
void pRadioButton::setGroup(const group<RadioButton>& group) {
}
void pRadioButton::setText(const string& text) {
void pRadioButton::setText(string text) {
@autoreleasepool {
[cocoaView setTitle:[NSString stringWithUTF8String:text]];
}

View File

@ -15,9 +15,9 @@ struct pRadioButton : public pWidget {
bool checked();
Size minimumSize();
void setChecked();
void setGeometry(const Geometry& geometry);
void setGeometry(Geometry geometry);
void setGroup(const group<RadioButton>& group);
void setText(const string& text);
void setText(string text);
pRadioButton(RadioButton& radioButton) : pWidget(radioButton), radioButton(radioButton) {}
void constructor();

View File

@ -57,13 +57,13 @@ void pTextEdit::setEditable(bool editable) {
}
}
void pTextEdit::setFont(const string& font) {
void pTextEdit::setFont(string font) {
@autoreleasepool {
[[cocoaView content] setFont:pFont::cocoaFont(font)];
}
}
void pTextEdit::setText(const string& text) {
void pTextEdit::setText(string text) {
@autoreleasepool {
[[cocoaView content] setString:[NSString stringWithUTF8String:text]];
}

View File

@ -17,8 +17,8 @@ struct pTextEdit : public pWidget {
void setCursorPosition(unsigned position);
void setEditable(bool editable);
void setFont(const string& font);
void setText(const string& text);
void setFont(string font);
void setText(string text);
void setWordWrap(bool wordWrap);
string text();

View File

@ -30,7 +30,7 @@ unsigned pVerticalSlider::position() {
}
}
void pVerticalSlider::setGeometry(const Geometry& geometry) {
void pVerticalSlider::setGeometry(Geometry geometry) {
pWidget::setGeometry({
geometry.x, geometry.y - 2,
geometry.width, geometry.height + 4

View File

@ -14,7 +14,7 @@ struct pVerticalSlider : public pWidget {
Size minimumSize();
unsigned position();
void setGeometry(const Geometry& geometry);
void setGeometry(Geometry geometry);
void setLength(unsigned length);
void setPosition(unsigned position);

View File

@ -16,6 +16,17 @@
return YES;
}
-(NSDragOperation) draggingEntered:(id<NSDraggingInfo>)sender {
return DropPathsOperation(sender);
}
-(BOOL) performDragOperation:(id<NSDraggingInfo>)sender {
lstring paths = DropPaths(sender);
if(paths.empty()) return NO;
if(viewport->onDrop) viewport->onDrop(paths);
return YES;
}
-(void) keyDown:(NSEvent*)event {
}
@ -30,6 +41,16 @@ uintptr_t pViewport::handle() {
return (uintptr_t)cocoaViewport;
}
void pViewport::setDroppable(bool droppable) {
@autoreleasepool {
if(droppable) {
[cocoaViewport registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
} else {
[cocoaViewport unregisterDraggedTypes];
}
}
}
void pViewport::constructor() {
@autoreleasepool {
cocoaView = cocoaViewport = [[CocoaViewport alloc] initWith:viewport];

View File

@ -5,6 +5,8 @@
-(id) initWith:(phoenix::Viewport&)viewport;
-(void) drawRect:(NSRect)rect;
-(BOOL) acceptsFirstResponder;
-(NSDragOperation) draggingEntered:(id<NSDraggingInfo>)sender;
-(BOOL) performDragOperation:(id<NSDraggingInfo>)sender;
-(void) keyDown:(NSEvent*)event;
-(void) keyUp:(NSEvent*)event;
@end
@ -16,6 +18,7 @@ struct pViewport : public pWidget {
CocoaViewport* cocoaViewport = nullptr;
uintptr_t handle();
void setDroppable(bool droppable);
pViewport(Viewport& viewport) : pWidget(viewport), viewport(viewport) {}
void constructor();

View File

@ -33,7 +33,7 @@ void pWidget::setFocused() {
}
}
void pWidget::setFont(const string& font) {
void pWidget::setFont(string font) {
@autoreleasepool {
if([cocoaView respondsToSelector:@selector(setFont:)]) {
[cocoaView setFont:pFont::cocoaFont(font)];
@ -41,7 +41,7 @@ void pWidget::setFont(const string& font) {
}
}
void pWidget::setGeometry(const Geometry& geometry) {
void pWidget::setGeometry(Geometry geometry) {
@autoreleasepool {
CGFloat windowHeight = [[cocoaView superview] frame].size.height;
[cocoaView setFrame:NSMakeRect(geometry.x, windowHeight - geometry.y - geometry.height, geometry.width, geometry.height)];

View File

@ -9,8 +9,8 @@ struct pWidget : public pSizable {
virtual Size minimumSize();
void setEnabled(bool enabled);
void setFocused();
virtual void setFont(const string& font);
virtual void setGeometry(const Geometry& geometry);
virtual void setFont(string font);
virtual void setGeometry(Geometry geometry);
void setVisible(bool visible);
pWidget(Widget& widget) : pSizable(widget), widget(widget) {}

View File

@ -105,6 +105,17 @@
return NO;
}
-(NSDragOperation) draggingEntered:(id<NSDraggingInfo>)sender {
return DropPathsOperation(sender);
}
-(BOOL) performDragOperation:(id<NSDraggingInfo>)sender {
lstring paths = DropPaths(sender);
if(paths.empty()) return NO;
if(window->onDrop) window->onDrop(paths);
return YES;
}
-(NSMenu*) menuBar {
return menuBar;
}
@ -217,7 +228,7 @@ void pWindow::remove(Widget& widget) {
}
}
void pWindow::setBackgroundColor(const Color& color) {
void pWindow::setBackgroundColor(Color color) {
@autoreleasepool {
[cocoaWindow
setBackgroundColor:[NSColor
@ -230,6 +241,16 @@ void pWindow::setBackgroundColor(const Color& color) {
}
}
void pWindow::setDroppable(bool droppable) {
@autoreleasepool {
if(droppable) {
[cocoaWindow registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
} else {
[cocoaWindow unregisterDraggedTypes];
}
}
}
void pWindow::setFocused() {
@autoreleasepool {
[cocoaWindow makeKeyAndOrderFront:nil];
@ -250,7 +271,7 @@ void pWindow::setFullScreen(bool fullScreen) {
}
}
void pWindow::setGeometry(const Geometry& geometry) {
void pWindow::setGeometry(Geometry geometry) {
locked = true;
@autoreleasepool {
@ -276,7 +297,7 @@ void pWindow::setGeometry(const Geometry& geometry) {
locked = false;
}
void pWindow::setMenuFont(const string& font) {
void pWindow::setMenuFont(string font) {
}
void pWindow::setMenuVisible(bool visible) {
@ -302,14 +323,14 @@ void pWindow::setResizable(bool resizable) {
}
}
void pWindow::setStatusFont(const string& font) {
void pWindow::setStatusFont(string font) {
@autoreleasepool {
[[cocoaWindow statusBar] setFont:pFont::cocoaFont(font)];
}
statusBarReposition();
}
void pWindow::setStatusText(const string& text) {
void pWindow::setStatusText(string text) {
@autoreleasepool {
[[cocoaWindow statusBar] setStringValue:[NSString stringWithUTF8String:text]];
}
@ -322,7 +343,7 @@ void pWindow::setStatusVisible(bool visible) {
}
}
void pWindow::setTitle(const string& text) {
void pWindow::setTitle(string text) {
@autoreleasepool {
[cocoaWindow setTitle:[NSString stringWithUTF8String:text]];
}
@ -335,7 +356,7 @@ void pWindow::setVisible(bool visible) {
}
}
void pWindow::setWidgetFont(const string& font) {
void pWindow::setWidgetFont(string font) {
}
void pWindow::constructor() {

View File

@ -12,6 +12,8 @@
-(void) windowDidMove:(NSNotification*)notification;
-(void) windowDidResize:(NSNotification*)notification;
-(BOOL) windowShouldClose:(id)sender;
-(NSDragOperation) draggingEntered:(id<NSDraggingInfo>)sender;
-(BOOL) performDragOperation:(id<NSDraggingInfo>)sender;
-(NSMenu*) menuBar;
-(void) menuAbout;
-(void) menuPreferences;
@ -37,20 +39,21 @@ struct pWindow : public pObject {
void remove(Layout& layout);
void remove(Menu& menu);
void remove(Widget& widget);
void setBackgroundColor(const Color& color);
void setBackgroundColor(Color color);
void setDroppable(bool droppable);
void setFocused();
void setFullScreen(bool fullScreen);
void setGeometry(const Geometry& geometry);
void setMenuFont(const string& font);
void setGeometry(Geometry geometry);
void setMenuFont(string font);
void setMenuVisible(bool visible);
void setModal(bool modal);
void setResizable(bool resizable);
void setStatusFont(const string& font);
void setStatusText(const string& text);
void setStatusFont(string font);
void setStatusText(string text);
void setStatusVisible(bool visible);
void setTitle(const string& text);
void setTitle(string text);
void setVisible(bool visible);
void setWidgetFont(const string& font);
void setWidgetFont(string font);
pWindow(Window& window) : pObject(window), window(window) {}
void constructor();

View File

@ -39,6 +39,9 @@ namespace phoenix {
function<void ()> Application::main;
function<void ()> Application::Windows::onModalBegin;
function<void ()> Application::Windows::onModalEnd;
function<void ()> Application::Cocoa::onAbout;
function<void ()> Application::Cocoa::onActivate;
function<void ()> Application::Cocoa::onPreferences;
@ -377,13 +380,18 @@ void Window::remove_(Widget& widget) {
}
}
void Window::setBackgroundColor(const Color& color) {
void Window::setBackgroundColor(Color color) {
state.backgroundColorOverride = true;
state.backgroundColor = color;
return p.setBackgroundColor(color);
}
void Window::setFrameGeometry(const Geometry& geometry) {
void Window::setDroppable(bool droppable) {
state.droppable = droppable;
return p.setDroppable(droppable);
}
void Window::setFrameGeometry(Geometry geometry) {
Geometry margin = p.frameMargin();
return setGeometry({
geometry.x + margin.x, geometry.y + margin.y,
@ -400,7 +408,7 @@ void Window::setFullScreen(bool fullScreen) {
return p.setFullScreen(fullScreen);
}
void Window::setGeometry(const Geometry& geometry) {
void Window::setGeometry(Geometry geometry) {
state.geometry = geometry;
return p.setGeometry(geometry);
}
@ -425,7 +433,7 @@ void Window::setResizable(bool resizable) {
return p.setResizable(resizable);
}
void Window::setSmartGeometry(const Geometry& geometry) {
void Window::setSmartGeometry(Geometry geometry) {
Geometry margin = p.frameMargin();
return setGeometry({
geometry.x + margin.x, geometry.y + margin.y,
@ -790,7 +798,7 @@ void Widget::setFont(string font) {
return p.setFont(font);
}
void Widget::setGeometry(const Geometry& geometry) {
void Widget::setGeometry(Geometry geometry) {
state.geometry = geometry;
return p.setGeometry(geometry);
}
@ -860,6 +868,11 @@ uint32_t* Canvas::data() {
return state.data;
}
void Canvas::setDroppable(bool droppable) {
state.droppable = droppable;
return p.setDroppable(droppable);
}
bool Canvas::setImage(const nall::image& image) {
if(image.data == nullptr || image.width == 0 || image.height == 0) return false;
state.width = image.width;
@ -869,7 +882,7 @@ bool Canvas::setImage(const nall::image& image) {
return true;
}
void Canvas::setSize(const Size& size) {
void Canvas::setSize(Size size) {
state.width = size.width;
state.height = size.height;
delete[] state.data;
@ -1416,7 +1429,13 @@ uintptr_t Viewport::handle() {
return p.handle();
}
void Viewport::setDroppable(bool droppable) {
state.droppable = droppable;
return p.setDroppable(droppable);
}
Viewport::Viewport():
state(*new State),
base_from_member<pViewport&>(*new pViewport(*this)),
Widget(base_from_member<pViewport&>::value),
p(base_from_member<pViewport&>::value) {
@ -1425,6 +1444,7 @@ p(base_from_member<pViewport&>::value) {
Viewport::~Viewport() {
p.destructor();
delete &state;
}
}

View File

@ -64,6 +64,11 @@ struct Application {
struct State;
static void initialize();
struct Windows {
static nall::function<void ()> onModalBegin;
static nall::function<void ()> onModalEnd;
};
struct Cocoa {
static nall::function<void ()> onAbout;
static nall::function<void ()> onActivate;
@ -72,8 +77,6 @@ struct Application {
};
};
typedef Application App;
enum : unsigned {
MaximumSize = ~0u,
MinimumSize = 0u,
@ -106,7 +109,7 @@ struct Geometry {
Size size() const;
nall::string text() const;
inline Geometry() : x(0), y(0), width(0), height(0) {}
inline Geometry(const Position& position, const Size& size) : x(position.x), y(position.y), width(size.width), height(size.height) {}
inline Geometry(Position position, Size size) : x(position.x), y(position.y), width(size.width), height(size.height) {}
template<typename X, typename Y, typename W, typename H> inline Geometry(X x, Y y, W width, H height) : x(x), y(y), width(width), height(height) {}
Geometry(nall::string text);
};
@ -212,6 +215,7 @@ struct Timer : private nall::base_from_member<pTimer&>, Object {
struct Window : private nall::base_from_member<pWindow&>, Object {
nall::function<void ()> onClose;
nall::function<void (nall::lstring)> onDrop;
nall::function<void (Keyboard::Keycode)> onKeyPress;
nall::function<void (Keyboard::Keycode)> onKeyRelease;
nall::function<void ()> onMove;
@ -236,16 +240,17 @@ struct Window : private nall::base_from_member<pWindow&>, Object {
void remove_(Layout& layout);
void remove_(Menu& menu);
void remove_(Widget& widget);
void setBackgroundColor(const Color& color);
void setFrameGeometry(const Geometry& geometry);
void setBackgroundColor(Color color);
void setDroppable(bool droppable = true);
void setFrameGeometry(Geometry geometry);
void setFocused();
void setFullScreen(bool fullScreen = true);
void setGeometry(const Geometry& geometry);
void setGeometry(Geometry geometry);
void setMenuFont(nall::string font);
void setMenuVisible(bool visible = true);
void setModal(bool modal = true);
void setResizable(bool resizable = true);
void setSmartGeometry(const Geometry& geometry);
void setSmartGeometry(Geometry geometry);
void setStatusFont(nall::string font);
void setStatusText(nall::string text);
void setStatusVisible(bool visible = true);
@ -348,7 +353,7 @@ struct Sizable : Object {
Layout* layout();
virtual Size minimumSize() = 0;
virtual void setEnabled(bool enabled = true) = 0;
virtual void setGeometry(const Geometry& geometry) = 0;
virtual void setGeometry(Geometry geometry) = 0;
virtual void setVisible(bool visible = true) = 0;
virtual bool visible() = 0;
Window* window();
@ -383,7 +388,7 @@ struct Widget : private nall::base_from_member<pWidget&>, Sizable {
void setEnabled(bool enabled = true);
void setFocused();
void setFont(nall::string font);
void setGeometry(const Geometry& geometry);
void setGeometry(Geometry geometry);
void setVisible(bool visible = true);
bool visible();
@ -409,14 +414,16 @@ struct Button : private nall::base_from_member<pButton&>, Widget {
};
struct Canvas : private nall::base_from_member<pCanvas&>, Widget {
nall::function<void (nall::lstring)> onDrop;
nall::function<void ()> onMouseLeave;
nall::function<void (Position)> onMouseMove;
nall::function<void (Mouse::Button)> onMousePress;
nall::function<void (Mouse::Button)> onMouseRelease;
uint32_t* data();
void setDroppable(bool droppable = true);
bool setImage(const nall::image& image);
void setSize(const Size& size);
void setSize(Size size);
Size size();
void update();
@ -641,15 +648,19 @@ struct VerticalSlider : private nall::base_from_member<pVerticalSlider&>, Widget
};
struct Viewport : private nall::base_from_member<pViewport&>, Widget {
nall::function<void (nall::lstring)> onDrop;
nall::function<void ()> onMouseLeave;
nall::function<void (Position)> onMouseMove;
nall::function<void (Mouse::Button)> onMousePress;
nall::function<void (Mouse::Button)> onMouseRelease;
uintptr_t handle();
void setDroppable(bool droppable = true);
Viewport();
~Viewport();
struct State;
State& state;
pViewport& p;
};

View File

@ -1,4 +1,4 @@
void FixedLayout::append(Sizable& sizable, const Geometry& geometry) {
void FixedLayout::append(Sizable& sizable, Geometry geometry) {
children.append({&sizable, geometry});
synchronizeLayout();
if(window()) window()->synchronizeLayout();
@ -48,7 +48,7 @@ void FixedLayout::setEnabled(bool enabled) {
}
}
void FixedLayout::setGeometry(const Geometry& geometry) {
void FixedLayout::setGeometry(Geometry geometry) {
}
void FixedLayout::setVisible(bool visible) {

View File

@ -1,12 +1,12 @@
struct FixedLayout : Layout {
void append(Sizable& sizable, const Geometry& geometry);
void append(Sizable& sizable, Geometry geometry);
void append(Sizable& sizable);
bool enabled();
Size minimumSize();
void remove(Sizable& sizable);
void reset();
void setEnabled(bool enabled = true);
void setGeometry(const Geometry& geometry);
void setGeometry(Geometry geometry);
void setVisible(bool visible = true);
void synchronizeLayout();
bool visible();

View File

@ -1,4 +1,4 @@
void HorizontalLayout::append(Sizable& sizable, const Size& size, unsigned spacing) {
void HorizontalLayout::append(Sizable& sizable, Size size, unsigned spacing) {
for(auto& child : children) if(child.sizable == &sizable) return;
children.append({&sizable, size.width, size.height, spacing});
synchronizeLayout();
@ -72,7 +72,7 @@ void HorizontalLayout::setEnabled(bool enabled) {
}
}
void HorizontalLayout::setGeometry(const Geometry& containerGeometry) {
void HorizontalLayout::setGeometry(Geometry containerGeometry) {
auto children = this->children;
for(auto& child : children) {
if(child.width == MinimumSize) child.width = child.sizable->minimumSize().width;

View File

@ -1,5 +1,5 @@
struct HorizontalLayout : public Layout {
void append(Sizable& sizable, const Size& size, unsigned spacing = 0);
void append(Sizable& sizable, Size size, unsigned spacing = 0);
void append(Sizable& sizable);
bool enabled();
Size minimumSize();
@ -7,7 +7,7 @@ struct HorizontalLayout : public Layout {
void reset();
void setAlignment(double alignment);
void setEnabled(bool enabled = true);
void setGeometry(const Geometry& geometry);
void setGeometry(Geometry geometry);
void setMargin(unsigned margin);
void setVisible(bool visible = true);
void synchronizeLayout();

View File

@ -1,4 +1,4 @@
void VerticalLayout::append(Sizable& sizable, const Size& size, unsigned spacing) {
void VerticalLayout::append(Sizable& sizable, Size size, unsigned spacing) {
for(auto& child : children) if(child.sizable == &sizable) return;
children.append({&sizable, size.width, size.height, spacing});
synchronizeLayout();
@ -72,7 +72,7 @@ void VerticalLayout::setEnabled(bool enabled) {
}
}
void VerticalLayout::setGeometry(const Geometry& containerGeometry) {
void VerticalLayout::setGeometry(Geometry containerGeometry) {
auto children = this->children;
for(auto& child : children) {
if(child.width == MinimumSize) child.width = child.sizable->minimumSize().width;

View File

@ -1,5 +1,5 @@
struct VerticalLayout : public Layout {
void append(Sizable& sizable, const Size& size, unsigned spacing = 0);
void append(Sizable& sizable, Size size, unsigned spacing = 0);
void append(Sizable& sizable);
bool enabled();
Size minimumSize();
@ -7,7 +7,7 @@ struct VerticalLayout : public Layout {
void reset();
void setAlignment(double alignment);
void setEnabled(bool enabled = true);
void setGeometry(const Geometry& geometry);
void setGeometry(Geometry geometry);
void setMargin(unsigned margin);
void setVisible(bool visible = true);
void synchronizeLayout();

View File

@ -25,6 +25,7 @@ struct MessageWindow::State {
struct Window::State {
bool backgroundColorOverride = false;
Color backgroundColor = {0, 0, 0, 255};
bool droppable = false;
bool fullScreen = false;
Geometry geometry = {128, 128, 256, 256};
group<Layout> layout;
@ -95,6 +96,7 @@ struct Button::State {
struct Canvas::State {
uint32_t* data = nullptr;
bool droppable = false;
unsigned width = 256;
unsigned height = 256;
};
@ -172,3 +174,7 @@ struct VerticalSlider::State {
unsigned length = 101;
unsigned position = 0;
};
struct Viewport::State {
bool droppable = false;
};

View File

@ -24,7 +24,7 @@ string pAction::mnemonic(string text) {
return text;
}
void pAction::setFont(const string& font) {
void pAction::setFont(string font) {
pFont::setFont(widget, font);
}

View File

@ -36,8 +36,8 @@ PangoFontDescription* pFont::create(string description) {
if(part[0] != "") family = part[0];
if(part.size() >= 2) size = decimal(part[1]);
if(part.size() >= 3) bold = part[2].position("Bold");
if(part.size() >= 3) italic = part[2].position("Italic");
if(part.size() >= 3) bold = part[2].find("Bold");
if(part.size() >= 3) italic = part[2].find("Italic");
PangoFontDescription* font = pango_font_description_new();
pango_font_description_set_family(font, family);

View File

@ -124,10 +124,11 @@ struct pWindow : public pObject {
void remove(Layout& layout);
void remove(Menu& menu);
void remove(Widget& widget);
void setBackgroundColor(const Color& color);
void setBackgroundColor(Color color);
void setDroppable(bool droppable);
void setFocused();
void setFullScreen(bool fullScreen);
void setGeometry(const Geometry& geometry);
void setGeometry(Geometry geometry);
void setMenuFont(string font);
void setMenuVisible(bool visible);
void setModal(bool modal);
@ -156,7 +157,7 @@ struct pAction : public pObject {
void constructor();
virtual void orphan();
string mnemonic(string text);
virtual void setFont(const string &font);
virtual void setFont(string font);
};
struct pMenu : public pAction {
@ -245,7 +246,7 @@ struct pWidget : public pSizable {
void setEnabled(bool enabled);
virtual void setFocused();
virtual void setFont(string font);
virtual void setGeometry(const Geometry& geometry);
virtual void setGeometry(Geometry geometry);
void setVisible(bool visible);
pWidget(Widget& widget) : pSizable(widget), widget(widget) {}
@ -271,7 +272,8 @@ struct pCanvas : public pWidget {
Canvas& canvas;
cairo_surface_t* surface;
void setSize(const Size& size);
void setDroppable(bool droppable);
void setSize(Size size);
void update();
pCanvas(Canvas& canvas) : pWidget(canvas), canvas(canvas) {}
@ -510,6 +512,7 @@ struct pViewport : public pWidget {
Viewport& viewport;
uintptr_t handle();
void setDroppable(bool droppable);
pViewport(Viewport& viewport) : pWidget(viewport), viewport(viewport) {}
void constructor();

View File

@ -18,6 +18,25 @@ static GtkImage* CreateImage(const nall::image& image, bool scale = false) {
return gtkImage;
}
static lstring DropPaths(GtkSelectionData* data) {
gchar** uris = gtk_selection_data_get_uris(data);
if(uris == nullptr) return {};
lstring paths;
for(unsigned n = 0; uris[n] != nullptr; n++) {
gchar* pathname = g_filename_from_uri(uris[n], nullptr, nullptr);
if(pathname == nullptr) continue;
string path = pathname;
g_free(pathname);
if(directory::exists(path) && !path.endswith("/")) path.append("/");
paths.append(path);
}
g_strfreev(uris);
return paths;
}
static Keyboard::Keycode Keysym(unsigned keysym) {
switch(keysym) {
case GDK_Escape: return Keyboard::Keycode::Escape;

View File

@ -8,6 +8,14 @@ static gboolean Canvas_expose(GtkWidget* widget, GdkEvent* event, pCanvas* self)
return true;
}
static void Canvas_dropEvent(GtkWidget* widget, GdkDragContext* context, gint x, gint y,
GtkSelectionData* data, guint type, guint timestamp, Canvas* canvas) {
if(canvas->state.droppable == false) return;
lstring paths = DropPaths(data);
if(paths.empty()) return;
if(canvas->onDrop) canvas->onDrop(paths);
}
static gboolean Canvas_mouseLeave(GtkWidget* widget, GdkEventButton* event, pCanvas* self) {
if(self->canvas.onMouseLeave) self->canvas.onMouseLeave();
return true;
@ -36,7 +44,12 @@ static gboolean Canvas_mouseRelease(GtkWidget* widget, GdkEventButton* event, pC
return true;
}
void pCanvas::setSize(const Size& size) {
void pCanvas::setDroppable(bool droppable) {
gtk_drag_dest_set(gtkWidget, GTK_DEST_DEFAULT_ALL, nullptr, 0, GDK_ACTION_COPY);
if(droppable) gtk_drag_dest_add_uri_targets(gtkWidget);
}
void pCanvas::setSize(Size size) {
cairo_surface_destroy(surface);
surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, canvas.state.width, canvas.state.height);
}
@ -54,6 +67,7 @@ void pCanvas::constructor() {
gtk_widget_set_double_buffered(gtkWidget, false);
gtk_widget_add_events(gtkWidget,
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK);
g_signal_connect(G_OBJECT(gtkWidget), "drag-data-received", G_CALLBACK(Canvas_dropEvent), (gpointer)&canvas);
g_signal_connect(G_OBJECT(gtkWidget), "button_press_event", G_CALLBACK(Canvas_mousePress), (gpointer)this);
g_signal_connect(G_OBJECT(gtkWidget), "button_release_event", G_CALLBACK(Canvas_mouseRelease), (gpointer)this);
g_signal_connect(G_OBJECT(gtkWidget), "expose_event", G_CALLBACK(Canvas_expose), (gpointer)this);

View File

@ -1,5 +1,13 @@
namespace phoenix {
static void Viewport_dropEvent(GtkWidget* widget, GdkDragContext* context, gint x, gint y,
GtkSelectionData* data, guint type, guint timestamp, Viewport* viewport) {
if(viewport->state.droppable == false) return;
lstring paths = DropPaths(data);
if(paths.empty()) return;
if(viewport->onDrop) viewport->onDrop(paths);
}
static gboolean Viewport_mouseLeave(GtkWidget* widget, GdkEventButton* event, pViewport* self) {
if(self->viewport.onMouseLeave) self->viewport.onMouseLeave();
return true;
@ -32,11 +40,17 @@ uintptr_t pViewport::handle() {
return GDK_WINDOW_XID(gtk_widget_get_window(gtkWidget));
}
void pViewport::setDroppable(bool droppable) {
gtk_drag_dest_set(gtkWidget, GTK_DEST_DEFAULT_ALL, nullptr, 0, GDK_ACTION_COPY);
if(droppable) gtk_drag_dest_add_uri_targets(gtkWidget);
}
void pViewport::constructor() {
gtkWidget = gtk_drawing_area_new();
//gtk_widget_set_double_buffered(gtkWidget, false);
gtk_widget_add_events(gtkWidget,
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK);
g_signal_connect(G_OBJECT(gtkWidget), "drag-data-received", G_CALLBACK(Viewport_dropEvent), (gpointer)&viewport);
g_signal_connect(G_OBJECT(gtkWidget), "button_press_event", G_CALLBACK(Viewport_mousePress), (gpointer)this);
g_signal_connect(G_OBJECT(gtkWidget), "button_release_event", G_CALLBACK(Viewport_mouseRelease), (gpointer)this);
g_signal_connect(G_OBJECT(gtkWidget), "leave_notify_event", G_CALLBACK(Viewport_mouseLeave), (gpointer)this);

View File

@ -26,7 +26,7 @@ void pWidget::setFont(string font) {
pFont::setFont(gtkWidget, font);
}
void pWidget::setGeometry(const Geometry& geometry) {
void pWidget::setGeometry(Geometry geometry) {
if(sizable.window() && sizable.window()->visible()) gtk_fixed_move(GTK_FIXED(sizable.window()->p.formContainer), gtkWidget, geometry.x, geometry.y);
unsigned width = (signed)geometry.width <= 0 ? 1U : geometry.width;
unsigned height = (signed)geometry.height <= 0 ? 1U : geometry.height;

View File

@ -80,6 +80,14 @@ static gboolean Window_configure(GtkWidget* widget, GdkEvent* event, Window* win
return false;
}
static void Window_dropEvent(GtkWidget* widget, GdkDragContext* context, gint x, gint y,
GtkSelectionData* data, guint type, guint timestamp, Window* window) {
if(window->state.droppable == false) return;
lstring paths = DropPaths(data);
if(paths.empty()) return;
if(window->onDrop) window->onDrop(paths);
}
static gboolean Window_keyPressEvent(GtkWidget* widget, GdkEventKey* event, Window* window) {
Keyboard::Keycode key = Keysym(event->keyval);
if(key != Keyboard::Keycode::None && window->onKeyPress) window->onKeyPress(key);
@ -203,7 +211,7 @@ void pWindow::remove(Widget& widget) {
widget.p.orphan();
}
void pWindow::setBackgroundColor(const Color& color) {
void pWindow::setBackgroundColor(Color color) {
GdkColor gdkColor;
gdkColor.pixel = (color.red << 16) | (color.green << 8) | (color.blue << 0);
gdkColor.red = (color.red << 8) | (color.red << 0);
@ -212,6 +220,11 @@ void pWindow::setBackgroundColor(const Color& color) {
gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &gdkColor);
}
void pWindow::setDroppable(bool droppable) {
gtk_drag_dest_set(widget, GTK_DEST_DEFAULT_ALL, nullptr, 0, GDK_ACTION_COPY);
if(droppable) gtk_drag_dest_add_uri_targets(widget);
}
void pWindow::setFocused() {
gtk_window_present(GTK_WINDOW(widget));
}
@ -224,7 +237,7 @@ void pWindow::setFullScreen(bool fullScreen) {
}
}
void pWindow::setGeometry(const Geometry& geometry) {
void pWindow::setGeometry(Geometry geometry) {
Geometry margin = frameMargin();
gtk_window_move(GTK_WINDOW(widget), geometry.x - margin.x, geometry.y - margin.y);
@ -362,6 +375,7 @@ void pWindow::constructor() {
g_signal_connect(G_OBJECT(widget), "delete-event", G_CALLBACK(Window_close), (gpointer)&window);
g_signal_connect(G_OBJECT(widget), "expose-event", G_CALLBACK(Window_expose), (gpointer)&window);
g_signal_connect(G_OBJECT(widget), "configure-event", G_CALLBACK(Window_configure), (gpointer)&window);
g_signal_connect(G_OBJECT(widget), "drag-data-received", G_CALLBACK(Window_dropEvent), (gpointer)&window);
g_signal_connect(G_OBJECT(widget), "key-press-event", G_CALLBACK(Window_keyPressEvent), (gpointer)&window);
g_signal_connect(G_OBJECT(widget), "key-release-event", G_CALLBACK(Window_keyPressEvent), (gpointer)&window);

Some files were not shown because too many files have changed in this diff Show More