diff --git a/sol/function.hpp b/sol/function.hpp index 45d26c0b..dc3b842e 100644 --- a/sol/function.hpp +++ b/sol/function.hpp @@ -26,6 +26,7 @@ #include "tuple.hpp" #include "stack.hpp" #include "function_types.hpp" +#include "userdata_traits.hpp" #include #include #include @@ -86,49 +87,48 @@ public: namespace stack { template <> struct pusher { - template - void set_isfunction_fx(lua_State* L, std::true_type, T&& key, TFx&& fx) { - set_fx(std::false_type(), std::forward(key), std::forward(fx)); + + template + static void set_isfunction_fx(std::true_type, lua_State* L, TFx&& fx) { + set_fx(std::false_type(), L, std::forward(fx)); } - template - void set_isfunction_fx(lua_State* L, std::false_type, T&& key, TFx&& fx) { + template + static void set_isfunction_fx(std::false_type, lua_State* L, TFx&& fx) { typedef Decay clean_lambda; typedef typename function_traits::free_function_pointer_type raw_func_t; - typedef std::is_convertible isconvertible; - set_isconvertible_fx(isconvertible(), std::forward(key), std::forward(fx)); + typedef std::is_convertible is_convertible; + set_isconvertible_fx(is_convertible(), L, std::forward(fx)); } - template - void set_isconvertible_fx(lua_State* L, std::true_type, T&& key, TFx&& fx) { + template + static void set_isconvertible_fx(std::true_type, lua_State* L, TFx&& fx) { typedef Decay clean_lambda; typedef typename function_traits::free_function_pointer_type raw_func_t; - set_isfunction_fx(std::true_type(), std::forward(key), raw_func_t(std::forward(fx))); + set_isfunction_fx(std::true_type(), L, raw_func_t(std::forward(fx))); } - template - void set_isconvertible_fx(lua_State* L, std::false_type, T&& key, TFx&& fx) { + template + static void set_isconvertible_fx(std::false_type, lua_State* L, TFx&& fx) { typedef typename std::remove_pointer>::type clean_fx; std::unique_ptr sptr(new functor_function(std::forward(fx))); - set_fx(std::forward(key), std::move(sptr)); + set_fx(L, std::move(sptr)); } - template - void set_lvalue_fx(lua_State* L, std::true_type, T&& key, TFx&& fx, TObj&& obj) { - set_fx(std::true_type(), std::forward(key), std::forward(fx), std::forward(obj)); + template + static void set_lvalue_fx(std::true_type, lua_State* L, TFx&& fx, TObj&& obj) { + set_fx(std::true_type(), L, std::forward(fx), std::forward(obj)); } - template - void set_lvalue_fx(lua_State* L, std::false_type, T&& key, TFx&& fx, TObj&& obj) { + template + static void set_lvalue_fx(std::false_type, lua_State* L, TFx&& fx, TObj&& obj) { typedef typename std::remove_pointer>::type clean_fx; std::unique_ptr sptr(new member_function(std::forward(obj), std::forward(fx))); - return set_fx(std::forward(key), std::move(sptr)); + return set_fx(L, std::move(sptr)); } - template - void set_fx(lua_State* L, std::true_type, T&& key, TFx&& fx, TObj&& obj) { - std::string fkey(key); - + template + static void set_fx(std::true_type, lua_State* L, TFx&& fx, TObj&& obj) { // Layout: // idx 1...n: verbatim data of member function pointer // idx n + 1: is the object's void pointer @@ -137,85 +137,24 @@ struct pusher { Decay fxptr(std::forward(fx)); void* userobjdata = static_cast(sol::detail::get_ptr(obj)); lua_CFunction freefunc = &static_member_function, TFx>::call; - const char* freefuncname = fkey.c_str(); - const luaL_Reg funcreg[2] = { - { freefuncname, freefunc }, - { nullptr, nullptr } - }; - int upvalues = stack::detail::push_as_upvalues(L, fxptr); stack::push(L, userobjdata); - luaL_setfuncs(L, funcreg, upvalues + 1); - + stack::pusher{}.push(L, freefunc, upvalues); } - template - void set_fx(lua_State* L, std::false_type, T&& key, TFx&& fx) { - std::string fkey(key); + template + static void set_fx(lua_State* L, std::false_type, TFx&& fx) { Decay target(std::forward(fx)); lua_CFunction freefunc = &static_function::call; - const char* freefuncname = fkey.c_str(); - const luaL_Reg funcreg[2] = { - { freefuncname, freefunc }, - { nullptr, nullptr } - }; int upvalues = stack::detail::push_as_upvalues(L, target); - luaL_setfuncs(L, funcreg, upvalues); - + stack::pusher{}.push(L, freefunc, upvalues); } - template - void set_fx(lua_State* L, T&& key, std::unique_ptr luafunc) { - std::string fkey(key); - std::string metakey("sol.stateful."); - metakey += fkey; - metakey += ".meta"; - base_function* target = luafunc.release(); - void* userdata = reinterpret_cast(target); - lua_CFunction freefunc = &base_function::call; - const char* freefuncname = fkey.c_str(); - const char* metatablename = metakey.c_str(); - const luaL_Reg funcreg[2] = { - { freefuncname, freefunc }, - { nullptr, nullptr } - }; - - if (luaL_newmetatable(L, metatablename) == 1) { - lua_pushstring(L, "__gc"); - lua_pushcclosure(L, &base_function::gc, 0); - lua_settable(L, -3); - } - - stack::detail::push_userdata(L, userdata, metatablename); - luaL_setfuncs(L, funcreg, 1); - } - - template - void set_function(T&& key, TFx&& fx) { - typedef typename std::remove_pointer>::type clean_fx; - set_isfunction_fx(std::is_function(), std::forward(key), std::forward(fx)); - } - - template - void set_function(T&& key, TFx&& fx, TObj&& obj) { - set_lvalue_fx(Bool::value || std::is_pointer::value>(), - std::forward(key), std::forward(fx), std::forward(obj)); - } - - template - void push(lua_State* L, Key&& key, Args&&... args) { - set_function(L, std::forward(key), std::forward(args)...); - } - -}; -template -struct pusher> { - typedef std::function fx_t; - - static void push_fx(lua_State* L, std::unique_ptr luafunc) { - auto&& metakey = userdata_traits::metatable; + template + static void set_fx(lua_State* L, std::unique_ptr luafunc) { + auto&& metakey = userdata_traits>::metatable; const char* metatablename = std::addressof(metakey[0]); base_function* target = luafunc.release(); void* userdata = reinterpret_cast(target); @@ -223,17 +162,36 @@ struct pusher> { if (luaL_newmetatable(L, metatablename) == 1) { lua_pushstring(L, "__gc"); - lua_pushcclosure(L, &base_function::gc, 0); + stack::push(L, &base_function::gc); lua_settable(L, -3); } stack::detail::push_userdata(L, userdata, metatablename); - lua_pushcclosure(L, freefunc, 1); + stack::pusher{}.push(L, freefunc, 1); } + template + static void set_function(lua_State* L, TFx&& fx) { + typedef typename std::remove_pointer>::type clean_fx; + set_isfunction_fx(std::is_function(), L, std::forward(fx)); + } + + template + static void set_function(lua_State* L, TFx&& fx, TObj&& obj) { + set_lvalue_fx(Bool::value || std::is_pointer::value>(), + L, std::forward(fx), std::forward(obj)); + } + + template + static void push(lua_State* L, Args&&... args) { + set_function(L, std::forward(args)...); + } +}; + +template +struct pusher> { static void push(lua_State* L, std::function fx) { - std::unique_ptr sptr(new functor_function(std::move(fx))); - push_fx(L, std::move(sptr)); + pusher{}.push(L, std::move(fx)); } };