From 21142e7e7d3f32baccfe385684a9338e8789fc7a Mon Sep 17 00:00:00 2001 From: ThePhD Date: Mon, 9 Dec 2013 12:05:17 -0500 Subject: [PATCH 1/2] Removed std::unordered_map storage on tables since they were getting deleted anyways. Memory leaks are currently present: will have to figure out how to patch those up. --- sol/table.hpp | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/sol/table.hpp b/sol/table.hpp index b849cc60..e1272208 100644 --- a/sol/table.hpp +++ b/sol/table.hpp @@ -42,11 +42,9 @@ namespace detail { } } class table : virtual public reference { -private: - std::unordered_map> funcs; public: - table() noexcept: reference(), funcs() {} - table(lua_State* L, int index = -1): reference(L, index), funcs() { + table() noexcept: reference() {} + table(lua_State* L, int index = -1): reference(L, index) { type_assert(L, index, type::table); } @@ -98,7 +96,7 @@ private: table& set_isfunction_fx(std::false_type, T&& key, TFx&& fx) { typedef typename std::decay::type clean_lambda; typedef typename detail::function_traits::free_function_pointer_type raw_func_t; - typedef std::is_convertible isconvertible; + typedef std::is_convertible isconvertible; return set_isconvertible_fx(isconvertible(), std::forward(key), std::forward(fx)); } @@ -190,31 +188,33 @@ private: template table& set_fx(T&& key, std::unique_ptr luafunc) { std::string fkey(key); - auto hint = funcs.find(fkey); - if (hint == funcs.end()) { - std::shared_ptr sptr(luafunc.release()); - hint = funcs.emplace_hint(hint, fkey, std::move(sptr)); - } - else { - hint->second.reset(luafunc.release()); - } - lua_func* target = hint->second.get(); + + lua_func* target = luafunc.release(); void* userdata = reinterpret_cast(target); lua_CFunction freefunc = &lua_func::call; - const char* freefuncname = hint->first.c_str(); - const luaL_Reg funcreg[ 2 ] = { + const char* freefuncname = fkey.c_str(); + const luaL_Reg funcreg[2] = { { freefuncname, freefunc }, { nullptr, nullptr } }; + + push(); - push(); - - stack::push(state(), userdata); - luaL_setfuncs(state(), funcreg, 1); - + // Actual function call we want + stack::push( state(), userdata ); + luaL_setfuncs(state(), funcreg, 1); + lua_pop(state(), 1); return *this; } + + static int destroyfunc( lua_State* L ) { + void* userdata = lua_touserdata( L, 1 ); + lua_func* ptr = static_cast( userdata ); + std::default_delete dx{ }; + dx( ptr ); + return 0; + } }; } // sol From 19d01ecd1df3f9586b5bc493e2e360a62caf84a1 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Mon, 9 Dec 2013 14:12:38 -0500 Subject: [PATCH 2/2] Okay, cleaned up includes and now the newest feature: STATEFUL FUNCTIONS! Any stateful function now works and is properly cleaned up, thanks to some additional metatables that are associated with the function values. This lays the ground work for class bindings, but that's a far off dream. For now, table retrieval and `operator[]` is what's for dinner. --- sol/lua_function.hpp | 30 +++++++++++++++++++++++++++--- sol/stack.hpp | 11 +++++++++++ sol/table.hpp | 40 ++++++++++++++++++---------------------- 3 files changed, 56 insertions(+), 25 deletions(-) diff --git a/sol/lua_function.hpp b/sol/lua_function.hpp index e2bd98ca..c69941e7 100644 --- a/sol/lua_function.hpp +++ b/sol/lua_function.hpp @@ -24,6 +24,7 @@ #include "functional.hpp" #include "stack.hpp" +#include namespace sol { @@ -112,13 +113,24 @@ struct static_object_lua_func { struct lua_func { static int call(lua_State* L) { - void* inheritancedata = lua_touserdata(L, lua_upvalueindex(1)); + void** pinheritancedata = static_cast(lua_touserdata(L, lua_upvalueindex(1))); + void* inheritancedata = *pinheritancedata; if (inheritancedata == nullptr) throw sol_error("call from lua to c++ function has null data"); - lua_func& fx = *static_cast(inheritancedata); + lua_func* pfx = static_cast(inheritancedata); + lua_func& fx = *pfx; int r = fx(L); return r; } + + static int gc(lua_State* L) { + void** puserdata = static_cast(lua_touserdata(L, 1)); + void* userdata = *puserdata; + lua_func* ptr = static_cast(userdata); + std::default_delete dx{ }; + dx(ptr); + return 0; + } virtual int operator()(lua_State*) { throw sol_error("Failure to call specialized wrapped C++ function from lua"); @@ -152,6 +164,10 @@ struct lambda_lua_func : public lua_func { stack::push(L, r); return sizeof...(TRn); } + + ~lambda_lua_func() { + + } }; template::value> @@ -179,6 +195,10 @@ struct explicit_lua_func : public lua_func { stack::push(L, std::move(r)); return sizeof...(TRn); } + + ~explicit_lua_func() { + + } }; template @@ -199,7 +219,7 @@ struct explicit_lua_func : public lua_func { } fx; template - explicit_lua_func(T m, FxArgs&&... fxargs): fx(std::move( m ), std::forward(fxargs)...) {} + explicit_lua_func(T m, FxArgs&&... fxargs): fx(std::move(m), std::forward(fxargs)...) {} virtual int operator()(lua_State* L) override { return (*this)(tuple_types(), typename fx_traits::args_type(), L); @@ -217,6 +237,10 @@ struct explicit_lua_func : public lua_func { stack::push(L, r); return sizeof...(TRn); } + + ~explicit_lua_func() { + + } }; } // sol diff --git a/sol/stack.hpp b/sol/stack.hpp index bb6baaec..925cf9a9 100644 --- a/sol/stack.hpp +++ b/sol/stack.hpp @@ -165,6 +165,17 @@ inline void push(lua_State* L, const std::string& str) { lua_pushlstring(L, str.c_str(), str.size()); } +template +inline void push_user(lua_State* L, T& userdata, const char* metatablekey) { + T* pdatum = static_cast(lua_newuserdata(L, sizeof(T))); + T& datum = *pdatum; + datum = userdata; + if (metatablekey != nullptr) { + lua_getfield(L, LUA_REGISTRYINDEX, metatablekey); + lua_setmetatable(L, -2); + } +} + template inline void push(lua_State* L, const std::array& data) { for (auto&& i : data) { diff --git a/sol/table.hpp b/sol/table.hpp index e1272208..e19ef713 100644 --- a/sol/table.hpp +++ b/sol/table.hpp @@ -24,9 +24,7 @@ #include "stack.hpp" #include "lua_function.hpp" -#include #include -#include #include namespace sol { @@ -122,7 +120,7 @@ private: template table& set_lvalue_fx(std::false_type, T&& key, TFx&& fx, TObj&& obj) { typedef typename std::remove_pointer::type>::type clean_fx; - std::unique_ptr sptr(new explicit_lua_func(std::forward( obj ), std::forward(fx))); + std::unique_ptr sptr(new explicit_lua_func(std::forward(obj), std::forward(fx))); return set_fx(std::forward(key), std::move(sptr)); } @@ -173,7 +171,7 @@ private: const char* freefuncname = fkey.c_str(); const luaL_Reg funcreg[ 2 ] = { { freefuncname, freefunc }, - { nullptr, nullptr } + { nullptr, nullptr } }; push(); @@ -188,33 +186,31 @@ private: template table& set_fx(T&& key, std::unique_ptr luafunc) { std::string fkey(key); - - lua_func* target = luafunc.release(); + std::string metakey("sol.stateful."); + metakey += fkey; + metakey += ".meta"; + lua_func* target = luafunc.release(); void* userdata = reinterpret_cast(target); lua_CFunction freefunc = &lua_func::call; const char* freefuncname = fkey.c_str(); + const char* metatablename = metakey.c_str(); const luaL_Reg funcreg[2] = { { freefuncname, freefunc }, - { nullptr, nullptr } - }; - - push(); + { nullptr, nullptr } + }; - // Actual function call we want - stack::push( state(), userdata ); - luaL_setfuncs(state(), funcreg, 1); - + int exists = luaL_newmetatable(state(), metatablename); + lua_pushstring(state(), "__gc"); + lua_pushcclosure(state(), &lua_func::gc, 0); + lua_settable(state(), -3); + push(); + + stack::push_user(state(), userdata, metatablename); + luaL_setfuncs(state(), funcreg, 1); + lua_pop(state(), 1); return *this; } - - static int destroyfunc( lua_State* L ) { - void* userdata = lua_touserdata( L, 1 ); - lua_func* ptr = static_cast( userdata ); - std::default_delete dx{ }; - dx( ptr ); - return 0; - } }; } // sol