diff --git a/sol/lua_function.hpp b/sol/lua_function.hpp index c69941e7..61a5249d 100644 --- a/sol/lua_function.hpp +++ b/sol/lua_function.hpp @@ -27,6 +27,37 @@ #include namespace sol { +namespace detail { +template +void get_upvalue_ptr( lua_State* L, T*& data, std::size_t datasize, std::array voiddata, int& upvalue ) { + for ( std::size_t i = 0, d = 0; d < datasize; ++i, d += sizeof( void* ) ) { + voiddata[ i ] = lua_touserdata( L, lua_upvalueindex( upvalue++ ) ); + } + data = reinterpret_cast( static_cast( voiddata.data( ) ) ); +} +template +void get_upvalue_ptr( lua_State* L, T*& data, std::array voiddata, int& upvalue ) { + get_upvalue_ptr( L, data, sizeof( T ), voiddata, upvalue ); +} +template +void get_upvalue_ptr( lua_State* L, T*& data, int& upvalue ) { + const static std::size_t data_t_count = ( sizeof(T)+( sizeof(void*)-1 ) ) / sizeof( void* ); + typedef std::array data_t; + data_t voiddata{{}}; + return get_upvalue_ptr(L, data, voiddata, upvalue); +} +template +void get_upvalue( lua_State* L, T& data, int& upvalue ) { + const static std::size_t data_t_count = ( sizeof(T)+( sizeof(void*)-1 ) ) / sizeof( void* ); + typedef std::array data_t; + data_t voiddata{ { } }; + for ( std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof( void* ) ) { + voiddata[ i ] = lua_touserdata( L, lua_upvalueindex( upvalue++ ) ); + } + data = *reinterpret_cast( static_cast( voiddata.data( ) ) ); +} +} // detail + template struct static_lua_func { @@ -47,10 +78,9 @@ struct static_lua_func { } static int call(lua_State* L) { - void* functiondata = lua_touserdata(L, lua_upvalueindex(1)); - //if (functiondata == nullptr) - // throw sol_error("call from lua to c++ function has null function pointer data"); - fx_t* fx = reinterpret_cast(functiondata); + int upvalue = 1; + fx_t* fx; + detail::get_upvalue( L, fx, upvalue ); int r = typed_call(tuple_types(), typename fx_traits::args_type(), fx, L); return r; } @@ -74,7 +104,9 @@ struct static_object_lua_func { template static int typed_call(types, types, T& item, fx_t& ifx, lua_State* L) { - auto fx = [ &item, &ifx ] (Args&&... args) -> TR { return (item.*ifx)(std::forward(args)...); }; + auto fx = [ &item, &ifx ] (Args&&... args) -> TR { + return (item.*ifx)(std::forward(args)...); + }; auto r = stack::pop_call(L, fx, types()); stack::push(L, std::move(r)); return 1; @@ -89,20 +121,19 @@ struct static_object_lua_func { } static int call(lua_State* L) { - const static std::size_t data_t_count = (sizeof(fx_t)+(sizeof(void*)-1)) / sizeof(void*); - typedef std::array data_t; - data_t fxptrdata; - int upvalue = 1; - for (std::size_t i = 0; i < fxptrdata.size(); ++i) { - fxptrdata[ i ] = lua_touserdata(L, lua_upvalueindex(upvalue++)); - } - void* objectdata = lua_touserdata(L, lua_upvalueindex(upvalue++)); - //if (objectdata == nullptr) - // throw sol_error("call from lua to c++ function has null object data"); - fx_t* fxptr = reinterpret_cast(static_cast(fxptrdata.data())); - fx_t& mem_ptr = *fxptr; - T& obj = *static_cast(objectdata); - int r = typed_call(tuple_types(), typename fx_traits::args_type(), obj, mem_ptr, L); + const static std::size_t data_t_count = ( sizeof(fx_t)+( sizeof(void*)-1 ) ) / sizeof( void* ); + typedef std::array data_t; + int upvalue = 1; + data_t data = { { } }; + fx_t* fxptr; + for ( std::size_t i = 0, d = 0; d < sizeof(fx_t*); ++i, d += sizeof( void* ) ) { + data[ i ] = lua_touserdata( L, lua_upvalueindex( upvalue++ ) ); + } + fxptr = reinterpret_cast( static_cast( data.data( ) ) ); + fx_t& mem_ptr = *fxptr; + void* objectdata = lua_touserdata( L, lua_upvalueindex( upvalue++ ) ); + T& obj = *static_cast( objectdata ); + int r = typed_call( tuple_types( ), typename fx_traits::args_type( ), obj, mem_ptr, L ); return r; } @@ -127,7 +158,7 @@ struct lua_func { void** puserdata = static_cast(lua_touserdata(L, 1)); void* userdata = *puserdata; lua_func* ptr = static_cast(userdata); - std::default_delete dx{ }; + std::default_delete dx{}; dx(ptr); return 0; } diff --git a/sol/stack.hpp b/sol/stack.hpp index 925cf9a9..1fa8a024 100644 --- a/sol/stack.hpp +++ b/sol/stack.hpp @@ -27,6 +27,7 @@ #include #include #include +#include namespace sol { template @@ -183,6 +184,21 @@ inline void push(lua_State* L, const std::array& data) { } } +template +inline int push_user( lua_State* L, T& item ) { + typedef typename std::decay::type TValue; + const static std::size_t itemsize = sizeof( TValue ); + const static std::size_t voidsize = sizeof( void* ); + const static std::size_t voidsizem1 = voidsize - 1; + const static std::size_t data_t_count = (sizeof(TValue) + voidsizem1) / voidsize; + typedef std::array data_t; + + data_t data{{}}; + std::memcpy( std::addressof( data[ 0 ] ), std::addressof( item ), itemsize ); + push( L, data ); + return data_t_count; +} + namespace detail { template inline void push(lua_State* L, indices, const T& tuplen) { diff --git a/sol/table.hpp b/sol/table.hpp index e19ef713..bcf635bb 100644 --- a/sol/table.hpp +++ b/sol/table.hpp @@ -41,8 +41,8 @@ namespace detail { } class table : virtual public reference { public: - table() noexcept: reference() {} - table(lua_State* L, int index = -1): reference(L, index) { + table() noexcept : reference() {} + table(lua_State* L, int index = -1) : reference(L, index) { type_assert(L, index, type::table); } @@ -70,12 +70,12 @@ public: template table& set_function(T&& key, TFx&& fx) { typedef typename std::remove_pointer::type>::type clean_fx; - return set_isfunction_fx(std::is_function(), std::forward(key), std::forward(fx)); + return set_isfunction_fx(std::is_function(), std::forward(key), std::forward(fx)); } template table& set_function(T&& key, TFx&& fx, TObj&& obj) { - return set_lvalue_fx(std::integral_constant::value || std::is_pointer::value>(), + return set_lvalue_fx(std::integral_constant::value || std::is_pointer::value>(), std::forward(key), std::forward(fx), std::forward(obj)); } @@ -92,10 +92,10 @@ private: template 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; - return set_isconvertible_fx(isconvertible(), std::forward(key), std::forward(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; + return set_isconvertible_fx(isconvertible(), std::forward(key), std::forward(fx)); } template @@ -107,9 +107,9 @@ private: template table& set_isconvertible_fx(std::false_type, T&& key, TFx&& fx) { - typedef typename std::remove_pointer::type>::type clean_fx; - std::unique_ptr sptr(new lambda_lua_func(std::forward(fx))); - return set_fx(std::forward(key), std::move(sptr)); + typedef typename std::remove_pointer::type>::type clean_fx; + std::unique_ptr sptr(new lambda_lua_func(std::forward(fx))); + return set_fx(std::forward(key), std::move(sptr)); } template @@ -128,20 +128,15 @@ private: table& set_fx(std::true_type, T&& key, TFx&& fx, TObj&& obj) { typedef typename std::decay::type decay_of_to; typedef typename std::decay::type decay_of_tfx; - const static std::size_t data_t_count = (sizeof(decay_of_tfx)+(sizeof(void*)-1)) / sizeof(void*); - typedef std::array data_t; - - std::string fkey(key); + std::string fkey(key); + // Layout: // idx 1...n: verbatim data of member function pointer // idx n + 1: is the object's void pointer // We don't need to store the size, because the other side is templated // with the same member function pointer type decay_of_tfx fxptr(std::forward(fx)); - data_t fxptrdata; - std::size_t fxptrsize = sizeof(fxptr); - std::memcpy(std::addressof(fxptrdata[ 0 ]), std::addressof(fxptr), fxptrsize); void* userobjdata = static_cast(detail::get_ptr(obj)); lua_CFunction freefunc = &static_object_lua_func::call; const char* freefuncname = fkey.c_str(); @@ -150,12 +145,12 @@ private: { nullptr, nullptr } }; - + push(); - stack::push(state(), fxptrdata); + int upvalues = stack::push_user(state(), fxptr); stack::push(state(), userobjdata); - luaL_setfuncs(state(), funcreg, fxptrdata.size() + 1); + luaL_setfuncs(state(), funcreg, upvalues + 1); lua_pop(state(), 1); return *this; @@ -164,50 +159,50 @@ private: template table& set_fx(std::false_type, T&& key, TFx&& fx) { typedef typename std::decay::type ptr_fx; - std::string fkey(key); - ptr_fx target(std::forward(fx)); - void* userdata = reinterpret_cast(target); - lua_CFunction freefunc = &static_lua_func::call; - const char* freefuncname = fkey.c_str(); - const luaL_Reg funcreg[ 2 ] = { - { freefuncname, freefunc }, - { nullptr, nullptr } - }; + std::string fkey(key); + ptr_fx target(std::forward(fx)); + lua_CFunction freefunc = &static_lua_func::call; + 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); + int upvalues = stack::push_user( state( ), target ); + luaL_setfuncs(state(), funcreg, upvalues); - lua_pop(state(), 1); - return *this; + lua_pop(state(), 1); + return *this; } template table& set_fx(T&& key, std::unique_ptr luafunc) { std::string fkey(key); - std::string metakey("sol.stateful."); - metakey += fkey; - metakey += ".meta"; - 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] = { + const char* metatablename = metakey.c_str(); + const luaL_Reg funcreg[ 2 ] = { { freefuncname, freefunc }, - { nullptr, nullptr } - }; + { nullptr, nullptr } + }; - int exists = luaL_newmetatable(state(), metatablename); - lua_pushstring(state(), "__gc"); - lua_pushcclosure(state(), &lua_func::gc, 0); - lua_settable(state(), -3); - push(); + if (luaL_newmetatable(state(), metatablename) == 1) { + 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); - stack::push_user(state(), userdata, metatablename); - luaL_setfuncs(state(), funcreg, 1); - lua_pop(state(), 1); return *this; }