SPEED AND FIXES, HOOOOOOOOO!

This commit is contained in:
ThePhD 2016-06-10 21:04:48 -04:00
parent 295b7b1a08
commit e1241c110a
10 changed files with 231 additions and 247 deletions

View File

@ -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<Types...>()`` 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<Types...>()`` 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:

View File

@ -145,7 +145,7 @@ namespace call_detail {
template <typename F, bool is_index, bool is_variable, typename = void>
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<meta::unqualified_t<F>> 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<is_index ? 1 : 2>(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<meta::unqualified_t<F>> 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<bool, is_variable>(), L, f);
}
};
template <typename F, bool is_index, bool is_variable>
struct agnostic_lua_call_wrapper<F, is_index, is_variable, std::enable_if_t<std::is_member_function_pointer<F>::value>> {
static int call(lua_State* L, F f) {
static int call(lua_State* L, F& f) {
typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::returns_list returns_list;
typedef typename wrap::args_list args_list;
@ -204,7 +204,7 @@ namespace call_detail {
template <bool is_index, bool is_variable, typename C>
struct agnostic_lua_call_wrapper<no_prop, is_index, is_variable, C> {
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<F, false, is_variable, std::enable_if_t<std::is_member_object_pointer<F>::value>> {
typedef sol::lua_bind_traits<F> 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<meta::unqualified_t<F>> 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<std::add_lvalue_reference_t<meta::unqualified_t<R>>, 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<typename traits_type::return_type>(), L, f);
}
};
@ -255,7 +255,7 @@ namespace call_detail {
struct agnostic_lua_call_wrapper<F, true, is_variable, std::enable_if_t<std::is_member_object_pointer<F>::value>> {
typedef sol::lua_bind_traits<F> traits_type;
static int call(lua_State* L, F f) {
static int call(lua_State* L, F& f) {
typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::object_type object_type;
typedef typename wrap::returns_list returns_list;

View File

@ -89,7 +89,7 @@ struct pusher<function_sig<Sigs...>> {
lua_CFunction freefunc = &function_detail::upvalue_member_variable<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>>::call;
int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr);
upvalues += stack::push(L, light_userdata_value(static_cast<void*>(userptr)));
upvalues += stack::push(L, lightuserdata_value(static_cast<void*>(userptr)));
stack::push(L, c_closure(freefunc, upvalues));
}
@ -127,7 +127,7 @@ struct pusher<function_sig<Sigs...>> {
lua_CFunction freefunc = &function_detail::upvalue_member_function<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>>::call;
int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr);
upvalues += stack::push(L, light_userdata_value(static_cast<void*>(userptr)));
upvalues += stack::push(L, lightuserdata_value(static_cast<void*>(userptr)));
stack::push(L, c_closure(freefunc, upvalues));
}

View File

@ -70,7 +70,7 @@ static void func_gc(std::true_type, lua_State*) {
template <std::size_t limit>
static void func_gc(std::false_type, lua_State* L) {
for (std::size_t i = 0; i < limit; ++i) {
void* value = stack::get<light_userdata_value>(L, up_value_index(static_cast<int>(i + 1)));
void* value = stack::get<lightuserdata_value>(L, up_value_index(static_cast<int>(i + 1)));
if (value == nullptr)
continue;
base_function* obj = static_cast<base_function*>(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<light_userdata_value>(L, up_value_index(1));
void* ludata = stack::get<lightuserdata_value>(L, up_value_index(1));
void** pinheritancedata = static_cast<void**>(ludata);
return base_call(L, *pinheritancedata);
}
@ -95,7 +95,7 @@ inline int gc(lua_State* L) {
template<std::size_t I>
inline int usertype_call(lua_State* L) {
// Zero-based template parameter, but upvalues start at 1
return base_call(L, stack::get<light_userdata_value>(L, up_value_index(static_cast<int>(I + 1))));
return base_call(L, stack::get<lightuserdata_value>(L, up_value_index(static_cast<int>(I + 1))));
}
template<std::size_t I>

View File

@ -34,171 +34,169 @@
#include <cstring>
#include <array>
namespace sol {
namespace stack {
namespace stack_detail {
template <typename T>
struct is_this_state_raw : std::false_type {};
template <>
struct is_this_state_raw<this_state> : std::true_type {};
template <typename T>
using is_this_state = is_this_state_raw<meta::unqualified_t<T>>;
namespace sol { namespace stack {
namespace stack_detail {
template <typename T>
struct is_this_state_raw : std::false_type {};
template <>
struct is_this_state_raw<this_state> : std::true_type {};
template <typename T>
using is_this_state = is_this_state_raw<meta::unqualified_t<T>>;
template<typename T>
inline int push_as_upvalues(lua_State* L, T& item) {
typedef std::decay_t<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<void*, data_t_count> data_t;
template<typename T>
inline int push_as_upvalues(lua_State* L, T& item) {
typedef std::decay_t<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<void*, data_t_count> 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<typename T>
inline std::pair<T, int> 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<void*, data_t_count> data_t;
data_t voiddata{ {} };
for(std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof(void*)) {
voiddata[i] = get<light_userdata_value>(L, up_value_index(index++));
}
return std::pair<T, int>(*reinterpret_cast<T*>(static_cast<void*>(voiddata.data())), index);
}
template<typename T>
inline std::pair<T, int> 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<void*, data_t_count> data_t;
data_t voiddata{ {} };
for (std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof(void*)) {
voiddata[i] = get<lightuserdata_value>(L, up_value_index(index++));
}
return std::pair<T, int>(*reinterpret_cast<T*>(static_cast<void*>(voiddata.data())), index);
}
template <bool checkargs = default_check_arguments, std::size_t... I, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>>
inline decltype(auto) call(types<R>, types<Args...> ta, std::index_sequence<I...> tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
template <bool checkargs = default_check_arguments, std::size_t... I, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>>
inline decltype(auto) call(types<R>, types<Args...> ta, std::index_sequence<I...> tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
#ifndef _MSC_VER
static_assert(meta::all<meta::is_not_move_only<Args>...>::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<meta::is_not_move_only<Args>...>::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<checkargs>{}.check(ta, tai, L, start, type_panic);
return fx(std::forward<FxArgs>(args)..., stack_detail::unchecked_get<Args>(L, start + I - meta::count_for_to_pack<I, is_transparent_argument, Args...>::value)...);
}
check_types<checkargs>{}.check(ta, tai, L, start, type_panic);
return fx(std::forward<FxArgs>(args)..., stack_detail::unchecked_get<Args>(L, start + I - meta::count_for_to_pack<I, is_transparent_argument, Args...>::value)...);
}
template <bool checkargs = default_check_arguments, std::size_t... I, typename... Args, typename Fx, typename... FxArgs>
inline void call(types<void>, types<Args...> ta, std::index_sequence<I...> tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
template <bool checkargs = default_check_arguments, std::size_t... I, typename... Args, typename Fx, typename... FxArgs>
inline void call(types<void>, types<Args...> ta, std::index_sequence<I...> tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
#ifndef _MSC_VER
static_assert(meta::all<meta::is_not_move_only<Args>...>::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<meta::is_not_move_only<Args>...>::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<checkargs>{}.check(ta, tai, L, start, type_panic);
fx(std::forward<FxArgs>(args)..., stack_detail::unchecked_get<Args>(L, start + I - meta::count_for_to_pack<I, is_transparent_argument, Args...>::value)...);
}
} // stack_detail
check_types<checkargs>{}.check(ta, tai, L, start, type_panic);
fx(std::forward<FxArgs>(args)..., stack_detail::unchecked_get<Args>(L, start + I - meta::count_for_to_pack<I, is_transparent_argument, Args...>::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<int>(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<int>(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 <bool check_args = stack_detail::default_check_arguments, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>>
inline decltype(auto) call(types<R> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
typedef std::make_index_sequence<sizeof...(Args)> args_indices;
return stack_detail::call<check_args>(tr, ta, args_indices(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
}
template <bool check_args = stack_detail::default_check_arguments, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>>
inline decltype(auto) call(types<R> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
typedef std::make_index_sequence<sizeof...(Args)> args_indices;
return stack_detail::call<check_args>(tr, ta, args_indices(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
}
template <bool check_args = stack_detail::default_check_arguments, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>>
inline decltype(auto) call(types<R> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) {
return call<check_args>(tr, ta, L, 1, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
}
template <bool check_args = stack_detail::default_check_arguments, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>>
inline decltype(auto) call(types<R> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) {
return call<check_args>(tr, ta, L, 1, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
}
template <bool check_args = stack_detail::default_check_arguments, typename... Args, typename Fx, typename... FxArgs>
inline void call(types<void> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
typedef std::make_index_sequence<sizeof...(Args)> args_indices;
stack_detail::call<check_args>(tr, ta, args_indices(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
}
template <bool check_args = stack_detail::default_check_arguments, typename... Args, typename Fx, typename... FxArgs>
inline void call(types<void> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
typedef std::make_index_sequence<sizeof...(Args)> args_indices;
stack_detail::call<check_args>(tr, ta, args_indices(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
}
template <bool check_args = stack_detail::default_check_arguments, typename... Args, typename Fx, typename... FxArgs>
inline void call(types<void> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) {
call<check_args>(tr, ta, L, 1, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
}
template <bool check_args = stack_detail::default_check_arguments, typename... Args, typename Fx, typename... FxArgs>
inline void call(types<void> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) {
call<check_args>(tr, ta, L, 1, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
}
template <bool check_args = stack_detail::default_check_arguments, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>>
inline decltype(auto) call_from_top(types<R> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) {
return call<check_args>(tr, ta, L, static_cast<int>(lua_gettop(L) - sizeof...(Args)), std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
}
template <bool check_args = stack_detail::default_check_arguments, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>>
inline decltype(auto) call_from_top(types<R> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) {
return call<check_args>(tr, ta, L, static_cast<int>(lua_gettop(L) - sizeof...(Args)), std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
}
template <bool check_args = stack_detail::default_check_arguments, typename... Args, typename Fx, typename... FxArgs>
inline void call_from_top(types<void> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) {
call<check_args>(tr, ta, L, static_cast<int>(lua_gettop(L) - sizeof...(Args)), std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
}
template <bool check_args = stack_detail::default_check_arguments, typename... Args, typename Fx, typename... FxArgs>
inline void call_from_top(types<void> tr, types<Args...> ta, lua_State* L, Fx&& fx, FxArgs&&... args) {
call<check_args>(tr, ta, L, static_cast<int>(lua_gettop(L) - sizeof...(Args)), std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
}
template<int additionalpop = 0, bool check_args = stack_detail::default_check_arguments, typename... Args, typename Fx, typename... FxArgs>
inline int call_into_lua(types<void> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) {
call<check_args>(tr, ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
int nargs = static_cast<int>(sizeof...(Args)) + additionalpop - meta::count_for_pack<stack_detail::is_this_state, Args...>::value;
lua_pop(L, nargs);
return 0;
}
template<int additionalpop = 0, bool check_args = stack_detail::default_check_arguments, typename... Args, typename Fx, typename... FxArgs>
inline int call_into_lua(types<void> tr, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) {
call<check_args>(tr, ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
int nargs = static_cast<int>(sizeof...(Args)) + additionalpop - meta::count_for_pack<stack_detail::is_this_state, Args...>::value;
lua_pop(L, nargs);
return 0;
}
template<int additionalpop = 0, bool check_args = stack_detail::default_check_arguments, typename Ret0, typename... Ret, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<meta::neg<std::is_void<Ret0>>::value>>
inline int call_into_lua(types<Ret0, Ret...>, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) {
decltype(auto) r = call<check_args>(types<meta::return_type_t<Ret0, Ret...>>(), ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
int nargs = static_cast<int>(sizeof...(Args)) + additionalpop - meta::count_for_pack<stack_detail::is_this_state, Args...>::value;
lua_pop(L, nargs);
return push_reference(L, std::forward<decltype(r)>(r));
}
template<int additionalpop = 0, bool check_args = stack_detail::default_check_arguments, typename Ret0, typename... Ret, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<meta::neg<std::is_void<Ret0>>::value>>
inline int call_into_lua(types<Ret0, Ret...>, types<Args...> ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) {
decltype(auto) r = call<check_args>(types<meta::return_type_t<Ret0, Ret...>>(), ta, L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
int nargs = static_cast<int>(sizeof...(Args)) + additionalpop - meta::count_for_pack<stack_detail::is_this_state, Args...>::value;
lua_pop(L, nargs);
return push_reference(L, std::forward<decltype(r)>(r));
}
template<int additionalpop = 0, bool check_args = stack_detail::default_check_arguments, typename Fx, typename... FxArgs>
inline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) {
typedef lua_bind_traits<meta::unqualified_t<Fx>> 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>(fx), std::forward<FxArgs>(fxargs)...);
}
template<int additionalpop = 0, bool check_args = stack_detail::default_check_arguments, typename Fx, typename... FxArgs>
inline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) {
typedef lua_bind_traits<meta::unqualified_t<Fx>> 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>(fx), std::forward<FxArgs>(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

View File

@ -260,7 +260,7 @@ struct checker<T, type::userdata, C> {
handler(L, index, type::userdata, indextype);
return false;
}
if (meta::any<std::is_same<T, light_userdata_value>, std::is_same<T, userdata_value>, std::is_same<T, userdata>, std::is_same<T, lightuserdata>>::value)
if (meta::any<std::is_same<T, lightuserdata_value>, std::is_same<T, userdata_value>, std::is_same<T, userdata>, std::is_same<T, lightuserdata>>::value)
return true;
if (lua_getmetatable(L, index) == 0) {
return true;
@ -271,30 +271,29 @@ struct checker<T, type::userdata, C> {
return true;
if (stack_detail::check_metatable<detail::unique_usertype<U>>(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<T>(basecast);
if (stack::get<type>(L) != type::nil) {
void* basecastdata = lua_touserdata(L, -1);
detail::throw_cast basecast = (detail::throw_cast)basecastdata;
success = detail::catch_check<T>(basecast);
}
#elif !defined(SOL_NO_RTTI)
lua_getfield(L, -1, &detail::base_class_check_key()[0]);
if (stack::get<type>(L) == type::nil) {
lua_pop(L, 2);
return false;
if (stack::get<type>(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<type>(L) == type::nil) {
lua_pop(L, 2);
return false;
if (stack::get<type>(L) != type::nil) {
void* basecastdata = lua_touserdata(L, -1);
detail::inheritance_check_function ic = (detail::inheritance_check_function)basecastdata;
success = ic(detail::id_for<T>::value);
}
void* basecastdata = lua_touserdata(L, -1);
detail::inheritance_check_function ic = (detail::inheritance_check_function)basecastdata;
bool success = ic(detail::id_for<T>::value);
#endif // No Runtime Type Information || Exceptions
lua_pop(L, 2);
if (!success) {

View File

@ -84,9 +84,9 @@ struct getter<userdata_value> {
};
template<>
struct getter<light_userdata_value> {
static light_userdata_value get(lua_State* L, int index = -1) {
return light_userdata_value( lua_touserdata(L, index) );
struct getter<lightuserdata_value> {
static lightuserdata_value get(lua_State* L, int index = -1) {
return lightuserdata_value( lua_touserdata(L, index) );
}
};

View File

@ -262,8 +262,8 @@ struct pusher<void*> {
};
template<>
struct pusher<light_userdata_value> {
static int push(lua_State* L, light_userdata_value userdata) {
struct pusher<lightuserdata_value> {
static int push(lua_State* L, lightuserdata_value userdata) {
lua_pushlightuserdata(L, userdata);
return 1;
}
@ -279,21 +279,39 @@ struct pusher<light<T>> {
template<typename T>
struct pusher<user<T>> {
template <typename... Args>
static int push(lua_State* L, Args&&... args ) {
template <bool with_meta = true, typename... Args>
static int push_with(lua_State* L, Args&&... args ) {
// A dumb pusher
void* rawdata = lua_newuserdata(L, sizeof(T));
std::allocator<T> alloc;
alloc.construct(static_cast<T*>(rawdata), std::forward<Args>(args)...);
lua_CFunction cdel = stack_detail::alloc_destroy<T>;
// 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<T>;
// 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<T>& u) {
return push_with(L, u.value);
}
static int push(lua_State* L, user<T>&& u) {
return push_with(L, std::move(u.value));
}
static int push(lua_State* L, no_metatable_t, const user<T>& u) {
return push_with<false>(L, u.value);
}
static int push(lua_State* L, no_metatable_t, user<T>&& u) {
return push_with<false>(L, std::move(u.value));
}
};
template<>

View File

@ -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_CFunction> lua_r_CFunction;
template <typename T>
@ -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 <typename A, typename B>
struct lua_type_of<std::pair<A, B>> : std::integral_constant<type, type::poly> {};
template <>
struct lua_type_of<light_userdata_value> : std::integral_constant<type, type::lightuserdata> {};
struct lua_type_of<lightuserdata_value> : std::integral_constant<type, type::lightuserdata> {};
template <>
struct lua_type_of<userdata_value> : std::integral_constant<type, type::userdata> {};
@ -600,12 +603,12 @@ template <typename T>
struct lua_type_of : detail::lua_type_of<T> {};
template <typename T>
struct is_lua_primitive : std::integral_constant<bool,
type::userdata != lua_type_of<meta::unqualified_t<T>>::value
|| std::is_base_of<reference, meta::unqualified_t<T>>::value
|| std::is_base_of<stack_reference, meta::unqualified_t<T>>::value
|| meta::is_specialization_of<std::tuple, meta::unqualified_t<T>>::value
|| meta::is_specialization_of<std::pair, meta::unqualified_t<T>>::value
struct is_lua_primitive : std::integral_constant<bool,
type::userdata != lua_type_of<meta::unqualified_t<T>>::value
|| std::is_base_of<reference, meta::unqualified_t<T>>::value
|| std::is_base_of<stack_reference, meta::unqualified_t<T>>::value
|| meta::is_specialization_of<std::tuple, meta::unqualified_t<T>>::value
|| meta::is_specialization_of<std::pair, meta::unqualified_t<T>>::value
> { };
template <typename T>
@ -617,7 +620,7 @@ struct is_lua_primitive<T*> : std::true_type {};
template <>
struct is_lua_primitive<userdata_value> : std::true_type {};
template <>
struct is_lua_primitive<light_userdata_value> : std::true_type {};
struct is_lua_primitive<lightuserdata_value> : std::true_type {};
template <typename T>
struct is_lua_primitive<non_null<T>> : is_lua_primitive<T*> {};

View File

@ -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<T>;
#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<T>::type_check;
baseclasscast = (void*)&detail::inheritance<T>::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<T>::type_check;
baseclasscast = (void*)&detail::inheritance<T>::type_cast;
#endif // No Runtime Type Information vs. Throw-Style Inheritance
return index;
}
@ -172,6 +155,7 @@ namespace sol {
baseclasscheck = (void*)&detail::inheritance<T, Args...>::type_check;
baseclasscast = (void*)&detail::inheritance<T, Args...>::type_cast;
#endif // No Runtime Type Information vs. Throw-Style Inheritance
return endindex;
}
template <std::size_t I = 0, typename N, typename F, typename... Args, typename = std::enable_if_t<!meta::any_same<meta::unqualified_t<N>, 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<T, Tuple> umt_t;
typedef typename umt_t::regs_t regs_t;
template <std::size_t... I>
static int push(std::index_sequence<I...>, lua_State* L, usertype_metatable<T, Tuple>&& umx) {
static usertype_metatable<T, Tuple>& make_cleanup(lua_State* L, usertype_metatable<T, Tuple>&& 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<T, Tuple>& um = stack::get<light<usertype_metatable<T, Tuple>>>(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<T>::gc_table[0];
stack::set_field<true>(L, gcmetakey, make_user(std::move(umx)));
stack::get_field<true>(L, gcmetakey);
return stack::pop<light<usertype_metatable<T, Tuple>>>(L);
}
template <std::size_t... I>
static int push(std::index_sequence<I...>, lua_State* L, usertype_metatable<T, Tuple>&& umx) {
usertype_metatable<T, Tuple>& 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<T> 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<T>::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;