struct lambda : container {
+ L object;
+ R operator()(P... p) const { return object(std::forward(p)...); }
+ container* copy() const { return new lambda(object); }
+ lambda(const L& object) : object(object) {}
+ };
+
+ public:
+ operator bool() const { return callback; }
+ R operator()(P... p) const { return (*callback)(std::forward
(p)...); }
+ void reset() { if(callback) { delete callback; callback = 0; } }
+
+ function& operator=(const function &source) {
+ if(this != &source) {
+ if(callback) { delete callback; callback = 0; }
+ if(source.callback) callback = source.callback->copy();
+ }
+ return *this;
+ }
+
+ function(const function &source) { operator=(source); }
+ function() : callback(0) {}
+ function(void *function) : callback(0) { if(function) callback = new global((R (*)(P...))function); }
+ function(R (*function)(P...)) { callback = new global(function); }
+ template function(R (C::*function)(P...), C *object) { callback = new member(function, object); }
+ template function(R (C::*function)(P...) const, C *object) { callback = new member((R (C::*)(P...))function, object); }
+ template function(const L& object) { callback = new lambda(object); }
+ ~function() { if(callback) delete callback; }
+ };
+}
+
+#endif
diff --git a/snespurify/nall/input.hpp b/snespurify/nall/input.hpp
new file mode 100755
index 00000000..28b10453
--- /dev/null
+++ b/snespurify/nall/input.hpp
@@ -0,0 +1,386 @@
+#ifndef NALL_INPUT_HPP
+#define NALL_INPUT_HPP
+
+#include
+#include
+#include
+
+#include
+#include
+
+namespace nall {
+
+struct Keyboard;
+Keyboard& keyboard(unsigned = 0);
+
+static const char KeyboardScancodeName[][64] = {
+ "Escape", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
+ "PrintScreen", "ScrollLock", "Pause", "Tilde",
+ "Num1", "Num2", "Num3", "Num4", "Num5", "Num6", "Num7", "Num8", "Num9", "Num0",
+ "Dash", "Equal", "Backspace",
+ "Insert", "Delete", "Home", "End", "PageUp", "PageDown",
+ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
+ "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
+ "LeftBracket", "RightBracket", "Backslash", "Semicolon", "Apostrophe", "Comma", "Period", "Slash",
+ "Keypad1", "Keypad2", "Keypad3", "Keypad4", "Keypad5", "Keypad6", "Keypad7", "Keypad8", "Keypad9", "Keypad0",
+ "Point", "Enter", "Add", "Subtract", "Multiply", "Divide",
+ "NumLock", "CapsLock",
+ "Up", "Down", "Left", "Right",
+ "Tab", "Return", "Spacebar", "Menu",
+ "Shift", "Control", "Alt", "Super",
+};
+
+struct Keyboard {
+ const unsigned ID;
+ enum { Base = 1 };
+ enum { Count = 8, Size = 128 };
+
+ enum Scancode {
+ Escape, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
+ PrintScreen, ScrollLock, Pause, Tilde,
+ Num1, Num2, Num3, Num4, Num5, Num6, Num7, Num8, Num9, Num0,
+ Dash, Equal, Backspace,
+ Insert, Delete, Home, End, PageUp, PageDown,
+ A, B, C, D, E, F, G, H, I, J, K, L, M,
+ N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
+ LeftBracket, RightBracket, Backslash, Semicolon, Apostrophe, Comma, Period, Slash,
+ Keypad1, Keypad2, Keypad3, Keypad4, Keypad5, Keypad6, Keypad7, Keypad8, Keypad9, Keypad0,
+ Point, Enter, Add, Subtract, Multiply, Divide,
+ NumLock, CapsLock,
+ Up, Down, Left, Right,
+ Tab, Return, Spacebar, Menu,
+ Shift, Control, Alt, Super,
+ Limit,
+ };
+
+ static signed numberDecode(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(keyboard(i).belongsTo(scancode)) return i;
+ }
+ return -1;
+ }
+
+ static signed keyDecode(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(keyboard(i).isKey(scancode)) return scancode - keyboard(i).key(Escape);
+ }
+ return -1;
+ }
+
+ static signed modifierDecode(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(keyboard(i).isModifier(scancode)) return scancode - keyboard(i).key(Shift);
+ }
+ return -1;
+ }
+
+ static bool isAnyKey(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(keyboard(i).isKey(scancode)) return true;
+ }
+ return false;
+ }
+
+ static bool isAnyModifier(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(keyboard(i).isModifier(scancode)) return true;
+ }
+ return false;
+ }
+
+ static uint16_t decode(const char *name) {
+ string s(name);
+ if(!strbegin(name, "KB")) return 0;
+ s.ltrim("KB");
+ unsigned id = strunsigned(s);
+ auto pos = strpos(s, "::");
+ if(!pos) return 0;
+ s = substr(s, pos() + 2);
+ for(unsigned i = 0; i < Limit; i++) {
+ if(s == KeyboardScancodeName[i]) return Base + Size * id + i;
+ }
+ return 0;
+ }
+
+ string encode(uint16_t code) const {
+ unsigned index = 0;
+ for(unsigned i = 0; i < Count; i++) {
+ if(code >= Base + Size * i && code < Base + Size * (i + 1)) {
+ index = code - (Base + Size * i);
+ break;
+ }
+ }
+ return string() << "KB" << ID << "::" << KeyboardScancodeName[index];
+ }
+
+ uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
+ uint16_t key(unsigned id) const { return Base + Size * ID + id; }
+ bool isKey(unsigned id) const { return id >= key(Escape) && id <= key(Menu); }
+ bool isModifier(unsigned id) const { return id >= key(Shift) && id <= key(Super); }
+ bool belongsTo(uint16_t scancode) const { return isKey(scancode) || isModifier(scancode); }
+
+ Keyboard(unsigned ID_) : ID(ID_) {}
+};
+
+inline Keyboard& keyboard(unsigned id) {
+ static Keyboard kb0(0), kb1(1), kb2(2), kb3(3), kb4(4), kb5(5), kb6(6), kb7(7);
+ switch(id) { default:
+ case 0: return kb0; case 1: return kb1; case 2: return kb2; case 3: return kb3;
+ case 4: return kb4; case 5: return kb5; case 6: return kb6; case 7: return kb7;
+ }
+}
+
+static const char MouseScancodeName[][64] = {
+ "Xaxis", "Yaxis", "Zaxis",
+ "Button0", "Button1", "Button2", "Button3", "Button4", "Button5", "Button6", "Button7",
+};
+
+struct Mouse;
+Mouse& mouse(unsigned = 0);
+
+struct Mouse {
+ const unsigned ID;
+ enum { Base = Keyboard::Base + Keyboard::Size * Keyboard::Count };
+ enum { Count = 8, Size = 16 };
+ enum { Axes = 3, Buttons = 8 };
+
+ enum Scancode {
+ Xaxis, Yaxis, Zaxis,
+ Button0, Button1, Button2, Button3, Button4, Button5, Button6, Button7,
+ Limit,
+ };
+
+ static signed numberDecode(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(mouse(i).belongsTo(scancode)) return i;
+ }
+ return -1;
+ }
+
+ static signed axisDecode(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(mouse(i).isAxis(scancode)) return scancode - mouse(i).axis(0);
+ }
+ return -1;
+ }
+
+ static signed buttonDecode(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(mouse(i).isButton(scancode)) return scancode - mouse(i).button(0);
+ }
+ return -1;
+ }
+
+ static bool isAnyAxis(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(mouse(i).isAxis(scancode)) return true;
+ }
+ return false;
+ }
+
+ static bool isAnyButton(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(mouse(i).isButton(scancode)) return true;
+ }
+ return false;
+ }
+
+ static uint16_t decode(const char *name) {
+ string s(name);
+ if(!strbegin(name, "MS")) return 0;
+ s.ltrim("MS");
+ unsigned id = strunsigned(s);
+ auto pos = strpos(s, "::");
+ if(!pos) return 0;
+ s = substr(s, pos() + 2);
+ for(unsigned i = 0; i < Limit; i++) {
+ if(s == MouseScancodeName[i]) return Base + Size * id + i;
+ }
+ return 0;
+ }
+
+ string encode(uint16_t code) const {
+ unsigned index = 0;
+ for(unsigned i = 0; i < Count; i++) {
+ if(code >= Base + Size * i && code < Base + Size * (i + 1)) {
+ index = code - (Base + Size * i);
+ break;
+ }
+ }
+ return string() << "MS" << ID << "::" << MouseScancodeName[index];
+ }
+
+ uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
+ uint16_t axis(unsigned id) const { return Base + Size * ID + Xaxis + id; }
+ uint16_t button(unsigned id) const { return Base + Size * ID + Button0 + id; }
+ bool isAxis(unsigned id) const { return id >= axis(0) && id <= axis(2); }
+ bool isButton(unsigned id) const { return id >= button(0) && id <= button(7); }
+ bool belongsTo(uint16_t scancode) const { return isAxis(scancode) || isButton(scancode); }
+
+ Mouse(unsigned ID_) : ID(ID_) {}
+};
+
+inline Mouse& mouse(unsigned id) {
+ static Mouse ms0(0), ms1(1), ms2(2), ms3(3), ms4(4), ms5(5), ms6(6), ms7(7);
+ switch(id) { default:
+ case 0: return ms0; case 1: return ms1; case 2: return ms2; case 3: return ms3;
+ case 4: return ms4; case 5: return ms5; case 6: return ms6; case 7: return ms7;
+ }
+}
+
+static const char JoypadScancodeName[][64] = {
+ "Hat0", "Hat1", "Hat2", "Hat3", "Hat4", "Hat5", "Hat6", "Hat7",
+ "Axis0", "Axis1", "Axis2", "Axis3", "Axis4", "Axis5", "Axis6", "Axis7",
+ "Axis8", "Axis9", "Axis10", "Axis11", "Axis12", "Axis13", "Axis14", "Axis15",
+ "Button0", "Button1", "Button2", "Button3", "Button4", "Button5", "Button6", "Button7",
+ "Button8", "Button9", "Button10", "Button11", "Button12", "Button13", "Button14", "Button15",
+ "Button16", "Button17", "Button18", "Button19", "Button20", "Button21", "Button22", "Button23",
+ "Button24", "Button25", "Button26", "Button27", "Button28", "Button29", "Button30", "Button31",
+};
+
+struct Joypad;
+Joypad& joypad(unsigned = 0);
+
+struct Joypad {
+ const unsigned ID;
+ enum { Base = Mouse::Base + Mouse::Size * Mouse::Count };
+ enum { Count = 8, Size = 64 };
+ enum { Hats = 8, Axes = 16, Buttons = 32 };
+
+ enum Scancode {
+ Hat0, Hat1, Hat2, Hat3, Hat4, Hat5, Hat6, Hat7,
+ Axis0, Axis1, Axis2, Axis3, Axis4, Axis5, Axis6, Axis7,
+ Axis8, Axis9, Axis10, Axis11, Axis12, Axis13, Axis14, Axis15,
+ Button0, Button1, Button2, Button3, Button4, Button5, Button6, Button7,
+ Button8, Button9, Button10, Button11, Button12, Button13, Button14, Button15,
+ Button16, Button17, Button18, Button19, Button20, Button21, Button22, Button23,
+ Button24, Button25, Button26, Button27, Button28, Button29, Button30, Button31,
+ Limit,
+ };
+
+ enum Hat { HatCenter = 0, HatUp = 1, HatRight = 2, HatDown = 4, HatLeft = 8 };
+
+ static signed numberDecode(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(joypad(i).belongsTo(scancode)) return i;
+ }
+ return -1;
+ }
+
+ static signed hatDecode(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(joypad(i).isHat(scancode)) return scancode - joypad(i).hat(0);
+ }
+ return -1;
+ }
+
+ static signed axisDecode(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(joypad(i).isAxis(scancode)) return scancode - joypad(i).axis(0);
+ }
+ return -1;
+ }
+
+ static signed buttonDecode(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(joypad(i).isButton(scancode)) return scancode - joypad(i).button(0);
+ }
+ return -1;
+ }
+
+ static bool isAnyHat(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(joypad(i).isHat(scancode)) return true;
+ }
+ return false;
+ }
+
+ static bool isAnyAxis(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(joypad(i).isAxis(scancode)) return true;
+ }
+ return false;
+ }
+
+ static bool isAnyButton(uint16_t scancode) {
+ for(unsigned i = 0; i < Count; i++) {
+ if(joypad(i).isButton(scancode)) return true;
+ }
+ return false;
+ }
+
+ static uint16_t decode(const char *name) {
+ string s(name);
+ if(!strbegin(name, "JP")) return 0;
+ s.ltrim("JP");
+ unsigned id = strunsigned(s);
+ auto pos = strpos(s, "::");
+ if(!pos) return 0;
+ s = substr(s, pos() + 2);
+ for(unsigned i = 0; i < Limit; i++) {
+ if(s == JoypadScancodeName[i]) return Base + Size * id + i;
+ }
+ return 0;
+ }
+
+ string encode(uint16_t code) const {
+ unsigned index = 0;
+ for(unsigned i = 0; i < Count; i++) {
+ if(code >= Base + Size * i && code < Base + Size * (i + 1)) {
+ index = code - (Base + Size * i);
+ }
+ }
+ return string() << "JP" << ID << "::" << JoypadScancodeName[index];
+ }
+
+ uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
+ uint16_t hat(unsigned id) const { return Base + Size * ID + Hat0 + id; }
+ uint16_t axis(unsigned id) const { return Base + Size * ID + Axis0 + id; }
+ uint16_t button(unsigned id) const { return Base + Size * ID + Button0 + id; }
+ bool isHat(unsigned id) const { return id >= hat(0) && id <= hat(7); }
+ bool isAxis(unsigned id) const { return id >= axis(0) && id <= axis(15); }
+ bool isButton(unsigned id) const { return id >= button(0) && id <= button(31); }
+ bool belongsTo(uint16_t scancode) const { return isHat(scancode) || isAxis(scancode) || isButton(scancode); }
+
+ Joypad(unsigned ID_) : ID(ID_) {}
+};
+
+inline Joypad& joypad(unsigned id) {
+ static Joypad jp0(0), jp1(1), jp2(2), jp3(3), jp4(4), jp5(5), jp6(6), jp7(7);
+ switch(id) { default:
+ case 0: return jp0; case 1: return jp1; case 2: return jp2; case 3: return jp3;
+ case 4: return jp4; case 5: return jp5; case 6: return jp6; case 7: return jp7;
+ }
+}
+
+struct Scancode {
+ enum { None = 0, Limit = Joypad::Base + Joypad::Size * Joypad::Count };
+
+ static uint16_t decode(const char *name) {
+ uint16_t code;
+ code = Keyboard::decode(name);
+ if(code) return code;
+ code = Mouse::decode(name);
+ if(code) return code;
+ code = Joypad::decode(name);
+ if(code) return code;
+ return None;
+ }
+
+ static string encode(uint16_t code) {
+ for(unsigned i = 0; i < Keyboard::Count; i++) {
+ if(keyboard(i).belongsTo(code)) return keyboard(i).encode(code);
+ }
+ for(unsigned i = 0; i < Mouse::Count; i++) {
+ if(mouse(i).belongsTo(code)) return mouse(i).encode(code);
+ }
+ for(unsigned i = 0; i < Joypad::Count; i++) {
+ if(joypad(i).belongsTo(code)) return joypad(i).encode(code);
+ }
+ return "None";
+ }
+};
+
+}
+
+#endif
diff --git a/snespurify/nall/lzss.hpp b/snespurify/nall/lzss.hpp
new file mode 100755
index 00000000..202bc814
--- /dev/null
+++ b/snespurify/nall/lzss.hpp
@@ -0,0 +1,81 @@
+#ifndef NALL_LZSS_HPP
+#define NALL_LZSS_HPP
+
+#include
+#include
+#include
+
+namespace nall {
+ class lzss {
+ public:
+ static bool encode(uint8_t *&output, unsigned &outlength, const uint8_t *input, unsigned inlength) {
+ output = new(zeromemory) uint8_t[inlength * 9 / 8 + 9];
+
+ unsigned i = 0, o = 0;
+ while(i < inlength) {
+ unsigned flagoffset = o++;
+ uint8_t flag = 0x00;
+
+ for(unsigned b = 0; b < 8 && i < inlength; b++) {
+ unsigned longest = 0, pointer;
+ for(unsigned index = 1; index < 4096; index++) {
+ unsigned count = 0;
+ while(true) {
+ if(count >= 15 + 3) break; //verify pattern match is not longer than max length
+ if(i + count >= inlength) break; //verify pattern match does not read past end of input
+ if(i + count < index) break; //verify read is not before start of input
+ if(input[i + count] != input[i + count - index]) break; //verify pattern still matches
+ count++;
+ }
+
+ if(count > longest) {
+ longest = count;
+ pointer = index;
+ }
+ }
+
+ if(longest < 3) output[o++] = input[i++];
+ else {
+ flag |= 1 << b;
+ uint16_t x = ((longest - 3) << 12) + pointer;
+ output[o++] = x;
+ output[o++] = x >> 8;
+ i += longest;
+ }
+ }
+
+ output[flagoffset] = flag;
+ }
+
+ outlength = o;
+ return true;
+ }
+
+ static bool decode(uint8_t *&output, const uint8_t *input, unsigned length) {
+ output = new(zeromemory) uint8_t[length];
+
+ unsigned i = 0, o = 0;
+ while(o < length) {
+ uint8_t flag = input[i++];
+
+ for(unsigned b = 0; b < 8 && o < length; b++) {
+ if(!(flag & (1 << b))) output[o++] = input[i++];
+ else {
+ uint16_t offset = input[i++];
+ offset += input[i++] << 8;
+ uint16_t lookuplength = (offset >> 12) + 3;
+ offset &= 4095;
+ for(unsigned index = 0; index < lookuplength && o + index < length; index++) {
+ output[o + index] = output[o + index - offset];
+ }
+ o += lookuplength;
+ }
+ }
+ }
+
+ return true;
+ }
+ };
+}
+
+#endif
diff --git a/snespurify/nall/moduloarray.hpp b/snespurify/nall/moduloarray.hpp
new file mode 100755
index 00000000..be549ae9
--- /dev/null
+++ b/snespurify/nall/moduloarray.hpp
@@ -0,0 +1,40 @@
+#ifndef NALL_MODULO_HPP
+#define NALL_MODULO_HPP
+
+#include
+
+namespace nall {
+ template class modulo_array {
+ public:
+ inline T operator[](int index) const {
+ return buffer[size + index];
+ }
+
+ inline T read(int index) const {
+ return buffer[size + index];
+ }
+
+ inline void write(unsigned index, const T value) {
+ buffer[index] =
+ buffer[index + size] =
+ buffer[index + size + size] = value;
+ }
+
+ void serialize(serializer &s) {
+ s.array(buffer, size * 3);
+ }
+
+ modulo_array() {
+ buffer = new T[size * 3]();
+ }
+
+ ~modulo_array() {
+ delete[] buffer;
+ }
+
+ private:
+ T *buffer;
+ };
+}
+
+#endif
diff --git a/snespurify/nall/platform.hpp b/snespurify/nall/platform.hpp
new file mode 100755
index 00000000..72eeec09
--- /dev/null
+++ b/snespurify/nall/platform.hpp
@@ -0,0 +1,122 @@
+#ifndef NALL_PLATFORM_HPP
+#define NALL_PLATFORM_HPP
+
+#include
+
+//=========================
+//standard platform headers
+//=========================
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if defined(_WIN32)
+ #include
+ #include
+ #include
+ #undef interface
+ #define dllexport __declspec(dllexport)
+#else
+ #include
+ #include
+ #include
+ #define dllexport
+#endif
+
+//==================
+//warning supression
+//==================
+
+//Visual C++
+#if defined(_MSC_VER)
+ //disable libc "deprecation" warnings
+ #pragma warning(disable:4996)
+#endif
+
+//================
+//POSIX compliance
+//================
+
+#if defined(_MSC_VER)
+ #define PATH_MAX _MAX_PATH
+ #define va_copy(dest, src) ((dest) = (src))
+#endif
+
+#if defined(_WIN32)
+ #define getcwd _getcwd
+ #define ftruncate _chsize
+ #define putenv _putenv
+ #define mkdir(n, m) _wmkdir(nall::utf16_t(n))
+ #define rmdir _rmdir
+ #define vsnprintf _vsnprintf
+ #define usleep(n) Sleep(n / 1000)
+#endif
+
+//================
+//inline expansion
+//================
+
+#if defined(__GNUC__)
+ #define noinline __attribute__((noinline))
+ #define inline inline
+ #define alwaysinline inline __attribute__((always_inline))
+#elif defined(_MSC_VER)
+ #define noinline __declspec(noinline)
+ #define inline inline
+ #define alwaysinline inline __forceinline
+#else
+ #define noinline
+ #define inline inline
+ #define alwaysinline inline
+#endif
+
+//=========================
+//file system functionality
+//=========================
+
+#if defined(_WIN32)
+ inline char* realpath(const char *filename, char *resolvedname) {
+ wchar_t fn[_MAX_PATH] = L"";
+ _wfullpath(fn, nall::utf16_t(filename), _MAX_PATH);
+ strcpy(resolvedname, nall::utf8_t(fn));
+ return resolvedname;
+ }
+
+ inline char* userpath(char *path) {
+ wchar_t fp[_MAX_PATH] = L"";
+ SHGetFolderPathW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, fp);
+ strcpy(path, nall::utf8_t(fp));
+ return path;
+ }
+
+ inline char* getcwd(char *path) {
+ wchar_t fp[_MAX_PATH] = L"";
+ _wgetcwd(fp, _MAX_PATH);
+ strcpy(path, nall::utf8_t(fp));
+ return path;
+ }
+#else
+ //realpath() already exists
+
+ inline char* userpath(char *path) {
+ *path = 0;
+ struct passwd *userinfo = getpwuid(getuid());
+ if(userinfo) strcpy(path, userinfo->pw_dir);
+ return path;
+ }
+
+ inline char *getcwd(char *path) {
+ return getcwd(path, PATH_MAX);
+ }
+#endif
+
+#endif
+
diff --git a/snespurify/nall/priorityqueue.hpp b/snespurify/nall/priorityqueue.hpp
new file mode 100755
index 00000000..7104e791
--- /dev/null
+++ b/snespurify/nall/priorityqueue.hpp
@@ -0,0 +1,109 @@
+#ifndef NALL_PRIORITYQUEUE_HPP
+#define NALL_PRIORITYQUEUE_HPP
+
+#include
+#include
+#include
+#include
+
+namespace nall {
+ template void priority_queue_nocallback(type_t) {}
+
+ //priority queue implementation using binary min-heap array;
+ //does not require normalize() function.
+ //O(1) find (tick)
+ //O(log n) insert (enqueue)
+ //O(log n) remove (dequeue)
+ template class priority_queue {
+ public:
+ inline void tick(unsigned ticks) {
+ basecounter += ticks;
+ while(heapsize && gte(basecounter, heap[0].counter)) callback(dequeue());
+ }
+
+ //counter is relative to current time (eg enqueue(64, ...) fires in 64 ticks);
+ //counter cannot exceed std::numeric_limits::max() >> 1.
+ void enqueue(unsigned counter, type_t event) {
+ unsigned child = heapsize++;
+ counter += basecounter;
+
+ while(child) {
+ unsigned parent = (child - 1) >> 1;
+ if(gte(counter, heap[parent].counter)) break;
+
+ heap[child].counter = heap[parent].counter;
+ heap[child].event = heap[parent].event;
+ child = parent;
+ }
+
+ heap[child].counter = counter;
+ heap[child].event = event;
+ }
+
+ type_t dequeue() {
+ type_t event(heap[0].event);
+ unsigned parent = 0;
+ unsigned counter = heap[--heapsize].counter;
+
+ while(true) {
+ unsigned child = (parent << 1) + 1;
+ if(child >= heapsize) break;
+ if(child + 1 < heapsize && gte(heap[child].counter, heap[child + 1].counter)) child++;
+ if(gte(heap[child].counter, counter)) break;
+
+ heap[parent].counter = heap[child].counter;
+ heap[parent].event = heap[child].event;
+ parent = child;
+ }
+
+ heap[parent].counter = counter;
+ heap[parent].event = heap[heapsize].event;
+ return event;
+ }
+
+ void reset() {
+ basecounter = 0;
+ heapsize = 0;
+ }
+
+ void serialize(serializer &s) {
+ s.integer(basecounter);
+ s.integer(heapsize);
+ for(unsigned n = 0; n < heapcapacity; n++) {
+ s.integer(heap[n].counter);
+ s.integer(heap[n].event);
+ }
+ }
+
+ priority_queue(unsigned size, function callback_ = &priority_queue_nocallback)
+ : callback(callback_) {
+ heap = new heap_t[size];
+ heapcapacity = size;
+ reset();
+ }
+
+ ~priority_queue() {
+ delete[] heap;
+ }
+
+ priority_queue& operator=(const priority_queue&) = delete;
+ priority_queue(const priority_queue&) = delete;
+
+ private:
+ function callback;
+ unsigned basecounter;
+ unsigned heapsize;
+ unsigned heapcapacity;
+ struct heap_t {
+ unsigned counter;
+ type_t event;
+ } *heap;
+
+ //return true if x is greater than or equal to y
+ inline bool gte(unsigned x, unsigned y) {
+ return x - y < (std::numeric_limits::max() >> 1);
+ }
+ };
+}
+
+#endif
diff --git a/snespurify/nall/property.hpp b/snespurify/nall/property.hpp
new file mode 100755
index 00000000..6fd33acd
--- /dev/null
+++ b/snespurify/nall/property.hpp
@@ -0,0 +1,91 @@
+#ifndef NALL_PROPERTY_HPP
+#define NALL_PROPERTY_HPP
+
+//nall::property implements ownership semantics into container classes
+//example: property::readonly implies that only owner has full
+//access to type; and all other code has readonly access.
+//
+//this code relies on extended friend semantics from C++0x to work, as it
+//declares a friend class via a template paramter. it also exploits a bug in
+//G++ 4.x to work even in C++98 mode.
+//
+//if compiling elsewhere, simply remove the friend class and private semantics
+
+//property can be used either of two ways:
+//struct foo {
+// property::readonly x;
+// property::readwrite y;
+//};
+//-or-
+//struct foo : property {
+// readonly x;
+// readwrite y;
+//};
+
+//return types are const T& (byref) instead fo T (byval) to avoid major speed
+//penalties for objects with expensive copy constructors
+
+//operator-> provides access to underlying object type:
+//readonly