mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
Overloaded functions now work properly when types are specified in signature
this triggered overhaul of set_function/pusher<function_t>::push(...) both state and table reflect changes to userdata structure to make it easier to use tests updated to account for overload resolution some function-related traits added to make use easier -- cleaned up archaic typenames in function_types.hpp Account for std::reference_wrapper for objects -- sol now uses copy-by-default (value-semantics) for all functors updated tests to reflect this
This commit is contained in:
parent
b41f92adc9
commit
eb25bb05bb
139
sol/function.hpp
139
sol/function.hpp
|
@ -85,76 +85,112 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace stack {
|
namespace stack {
|
||||||
template <>
|
template <typename... Sigs>
|
||||||
struct pusher<function_t> {
|
struct pusher<function_sig_t<Sigs...>> {
|
||||||
|
|
||||||
template<typename TFx>
|
template<typename R, typename... Args, typename Fx, typename = typename std::result_of<Fx(Args...)>::type>
|
||||||
static void set_isfunction_fx(std::true_type, lua_State* L, TFx&& fx) {
|
static void set_memfx(types<R(Args...)> t, lua_State* L, Fx&& fx) {
|
||||||
set_fx(std::false_type(), L, std::forward<TFx>(fx));
|
typedef Decay<Unwrap<Fx>> raw_fx_t;
|
||||||
|
typedef R(* fx_ptr_t)(Args...);
|
||||||
|
typedef std::is_convertible<raw_fx_t, fx_ptr_t> is_convertible;
|
||||||
|
set_isconvertible_fx(is_convertible(), t, L, std::forward<Fx>(fx));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename TFx>
|
template<typename... Args, typename Fx, typename... Cx, typename R = typename std::result_of<Fx(Args...)>::type>
|
||||||
static void set_isfunction_fx(std::false_type, lua_State* L, TFx&& fx) {
|
static void set_memfx(types<Args...>, lua_State* L, Fx&& fx){
|
||||||
typedef Decay<TFx> clean_lambda;
|
set_memfx(types<R(Args...)>(), L, std::forward<Fx>(fx));
|
||||||
typedef typename function_traits<decltype(&clean_lambda::operator())>::free_function_pointer_type raw_func_t;
|
|
||||||
typedef std::is_convertible<clean_lambda, raw_func_t> is_convertible;
|
|
||||||
set_isconvertible_fx(is_convertible(), L, std::forward<TFx>(fx));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename TFx>
|
template<typename Fx>
|
||||||
static void set_isconvertible_fx(std::true_type, lua_State* L, TFx&& fx) {
|
static void set_memfx(types<>, lua_State* L, Fx&& fx) {
|
||||||
typedef Decay<TFx> clean_lambda;
|
typedef Unqualified<Unwrap<Fx>> fx_t;
|
||||||
typedef typename function_traits<decltype(&clean_lambda::operator())>::free_function_pointer_type raw_func_t;
|
typedef decltype(&fx_t::operator()) Sig;
|
||||||
set_isfunction_fx(std::true_type(), L, raw_func_t(std::forward<TFx>(fx)));
|
set_memfx(types<function_signature_t<Sig>>(), L, std::forward<Fx>(fx));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename TFx>
|
template<typename... Args, typename R>
|
||||||
static void set_isconvertible_fx(std::false_type, lua_State* L, TFx&& fx) {
|
static void set(lua_State* L, R fxptr(Args...)){
|
||||||
typedef typename std::remove_pointer<Decay<TFx>>::type clean_fx;
|
set_fx(std::false_type(), L, fxptr);
|
||||||
std::unique_ptr<base_function> sptr(new functor_function<clean_fx>(std::forward<TFx>(fx)));
|
|
||||||
set_fx<TFx>(L, std::move(sptr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename TFx, typename TObj>
|
template<typename Sig>
|
||||||
static void set_lvalue_fx(std::true_type, lua_State* L, TFx&& fx, TObj&& obj) {
|
static void set(lua_State* L, Sig* fxptr){
|
||||||
set_fx(std::true_type(), L, std::forward<TFx>(fx), std::forward<TObj>(obj));
|
set_fx(std::false_type(), L, fxptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename TFx, typename TObj>
|
template<typename... Args, typename R, typename C, typename T>
|
||||||
static void set_lvalue_fx(std::false_type, lua_State* L, TFx&& fx, TObj&& obj) {
|
static void set(lua_State* L, R (C::*memfxptr)(Args...), T&& obj) {
|
||||||
typedef typename std::remove_pointer<Decay<TFx>>::type clean_fx;
|
typedef Bool<is_specialization_of<T, std::reference_wrapper>::value || std::is_pointer<T>::value> is_reference;
|
||||||
std::unique_ptr<base_function> sptr(new member_function<clean_fx, TObj>(std::forward<TObj>(obj), std::forward<TFx>(fx)));
|
set_reference_fx(is_reference(), L, memfxptr, std::forward<T>(obj));
|
||||||
return set_fx<TFx>(L, std::move(sptr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename TFx, typename TObj>
|
template<typename Sig, typename C, typename T>
|
||||||
static void set_fx(std::true_type, lua_State* L, TFx&& fx, TObj&& obj) {
|
static void set(lua_State* L, Sig C::* memfxptr, T&& obj) {
|
||||||
|
typedef Bool<is_specialization_of<T, std::reference_wrapper>::value || std::is_pointer<T>::value> is_reference;
|
||||||
|
set_reference_fx(is_reference(), L, memfxptr, std::forward<T>(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Sig, typename Fx>
|
||||||
|
static void set(lua_State* L, Fx&& fx) {
|
||||||
|
set_memfx(types<Sig...>(), L, std::forward<Fx>(fx));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Fx, typename R, typename... Args>
|
||||||
|
static void set_isconvertible_fx(std::true_type, types<R(Args...)>, lua_State* L, Fx&& fx) {
|
||||||
|
typedef R(* fx_ptr_t)(Args...);
|
||||||
|
fx_ptr_t fxptr = unwrapper(std::forward<Fx>(fx));
|
||||||
|
set(L, fxptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Fx, typename R, typename... Args>
|
||||||
|
static void set_isconvertible_fx(std::false_type, types<R(Args...)>, lua_State* L, Fx&& fx) {
|
||||||
|
typedef Decay<Unwrap<Fx>> fx_t;
|
||||||
|
std::unique_ptr<base_function> sptr(new functor_function<fx_t>(std::forward<Fx>(fx)));
|
||||||
|
set_fx<Fx>(L, std::move(sptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Fx, typename T>
|
||||||
|
static void set_reference_fx(std::true_type, lua_State* L, Fx&& fx, T&& obj) {
|
||||||
|
set_fx(std::true_type(), L, std::forward<Fx>(fx), std::forward<T>(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Fx, typename T>
|
||||||
|
static void set_reference_fx(std::false_type, lua_State* L, Fx&& fx, T&& obj) {
|
||||||
|
typedef typename std::remove_pointer<Decay<Fx>>::type clean_fx;
|
||||||
|
std::unique_ptr<base_function> sptr(new member_function<clean_fx, T>(std::forward<T>(obj), std::forward<Fx>(fx)));
|
||||||
|
return set_fx<Fx>(L, std::move(sptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Fx, typename T>
|
||||||
|
static void set_fx(std::true_type, lua_State* L, Fx&& fx, T&& obj) {
|
||||||
// Layout:
|
// Layout:
|
||||||
// idx 1...n: verbatim data of member function pointer
|
// idx 1...n: verbatim data of member function pointer
|
||||||
// idx n + 1: is the object's void pointer
|
// idx n + 1: is the object's void pointer
|
||||||
// We don't need to store the size, because the other side is templated
|
// We don't need to store the size, because the other side is templated
|
||||||
// with the same member function pointer type
|
// with the same member function pointer type
|
||||||
Decay<TFx> fxptr(std::forward<TFx>(fx));
|
Decay<Fx> memfxptr(std::forward<Fx>(fx));
|
||||||
void* userobjdata = static_cast<void*>(sol::detail::get_ptr(obj));
|
auto userptr = sol::detail::get_ptr(obj);
|
||||||
lua_CFunction freefunc = &static_member_function<Decay<TObj>, TFx>::call;
|
void* userobjdata = static_cast<void*>(userptr);
|
||||||
|
lua_CFunction freefunc = &static_member_function<Decay<decltype(*userptr)>, Fx>::call;
|
||||||
|
|
||||||
int upvalues = stack::detail::push_as_upvalues(L, fxptr);
|
int upvalues = stack::detail::push_as_upvalues(L, memfxptr);
|
||||||
stack::push(L, userobjdata);
|
stack::push(L, userobjdata);
|
||||||
stack::pusher<lua_CFunction>{}.push(L, freefunc, upvalues);
|
++upvalues;
|
||||||
|
stack::push(L, freefunc, upvalues);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename TFx>
|
template<typename Fx>
|
||||||
static void set_fx(lua_State* L, std::false_type, TFx&& fx) {
|
static void set_fx(std::false_type, lua_State* L, Fx&& fx) {
|
||||||
Decay<TFx> target(std::forward<TFx>(fx));
|
Decay<Fx> target(std::forward<Fx>(fx));
|
||||||
lua_CFunction freefunc = &static_function<TFx>::call;
|
lua_CFunction freefunc = &static_function<Fx>::call;
|
||||||
|
|
||||||
int upvalues = stack::detail::push_as_upvalues(L, target);
|
int upvalues = stack::detail::push_as_upvalues(L, target);
|
||||||
stack::pusher<lua_CFunction>{}.push(L, freefunc, upvalues);
|
stack::push(L, freefunc, upvalues);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename TFx>
|
template<typename Fx>
|
||||||
static void set_fx(lua_State* L, std::unique_ptr<base_function> luafunc) {
|
static void set_fx(lua_State* L, std::unique_ptr<base_function> luafunc) {
|
||||||
auto&& metakey = userdata_traits<Unqualified<TFx>>::metatable;
|
auto&& metakey = userdata_traits<Unqualified<Fx>>::metatable;
|
||||||
const char* metatablename = std::addressof(metakey[0]);
|
const char* metatablename = std::addressof(metakey[0]);
|
||||||
base_function* target = luafunc.release();
|
base_function* target = luafunc.release();
|
||||||
void* userdata = reinterpret_cast<void*>(target);
|
void* userdata = reinterpret_cast<void*>(target);
|
||||||
|
@ -164,27 +200,16 @@ struct pusher<function_t> {
|
||||||
lua_pushstring(L, "__gc");
|
lua_pushstring(L, "__gc");
|
||||||
stack::push(L, &base_function::gc);
|
stack::push(L, &base_function::gc);
|
||||||
lua_settable(L, -3);
|
lua_settable(L, -3);
|
||||||
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
stack::detail::push_userdata<void*>(L, metatablename, userdata);
|
stack::detail::push_userdata<void*>(L, metatablename, userdata);
|
||||||
stack::pusher<lua_CFunction>{}.push(L, freefunc, 1);
|
stack::push(L, freefunc, 1);
|
||||||
}
|
|
||||||
|
|
||||||
template<typename TFx>
|
|
||||||
static void set_function(lua_State* L, TFx&& fx) {
|
|
||||||
typedef typename std::remove_pointer<Decay<TFx>>::type clean_fx;
|
|
||||||
set_isfunction_fx(std::is_function<clean_fx>(), L, std::forward<TFx>(fx));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename TFx, typename TObj>
|
|
||||||
static void set_function(lua_State* L, TFx&& fx, TObj&& obj) {
|
|
||||||
set_lvalue_fx(Bool<std::is_lvalue_reference<TObj>::value || std::is_pointer<TObj>::value>(),
|
|
||||||
L, std::forward<TFx>(fx), std::forward<TObj>(obj));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
static void push(lua_State* L, Args&&... args) {
|
static void push(lua_State* L, Args&&... args) {
|
||||||
set_function(L, std::forward<Args>(args)...);
|
set(L, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -208,7 +208,8 @@ struct base_function {
|
||||||
template<typename Function>
|
template<typename Function>
|
||||||
struct functor_function : public base_function {
|
struct functor_function : public base_function {
|
||||||
typedef decltype(&Function::operator()) function_type;
|
typedef decltype(&Function::operator()) function_type;
|
||||||
typedef function_traits<function_type> traits_type;
|
typedef function_return_t<function_type> return_type;
|
||||||
|
typedef function_args_t<function_type> args_type;
|
||||||
Function fx;
|
Function fx;
|
||||||
|
|
||||||
template<typename... FxArgs>
|
template<typename... FxArgs>
|
||||||
|
@ -229,7 +230,6 @@ struct functor_function : public base_function {
|
||||||
|
|
||||||
template<typename... Ret, typename... Args>
|
template<typename... Ret, typename... Args>
|
||||||
int operator()(types<Ret...>, types<Args...> t, lua_State* L) {
|
int operator()(types<Ret...>, types<Args...> t, lua_State* L) {
|
||||||
typedef typename return_type<Ret...>::type return_type;
|
|
||||||
return_type r = stack::get_call(L, fx, t);
|
return_type r = stack::get_call(L, fx, t);
|
||||||
std::ptrdiff_t nargs = sizeof...(Args);
|
std::ptrdiff_t nargs = sizeof...(Args);
|
||||||
lua_pop(L, nargs);
|
lua_pop(L, nargs);
|
||||||
|
@ -238,29 +238,30 @@ struct functor_function : public base_function {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int operator()(lua_State* L) override {
|
virtual int operator()(lua_State* L) override {
|
||||||
return (*this)(tuple_types<typename traits_type::return_type>(), typename traits_type::args_type(), L);
|
return (*this)(tuple_types<return_type>(), args_type(), L);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Function, typename T>
|
template<typename Function, typename T>
|
||||||
struct member_function : public base_function {
|
struct member_function : public base_function {
|
||||||
typedef typename std::remove_pointer<typename std::decay<Function>::type>::type function_type;
|
typedef typename std::remove_pointer<Decay<Function>>::type function_type;
|
||||||
typedef function_traits<function_type> traits_type;
|
typedef function_return_t<function_type> return_type;
|
||||||
|
typedef function_args_t<function_type> args_type;
|
||||||
struct functor {
|
struct functor {
|
||||||
T member;
|
T member;
|
||||||
function_type invocation;
|
function_type invocation;
|
||||||
|
|
||||||
template<typename... FxArgs>
|
template<typename Tm, typename... FxArgs>
|
||||||
functor(T m, FxArgs&&... fxargs): member(std::move(m)), invocation(std::forward<FxArgs>(fxargs)...) {}
|
functor(Tm&& m, FxArgs&&... fxargs): member(std::forward<Tm>(m)), invocation(std::forward<FxArgs>(fxargs)...) {}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
typename traits_type::return_type operator()(Args&&... args) {
|
return_type operator()(Args&&... args) {
|
||||||
return (member.*invocation)(std::forward<Args>(args)...);
|
return (member.*invocation)(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
} fx;
|
} fx;
|
||||||
|
|
||||||
template<typename... FxArgs>
|
template<typename Tm, typename... FxArgs>
|
||||||
member_function(T m, FxArgs&&... fxargs): fx(std::move(m), std::forward<FxArgs>(fxargs)...) {}
|
member_function(Tm&& m, FxArgs&&... fxargs): fx(std::forward<Tm>(m), std::forward<FxArgs>(fxargs)...) {}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
int operator()(types<void>, types<Args...> t, lua_State* L) {
|
int operator()(types<void>, types<Args...> t, lua_State* L) {
|
||||||
|
@ -275,7 +276,6 @@ struct member_function : public base_function {
|
||||||
|
|
||||||
template<typename... Ret, typename... Args>
|
template<typename... Ret, typename... Args>
|
||||||
int operator()(types<Ret...>, types<Args...> t, lua_State* L) {
|
int operator()(types<Ret...>, types<Args...> t, lua_State* L) {
|
||||||
typedef typename return_type<Ret...>::type return_type;
|
|
||||||
return_type r = stack::get_call(L, fx, t);
|
return_type r = stack::get_call(L, fx, t);
|
||||||
std::ptrdiff_t nargs = sizeof...(Args);
|
std::ptrdiff_t nargs = sizeof...(Args);
|
||||||
lua_pop(L, nargs);
|
lua_pop(L, nargs);
|
||||||
|
@ -284,7 +284,7 @@ struct member_function : public base_function {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int operator()(lua_State* L) override {
|
virtual int operator()(lua_State* L) override {
|
||||||
return (*this)(tuple_types<typename traits_type::return_type>(), typename traits_type::args_type(), L);
|
return (*this)(tuple_types<return_type>(), args_type(), L);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -292,8 +292,8 @@ template<typename Function, typename Tp>
|
||||||
struct userdata_function : public base_function {
|
struct userdata_function : public base_function {
|
||||||
typedef typename std::remove_pointer<Tp>::type T;
|
typedef typename std::remove_pointer<Tp>::type T;
|
||||||
typedef typename std::remove_pointer<typename std::decay<Function>::type>::type function_type;
|
typedef typename std::remove_pointer<typename std::decay<Function>::type>::type function_type;
|
||||||
typedef function_traits<function_type> traits_type;
|
typedef function_args_t<function_type> args_type;
|
||||||
typedef typename traits_type::return_type return_type;
|
typedef function_return_t<function_type> return_type;
|
||||||
|
|
||||||
detail::functor<T, function_type, return_type> fx;
|
detail::functor<T, function_type, return_type> fx;
|
||||||
|
|
||||||
|
@ -347,7 +347,7 @@ struct userdata_function : public base_function {
|
||||||
fx.item = detail::get_ptr(stack::get<Tp>(L, 1));
|
fx.item = detail::get_ptr(stack::get<Tp>(L, 1));
|
||||||
if (fx.item == nullptr)
|
if (fx.item == nullptr)
|
||||||
throw error("userdata for function call is null: are you using wrong call syntax? (use item:function(...) synax)");
|
throw error("userdata for function call is null: are you using wrong call syntax? (use item:function(...) synax)");
|
||||||
return (*this)(tuple_types<typename traits_type::return_type>(), typename traits_type::args_type(), L);
|
return (*this)(tuple_types<return_type>(), args_type(), L);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,11 @@ inline T* get_ptr(T& val) {
|
||||||
return std::addressof(val);
|
return std::addressof(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline T* get_ptr(std::reference_wrapper<T> val) {
|
||||||
|
return std::addressof(val.get());
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline T* get_ptr(T* val) {
|
inline T* get_ptr(T* val) {
|
||||||
return val;
|
return val;
|
||||||
|
@ -310,8 +315,8 @@ inline void push(lua_State* L, T&& t, Args&&... args) {
|
||||||
|
|
||||||
// overload allows to use a pusher of a specific type, but pass in any kind of args
|
// overload allows to use a pusher of a specific type, but pass in any kind of args
|
||||||
template<typename T, typename Arg, typename... Args>
|
template<typename T, typename Arg, typename... Args>
|
||||||
inline void push(lua_State* L, Arg&& t, Args&&... args) {
|
inline void push(lua_State* L, Arg&& arg, Args&&... args) {
|
||||||
pusher<Unqualified<T>>{}.push(L, std::forward<T>(t), std::forward<Args>(args)...);
|
pusher<Unqualified<T>>{}.push(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void push_args(lua_State*) {
|
inline void push_args(lua_State*) {
|
||||||
|
|
|
@ -61,6 +61,10 @@ public:
|
||||||
lua_atpanic(L.get(), detail::atpanic);
|
lua_atpanic(L.get(), detail::atpanic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lua_State* lua_state() const {
|
||||||
|
return L.get();
|
||||||
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void open_libraries(Args&&... args) {
|
void open_libraries(Args&&... args) {
|
||||||
static_assert(are_same<lib, Args...>::value, "all types must be libraries");
|
static_assert(are_same<lib, Args...>::value, "all types must be libraries");
|
||||||
|
@ -133,21 +137,14 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename TFx>
|
|
||||||
state& set_function(T&& key, TFx&& fx) {
|
|
||||||
global.set_function(std::forward<T>(key), std::forward<TFx>(fx));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename TFx, typename TObj>
|
|
||||||
state& set_function(T&& key, TFx&& fx, TObj&& obj) {
|
|
||||||
global.set_function(std::forward<T>(key), std::forward<TFx>(fx), std::forward<TObj>(obj));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
state& set_userdata(userdata<T>& user) {
|
state& set_userdata(userdata<T>& user) {
|
||||||
global.set_userdata(user);
|
return set_userdata(user.name(), user);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Key, typename T>
|
||||||
|
state& set_userdata(Key&& key, userdata<T>& user) {
|
||||||
|
global.set_userdata(std::forward<Key>(key), user);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,8 +195,34 @@ public:
|
||||||
return global[std::forward<T>(key)];
|
return global[std::forward<T>(key)];
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_State* lua_state() const {
|
template<typename... Args, typename R, typename Key>
|
||||||
return L.get();
|
state& set_function(Key&& key, R fun_ptr(Args...)){
|
||||||
|
global.set_function(std::forward<Key>(key), fun_ptr);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Sig, typename Key>
|
||||||
|
state& set_function(Key&& key, Sig* fun_ptr){
|
||||||
|
global.set_function(std::forward<Key>(key), fun_ptr);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args, typename R, typename C, typename T, typename Key>
|
||||||
|
state& set_function(Key&& key, R (C::*mem_ptr)(Args...), T&& obj) {
|
||||||
|
global.set_function(std::forward<Key>(key), mem_ptr, std::forward<T>(obj));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Sig, typename C, typename T, typename Key>
|
||||||
|
state& set_function(Key&& key, Sig C::* mem_ptr, T&& obj) {
|
||||||
|
global.set_function(std::forward<Key>(key), mem_ptr, std::forward<T>(obj));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Sig, typename Fx, typename Key>
|
||||||
|
state& set_function(Key&& key, Fx&& fx) {
|
||||||
|
global.set_function<Sig...>(std::forward<Key>(key), std::forward<Fx>(fx));
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // sol
|
} // sol
|
||||||
|
|
177
sol/table.hpp
177
sol/table.hpp
|
@ -83,23 +83,16 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename TFx>
|
|
||||||
table& set_function(T&& key, TFx&& fx) {
|
|
||||||
typedef typename std::remove_pointer<Decay<TFx>>::type clean_fx;
|
|
||||||
return set_isfunction_fx(std::is_function<clean_fx>(), std::forward<T>(key), std::forward<TFx>(fx));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename TFx, typename TObj>
|
|
||||||
table& set_function(T&& key, TFx&& fx, TObj&& obj) {
|
|
||||||
return set_lvalue_fx(Bool<std::is_lvalue_reference<TObj>::value || std::is_pointer<TObj>::value>(),
|
|
||||||
std::forward<T>(key), std::forward<TFx>(fx), std::forward<TObj>(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
table& set_userdata(userdata<T>& user) {
|
table& set_userdata(userdata<T>& user) {
|
||||||
stack::push(state(), user);
|
return set_userdata(user.name(), user);
|
||||||
lua_setglobal(state(), user.name().c_str());
|
}
|
||||||
|
|
||||||
|
template<typename Key, typename T>
|
||||||
|
table& set_userdata(Key&& key, userdata<T>& user) {
|
||||||
|
std::string ukey(std::forward<Key>(key));
|
||||||
|
stack::push(state(), user);
|
||||||
|
lua_setglobal(state(), ukey.c_str());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,121 +114,63 @@ public:
|
||||||
void pop(int n = 1) const noexcept {
|
void pop(int n = 1) const noexcept {
|
||||||
lua_pop(state(), n);
|
lua_pop(state(), n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename... Args, typename R, typename Key>
|
||||||
|
table& set_function(Key&& key, R fun_ptr(Args...)){
|
||||||
|
set_resolved_function(std::forward<Key>(key), fun_ptr);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Sig, typename Key>
|
||||||
|
table& set_function(Key&& key, Sig* fun_ptr){
|
||||||
|
set_resolved_function(std::forward<Key>(key), fun_ptr);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args, typename R, typename C, typename T, typename Key>
|
||||||
|
table& set_function(Key&& key, R (C::*mem_ptr)(Args...), T&& obj) {
|
||||||
|
set_resolved_function(std::forward<Key>(key), mem_ptr, std::forward<T>(obj));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Sig, typename C, typename T, typename Key>
|
||||||
|
table& set_function(Key&& key, Sig C::* mem_ptr, T&& obj) {
|
||||||
|
set_resolved_function(std::forward<Key>(key), mem_ptr, std::forward<T>(obj));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Sig, typename Fx, typename Key>
|
||||||
|
table& set_function(Key&& key, Fx&& fx) {
|
||||||
|
set_fx(types<Sig...>(), std::forward<Key>(key), std::forward<Fx>(fx));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<typename T, typename TFx>
|
template<typename R, typename... Args, typename Fx, typename Key, typename = typename std::result_of<Fx(Args...)>::type>
|
||||||
table& set_isfunction_fx(std::true_type, T&& key, TFx&& fx) {
|
void set_fx(types<R(Args...)>, Key&& key, Fx&& fx) {
|
||||||
return set_fx(std::false_type(), std::forward<T>(key), std::forward<TFx>(fx));
|
set_resolved_function<R(Args...)>(std::forward<Key>(key), std::forward<Fx>(fx));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename TFx>
|
template<typename... Args, typename Fx, typename Key, typename R = typename std::result_of<Fx(Args...)>::type>
|
||||||
table& set_isfunction_fx(std::false_type, T&& key, TFx&& fx) {
|
void set_fx(types<Args...>, Key&& key, Fx&& fx){
|
||||||
typedef Decay<TFx> clean_lambda;
|
set_fx(types<R(Args...)>(), std::forward<Key>(key), std::forward<Fx>(fx));
|
||||||
typedef typename function_traits<decltype(&clean_lambda::operator())>::free_function_pointer_type raw_func_t;
|
|
||||||
typedef std::is_convertible<clean_lambda, raw_func_t> isconvertible;
|
|
||||||
return set_isconvertible_fx(isconvertible(), std::forward<T>(key), std::forward<TFx>(fx));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename TFx>
|
template<typename Fx, typename Key>
|
||||||
table& set_isconvertible_fx(std::true_type, T&& key, TFx&& fx) {
|
void set_fx(types<>, Key&& key, Fx&& fx) {
|
||||||
typedef Decay<TFx> clean_lambda;
|
typedef Unqualified<Unwrap<Fx>> fx_t;
|
||||||
typedef typename function_traits<decltype(&clean_lambda::operator())>::free_function_pointer_type raw_func_t;
|
typedef decltype(&fx_t::operator()) Sig;
|
||||||
return set_isfunction_fx(std::true_type(), std::forward<T>(key), raw_func_t(std::forward<TFx>(fx)));
|
set_fx(types<function_signature_t<Sig>>(), std::forward<Key>(key), std::forward<Fx>(fx));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename TFx>
|
template<typename... Sig, typename... Args, typename Key>
|
||||||
table& set_isconvertible_fx(std::false_type, T&& key, TFx&& fx) {
|
void set_resolved_function(Key&& key, Args&&... args) {
|
||||||
typedef typename std::remove_pointer<Decay<TFx>>::type clean_fx;
|
std::string fkey(std::forward<Key>(key));
|
||||||
std::unique_ptr<base_function> sptr(new functor_function<clean_fx>(std::forward<TFx>(fx)));
|
|
||||||
return set_fx(std::forward<T>(key), std::move(sptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename TFx, typename TObj>
|
|
||||||
table& set_lvalue_fx(std::true_type, T&& key, TFx&& fx, TObj&& obj) {
|
|
||||||
return set_fx(std::true_type(), std::forward<T>(key), std::forward<TFx>(fx), std::forward<TObj>(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename TFx, typename TObj>
|
|
||||||
table& set_lvalue_fx(std::false_type, T&& key, TFx&& fx, TObj&& obj) {
|
|
||||||
typedef typename std::remove_pointer<Decay<TFx>>::type clean_fx;
|
|
||||||
std::unique_ptr<base_function> sptr(new member_function<clean_fx, TObj>(std::forward<TObj>(obj), std::forward<TFx>(fx)));
|
|
||||||
return set_fx(std::forward<T>(key), std::move(sptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename TFx, typename TObj>
|
|
||||||
table& set_fx(std::true_type, T&& key, TFx&& fx, TObj&& obj) {
|
|
||||||
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<TFx> fxptr(std::forward<TFx>(fx));
|
|
||||||
void* userobjdata = static_cast<void*>(detail::get_ptr(obj));
|
|
||||||
lua_CFunction freefunc = &static_member_function<Decay<TObj>, TFx>::call;
|
|
||||||
const char* freefuncname = fkey.c_str();
|
|
||||||
const luaL_Reg funcreg[2] = {
|
|
||||||
{ freefuncname, freefunc },
|
|
||||||
{ nullptr, nullptr }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
push();
|
push();
|
||||||
|
int tabletarget = lua_gettop(state());
|
||||||
int upvalues = stack::detail::push_as_upvalues(state(), fxptr);
|
stack::push<function_sig_t<Sig...>>(state(), std::forward<Args>(args)...);
|
||||||
stack::push(state(), userobjdata);
|
lua_setfield(state(), tabletarget, fkey.c_str());
|
||||||
luaL_setfuncs(state(), funcreg, upvalues + 1);
|
|
||||||
|
|
||||||
pop();
|
pop();
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename TFx>
|
|
||||||
table& set_fx(std::false_type, T&& key, TFx&& fx) {
|
|
||||||
std::string fkey(key);
|
|
||||||
Decay<TFx> target(std::forward<TFx>(fx));
|
|
||||||
lua_CFunction freefunc = &static_function<TFx>::call;
|
|
||||||
const char* freefuncname = fkey.c_str();
|
|
||||||
const luaL_Reg funcreg[2] = {
|
|
||||||
{ freefuncname, freefunc },
|
|
||||||
{ nullptr, nullptr }
|
|
||||||
};
|
|
||||||
|
|
||||||
push();
|
|
||||||
int upvalues = stack::detail::push_as_upvalues(state(), target);
|
|
||||||
luaL_setfuncs(state(), funcreg, upvalues);
|
|
||||||
pop();
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
table& set_fx(T&& key, std::unique_ptr<base_function> luafunc) {
|
|
||||||
std::string fkey(key);
|
|
||||||
std::string metakey("sol.stateful.");
|
|
||||||
metakey += fkey;
|
|
||||||
metakey += ".meta";
|
|
||||||
base_function* target = luafunc.release();
|
|
||||||
void* userdata = reinterpret_cast<void*>(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(state(), metatablename) == 1) {
|
|
||||||
lua_pushstring(state(), "__gc");
|
|
||||||
lua_pushcclosure(state(), &base_function::gc, 0);
|
|
||||||
lua_settable(state(), -3);
|
|
||||||
}
|
|
||||||
|
|
||||||
push();
|
|
||||||
stack::detail::push_userdata<void*>(state(), metatablename, userdata);
|
|
||||||
luaL_setfuncs(state(), funcreg, 1);
|
|
||||||
pop();
|
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // sol
|
} // sol
|
||||||
|
|
|
@ -24,11 +24,33 @@
|
||||||
|
|
||||||
#include "tuple.hpp"
|
#include "tuple.hpp"
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace sol {
|
namespace sol {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct identity { typedef T type; };
|
struct identity { typedef T type; };
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
struct is_tuple : std::false_type{ };
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
struct is_tuple<std::tuple<Args...>> : std::true_type{ };
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct unwrap {
|
||||||
|
typedef T type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct unwrap<std::reference_wrapper<T>> {
|
||||||
|
typedef typename std::add_lvalue_reference<T>::type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, template <typename...> class Templ>
|
||||||
|
struct is_specialization_of : std::false_type { };
|
||||||
|
template <typename... T, template <typename...> class Templ>
|
||||||
|
struct is_specialization_of<Templ<T...>, Templ> : std::true_type { };
|
||||||
|
|
||||||
template<class T, class...>
|
template<class T, class...>
|
||||||
struct are_same : std::true_type { };
|
struct are_same : std::true_type { };
|
||||||
|
|
||||||
|
@ -68,6 +90,9 @@ using Unqualified = typename std::remove_cv<typename std::remove_reference<T>::t
|
||||||
template<typename T>
|
template<typename T>
|
||||||
using Decay = typename std::decay<T>::type;
|
using Decay = typename std::decay<T>::type;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using Unwrap = typename unwrap<T>::type;
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
struct return_type {
|
struct return_type {
|
||||||
typedef std::tuple<Args...> type;
|
typedef std::tuple<Args...> type;
|
||||||
|
@ -83,17 +108,6 @@ struct return_type<> : types<>{
|
||||||
typedef void type;
|
typedef void type;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
struct is_tuple : std::false_type{ };
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
struct is_tuple<std::tuple<Args...>> : std::true_type{ };
|
|
||||||
|
|
||||||
template <typename T, template <typename...> class Templ>
|
|
||||||
struct is_specialization_of : std::false_type { };
|
|
||||||
template <typename... T, template <typename...> class Templ>
|
|
||||||
struct is_specialization_of<Templ<T...>, Templ> : std::true_type { };
|
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template<typename T, bool isclass = std::is_class<Unqualified<T>>::value>
|
template<typename T, bool isclass = std::is_class<Unqualified<T>>::value>
|
||||||
struct is_function_impl : std::is_function<typename std::remove_pointer<T>::type> {};
|
struct is_function_impl : std::is_function<typename std::remove_pointer<T>::type> {};
|
||||||
|
@ -123,6 +137,15 @@ struct Function : Bool<detail::is_function_impl<T>::value> {};
|
||||||
template<typename TFuncSignature>
|
template<typename TFuncSignature>
|
||||||
struct function_traits;
|
struct function_traits;
|
||||||
|
|
||||||
|
template <typename TFuncSignature>
|
||||||
|
using function_args_t = typename function_traits<TFuncSignature>::args_type;
|
||||||
|
|
||||||
|
template <typename TFuncSignature>
|
||||||
|
using function_signature_t = typename function_traits<TFuncSignature>::signature_type;
|
||||||
|
|
||||||
|
template <typename TFuncSignature>
|
||||||
|
using function_return_t = typename function_traits<TFuncSignature>::return_type;
|
||||||
|
|
||||||
template<typename T, typename R, typename... Args>
|
template<typename T, typename R, typename... Args>
|
||||||
struct function_traits<R(T::*)(Args...)> {
|
struct function_traits<R(T::*)(Args...)> {
|
||||||
static const std::size_t arity = sizeof...(Args);
|
static const std::size_t arity = sizeof...(Args);
|
||||||
|
@ -133,6 +156,7 @@ struct function_traits<R(T::*)(Args...)> {
|
||||||
typedef typename std::remove_pointer<function_pointer_type>::type function_type;
|
typedef typename std::remove_pointer<function_pointer_type>::type function_type;
|
||||||
typedef R(*free_function_pointer_type)(Args...);
|
typedef R(*free_function_pointer_type)(Args...);
|
||||||
typedef R return_type;
|
typedef R return_type;
|
||||||
|
typedef typename std::remove_pointer<free_function_pointer_type>::type signature_type;
|
||||||
template<std::size_t i>
|
template<std::size_t i>
|
||||||
using arg = typename std::tuple_element<i, arg_tuple_type>::type;
|
using arg = typename std::tuple_element<i, arg_tuple_type>::type;
|
||||||
};
|
};
|
||||||
|
@ -147,6 +171,7 @@ struct function_traits<R(T::*)(Args...) const> {
|
||||||
typedef typename std::remove_pointer<function_pointer_type>::type function_type;
|
typedef typename std::remove_pointer<function_pointer_type>::type function_type;
|
||||||
typedef R(*free_function_pointer_type)(Args...);
|
typedef R(*free_function_pointer_type)(Args...);
|
||||||
typedef R return_type;
|
typedef R return_type;
|
||||||
|
typedef typename std::remove_pointer<free_function_pointer_type>::type signature_type;
|
||||||
template<std::size_t i>
|
template<std::size_t i>
|
||||||
using arg = typename std::tuple_element<i, arg_tuple_type>::type;
|
using arg = typename std::tuple_element<i, arg_tuple_type>::type;
|
||||||
};
|
};
|
||||||
|
@ -161,6 +186,7 @@ struct function_traits<R(Args...)> {
|
||||||
typedef R(*function_pointer_type)(Args...);
|
typedef R(*function_pointer_type)(Args...);
|
||||||
typedef R(*free_function_pointer_type)(Args...);
|
typedef R(*free_function_pointer_type)(Args...);
|
||||||
typedef R return_type;
|
typedef R return_type;
|
||||||
|
typedef typename std::remove_pointer<free_function_pointer_type>::type signature_type;
|
||||||
template<std::size_t i>
|
template<std::size_t i>
|
||||||
using arg = typename std::tuple_element<i, arg_tuple_type>::type;
|
using arg = typename std::tuple_element<i, arg_tuple_type>::type;
|
||||||
};
|
};
|
||||||
|
@ -175,6 +201,7 @@ struct function_traits<R(*)(Args...)> {
|
||||||
typedef R(*function_pointer_type)(Args...);
|
typedef R(*function_pointer_type)(Args...);
|
||||||
typedef R(*free_function_pointer_type)(Args...);
|
typedef R(*free_function_pointer_type)(Args...);
|
||||||
typedef R return_type;
|
typedef R return_type;
|
||||||
|
typedef typename std::remove_pointer<free_function_pointer_type>::type signature_type;
|
||||||
template<std::size_t i>
|
template<std::size_t i>
|
||||||
using arg = typename std::tuple_element<i, arg_tuple_type>::type;
|
using arg = typename std::tuple_element<i, arg_tuple_type>::type;
|
||||||
};
|
};
|
||||||
|
@ -205,6 +232,16 @@ struct has_key_value_pair_impl {
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct has_key_value_pair : decltype(has_key_value_pair_impl::test<T>(0)) {};
|
struct has_key_value_pair : decltype(has_key_value_pair_impl::test<T>(0)) {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
auto unwrapper(T&& item) -> decltype(std::forward<T>(item)) {
|
||||||
|
return std::forward<T>(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Arg>
|
||||||
|
Unwrap<Arg> unwrapper(std::reference_wrapper<Arg> arg) {
|
||||||
|
return arg.get();
|
||||||
|
}
|
||||||
} // sol
|
} // sol
|
||||||
|
|
||||||
#endif // SOL_TRAITS_HPP
|
#endif // SOL_TRAITS_HPP
|
||||||
|
|
|
@ -31,7 +31,11 @@ struct nil_t {};
|
||||||
const nil_t nil {};
|
const nil_t nil {};
|
||||||
struct void_type {};
|
struct void_type {};
|
||||||
const void_type Void {};
|
const void_type Void {};
|
||||||
struct function_t {};
|
|
||||||
|
template <typename... T>
|
||||||
|
struct function_sig_t {};
|
||||||
|
using function_t = function_sig_t<>;
|
||||||
|
|
||||||
struct upvalue_t {
|
struct upvalue_t {
|
||||||
void* value;
|
void* value;
|
||||||
upvalue_t(void* data) : value(data) {}
|
upvalue_t(void* data) : value(data) {}
|
||||||
|
|
144
sol/userdata.hpp
144
sol/userdata.hpp
|
@ -108,6 +108,36 @@ private:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <bool release = false, typename TCont>
|
||||||
|
static int push_upvalues (lua_State* L, TCont&& cont) {
|
||||||
|
int n = 0;
|
||||||
|
for (auto& c : cont) {
|
||||||
|
if (release)
|
||||||
|
stack::push<upvalue_t>(L, c.release());
|
||||||
|
else
|
||||||
|
stack::push<upvalue_t>(L, c.get());
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Meta, typename Funcs, typename FuncTable, typename MetaFuncs, typename MetaFuncTable>
|
||||||
|
static void push_metatable(lua_State* L, Meta&& meta, Funcs&& funcs, FuncTable&& functable, MetaFuncs&& metafuncs, MetaFuncTable&& metafunctable) {
|
||||||
|
luaL_newmetatable(L, std::addressof(meta[0]));
|
||||||
|
if (functable.size() > 1) {
|
||||||
|
// regular functions accessed through __index semantics
|
||||||
|
int up = push_upvalues(L, funcs);
|
||||||
|
luaL_setfuncs(L, functable.data(), up);
|
||||||
|
}
|
||||||
|
if (metafunctable.size() > 1) {
|
||||||
|
// meta functions
|
||||||
|
int up = push_upvalues(L, metafuncs);
|
||||||
|
luaL_setfuncs(L, metafunctable.data(), up);
|
||||||
|
}
|
||||||
|
lua_pushvalue(L, -1);
|
||||||
|
lua_setfield(L, -1, "__index");
|
||||||
|
}
|
||||||
|
|
||||||
template<std::size_t N, std::size_t M>
|
template<std::size_t N, std::size_t M>
|
||||||
void build_function_tables() {}
|
void build_function_tables() {}
|
||||||
|
|
||||||
|
@ -177,49 +207,33 @@ public:
|
||||||
userdata(const char* name, constructors<CArgs...> c, Args&&... args) :
|
userdata(const char* name, constructors<CArgs...> c, Args&&... args) :
|
||||||
userdata(std::string(name), std::move(c), std::forward<Args>(args)...) {}
|
userdata(std::string(name), std::move(c), std::forward<Args>(args)...) {}
|
||||||
|
|
||||||
std::vector<std::string>& function_names () {
|
|
||||||
return functionnames;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<base_function>>& functions () {
|
|
||||||
return funcs;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<base_function>>& reference_functions () {
|
|
||||||
return ptrfuncs;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<base_function>>& meta_functions () {
|
|
||||||
return metafuncs;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<base_function>>& meta_reference_functions () {
|
|
||||||
return ptrmetafuncs;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<luaL_Reg>& function_table () {
|
|
||||||
return functiontable;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<luaL_Reg>& reference_function_table () {
|
|
||||||
return ptrfunctiontable;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<luaL_Reg>& meta_function_table () {
|
|
||||||
return metafunctiontable;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<luaL_Reg>& meta_reference_function_table () {
|
|
||||||
return ptrmetafunctiontable;
|
|
||||||
}
|
|
||||||
|
|
||||||
lua_CFunction cleanup_function () {
|
|
||||||
return cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& name () const {
|
const std::string& name () const {
|
||||||
return luaname;
|
return luaname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void push (lua_State* L) {
|
||||||
|
// push pointer tables first,
|
||||||
|
// but leave the regular T table on last so it can be linked to a type for usage with `.new(...)`
|
||||||
|
push_metatable(L, userdata_traits<T*>::metatable,
|
||||||
|
ptrfuncs, ptrfunctiontable,
|
||||||
|
ptrmetafuncs, ptrmetafunctiontable);
|
||||||
|
push_metatable(L, userdata_traits<T>::metatable,
|
||||||
|
funcs, functiontable,
|
||||||
|
metafuncs, metafunctiontable);
|
||||||
|
// Automatic deleter table -- stays alive until lua VM dies
|
||||||
|
// even if the user calls collectgarbage()
|
||||||
|
lua_createtable(L, 0, 0);
|
||||||
|
lua_createtable(L, 0, 1);
|
||||||
|
int up = push_upvalues<true>(L, funcs);
|
||||||
|
up += push_upvalues<true>(L, ptrfuncs);
|
||||||
|
up += push_upvalues<true>(L, metafuncs);
|
||||||
|
up += push_upvalues<true>(L, ptrmetafuncs);
|
||||||
|
lua_pushcclosure(L, cleanup, up);
|
||||||
|
lua_setfield(L, -2, "__gc");
|
||||||
|
lua_setmetatable(L, -2);
|
||||||
|
// gctable name by default has ♻ part of it
|
||||||
|
lua_setglobal(L, std::addressof(userdata_traits<T>::gctable[0]));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -248,56 +262,8 @@ const std::array<std::string, 19> userdata<T>::metafunctionnames = {
|
||||||
namespace stack {
|
namespace stack {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct pusher<userdata<T>> {
|
struct pusher<userdata<T>> {
|
||||||
template <bool release = false, typename TCont>
|
|
||||||
static int push_upvalues (lua_State* L, TCont&& cont) {
|
|
||||||
int n = 0;
|
|
||||||
for (auto& c : cont) {
|
|
||||||
if (release)
|
|
||||||
stack::push<upvalue_t>(L, c.release());
|
|
||||||
else
|
|
||||||
stack::push<upvalue_t>(L, c.get());
|
|
||||||
++n;
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Meta, typename Funcs, typename FuncTable, typename MetaFuncs, typename MetaFuncTable>
|
|
||||||
static void push_metatable(lua_State* L, Meta&& meta, Funcs&& funcs, FuncTable&& functable, MetaFuncs&& metafuncs, MetaFuncTable&& metafunctable) {
|
|
||||||
luaL_newmetatable(L, std::addressof(meta[0]));
|
|
||||||
if (functable.size() > 1) {
|
|
||||||
// regular functions accessed through __index semantics
|
|
||||||
int up = push_upvalues(L, funcs);
|
|
||||||
luaL_setfuncs(L, functable.data(), up);
|
|
||||||
}
|
|
||||||
if (metafunctable.size() > 1) {
|
|
||||||
// meta functions
|
|
||||||
int up = push_upvalues(L, metafuncs);
|
|
||||||
luaL_setfuncs(L, metafunctable.data(), up);
|
|
||||||
}
|
|
||||||
lua_pushvalue(L, -1);
|
|
||||||
lua_setfield(L, -1, "__index");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void push (lua_State* L, userdata<T>& user) {
|
static void push (lua_State* L, userdata<T>& user) {
|
||||||
// push pointer tables first,
|
user.push(L);
|
||||||
// but leave the regular T table on last so it can be linked to a type for usage with `.new(...)`
|
|
||||||
push_metatable(L, userdata_traits<T*>::metatable, user.reference_functions(), user.reference_function_table(), user.meta_reference_functions(), user.meta_reference_function_table());
|
|
||||||
push_metatable(L, userdata_traits<T>::metatable, user.functions(), user.function_table(), user.meta_functions(), user.meta_function_table());
|
|
||||||
|
|
||||||
// Automatic deleter table -- stays alive until lua VM dies
|
|
||||||
// even if the user calls collectgarbage()
|
|
||||||
auto cleanup = user.cleanup_function();
|
|
||||||
lua_createtable(L, 0, 0);
|
|
||||||
lua_createtable(L, 0, 1);
|
|
||||||
int up = push_upvalues<true>(L, user.functions());
|
|
||||||
up += push_upvalues<true>(L, user.reference_functions());
|
|
||||||
up += push_upvalues<true>(L, user.meta_functions());
|
|
||||||
up += push_upvalues<true>(L, user.meta_reference_functions());
|
|
||||||
lua_pushcclosure(L, cleanup, up);
|
|
||||||
lua_setfield(L, -2, "__gc");
|
|
||||||
lua_setmetatable(L, -2);
|
|
||||||
// gctable name by default has ♻ part of it
|
|
||||||
lua_setglobal(L, std::addressof(userdata_traits<T>::gctable[0]));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // stack
|
} // stack
|
||||||
|
|
68
tests.cpp
68
tests.cpp
|
@ -31,6 +31,26 @@ std::string free_function() {
|
||||||
return "test";
|
return "test";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int overloaded(int x) {
|
||||||
|
std::cout << x << std::endl;
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
int overloaded(int x, int y) {
|
||||||
|
std::cout << x << " " << y << std::endl;
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
int overloaded(int x, int y, int z) {
|
||||||
|
std::cout << x << " " << y << " " << z << std::endl;
|
||||||
|
return 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
int non_overloaded(int x, int y, int z) {
|
||||||
|
std::cout << x << " " << y << " " << z << std::endl;
|
||||||
|
return 13;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<int> test_table_return_one() {
|
std::vector<int> test_table_return_one() {
|
||||||
return { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
|
return { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
|
||||||
}
|
}
|
||||||
|
@ -332,25 +352,33 @@ TEST_CASE("tables/functions_variables", "Check if tables and function calls work
|
||||||
std::cout << "stateless lambda()" << std::endl;
|
std::cout << "stateless lambda()" << std::endl;
|
||||||
return "test";
|
return "test";
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
REQUIRE_NOTHROW(run_script(lua));
|
REQUIRE_NOTHROW(run_script(lua));
|
||||||
|
|
||||||
lua.get<sol::table>("os").set_function("fun", &free_function);
|
lua.get<sol::table>("os").set_function("fun", &free_function);
|
||||||
REQUIRE_NOTHROW(run_script(lua));
|
REQUIRE_NOTHROW(run_script(lua));
|
||||||
|
|
||||||
// l-value, can optimise
|
// l-value, canNOT optimise
|
||||||
|
// prefer value semantics unless wrapped with std::reference_wrapper
|
||||||
|
{
|
||||||
auto lval = object();
|
auto lval = object();
|
||||||
lua.get<sol::table>("os").set_function("fun", &object::operator(), lval);
|
lua.get<sol::table>("os").set_function("fun", &object::operator(), lval);
|
||||||
|
}
|
||||||
REQUIRE_NOTHROW(run_script(lua));
|
REQUIRE_NOTHROW(run_script(lua));
|
||||||
|
|
||||||
|
auto reflval = object();
|
||||||
|
lua.get<sol::table>("os").set_function("fun", &object::operator(), std::ref(reflval));
|
||||||
|
REQUIRE_NOTHROW(run_script(lua));
|
||||||
|
|
||||||
|
|
||||||
// stateful lambda: non-convertible, cannot be optimised
|
// stateful lambda: non-convertible, cannot be optimised
|
||||||
int breakit = 50;
|
int breakit = 50;
|
||||||
lua.get<sol::table>("os").set_function("fun",
|
lua.get<sol::table>("os").set_function("fun",
|
||||||
[&breakit] () {
|
[&breakit] () {
|
||||||
std::cout << "stateless lambda()" << std::endl;
|
std::cout << "stateful lambda()" << std::endl;
|
||||||
return "test";
|
return "test";
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
REQUIRE_NOTHROW(run_script(lua));
|
REQUIRE_NOTHROW(run_script(lua));
|
||||||
|
|
||||||
// r-value, cannot optimise
|
// r-value, cannot optimise
|
||||||
|
@ -363,6 +391,26 @@ TEST_CASE("tables/functions_variables", "Check if tables and function calls work
|
||||||
REQUIRE_NOTHROW(run_script(lua));
|
REQUIRE_NOTHROW(run_script(lua));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("functions/overloaded", "Check if overloaded function resolution templates compile/work") {
|
||||||
|
sol::state lua;
|
||||||
|
lua.open_libraries(sol::lib::base);
|
||||||
|
|
||||||
|
lua.set_function("non_overloaded", non_overloaded);
|
||||||
|
REQUIRE_NOTHROW(lua.script("x = non_overloaded(1)\nprint(x)"));
|
||||||
|
|
||||||
|
lua.set_function<int>("overloaded", overloaded);
|
||||||
|
REQUIRE_NOTHROW(lua.script("print(overloaded(1))"));
|
||||||
|
|
||||||
|
lua.set_function<int, int>("overloaded", overloaded);
|
||||||
|
REQUIRE_NOTHROW(lua.script("print(overloaded(1, 2))"));
|
||||||
|
|
||||||
|
lua.set_function<int(int, int)>("overloaded", overloaded);
|
||||||
|
REQUIRE_NOTHROW(lua.script("print(overloaded(1, 2))"));
|
||||||
|
|
||||||
|
lua.set_function<int, int, int>("overloaded", overloaded);
|
||||||
|
REQUIRE_NOTHROW(lua.script("print(overloaded(1, 2, 3))"));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("functions/return_order_and_multi_get", "Check if return order is in the same reading order specified in Lua") {
|
TEST_CASE("functions/return_order_and_multi_get", "Check if return order is in the same reading order specified in Lua") {
|
||||||
const static std::tuple<int, int, int> triple = std::make_tuple(10, 11, 12);
|
const static std::tuple<int, int, int> triple = std::make_tuple(10, 11, 12);
|
||||||
sol::state lua;
|
sol::state lua;
|
||||||
|
@ -730,10 +778,10 @@ TEST_CASE("userdata/lua-stored-userdata", "ensure userdata values can be stored
|
||||||
// userdata dies, but still usable in lua!
|
// userdata dies, but still usable in lua!
|
||||||
}
|
}
|
||||||
|
|
||||||
lua.script("collectgarbage()\n"
|
REQUIRE_NOTHROW(lua.script("collectgarbage()\n"
|
||||||
"v = Vec.new(1, 2, 3)\n"
|
"v = Vec.new(1, 2, 3)\n"
|
||||||
"print(v:length())");
|
"print(v:length())"));
|
||||||
|
|
||||||
lua.script("v = Vec.new(1, 2, 3)\n"
|
REQUIRE_NOTHROW(lua.script("v = Vec.new(1, 2, 3)\n"
|
||||||
"print(v:normalized():length())" );
|
"print(v:normalized():length())" ));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user