From e1241c110ab5d21f1609e77c11c543689b6e04b5 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Fri, 10 Jun 2016 21:04:48 -0400 Subject: [PATCH] SPEED AND FIXES, HOOOOOOOOO! --- docs/source/api/usertype.rst | 12 +- sol/call.hpp | 22 +-- sol/function_types.hpp | 4 +- sol/function_types_core.hpp | 6 +- sol/stack.hpp | 272 +++++++++++++++++------------------ sol/stack_check.hpp | 31 ++-- sol/stack_get.hpp | 6 +- sol/stack_push.hpp | 40 ++++-- sol/types.hpp | 23 +-- sol/usertype_metatable.hpp | 62 +++----- 10 files changed, 231 insertions(+), 247 deletions(-) diff --git a/docs/source/api/usertype.rst b/docs/source/api/usertype.rst index 03aa394b..f8dd4350 100644 --- a/docs/source/api/usertype.rst +++ b/docs/source/api/usertype.rst @@ -189,17 +189,9 @@ inheritance Sol can adjust pointers from derived classes to base classes at runtime, but it has some caveats based on what you compile with: -.. _exceptions_enabled: +If your class has no complicated™ virtual inheritance or multiple inheritance, than you can try to sneak away with the performance boost from not specifying any base classes and doing any casting checks. (What does "complicated™" mean? Ask your compiler's documentation, if you're in that deep.) -**With Exceptions Enabled** - -You do not need to manually specify the base classes. We use a technique that infinitely scales and automatically casts derived pointers to their base classes by exploiting the necessity of exception type matching. - -.. _exceptions_disabled: - -**With Exceptions Disabled** - -You must specify the ``sol::base_classes`` tag with the ``sol::bases()`` argument, where ``Types...`` are all the base classes of the single type ``T`` that you are making a usertype out of. If you turn exceptions off and are also completely mad and turn off :doc:`run-time type information<../rtti>` as well, we fallback to a id-based systemthat still requires you to specifically list the base classes as well. For example: +For the rest of us safe individuals out there: You must specify the ``sol::base_classes`` tag with the ``sol::bases()`` argument, where ``Types...`` are all the base classes of the single type ``T`` that you are making a usertype out of. If you turn exceptions off and are also completely mad and turn off :doc:`run-time type information<../rtti>` as well, we fallback to a id-based systemthat still requires you to specifically list the base classes as well. For example: .. code-block:: cpp :linenos: diff --git a/sol/call.hpp b/sol/call.hpp index d8039548..34bcd153 100644 --- a/sol/call.hpp +++ b/sol/call.hpp @@ -145,7 +145,7 @@ namespace call_detail { template struct agnostic_lua_call_wrapper { - static int var_call(std::true_type, lua_State* L, F f) { + static int var_call(std::true_type, lua_State* L, F& f) { typedef wrapper> wrap; typedef typename wrap::returns_list returns_list; typedef typename wrap::free_args_list args_list; @@ -153,7 +153,7 @@ namespace call_detail { return stack::call_into_lua(returns_list(), args_list(), L, is_index ? 2 : 3, caller(), f); } - static int var_call(std::false_type, lua_State* L, F f) { + static int var_call(std::false_type, lua_State* L, F& f) { typedef wrapper> wrap; typedef typename wrap::free_args_list args_list; typedef typename wrap::returns_list returns_list; @@ -161,14 +161,14 @@ namespace call_detail { return stack::call_into_lua(returns_list(), args_list(), L, 1, caller(), f); } - static int call(lua_State* L, F f) { + static int call(lua_State* L, F& f) { return var_call(std::integral_constant(), L, f); } }; template struct agnostic_lua_call_wrapper::value>> { - static int call(lua_State* L, F f) { + static int call(lua_State* L, F& f) { typedef wrapper> wrap; typedef typename wrap::returns_list returns_list; typedef typename wrap::args_list args_list; @@ -204,7 +204,7 @@ namespace call_detail { template struct agnostic_lua_call_wrapper { - static int call(lua_State* L, no_prop) { + static int call(lua_State* L, no_prop&) { return luaL_error(L, is_index ? "sol: cannot read from a writeonly property" : "sol: cannot write to a readonly property"); } }; @@ -213,7 +213,7 @@ namespace call_detail { struct agnostic_lua_call_wrapper::value>> { typedef sol::lua_bind_traits traits_type; - static int call_assign(std::true_type, lua_State* L, F f) { + static int call_assign(std::true_type, lua_State* L, F& f) { typedef wrapper> wrap; typedef typename wrap::args_list args_list; typedef typename wrap::object_type object_type; @@ -233,20 +233,20 @@ namespace call_detail { #endif // Safety } - static int call_assign(std::false_type, lua_State* L, F) { + static int call_assign(std::false_type, lua_State* L, F&) { return luaL_error(L, "sol: cannot write to this variable: copy assignment/constructor not available"); } - static int call_const(std::false_type, lua_State* L, F f) { + static int call_const(std::false_type, lua_State* L, F& f) { typedef typename traits_type::return_type R; return call_assign(std::is_assignable>, R>(), L, f); } - static int call_const(std::true_type, lua_State* L, F) { + static int call_const(std::true_type, lua_State* L, F&) { return luaL_error(L, "sol: cannot write to a readonly (const) variable"); } - static int call(lua_State* L, F f) { + static int call(lua_State* L, F& f) { return call_const(std::is_const(), L, f); } }; @@ -255,7 +255,7 @@ namespace call_detail { struct agnostic_lua_call_wrapper::value>> { typedef sol::lua_bind_traits traits_type; - static int call(lua_State* L, F f) { + static int call(lua_State* L, F& f) { typedef wrapper> wrap; typedef typename wrap::object_type object_type; typedef typename wrap::returns_list returns_list; diff --git a/sol/function_types.hpp b/sol/function_types.hpp index c0b669c0..038d8af7 100644 --- a/sol/function_types.hpp +++ b/sol/function_types.hpp @@ -89,7 +89,7 @@ struct pusher> { lua_CFunction freefunc = &function_detail::upvalue_member_variable, meta::unqualified_t>::call; int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr); - upvalues += stack::push(L, light_userdata_value(static_cast(userptr))); + upvalues += stack::push(L, lightuserdata_value(static_cast(userptr))); stack::push(L, c_closure(freefunc, upvalues)); } @@ -127,7 +127,7 @@ struct pusher> { lua_CFunction freefunc = &function_detail::upvalue_member_function, meta::unqualified_t>::call; int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr); - upvalues += stack::push(L, light_userdata_value(static_cast(userptr))); + upvalues += stack::push(L, lightuserdata_value(static_cast(userptr))); stack::push(L, c_closure(freefunc, upvalues)); } diff --git a/sol/function_types_core.hpp b/sol/function_types_core.hpp index 82cdf2f0..b55d6bfd 100644 --- a/sol/function_types_core.hpp +++ b/sol/function_types_core.hpp @@ -70,7 +70,7 @@ static void func_gc(std::true_type, lua_State*) { template static void func_gc(std::false_type, lua_State* L) { for (std::size_t i = 0; i < limit; ++i) { - void* value = stack::get(L, up_value_index(static_cast(i + 1))); + void* value = stack::get(L, up_value_index(static_cast(i + 1))); if (value == nullptr) continue; base_function* obj = static_cast(value); @@ -81,7 +81,7 @@ static void func_gc(std::false_type, lua_State* L) { } inline int call(lua_State* L) { - void* ludata = stack::get(L, up_value_index(1)); + void* ludata = stack::get(L, up_value_index(1)); void** pinheritancedata = static_cast(ludata); return base_call(L, *pinheritancedata); } @@ -95,7 +95,7 @@ inline int gc(lua_State* L) { template inline int usertype_call(lua_State* L) { // Zero-based template parameter, but upvalues start at 1 - return base_call(L, stack::get(L, up_value_index(static_cast(I + 1)))); + return base_call(L, stack::get(L, up_value_index(static_cast(I + 1)))); } template diff --git a/sol/stack.hpp b/sol/stack.hpp index 9f9e28e7..0ecd978c 100644 --- a/sol/stack.hpp +++ b/sol/stack.hpp @@ -34,171 +34,169 @@ #include #include -namespace sol { -namespace stack { -namespace stack_detail { -template -struct is_this_state_raw : std::false_type {}; -template <> -struct is_this_state_raw : std::true_type {}; -template -using is_this_state = is_this_state_raw>; +namespace sol { namespace stack { + namespace stack_detail { + template + struct is_this_state_raw : std::false_type {}; + template <> + struct is_this_state_raw : std::true_type {}; + template + using is_this_state = is_this_state_raw>; -template -inline int push_as_upvalues(lua_State* L, T& item) { - typedef std::decay_t 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; + template + inline int push_as_upvalues(lua_State* L, T& item) { + typedef std::decay_t 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(&data[0], std::addressof(item), itemsize); - int pushcount = 0; - for(auto&& v : data) { - pushcount += push(L, light_userdata_value(v)); - } - return pushcount; -} + data_t data{ {} }; + std::memcpy(&data[0], std::addressof(item), itemsize); + int pushcount = 0; + for (auto&& v : data) { + pushcount += push(L, lightuserdata_value(v)); + } + return pushcount; + } -template -inline std::pair get_as_upvalues(lua_State* L, int index = 1) { - 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] = get(L, up_value_index(index++)); - } - return std::pair(*reinterpret_cast(static_cast(voiddata.data())), index); -} + template + inline std::pair get_as_upvalues(lua_State* L, int index = 1) { + 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] = get(L, up_value_index(index++)); + } + return std::pair(*reinterpret_cast(static_cast(voiddata.data())), index); + } -template ::value>> -inline decltype(auto) call(types, types ta, std::index_sequence tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { + template ::value>> + inline decltype(auto) call(types, types ta, std::index_sequence tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { #ifndef _MSC_VER - static_assert(meta::all...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention."); + static_assert(meta::all...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention."); #endif // This compiler make me so fucking sad - check_types{}.check(ta, tai, L, start, type_panic); - return fx(std::forward(args)..., stack_detail::unchecked_get(L, start + I - meta::count_for_to_pack::value)...); -} + check_types{}.check(ta, tai, L, start, type_panic); + return fx(std::forward(args)..., stack_detail::unchecked_get(L, start + I - meta::count_for_to_pack::value)...); + } -template -inline void call(types, types ta, std::index_sequence tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { + template + inline void call(types, types ta, std::index_sequence tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { #ifndef _MSC_VER - static_assert(meta::all...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention."); + static_assert(meta::all...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention."); #endif // This compiler make me so fucking sad - check_types{}.check(ta, tai, L, start, type_panic); - fx(std::forward(args)..., stack_detail::unchecked_get(L, start + I - meta::count_for_to_pack::value)...); -} -} // stack_detail + check_types{}.check(ta, tai, L, start, type_panic); + fx(std::forward(args)..., stack_detail::unchecked_get(L, start + I - meta::count_for_to_pack::value)...); + } + } // stack_detail -inline void remove( lua_State* L, int index, int count ) { - if ( count < 1 ) - return; - int top = lua_gettop(L); - if ( index == -1 || top == index ) { - // Slice them right off the top - lua_pop( L, static_cast(count) ); - return; - } + inline void remove(lua_State* L, int index, int count) { + if (count < 1) + return; + int top = lua_gettop(L); + if (index == -1 || top == index) { + // Slice them right off the top + lua_pop(L, static_cast(count)); + return; + } - // Remove each item one at a time using stack operations - // Probably slower, maybe, haven't benchmarked, - // but necessary - if ( index < 0 ) { - index = lua_gettop(L) + (index + 1); - } - int last = index + count; - for ( int i = index; i < last; ++i ) { - lua_remove(L, i); - } -} + // Remove each item one at a time using stack operations + // Probably slower, maybe, haven't benchmarked, + // but necessary + if (index < 0) { + index = lua_gettop(L) + (index + 1); + } + int last = index + count; + for (int i = index; i < last; ++i) { + lua_remove(L, i); + } + } -template ::value>> -inline decltype(auto) call(types tr, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { - typedef std::make_index_sequence args_indices; - return stack_detail::call(tr, ta, args_indices(), L, start, std::forward(fx), std::forward(args)...); -} + template ::value>> + inline decltype(auto) call(types tr, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { + typedef std::make_index_sequence args_indices; + return stack_detail::call(tr, ta, args_indices(), L, start, std::forward(fx), std::forward(args)...); + } -template ::value>> -inline decltype(auto) call(types tr, types ta, lua_State* L, Fx&& fx, FxArgs&&... args) { - return call(tr, ta, L, 1, std::forward(fx), std::forward(args)...); -} + template ::value>> + inline decltype(auto) call(types tr, types ta, lua_State* L, Fx&& fx, FxArgs&&... args) { + return call(tr, ta, L, 1, std::forward(fx), std::forward(args)...); + } -template -inline void call(types tr, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { - typedef std::make_index_sequence args_indices; - stack_detail::call(tr, ta, args_indices(), L, start, std::forward(fx), std::forward(args)...); -} + template + inline void call(types tr, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { + typedef std::make_index_sequence args_indices; + stack_detail::call(tr, ta, args_indices(), L, start, std::forward(fx), std::forward(args)...); + } -template -inline void call(types tr, types ta, lua_State* L, Fx&& fx, FxArgs&&... args) { - call(tr, ta, L, 1, std::forward(fx), std::forward(args)...); -} + template + inline void call(types tr, types ta, lua_State* L, Fx&& fx, FxArgs&&... args) { + call(tr, ta, L, 1, std::forward(fx), std::forward(args)...); + } -template ::value>> -inline decltype(auto) call_from_top(types tr, types ta, lua_State* L, Fx&& fx, FxArgs&&... args) { - return call(tr, ta, L, static_cast(lua_gettop(L) - sizeof...(Args)), std::forward(fx), std::forward(args)...); -} + template ::value>> + inline decltype(auto) call_from_top(types tr, types ta, lua_State* L, Fx&& fx, FxArgs&&... args) { + return call(tr, ta, L, static_cast(lua_gettop(L) - sizeof...(Args)), std::forward(fx), std::forward(args)...); + } -template -inline void call_from_top(types tr, types ta, lua_State* L, Fx&& fx, FxArgs&&... args) { - call(tr, ta, L, static_cast(lua_gettop(L) - sizeof...(Args)), std::forward(fx), std::forward(args)...); -} + template + inline void call_from_top(types tr, types ta, lua_State* L, Fx&& fx, FxArgs&&... args) { + call(tr, ta, L, static_cast(lua_gettop(L) - sizeof...(Args)), std::forward(fx), std::forward(args)...); + } -template -inline int call_into_lua(types tr, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { - call(tr, ta, L, start, std::forward(fx), std::forward(fxargs)...); - int nargs = static_cast(sizeof...(Args)) + additionalpop - meta::count_for_pack::value; - lua_pop(L, nargs); - return 0; -} + template + inline int call_into_lua(types tr, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { + call(tr, ta, L, start, std::forward(fx), std::forward(fxargs)...); + int nargs = static_cast(sizeof...(Args)) + additionalpop - meta::count_for_pack::value; + lua_pop(L, nargs); + return 0; + } -template>::value>> -inline int call_into_lua(types, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { - decltype(auto) r = call(types>(), ta, L, start, std::forward(fx), std::forward(fxargs)...); - int nargs = static_cast(sizeof...(Args)) + additionalpop - meta::count_for_pack::value; - lua_pop(L, nargs); - return push_reference(L, std::forward(r)); -} + template>::value>> + inline int call_into_lua(types, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { + decltype(auto) r = call(types>(), ta, L, start, std::forward(fx), std::forward(fxargs)...); + int nargs = static_cast(sizeof...(Args)) + additionalpop - meta::count_for_pack::value; + lua_pop(L, nargs); + return push_reference(L, std::forward(r)); + } -template -inline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { - typedef lua_bind_traits> traits_type; - typedef typename traits_type::args_list args_list; - typedef typename traits_type::returns_list returns_list; - return call_into_lua(returns_list(), args_list(), L, start, std::forward(fx), std::forward(fxargs)...); -} + template + inline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { + typedef lua_bind_traits> traits_type; + typedef typename traits_type::args_list args_list; + typedef typename traits_type::returns_list returns_list; + return call_into_lua(returns_list(), args_list(), L, start, std::forward(fx), std::forward(fxargs)...); + } -inline call_syntax get_call_syntax(lua_State* L, const std::string& key, int index = -2) { - luaL_getmetatable(L, key.c_str()); - if (lua_compare(L, -1, index, LUA_OPEQ) == 1) { - lua_pop(L, 1); - return call_syntax::colon; - } - lua_pop(L, 1); - return call_syntax::dot; -} + inline call_syntax get_call_syntax(lua_State* L, const std::string& key, int index = -2) { + luaL_getmetatable(L, key.c_str()); + if (lua_compare(L, -1, index, LUA_OPEQ) == 1) { + lua_pop(L, 1); + return call_syntax::colon; + } + lua_pop(L, 1); + return call_syntax::dot; + } -inline void luajit_exception_handler(lua_State* L, int(*handler)(lua_State*, lua_CFunction) = detail::c_trampoline) { + inline void luajit_exception_handler(lua_State* L, int(*handler)(lua_State*, lua_CFunction) = detail::c_trampoline) { #ifdef SOL_LUAJIT - lua_pushlightuserdata(L, (void*)handler); - luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_ON); - lua_pop(L, 1); + lua_pushlightuserdata(L, (void*)handler); + luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_ON); + lua_pop(L, 1); #else - (void)L; - (void)handler; + (void)L; + (void)handler; #endif -} + } -inline void luajit_exception_off(lua_State* L) { + inline void luajit_exception_off(lua_State* L) { #ifdef SOL_LUAJIT - luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_OFF); + luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_OFF); #else - (void)L; + (void)L; #endif -} -} // stack -} // sol + } +}} // sol::stack #endif // SOL_STACK_HPP diff --git a/sol/stack_check.hpp b/sol/stack_check.hpp index 93e1c92b..7c1a7669 100644 --- a/sol/stack_check.hpp +++ b/sol/stack_check.hpp @@ -260,7 +260,7 @@ struct checker { handler(L, index, type::userdata, indextype); return false; } - if (meta::any, std::is_same, std::is_same, std::is_same>::value) + if (meta::any, std::is_same, std::is_same, std::is_same>::value) return true; if (lua_getmetatable(L, index) == 0) { return true; @@ -271,30 +271,29 @@ struct checker { return true; if (stack_detail::check_metatable>(L)) return true; + bool success = true; #ifndef SOL_NO_EXCEPTIONS lua_getfield(L, -1, &detail::base_class_check_key()[0]); - void* basecastdata = lua_touserdata(L, -1); - detail::throw_cast basecast = (detail::throw_cast)basecastdata; - bool success = detail::catch_check(basecast); + if (stack::get(L) != type::nil) { + void* basecastdata = lua_touserdata(L, -1); + detail::throw_cast basecast = (detail::throw_cast)basecastdata; + success = detail::catch_check(basecast); + } #elif !defined(SOL_NO_RTTI) lua_getfield(L, -1, &detail::base_class_check_key()[0]); - if (stack::get(L) == type::nil) { - lua_pop(L, 2); - return false; + if (stack::get(L) != type::nil) { + void* basecastdata = lua_touserdata(L, -1); + detail::inheritance_check_function ic = (detail::inheritance_check_function)basecastdata; + success = ic(typeid(T)); } - void* basecastdata = lua_touserdata(L, -1); - detail::inheritance_check_function ic = (detail::inheritance_check_function)basecastdata; - bool success = ic(typeid(T)); #else // Topkek lua_getfield(L, -1, &detail::base_class_check_key()[0]); - if (stack::get(L) == type::nil) { - lua_pop(L, 2); - return false; + if (stack::get(L) != type::nil) { + void* basecastdata = lua_touserdata(L, -1); + detail::inheritance_check_function ic = (detail::inheritance_check_function)basecastdata; + success = ic(detail::id_for::value); } - void* basecastdata = lua_touserdata(L, -1); - detail::inheritance_check_function ic = (detail::inheritance_check_function)basecastdata; - bool success = ic(detail::id_for::value); #endif // No Runtime Type Information || Exceptions lua_pop(L, 2); if (!success) { diff --git a/sol/stack_get.hpp b/sol/stack_get.hpp index dfc6299b..a31bc77b 100644 --- a/sol/stack_get.hpp +++ b/sol/stack_get.hpp @@ -84,9 +84,9 @@ struct getter { }; template<> -struct getter { - static light_userdata_value get(lua_State* L, int index = -1) { - return light_userdata_value( lua_touserdata(L, index) ); +struct getter { + static lightuserdata_value get(lua_State* L, int index = -1) { + return lightuserdata_value( lua_touserdata(L, index) ); } }; diff --git a/sol/stack_push.hpp b/sol/stack_push.hpp index 5159fbba..d36753ba 100644 --- a/sol/stack_push.hpp +++ b/sol/stack_push.hpp @@ -262,8 +262,8 @@ struct pusher { }; template<> -struct pusher { - static int push(lua_State* L, light_userdata_value userdata) { +struct pusher { + static int push(lua_State* L, lightuserdata_value userdata) { lua_pushlightuserdata(L, userdata); return 1; } @@ -279,21 +279,39 @@ struct pusher> { template struct pusher> { - template - static int push(lua_State* L, Args&&... args ) { + template + static int push_with(lua_State* L, Args&&... args ) { // A dumb pusher void* rawdata = lua_newuserdata(L, sizeof(T)); std::allocator alloc; alloc.construct(static_cast(rawdata), std::forward(args)...); - lua_CFunction cdel = stack_detail::alloc_destroy; - // Make sure we have a plain GC set for this data - lua_createtable(L, 0, 1); - lua_pushlightuserdata(L, rawdata); - lua_pushcclosure(L, cdel, 1); - lua_setfield(L, -2, "__gc"); - lua_setmetatable(L, -2); + if (with_meta) { + lua_CFunction cdel = stack_detail::alloc_destroy; + // Make sure we have a plain GC set for this data + lua_createtable(L, 0, 1); + lua_pushlightuserdata(L, rawdata); + lua_pushcclosure(L, cdel, 1); + lua_setfield(L, -2, "__gc"); + lua_setmetatable(L, -2); + } return 1; } + + static int push(lua_State* L, const user& u) { + return push_with(L, u.value); + } + + static int push(lua_State* L, user&& u) { + return push_with(L, std::move(u.value)); + } + + static int push(lua_State* L, no_metatable_t, const user& u) { + return push_with(L, u.value); + } + + static int push(lua_State* L, no_metatable_t, user&& u) { + return push_with(L, std::move(u.value)); + } }; template<> diff --git a/sol/types.hpp b/sol/types.hpp index 32cc1faa..244dd42d 100644 --- a/sol/types.hpp +++ b/sol/types.hpp @@ -110,6 +110,9 @@ inline bool operator!=(nil_t, nil_t) { return false; } struct metatable_key_t {}; const metatable_key_t metatable_key = {}; +struct no_metatable_t {}; +const no_metatable_t no_metatable = {}; + typedef std::remove_pointer_t lua_r_CFunction; template @@ -177,9 +180,9 @@ struct absolute_index { operator int() const { return index; } }; -struct light_userdata_value { +struct lightuserdata_value { void* value; - light_userdata_value(void* data) : value(data) {} + lightuserdata_value(void* data) : value(data) {} operator void*() const { return value; } }; @@ -533,7 +536,7 @@ template struct lua_type_of> : std::integral_constant {}; template <> -struct lua_type_of : std::integral_constant {}; +struct lua_type_of : std::integral_constant {}; template <> struct lua_type_of : std::integral_constant {}; @@ -600,12 +603,12 @@ template struct lua_type_of : detail::lua_type_of {}; template -struct is_lua_primitive : std::integral_constant>::value - || std::is_base_of>::value - || std::is_base_of>::value - || meta::is_specialization_of>::value - || meta::is_specialization_of>::value +struct is_lua_primitive : std::integral_constant>::value + || std::is_base_of>::value + || std::is_base_of>::value + || meta::is_specialization_of>::value + || meta::is_specialization_of>::value > { }; template @@ -617,7 +620,7 @@ struct is_lua_primitive : std::true_type {}; template <> struct is_lua_primitive : std::true_type {}; template <> -struct is_lua_primitive : std::true_type {}; +struct is_lua_primitive : std::true_type {}; template struct is_lua_primitive> : is_lua_primitive {}; diff --git a/sol/usertype_metatable.hpp b/sol/usertype_metatable.hpp index 1437a336..33ca10b8 100644 --- a/sol/usertype_metatable.hpp +++ b/sol/usertype_metatable.hpp @@ -125,23 +125,6 @@ namespace sol { l[index] = { name_of(meta_function::garbage_collect).c_str(), destructfunc }; ++index; } - if (baseclasscast != nullptr) - return index; -#ifndef SOL_NO_EXCEPTIONS - static_assert(sizeof(void*) <= sizeof(detail::throw_cast), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report."); - baseclasscheck = baseclasscast = (void*)&detail::throw_as; -#elif !defined(SOL_NO_RTTI) - static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report."); - static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report."); - baseclasscheck = (void*)&detail::inheritance::type_check; - baseclasscast = (void*)&detail::inheritance::type_cast; -#else - static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report."); - static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report."); - baseclasscheck = (void*)&detail::inheritance::type_check; - baseclasscast = (void*)&detail::inheritance::type_cast; -#endif // No Runtime Type Information vs. Throw-Style Inheritance - return index; } @@ -172,6 +155,7 @@ namespace sol { baseclasscheck = (void*)&detail::inheritance::type_check; baseclasscast = (void*)&detail::inheritance::type_cast; #endif // No Runtime Type Information vs. Throw-Style Inheritance + return endindex; } template , base_classes_tag, call_construction>::value>> @@ -249,6 +233,10 @@ namespace sol { virtual int push_um(lua_State* L) override { return stack::push(L, std::move(*this)); } + + ~usertype_metatable() override { + + } }; namespace stack { @@ -258,15 +246,22 @@ namespace sol { typedef usertype_metatable umt_t; typedef typename umt_t::regs_t regs_t; - template - static int push(std::index_sequence, lua_State* L, usertype_metatable&& umx) { + static usertype_metatable& make_cleanup(lua_State* L, usertype_metatable&& umx) { // Make sure userdata's memory is properly in lua first, // otherwise all the light userdata we make later will become invalid - stack::push(L, make_user(std::move(umx))); - usertype_metatable& um = stack::get>>(L, -1); - reference umt(L, -1); - umt.pop(); + // Create the top level thing that will act as our deleter later on + const char* gcmetakey = &usertype_traits::gc_table[0]; + stack::set_field(L, gcmetakey, make_user(std::move(umx))); + stack::get_field(L, gcmetakey); + return stack::pop>>(L); + } + + template + static int push(std::index_sequence, lua_State* L, usertype_metatable&& umx) { + + usertype_metatable& um = make_cleanup(L, std::move(umx)); + // Now use um const bool& mustindex = um.mustindex; stack_reference t; @@ -328,27 +323,6 @@ namespace sol { if (i < 2) { t.pop(); } - else { - // NOT NEEDED - // Perhaps we should look into - // whether or not doing ti like this - // is better than just letting user handle it? - - // Add cleanup to metatable - // Essentially, when the metatable dies, - // this too will call the class and kill itself - /*const char* metakey = &usertype_traits::gc_table[0]; - lua_createtable(L, 1, 0); - stack_reference cleanup(L, -1); - stack::set_field(L, meta_function::garbage_collect, make_closure(umt_t::gc_call, umt), cleanup.stack_index()); - stack::set_field(L, metatable_key, cleanup, cleanup.stack_index()); - // Needs to be raw since we - // override the metatable's metatable on 't' - // otherwise, it will trigger the __index metamethod - // we just set - stack::raw_set_field(L, metakey, t, t.stack_index()); - cleanup.pop();*/ - } } return 1;