diff --git a/src/common/Variant.cpp b/src/common/Variant.cpp index 32e9ba5ea..3426ed33e 100644 --- a/src/common/Variant.cpp +++ b/src/common/Variant.cpp @@ -26,35 +26,21 @@ namespace love static love::Type extractudatatype(lua_State *L, int idx) { - Type t = INVALID_ID; - if (!lua_isuserdata(L, idx)) - return t; - if (luaL_getmetafield(L, idx, "type") == 0) - return t; - lua_pushvalue(L, idx); - int result = lua_pcall(L, 1, 1, 0); - if (result == 0) - getTypeName(lua_tostring(L, -1), t); - if (result == 0 || result == LUA_ERRRUN) - lua_pop(L, 1); - return t; -} + Proxy *u = (Proxy *)lua_touserdata(L, idx); -static inline void delete_table(std::vector > *table) -{ - while (!table->empty()) - { - std::pair &kv = table->back(); - kv.first->release(); - kv.second->release(); - table->pop_back(); - } - delete table; + if (u == nullptr || u->type <= INVALID_ID || u->type >= TYPE_MAX_ENUM) + return INVALID_ID; + + // We could get rid of the dynamic_cast for more performance, but it would + // be less safe... + if (dynamic_cast(u->object) != nullptr) + return u->type; + + return INVALID_ID; } Variant::Variant() : type(NIL) - , data() { } @@ -71,19 +57,18 @@ Variant::Variant(double number) } Variant::Variant(const char *string, size_t len) - : type(STRING) { - char *buf = new char[len+1]; - memset(buf, 0, len+1); - memcpy(buf, string, len); - data.string.str = buf; - data.string.len = len; -} - -Variant::Variant(char c) - : type(CHARACTER) -{ - data.character = c; + if (len <= MAX_SMALL_STRING_LENGTH) + { + type = SMALLSTRING; + memcpy(data.smallstring.str, string, len); + data.smallstring.len = (uint8) len; + } + else + { + type = STRING; + data.string = new SharedString(string, len); + } } Variant::Variant(void *userdata) @@ -107,10 +92,23 @@ Variant::Variant(love::Type udatatype, void *userdata) } // Variant gets ownership of the vector. -Variant::Variant(std::vector > *table) +Variant::Variant(std::vector> *table) : type(TABLE) { - data.table = table; + data.table = new SharedTable(table); +} + +Variant::Variant(const Variant &v) + : type(v.type) + , data(v.data) + , udatatype(v.udatatype) +{ + if (type == STRING) + data.string->retain(); + else if (type == FUSERDATA) + ((love::Object *) data.userdata)->retain(); + else if (type == TABLE) + data.table->retain(); } Variant::~Variant() @@ -118,102 +116,122 @@ Variant::~Variant() switch (type) { case STRING: - delete[] data.string.str; + data.string->release(); break; case FUSERDATA: ((love::Object *) data.userdata)->release(); break; case TABLE: - delete_table(data.table); + data.table->release(); + break; default: break; } } -Variant *Variant::fromLua(lua_State *L, int n, bool allowTables) +Variant &Variant::operator = (const Variant &v) +{ + if (v.type == STRING) + v.data.string->retain(); + else if (v.type == FUSERDATA) + ((love::Object *) v.data.userdata)->retain(); + else if (v.type == TABLE) + v.data.table->retain(); + + if (type == STRING) + data.string->release(); + else if (type == FUSERDATA) + ((love::Object *) v.data.userdata)->release(); + else if (type == TABLE) + data.table->release(); + + type = v.type; + data = v.data; + udatatype = v.udatatype; + + return *this; +} + +bool Variant::fromLua(lua_State *L, int n, Variant *v, bool allowTables) { - Variant *v = nullptr; size_t len; const char *str; + if (n < 0) // Fix the stack position, we might modify it later n += lua_gettop(L) + 1; switch (lua_type(L, n)) { case LUA_TBOOLEAN: - v = new Variant(luax_toboolean(L, n)); - break; + *v = Variant(luax_toboolean(L, n)); + return true; case LUA_TNUMBER: - v = new Variant(lua_tonumber(L, n)); - break; + *v = Variant(lua_tonumber(L, n)); + return true; case LUA_TSTRING: str = lua_tolstring(L, n, &len); - v = new Variant(str, len); - break; + *v = Variant(str, len); + return true; case LUA_TLIGHTUSERDATA: - v = new Variant(lua_touserdata(L, n)); - break; + *v = Variant(lua_touserdata(L, n)); + return true; case LUA_TUSERDATA: - v = new Variant(extractudatatype(L, n), lua_touserdata(L, n)); - break; + *v = Variant(extractudatatype(L, n), lua_touserdata(L, n)); + return true; case LUA_TNIL: - v = new Variant(); - break; + *v = Variant(); + return true; case LUA_TTABLE: if (allowTables) { bool success = true; - std::vector> *table = new std::vector>(); + std::vector> *table = new std::vector>(); + std::pair pair; + lua_pushnil(L); + while (lua_next(L, n)) { - Variant *key = fromLua(L, -2, false); - if (!key) + if (!fromLua(L, -2, &pair.first, false) || !fromLua(L, -1, &pair.second, false)) { success = false; lua_pop(L, 2); break; } - Variant *value = fromLua(L, -1, false); - if (!value) - { - delete key; - success = false; - lua_pop(L, 2); - break; - } - - table->push_back(std::make_pair(key, value)); - + table->push_back(pair); lua_pop(L, 1); } if (success) - v = new Variant(table); + { + *v = Variant(table); + return true; + } else - delete_table(table); + delete table; } break; } - return v; + + return false; } -void Variant::toLua(lua_State *L) +void Variant::toLua(lua_State *L) const { switch (type) { case BOOLEAN: lua_pushboolean(L, data.boolean); break; - case CHARACTER: - lua_pushlstring(L, &data.character, 1); - break; case NUMBER: lua_pushnumber(L, data.number); break; case STRING: - lua_pushlstring(L, data.string.str, data.string.len); + lua_pushlstring(L, data.string->str, data.string->len); + break; + case SMALLSTRING: + lua_pushlstring(L, data.smallstring.str, data.smallstring.len); break; case LUSERDATA: lua_pushlightuserdata(L, data.userdata); @@ -228,15 +246,20 @@ void Variant::toLua(lua_State *L) // I can do (at the moment). break; case TABLE: - lua_createtable(L, 0, (int) data.table->size()); - for (size_t i = 0; i < data.table->size(); ++i) + { + std::vector> *table = data.table->table; + lua_createtable(L, 0, (int) table->size()); + + for (size_t i = 0; i < table->size(); ++i) { - std::pair &kv = data.table->at(i); - kv.first->toLua(L); - kv.second->toLua(L); + std::pair &kv = table->at(i); + kv.first.toLua(L); + kv.second.toLua(L); lua_settable(L, -3); } + break; + } case NIL: default: lua_pushnil(L); diff --git a/src/common/Variant.h b/src/common/Variant.h index ce7dad08e..cc99f198b 100644 --- a/src/common/Variant.h +++ b/src/common/Variant.h @@ -23,15 +23,15 @@ #include "common/runtime.h" #include "common/Object.h" +#include "common/int.h" #include #include -#include namespace love { -class Variant : public love::Object +class Variant { public: @@ -39,42 +39,78 @@ public: Variant(bool boolean); Variant(double number); Variant(const char *string, size_t len); - Variant(char c); Variant(void *userdata); Variant(love::Type udatatype, void *userdata); - Variant(std::vector > *table); - virtual ~Variant(); + Variant(std::vector> *table); + Variant(const Variant &v); + ~Variant(); - static Variant *fromLua(lua_State *L, int n, bool allowTables = true); - void toLua(lua_State *L); + Variant &operator = (const Variant &v); + + static bool fromLua(lua_State *L, int n, Variant *v, bool allowTables = true); + void toLua(lua_State *L) const; + +private: + + class SharedString : public love::Object + { + public: + + SharedString(const char *string, size_t len) + : len(len) + { + str = new char[len+1]; + memcpy(str, string, len); + } + virtual ~SharedString() { delete[] str; } + + char *str; + size_t len; + }; + + class SharedTable : public love::Object + { + public: + + SharedTable(std::vector> *table) + : table(table) + { + } + + virtual ~SharedTable() { delete table; } + + std::vector> *table; + }; enum Type { UNKNOWN = 0, BOOLEAN, NUMBER, - CHARACTER, STRING, + SMALLSTRING, LUSERDATA, FUSERDATA, NIL, TABLE } type; - union + + static const int MAX_SMALL_STRING_LENGTH = 15; + + union Data { bool boolean; - char character; double number; + SharedString *string; + void *userdata; + SharedTable *table; struct { - const char *str; - size_t len; - } string; - void *userdata; - std::vector> *table; + char str[MAX_SMALL_STRING_LENGTH]; + uint8 len; + } smallstring; } data; -private: love::Type udatatype; }; // Variant diff --git a/src/common/runtime.h b/src/common/runtime.h index 08020d7c7..9072c99db 100644 --- a/src/common/runtime.h +++ b/src/common/runtime.h @@ -445,7 +445,7 @@ T *luax_checktype(lua_State *L, int idx, love::Type type) Proxy *u = (Proxy *)lua_touserdata(L, idx); - if (!typeFlags[u->type][type]) + if (u->type <= INVALID_ID || u->type >= TYPE_MAX_ENUM || !typeFlags[u->type][type]) { const char *name = "Invalid"; getTypeName(type, name); @@ -469,7 +469,7 @@ T *luax_getmodule(lua_State *L, love::Type type) Proxy *u = (Proxy *)lua_touserdata(L, -1); - if (!typeFlags[u->type][type]) + if (u->type <= INVALID_ID || u->type >= TYPE_MAX_ENUM || !typeFlags[u->type][type]) luaL_error(L, "Incorrect module %s", name); lua_pop(L, 2); diff --git a/src/modules/event/Event.cpp b/src/modules/event/Event.cpp index d35f533d2..af5d86b08 100644 --- a/src/modules/event/Event.cpp +++ b/src/modules/event/Event.cpp @@ -28,7 +28,7 @@ namespace love namespace event { -Message::Message(const std::string &name, const std::vector> &vargs) +Message::Message(const std::string &name, const std::vector &vargs) : name(name) , args(vargs) { @@ -42,13 +42,8 @@ int Message::toLua(lua_State *L) { luax_pushstring(L, name); - for (const StrongRef &v : args) - { - if (v.get() != nullptr) - v->toLua(L); - else - lua_pushnil(L); - } + for (const Variant &v : args) + v.toLua(L); return (int) args.size() + 1; } @@ -56,26 +51,26 @@ int Message::toLua(lua_State *L) Message *Message::fromLua(lua_State *L, int n) { std::string name = luax_checkstring(L, n); - std::vector> vargs; + std::vector vargs; int count = lua_gettop(L) - n; n++; + Variant varg; + for (int i = 0; i < count; i++) { if (lua_isnoneornil(L, n+i)) break; - vargs.push_back(Variant::fromLua(L, n+i)); - - if (!vargs.back().get()) + if (!Variant::fromLua(L, n+i, &varg)) { vargs.clear(); luaL_error(L, "Argument %d can't be stored safely\nExpected boolean, number, string or userdata.", n+i); return nullptr; } - vargs.back()->release(); // fromLua gave a +1 ref. + vargs.push_back(varg); } return new Message(name, vargs); diff --git a/src/modules/event/Event.h b/src/modules/event/Event.h index 1ca6e947e..d597855e9 100644 --- a/src/modules/event/Event.h +++ b/src/modules/event/Event.h @@ -43,7 +43,7 @@ class Message : public Object { public: - Message(const std::string &name, const std::vector> &vargs = {}); + Message(const std::string &name, const std::vector &vargs = {}); ~Message(); int toLua(lua_State *L); @@ -52,7 +52,7 @@ public: private: std::string name; - std::vector> args; + std::vector args; }; // Message diff --git a/src/modules/event/sdl/Event.cpp b/src/modules/event/sdl/Event.cpp index 364f1570d..52caa11ca 100644 --- a/src/modules/event/sdl/Event.cpp +++ b/src/modules/event/sdl/Event.cpp @@ -150,7 +150,7 @@ Message *Event::convert(const SDL_Event &e) const { Message *msg = nullptr; - std::vector> vargs; + std::vector vargs; vargs.reserve(4); love::filesystem::Filesystem *filesystem = nullptr; @@ -192,9 +192,9 @@ Message *Event::convert(const SDL_Event &e) const if (!love::keyboard::Keyboard::getConstant(scancode, txt2)) txt2 = "unknown"; - vargs.push_back(new Variant(txt, strlen(txt))); - vargs.push_back(new Variant(txt2, strlen(txt2))); - vargs.push_back(new Variant(e.key.repeat != 0)); + vargs.emplace_back(txt, strlen(txt)); + vargs.emplace_back(txt2, strlen(txt2)); + vargs.emplace_back(e.key.repeat != 0); msg = new Message("keypressed", vargs); break; case SDL_KEYUP: @@ -209,20 +209,20 @@ Message *Event::convert(const SDL_Event &e) const if (!love::keyboard::Keyboard::getConstant(scancode, txt2)) txt2 = "unknown"; - vargs.push_back(new Variant(txt, strlen(txt))); - vargs.push_back(new Variant(txt2, strlen(txt2))); + vargs.emplace_back(txt, strlen(txt)); + vargs.emplace_back(txt2, strlen(txt2)); msg = new Message("keyreleased", vargs); break; case SDL_TEXTINPUT: txt = e.text.text; - vargs.push_back(new Variant(txt, strlen(txt))); + vargs.emplace_back(txt, strlen(txt)); msg = new Message("textinput", vargs); break; case SDL_TEXTEDITING: txt = e.edit.text; - vargs.push_back(new Variant(txt, strlen(txt))); - vargs.push_back(new Variant((double) e.edit.start)); - vargs.push_back(new Variant((double) e.edit.length)); + vargs.emplace_back(txt, strlen(txt)); + vargs.emplace_back((double) e.edit.start); + vargs.emplace_back((double) e.edit.length); msg = new Message("textedited", vargs); break; case SDL_MOUSEMOTION: @@ -233,11 +233,11 @@ Message *Event::convert(const SDL_Event &e) const double yrel = (double) e.motion.yrel; windowToPixelCoords(&x, &y); windowToPixelCoords(&xrel, &yrel); - vargs.push_back(new Variant(x)); - vargs.push_back(new Variant(y)); - vargs.push_back(new Variant(xrel)); - vargs.push_back(new Variant(yrel)); - vargs.push_back(new Variant(e.motion.which == SDL_TOUCH_MOUSEID)); + vargs.emplace_back(x); + vargs.emplace_back(y); + vargs.emplace_back(xrel); + vargs.emplace_back(yrel); + vargs.emplace_back(e.motion.which == SDL_TOUCH_MOUSEID); msg = new Message("mousemoved", vargs); } break; @@ -260,18 +260,18 @@ Message *Event::convert(const SDL_Event &e) const double x = (double) e.button.x; double y = (double) e.button.y; windowToPixelCoords(&x, &y); - vargs.push_back(new Variant(x)); - vargs.push_back(new Variant(y)); - vargs.push_back(new Variant((double) button)); - vargs.push_back(new Variant(e.button.which == SDL_TOUCH_MOUSEID)); + vargs.emplace_back(x); + vargs.emplace_back(y); + vargs.emplace_back((double) button); + vargs.emplace_back(e.button.which == SDL_TOUCH_MOUSEID); msg = new Message((e.type == SDL_MOUSEBUTTONDOWN) ? "mousepressed" : "mousereleased", vargs); } break; case SDL_MOUSEWHEEL: - vargs.push_back(new Variant((double) e.wheel.x)); - vargs.push_back(new Variant((double) e.wheel.y)); + vargs.emplace_back((double) e.wheel.x); + vargs.emplace_back((double) e.wheel.y); msg = new Message("wheelmoved", vargs); break; case SDL_FINGERDOWN: @@ -316,12 +316,12 @@ Message *Event::convert(const SDL_Event &e) const // bits as can fit in a pointer (for now.) // We use lightuserdata instead of a lua_Number (double) because doubles // can't represent all possible id values on 64-bit systems. - vargs.push_back(new Variant((void *) (intptr_t) touchinfo.id)); - vargs.push_back(new Variant(touchinfo.x)); - vargs.push_back(new Variant(touchinfo.y)); - vargs.push_back(new Variant(touchinfo.dx)); - vargs.push_back(new Variant(touchinfo.dy)); - vargs.push_back(new Variant(touchinfo.pressure)); + vargs.emplace_back((void *) (intptr_t) touchinfo.id); + vargs.emplace_back(touchinfo.x); + vargs.emplace_back(touchinfo.y); + vargs.emplace_back(touchinfo.dx); + vargs.emplace_back(touchinfo.dy); + vargs.emplace_back(touchinfo.pressure); if (e.type == SDL_FINGERDOWN) txt = "touchpressed"; @@ -356,7 +356,7 @@ Message *Event::convert(const SDL_Event &e) const if (filesystem->isRealDirectory(e.drop.file)) { - vargs.push_back(new Variant(e.drop.file, strlen(e.drop.file))); + vargs.emplace_back(e.drop.file, strlen(e.drop.file)); msg = new Message("directorydropped", vargs); } else @@ -364,7 +364,7 @@ Message *Event::convert(const SDL_Event &e) const Proxy proxy; proxy.object = new love::filesystem::DroppedFile(e.drop.file); proxy.type = FILESYSTEM_DROPPED_FILE_ID; - vargs.push_back(new Variant(proxy.type, &proxy)); + vargs.emplace_back(proxy.type, &proxy); msg = new Message("filedropped", vargs); proxy.object->release(); } @@ -382,13 +382,6 @@ Message *Event::convert(const SDL_Event &e) const break; } - // We gave +1 refs to the StrongRef list, so we should release them. - for (const StrongRef &v : vargs) - { - if (v.get() != nullptr) - v->release(); - } - return msg; } @@ -400,7 +393,7 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const Message *msg = nullptr; - std::vector> vargs; + std::vector vargs; vargs.reserve(4); Proxy proxy; @@ -418,8 +411,8 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const if (!proxy.object) break; - vargs.push_back(new Variant(proxy.type, (void *) &proxy)); - vargs.push_back(new Variant((double)(e.jbutton.button+1))); + vargs.emplace_back(proxy.type, (void *) &proxy); + vargs.emplace_back((double)(e.jbutton.button+1)); msg = new Message((e.type == SDL_JOYBUTTONDOWN) ? "joystickpressed" : "joystickreleased", vargs); @@ -431,10 +424,10 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const if (!proxy.object) break; - vargs.push_back(new Variant(proxy.type, (void *) &proxy)); - vargs.push_back(new Variant((double)(e.jaxis.axis+1))); + vargs.emplace_back(proxy.type, (void *) &proxy); + vargs.emplace_back((double)(e.jaxis.axis+1)); float value = joystick::Joystick::clampval(e.jaxis.value / 32768.0f); - vargs.push_back(new Variant((double) value)); + vargs.emplace_back((double) value); msg = new Message("joystickaxis", vargs); } break; @@ -447,9 +440,9 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const if (!proxy.object) break; - vargs.push_back(new Variant(proxy.type, (void *) &proxy)); - vargs.push_back(new Variant((double)(e.jhat.hat+1))); - vargs.push_back(new Variant(txt, strlen(txt))); + vargs.emplace_back(proxy.type, (void *) &proxy); + vargs.emplace_back((double)(e.jhat.hat+1)); + vargs.emplace_back(txt, strlen(txt)); msg = new Message("joystickhat", vargs); break; case SDL_CONTROLLERBUTTONDOWN: @@ -465,8 +458,8 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const if (!proxy.object) break; - vargs.push_back(new Variant(proxy.type, (void *) &proxy)); - vargs.push_back(new Variant(txt, strlen(txt))); + vargs.emplace_back(proxy.type, (void *) &proxy); + vargs.emplace_back(txt, strlen(txt)); msg = new Message(e.type == SDL_CONTROLLERBUTTONDOWN ? "gamepadpressed" : "gamepadreleased", vargs); break; @@ -481,11 +474,11 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const if (!proxy.object) break; - vargs.push_back(new Variant(proxy.type, (void *) &proxy)); + vargs.emplace_back(proxy.type, (void *) &proxy); - vargs.push_back(new Variant(txt, strlen(txt))); + vargs.emplace_back(txt, strlen(txt)); float value = joystick::Joystick::clampval(e.caxis.value / 32768.0f); - vargs.push_back(new Variant((double) value)); + vargs.emplace_back((double) value); msg = new Message("gamepadaxis", vargs); } break; @@ -495,7 +488,7 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const proxy.type = JOYSTICK_JOYSTICK_ID; if (proxy.object) { - vargs.push_back(new Variant(proxy.type, (void *) &proxy)); + vargs.emplace_back(proxy.type, (void *) &proxy); msg = new Message("joystickadded", vargs); } break; @@ -506,7 +499,7 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const if (proxy.object) { joymodule->removeJoystick((joystick::Joystick *) proxy.object); - vargs.push_back(new Variant(proxy.type, (void *) &proxy)); + vargs.emplace_back(proxy.type, (void *) &proxy); msg = new Message("joystickremoved", vargs); } break; @@ -514,13 +507,6 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const break; } - // We gave +1 refs to the StrongRef list, so we should release them. - for (const StrongRef &v : vargs) - { - if (v.get() != nullptr) - v->release(); - } - return msg; } @@ -528,7 +514,7 @@ Message *Event::convertWindowEvent(const SDL_Event &e) const { Message *msg = nullptr; - std::vector> vargs; + std::vector vargs; vargs.reserve(4); window::Window *win = nullptr; @@ -540,17 +526,17 @@ Message *Event::convertWindowEvent(const SDL_Event &e) const { case SDL_WINDOWEVENT_FOCUS_GAINED: case SDL_WINDOWEVENT_FOCUS_LOST: - vargs.push_back(new Variant(e.window.event == SDL_WINDOWEVENT_FOCUS_GAINED)); + vargs.emplace_back(e.window.event == SDL_WINDOWEVENT_FOCUS_GAINED); msg = new Message("focus", vargs); break; case SDL_WINDOWEVENT_ENTER: case SDL_WINDOWEVENT_LEAVE: - vargs.push_back(new Variant(e.window.event == SDL_WINDOWEVENT_ENTER)); + vargs.emplace_back(e.window.event == SDL_WINDOWEVENT_ENTER); msg = new Message("mousefocus", vargs); break; case SDL_WINDOWEVENT_SHOWN: case SDL_WINDOWEVENT_HIDDEN: - vargs.push_back(new Variant(e.window.event == SDL_WINDOWEVENT_SHOWN)); + vargs.emplace_back(e.window.event == SDL_WINDOWEVENT_SHOWN); msg = new Message("visible", vargs); break; case SDL_WINDOWEVENT_RESIZED: @@ -562,10 +548,10 @@ Message *Event::convertWindowEvent(const SDL_Event &e) const if (sdlwin) SDL_GL_GetDrawableSize(sdlwin, &px_w, &px_h); - vargs.push_back(new Variant((double) px_w)); - vargs.push_back(new Variant((double) px_h)); - vargs.push_back(new Variant((double) e.window.data1)); - vargs.push_back(new Variant((double) e.window.data2)); + vargs.emplace_back((double) px_w); + vargs.emplace_back((double) px_h); + vargs.emplace_back((double) e.window.data1); + vargs.emplace_back((double) e.window.data2); msg = new Message("resize", vargs); } break; @@ -591,13 +577,6 @@ Message *Event::convertWindowEvent(const SDL_Event &e) const break; } - // We gave +1 refs to the StrongRef list, so we should release them. - for (const StrongRef &v : vargs) - { - if (v.get() != nullptr) - v->release(); - } - return msg; } diff --git a/src/modules/event/wrap_Event.cpp b/src/modules/event/wrap_Event.cpp index 06aa53a30..efe8191df 100644 --- a/src/modules/event/wrap_Event.cpp +++ b/src/modules/event/wrap_Event.cpp @@ -95,14 +95,11 @@ int w_clear(lua_State *) int w_quit(lua_State *L) { - std::vector> args; + std::vector args; - Variant *v = Variant::fromLua(L, 1); - if (v) - { + Variant v; + if (Variant::fromLua(L, 1, &v)) args.push_back(v); - v->release(); - } Message *m = new Message("quit", args); instance()->push(m); diff --git a/src/modules/thread/Channel.cpp b/src/modules/thread/Channel.cpp index e86d018bf..e36e69db7 100644 --- a/src/modules/thread/Channel.cpp +++ b/src/modules/thread/Channel.cpp @@ -88,12 +88,6 @@ Channel::Channel(const std::string &name) Channel::~Channel() { - while (!queue.empty()) - { - queue.front()->release(); - queue.pop(); - } - delete mutex; delete cond; @@ -101,13 +95,9 @@ Channel::~Channel() namedChannels.erase(name); } -unsigned long Channel::push(Variant *var) +unsigned long Channel::push(const Variant &var) { - if (!var) - return 0; - Lock l(mutex); - var->retain(); // Keep a reference to ourselves // if we're non-empty and named. @@ -120,11 +110,8 @@ unsigned long Channel::push(Variant *var) return ++sent; } -void Channel::supply(Variant *var) +void Channel::supply(const Variant &var) { - if (!var) - return; - Lock l(mutex); unsigned long id = push(var); @@ -132,13 +119,14 @@ void Channel::supply(Variant *var) cond->wait(mutex); } -Variant *Channel::pop() +bool Channel::pop(Variant *var) { Lock l(mutex); - if (queue.empty()) - return 0; - Variant *var = queue.front(); + if (queue.empty()) + return false; + + *var = queue.front(); queue.pop(); received++; @@ -149,28 +137,26 @@ Variant *Channel::pop() if (named && queue.empty()) release(); - return var; -} // NOTE: Returns a retained Variant - -Variant *Channel::demand() -{ - Variant *var; - Lock l(mutex); - while (!(var = pop())) - cond->wait(mutex); - - return var; + return true; } -Variant *Channel::peek() +void Channel::demand(Variant *var) { Lock l(mutex); - if (queue.empty()) - return 0; - Variant *var = queue.front(); - var->retain(); - return var; + while (!pop(var)) + cond->wait(mutex); +} + +bool Channel::peek(Variant *var) +{ + Lock l(mutex); + + if (queue.empty()) + return false; + + *var = queue.front(); + return true; } int Channel::getCount() @@ -188,10 +174,7 @@ void Channel::clear() return; while (!queue.empty()) - { - queue.front()->release(); queue.pop(); - } // Finish all the supply waits received = sent; diff --git a/src/modules/thread/Channel.h b/src/modules/thread/Channel.h index d034ef095..b7ddedc74 100644 --- a/src/modules/thread/Channel.h +++ b/src/modules/thread/Channel.h @@ -37,8 +37,6 @@ namespace thread class Channel : public love::Object { // FOR WRAPPER USE ONLY -friend void retainVariant(Channel *, Variant *); -friend void releaseVariant(Channel *, Variant *); friend int w_Channel_performAtomic(lua_State *); public: @@ -48,11 +46,11 @@ public: static Channel *getChannel(const std::string &name); - unsigned long push(Variant *var); - void supply(Variant *var); // blocking push - Variant *pop(); - Variant *demand(); // blocking pop - Variant *peek(); + unsigned long push(const Variant &var); + void supply(const Variant &var); // blocking push + bool pop(Variant *var); + void demand(Variant *var); // blocking pop + bool peek(Variant *var); int getCount(); void clear(); @@ -67,7 +65,7 @@ private: Mutex *mutex; Conditional *cond; - std::queue queue; + std::queue queue; bool named; std::string name; diff --git a/src/modules/thread/LuaThread.cpp b/src/modules/thread/LuaThread.cpp index c61594fda..0c5b096ae 100644 --- a/src/modules/thread/LuaThread.cpp +++ b/src/modules/thread/LuaThread.cpp @@ -33,18 +33,12 @@ namespace thread LuaThread::LuaThread(const std::string &name, love::Data *code) : code(code) , name(name) - , args(nullptr) - , nargs(0) { threadName = name; } LuaThread::~LuaThread() { - // No args should still exist at this point, - // but you never know. - for (int i = 0; i < nargs; ++i) - args[i]->release(); } void LuaThread::threadFunction() @@ -74,16 +68,12 @@ void LuaThread::threadFunction() error = luax_tostring(L, -1); else { - int pushedargs = nargs; - for (int i = 0; i < nargs; ++i) - { - args[i]->toLua(L); - args[i]->release(); - } - // Set both args and nargs to nil, prevents the deconstructor from - // accessing it again. - nargs = 0; - args = nullptr; + int pushedargs = (int) args.size(); + + for (int i = 0; i < pushedargs; i++) + args[i].toLua(L); + + args.clear(); if (lua_pcall(L, pushedargs, 0, 0) != 0) error = luax_tostring(L, -1); @@ -97,14 +87,9 @@ void LuaThread::threadFunction() this->release(); } -bool LuaThread::start(Variant **args, int nargs) +bool LuaThread::start(const std::vector &args) { - for (int i = 0; i < this->nargs; ++i) - this->args[i]->release(); - this->args = args; - this->nargs = nargs; - return Threadable::start(); } @@ -126,16 +111,12 @@ void LuaThread::onError() p.type = THREAD_THREAD_ID; p.object = this; - std::vector> vargs = { - new Variant(THREAD_THREAD_ID, &p), - new Variant(error.c_str(), error.length()) + std::vector vargs = { + Variant(p.type, &p), + Variant(error.c_str(), error.length()) }; event::Message *msg = new event::Message("threaderror", vargs); - - for (const StrongRef &v : vargs) - v->release(); - eventmodule->push(msg); msg->release(); } diff --git a/src/modules/thread/LuaThread.h b/src/modules/thread/LuaThread.h index be8c1b84e..a3ce4729a 100644 --- a/src/modules/thread/LuaThread.h +++ b/src/modules/thread/LuaThread.h @@ -23,6 +23,7 @@ // STL #include +#include // LOVE #include "common/Data.h" @@ -44,7 +45,7 @@ public: void threadFunction(); const std::string &getError() const; - bool start(Variant **args, int nargs); + bool start(const std::vector &args); private: @@ -54,8 +55,7 @@ private: std::string name; std::string error; - Variant **args; - int nargs; + std::vector args; }; // LuaThread diff --git a/src/modules/thread/wrap_Channel.cpp b/src/modules/thread/wrap_Channel.cpp index 0885e319b..ff11fb304 100644 --- a/src/modules/thread/wrap_Channel.cpp +++ b/src/modules/thread/wrap_Channel.cpp @@ -25,20 +25,6 @@ namespace love namespace thread { -void retainVariant(Channel *c, Variant *v) -{ - c->lockMutex(); - v->retain(); - c->unlockMutex(); -} - -void releaseVariant(Channel *c, Variant *v) -{ - c->lockMutex(); - v->release(); - c->unlockMutex(); -} - Channel *luax_checkchannel(lua_State *L, int idx) { return luax_checktype(L, idx, THREAD_CHANNEL_ID); @@ -47,34 +33,29 @@ Channel *luax_checkchannel(lua_State *L, int idx) int w_Channel_push(lua_State *L) { Channel *c = luax_checkchannel(L, 1); - Variant *var = lua_isnoneornil(L, 2) ? 0 : Variant::fromLua(L, 2); - if (!var) + Variant var; + if (!Variant::fromLua(L, 2, &var)) return luaL_argerror(L, 2, "boolean, number, string, love type, or flat table expected"); c->push(var); - releaseVariant(c, var); return 0; } int w_Channel_supply(lua_State *L) { Channel *c = luax_checkchannel(L, 1); - Variant *var = lua_isnoneornil(L, 2) ? 0 : Variant::fromLua(L, 2); - if (!var) + Variant var; + if (!Variant::fromLua(L, 2, &var)) return luaL_argerror(L, 2, "boolean, number, string, love type, or flat table expected"); c->supply(var); - releaseVariant(c, var); return 0; } int w_Channel_pop(lua_State *L) { Channel *c = luax_checkchannel(L, 1); - Variant *var = c->pop(); - if (var) - { - var->toLua(L); - releaseVariant(c, var); - } + Variant var; + if (c->pop(&var)) + var.toLua(L); else lua_pushnil(L); return 1; @@ -83,21 +64,18 @@ int w_Channel_pop(lua_State *L) int w_Channel_demand(lua_State *L) { Channel *c = luax_checkchannel(L, 1); - Variant *var = c->demand(); - var->toLua(L); - releaseVariant(c, var); + Variant var; + c->demand(&var); + var.toLua(L); return 1; } int w_Channel_peek(lua_State *L) { Channel *c = luax_checkchannel(L, 1); - Variant *var = c->peek(); - if (var) - { - var->toLua(L); - releaseVariant(c, var); - } + Variant var; + if (c->peek(&var)) + var.toLua(L); else lua_pushnil(L); return 1; diff --git a/src/modules/thread/wrap_LuaThread.cpp b/src/modules/thread/wrap_LuaThread.cpp index ee2e4d6a0..9fe432047 100644 --- a/src/modules/thread/wrap_LuaThread.cpp +++ b/src/modules/thread/wrap_LuaThread.cpp @@ -33,26 +33,22 @@ LuaThread *luax_checkthread(lua_State *L, int idx) int w_Thread_start(lua_State *L) { LuaThread *t = luax_checkthread(L, 1); + std::vector args; int nargs = lua_gettop(L) - 1; - Variant **args = 0; - if (nargs > 0) + Variant v; + for (int i = 0; i < nargs; ++i) { - args = new Variant*[nargs]; - for (int i = 0; i < nargs; ++i) + if (!Variant::fromLua(L, i+2, &v)) { - args[i] = Variant::fromLua(L, i+2); - if (!args[i]) - { - for (int j = i; j >= 0; j--) - delete args[j]; - delete[] args; - return luaL_argerror(L, i+2, "boolean, number, string, love type, or flat table expected"); - } + args.clear(); + return luaL_argerror(L, i+2, "boolean, number, string, love type, or flat table expected"); } + + args.push_back(v); } - luax_pushboolean(L, t->start(args, nargs)); + luax_pushboolean(L, t->start(args)); return 1; }