cull a good chunk of SFINAE, see what results...

This commit is contained in:
ThePhD 2019-01-28 11:32:32 -05:00
parent ad494bd063
commit e1f3e5f009
No known key found for this signature in database
GPG Key ID: 1509DB1C0F702BFA
8 changed files with 712 additions and 589 deletions

View File

@ -35,49 +35,99 @@
namespace sol { namespace sol {
namespace function_detail { namespace function_detail {
template <typename T> template <typename T>
struct class_indicator {}; struct class_indicator {
using type = T;
};
struct call_indicator {}; struct call_indicator {};
} // namespace function_detail
namespace stack { template <bool yielding>
template <typename... Sigs> inline int lua_c_wrapper(lua_State* L) {
struct unqualified_pusher<function_sig<Sigs...>> { lua_CFunction cf = lua_tocfunction(L, lua_upvalueindex(2));
template <bool is_yielding, typename R, typename... A, typename Fx, typename... Args> int nr = cf(L);
static void select_convertible(types<R(A...)> t, lua_State* L, Fx&& fx, Args&&... args) { if constexpr (yielding) {
typedef std::decay_t<meta::unwrap_unqualified_t<Fx>> raw_fx_t; return lua_yield(L, nr);
typedef R (*fx_ptr_t)(A...);
constexpr bool is_convertible = std::is_convertible_v<raw_fx_t, fx_ptr_t>;
if constexpr (is_convertible) {
using fx_ptr_t = R (*)(A...);
fx_ptr_t fxptr = detail::unwrap(std::forward<Fx>(fx));
select_function<is_yielding>(std::true_type(), L, fxptr, std::forward<Args>(args)...);
} }
else { else {
typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx; return nr;
typedef function_detail::functor_function<clean_fx, is_yielding, true> F; }
set_fx<false, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...); }
template <bool yielding>
inline int lua_c_noexcept_wrapper(lua_State* L) noexcept {
detail::lua_CFunction_noexcept cf = reinterpret_cast<detail::lua_CFunction_noexcept>(lua_tocfunction(L, lua_upvalueindex(2)));
int nr = cf(L);
if constexpr (yielding) {
return lua_yield(L, nr);
}
else {
return nr;
}
}
struct c_function_invocation {};
template <bool is_yielding, typename Fx, typename... Args>
inline void select(lua_State* L, Fx&& fx, Args&&... args);
template <bool is_yielding, typename Fx, typename... Args>
inline void select_set_fx(lua_State* L, Args&&... args) {
lua_CFunction freefunc = detail::static_trampoline<function_detail::call<meta::unqualified_t<Fx>, 2, is_yielding>>;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::push<user<Fx>>(L, std::forward<Args>(args)...);
stack::push(L, c_closure(freefunc, upvalues));
}
template <bool is_yielding, typename R, typename... A, typename Fx, typename... Args>
inline void select_convertible(types<R(A...)>, lua_State* L, Fx&& fx, Args&&... args) {
using dFx = std::decay_t<meta::unwrap_unqualified_t<Fx>>;
using fx_ptr_t = R (*)(A...);
constexpr bool is_convertible = std::is_convertible_v<dFx, fx_ptr_t>;
if constexpr (is_convertible) {
fx_ptr_t fxptr = detail::unwrap(std::forward<Fx>(fx));
select<is_yielding>(L, std::move(fxptr), std::forward<Args>(args)...);
}
else {
using F = function_detail::functor_function<dFx, is_yielding, true>;
select_set_fx<false, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
} }
} }
template <bool is_yielding, typename Fx, typename... Args> template <bool is_yielding, typename Fx, typename... Args>
static void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) { inline void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) {
typedef meta::function_signature_t<meta::unwrap_unqualified_t<Fx>> Sig; typedef meta::function_signature_t<meta::unwrap_unqualified_t<Fx>> Sig;
select_convertible<is_yielding>(types<Sig>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...); select_convertible<is_yielding>(types<Sig>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
} }
template <bool is_yielding, typename Fx, typename... Args> template <bool is_yielding, typename Fx, typename... Args>
static void select_member_variable(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { inline void select_member_variable(lua_State* L, Fx&& fx, Args&&... args) {
select_convertible<is_yielding>(types<Sigs...>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...); using uFx = meta::unqualified_t<Fx>;
} if constexpr (sizeof...(Args) < 1) {
using C = typename meta::bind_traits<uFx>::object_type;
lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx, is_yielding>::call;
template <bool is_yielding, typename Fx, typename T, typename... Args, meta::disable<meta::is_specialization_of<meta::unqualified_t<T>, function_detail::class_indicator>> = meta::enabler> int upvalues = 0;
static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { upvalues += stack::push(L, nullptr);
constexpr bool is_reference = meta::is_specialization_of_v<meta::unqualified_t<T>, std::reference_wrapper> || std::is_pointer_v<T>; upvalues += stack::stack_detail::push_as_upvalues(L, fx);
if constexpr(is_reference) { stack::push(L, c_closure(freefunc, upvalues));
}
else if constexpr (sizeof...(Args) < 2) {
using Tu = typename meta::unqualified<Args...>::type;
constexpr bool is_reference = meta::is_specialization_of_v<Tu, std::reference_wrapper> || std::is_pointer_v<Tu>;
if constexpr (meta::is_specialization_of_v<Tu, function_detail::class_indicator>) {
lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<typename Tu::type, Fx, is_yielding>::call;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, fx);
stack::push(L, c_closure(freefunc, upvalues));
}
else if constexpr (is_reference) {
typedef std::decay_t<Fx> dFx; typedef std::decay_t<Fx> dFx;
dFx memfxptr(std::forward<Fx>(fx)); dFx memfxptr(std::forward<Fx>(fx));
auto userptr = detail::ptr(std::forward<T>(obj), std::forward<Args>(args)...); auto userptr = detail::ptr(std::forward<Args>(args)...);
lua_CFunction freefunc lua_CFunction freefunc
= &function_detail::upvalue_member_variable<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>, is_yielding>::call; = &function_detail::upvalue_member_variable<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>, is_yielding>::call;
@ -89,94 +139,93 @@ namespace sol {
} }
else { else {
using clean_fx = std::remove_pointer_t<std::decay_t<Fx>>; using clean_fx = std::remove_pointer_t<std::decay_t<Fx>>;
using F = function_detail::member_variable<meta::unwrap_unqualified_t<T>, clean_fx, is_yielding>; using F = function_detail::member_variable<Tu, clean_fx, is_yielding>;
set_fx<false, F>(L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...); select_set_fx<false, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
} }
} }
else {
template <bool is_yielding, typename Fx, typename C> using C = typename meta::bind_traits<uFx>::object_type;
static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator<C>) { using clean_fx = std::remove_pointer_t<std::decay_t<Fx>>;
lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx, is_yielding>::call; using F = function_detail::member_variable<C, clean_fx, is_yielding>;
select_set_fx<false, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, fx);
stack::push(L, c_closure(freefunc, upvalues));
} }
template <bool is_yielding, typename Fx>
static void select_member_variable(std::true_type, lua_State* L, Fx&& fx) {
typedef typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type C;
lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx, is_yielding>::call;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, fx);
stack::push(L, c_closure(freefunc, upvalues));
} }
template <bool is_yielding, typename Fx, typename T, typename... Args> template <bool is_yielding, typename Fx, typename T, typename... Args>
static void select_reference_member_function(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { inline void select_member_function_with(lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
typedef std::decay_t<Fx> clean_fx;
typedef function_detail::member_function<meta::unwrap_unqualified_t<T>, clean_fx, is_yielding> F;
set_fx<false, F>(L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
}
template <bool is_yielding, typename Fx, typename T, typename... Args>
static void select_reference_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
using dFx = std::decay_t<Fx>; using dFx = std::decay_t<Fx>;
dFx memfxptr(std::forward<Fx>(fx)); using Tu = meta::unqualified_t<T>;
auto userptr = detail::ptr(std::forward<T>(obj), std::forward<Args>(args)...); if constexpr (meta::is_specialization_of_v<Tu, function_detail::class_indicator>) {
lua_CFunction freefunc = &function_detail::upvalue_member_function<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>, is_yielding>::call; using C = typename Tu::type;
lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, dFx, is_yielding>::call;
int upvalues = 0; int upvalues = 0;
upvalues += stack::push(L, nullptr); upvalues += stack::push(L, nullptr);
upvalues += stack::push<user<dFx>>(L, memfxptr); upvalues += stack::push<user<dFx>>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
stack::push(L, c_closure(freefunc, upvalues));
}
else {
constexpr bool is_reference = meta::is_specialization_of_v<Tu, std::reference_wrapper> || std::is_pointer_v<Tu>;
if constexpr (is_reference) {
auto userptr = detail::ptr(std::forward<T>(obj));
lua_CFunction freefunc = &function_detail::upvalue_member_function<std::decay_t<decltype(*userptr)>, dFx, is_yielding>::call;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::push<user<dFx>>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
upvalues += stack::push(L, lightuserdata_value(static_cast<void*>(userptr))); upvalues += stack::push(L, lightuserdata_value(static_cast<void*>(userptr)));
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
else {
using F = function_detail::member_function<Tu, dFx, is_yielding>;
select_set_fx<false, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
}
}
template <bool is_yielding, typename Fx, typename... Args> template <bool is_yielding, typename Fx, typename... Args>
static void select_member_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { inline void select_member_function(lua_State* L, Fx&& fx, Args&&... args) {
select_member_variable<is_yielding>(meta::is_member_object<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
template <bool is_yielding, typename Fx, typename T, typename... Args, meta::disable<meta::is_specialization_of<meta::unqualified_t<T>, function_detail::class_indicator>> = meta::enabler>
static void select_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
typedef meta::boolean<meta::is_specialization_of<meta::unqualified_t<T>, std::reference_wrapper>::value || std::is_pointer<T>::value> is_reference;
select_reference_member_function<is_yielding>(is_reference(), L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
}
template <bool is_yielding, typename Fx, typename C>
static void select_member_function(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator<C>) {
using dFx = std::decay_t<Fx>; using dFx = std::decay_t<Fx>;
if constexpr (sizeof...(Args) < 1) {
using C = typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type;
lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, dFx, is_yielding>::call; lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, dFx, is_yielding>::call;
int upvalues = 0; int upvalues = 0;
upvalues += stack::push(L, nullptr); upvalues += stack::push(L, nullptr);
upvalues += stack::push<user<dFx>>(L, fx); upvalues += stack::push<user<dFx>>(L, std::forward<Fx>(fx));
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
else {
select_member_function_with<is_yielding>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
}
template <bool is_yielding, typename Fx> template <bool is_yielding, typename Fx, typename... Args>
static void select_member_function(std::true_type, lua_State* L, Fx&& fx) { inline void select(lua_State* L, Fx&& fx, Args&&... args) {
using dFx = std::decay_t<Fx>; using uFx = meta::unqualified_t<Fx>;
typedef typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type C; if constexpr (is_lua_reference_v<uFx>) {
lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, dFx, is_yielding>::call; // TODO: hoist into lambda in this case for yielding???
stack::push(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
else if constexpr (is_lua_c_function_v<uFx>) {
int upvalues = 0; int upvalues = 0;
upvalues += stack::push(L, nullptr); upvalues += stack::push(L, nullptr);
upvalues += stack::push<user<dFx>>(L, fx); upvalues += stack::push(L, std::forward<Fx>(fx));
stack::push(L, c_closure(freefunc, upvalues)); #if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE
if constexpr (std::is_nothrow_invocable_r_v<int, uFx, lua_State*>) {
detail::lua_CFunction_noexcept cf = &lua_c_noexcept_wrapper<is_yielding>;
lua_pushcclosure(L, reinterpret_cast<lua_CFunction>(cf), 2);
} }
else {
template <bool is_yielding, typename Fx, typename... Args> lua_CFunction cf = &lua_c_wrapper<is_yielding>;
static void select_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { lua_pushcclosure(L, cf, 2);
select_member_function<is_yielding>(std::is_member_function_pointer<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
} }
#else
template <bool is_yielding, typename Fx, typename... Args> lua_CFunction cf = &function_detail::lua_c_wrapper<is_yielding>;
static void select_function(std::true_type, lua_State* L, Fx&& fx, Args&&... args) { lua_pushcclosure(L, cf, 2);
#endif
}
else if constexpr (std::is_function_v<std::remove_pointer_t<uFx>>) {
std::decay_t<Fx> target(std::forward<Fx>(fx), std::forward<Args>(args)...); std::decay_t<Fx> target(std::forward<Fx>(fx), std::forward<Args>(args)...);
lua_CFunction freefunc = &function_detail::upvalue_free_function<Fx, is_yielding>::call; lua_CFunction freefunc = &function_detail::upvalue_free_function<Fx, is_yielding>::call;
@ -185,74 +234,45 @@ namespace sol {
upvalues += stack::stack_detail::push_as_upvalues(L, target); upvalues += stack::stack_detail::push_as_upvalues(L, target);
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
else if constexpr (std::is_member_function_pointer_v<uFx>) {
template <bool is_yielding> select_member_function<is_yielding>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
static void select_function(std::true_type, lua_State* L, lua_CFunction f) {
// TODO: support yielding
stack::push(L, f);
} }
else if constexpr (meta::is_member_object_v<uFx>) {
#if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE select_member_variable<is_yielding>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
template <bool is_yielding>
static void select_function(std::true_type, lua_State* L, detail::lua_CFunction_noexcept f) {
// TODO: support yielding
stack::push(L, f);
} }
#endif // noexcept function type else {
select_convertible<is_yielding>(types<>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
template <bool is_yielding, typename Fx, typename... Args, meta::disable<is_lua_reference<meta::unqualified_t<Fx>>> = meta::enabler>
static void select(lua_State* L, Fx&& fx, Args&&... args) {
select_function<is_yielding>(std::is_function<std::remove_pointer_t<meta::unqualified_t<Fx>>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
} }
template <bool is_yielding, typename Fx, meta::enable<is_lua_reference<meta::unqualified_t<Fx>>> = meta::enabler>
static void select(lua_State* L, Fx&& fx) {
// TODO: hoist into lambda in this case??
stack::push(L, std::forward<Fx>(fx));
}
template <bool is_yielding, typename Fx, typename... Args>
static void set_fx(lua_State* L, Args&&... args) {
lua_CFunction freefunc = detail::static_trampoline<function_detail::call<meta::unqualified_t<Fx>, 2, is_yielding>>;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::push<user<Fx>>(L, std::forward<Args>(args)...);
stack::push(L, c_closure(freefunc, upvalues));
} }
} // namespace function_detail
namespace stack {
template <typename... Sigs>
struct unqualified_pusher<function_sig<Sigs...>> {
template <typename Arg0, typename... Args> template <typename Arg0, typename... Args>
static int push(lua_State* L, Arg0&& arg0, Args&&... args) { static int push(lua_State* L, Arg0&& arg0, Args&&... args) {
if constexpr (std::is_same_v<meta::unqualified_t<Arg0>, detail::yield_tag_t>) { if constexpr (std::is_same_v<meta::unqualified_t<Arg0>, detail::yield_tag_t>) {
select<true>(L, std::forward<Args>(args)...); function_detail::select<true>(L, std::forward<Args>(args)...);
} }
else { else {
select<false>(L, std::forward<Arg0>(arg0), std::forward<Args>(args)...); function_detail::select<false>(L, std::forward<Arg0>(arg0), std::forward<Args>(args)...);
} }
return 1; return 1;
} }
template <typename... Args>
static int push(lua_State* L, detail::yield_tag_t, Args&&... args) {
// Set will always place one thing (function) on the stack
return 1;
}
}; };
template <typename T> template <typename T>
struct unqualified_pusher<yielding_t<T>> { struct unqualified_pusher<yielding_t<T>> {
template <typename... Args> template <typename... Args>
static int push(lua_State* L, const yielding_t<T>& f, Args&&... args) { static int push(lua_State* L, const yielding_t<T>& f, Args&&... args) {
unqualified_pusher<function_sig<>> p{}; function_detail::select<true>(L, f.func, std::forward<Args>(args)...);
(void)p; return 1;
return p.push(L, detail::yield_tag, f.func, std::forward<Args>(args)...);
} }
template <typename... Args> template <typename... Args>
static int push(lua_State* L, yielding_t<T>&& f, Args&&... args) { static int push(lua_State* L, yielding_t<T>&& f, Args&&... args) {
unqualified_pusher<function_sig<>> p{}; function_detail::select<true>(L, std::move(f.func), std::forward<Args>(args)...);
(void)p; return 1;
return p.push(L, detail::yield_tag, std::move(f.func), std::forward<Args>(args)...);
} }
}; };
@ -275,50 +295,53 @@ namespace sol {
template <typename Signature> template <typename Signature>
struct unqualified_pusher<std::function<Signature>> { struct unqualified_pusher<std::function<Signature>> {
static int push(lua_State* L, const std::function<Signature>& fx) { static int push(lua_State* L, const std::function<Signature>& fx) {
return unqualified_pusher<function_sig<Signature>>{}.push(L, fx); function_detail::select<false>(L, fx);
return 1;
} }
static int push(lua_State* L, std::function<Signature>&& fx) { static int push(lua_State* L, std::function<Signature>&& fx) {
return unqualified_pusher<function_sig<Signature>>{}.push(L, std::move(fx)); function_detail::select<false>(L, std::move(fx));
return 1;
} }
}; };
template <typename Signature> template <typename Signature>
struct unqualified_pusher<Signature, std::enable_if_t<std::is_member_pointer<Signature>::value>> { struct unqualified_pusher<Signature, std::enable_if_t<std::is_member_pointer<Signature>::value>> {
template <typename F, typename... Args> template <typename... Args>
static int push(lua_State* L, F&& f, Args&&... args) { static int push(lua_State* L, Args&&... args) {
unqualified_pusher<function_sig<>> p{}; function_detail::select<false>(L, std::forward<Args>(args)...);
(void)p; return 1;
return p.push(L, std::forward<F>(f), std::forward<Args>(args)...);
} }
}; };
template <typename Signature> template <typename Signature>
struct unqualified_pusher<Signature, std::enable_if_t<meta::all<std::is_function<std::remove_pointer_t<Signature>>, meta::neg<std::is_same<Signature, lua_CFunction>>, meta::neg<std::is_same<Signature, std::remove_pointer_t<lua_CFunction>>> struct unqualified_pusher<Signature,
std::enable_if_t<meta::all<std::is_function<std::remove_pointer_t<Signature>>, meta::neg<std::is_same<Signature, lua_CFunction>>,
meta::neg<std::is_same<Signature, std::remove_pointer_t<lua_CFunction>>>
#if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE #if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE
, ,
meta::neg<std::is_same<Signature, detail::lua_CFunction_noexcept>>, meta::neg<std::is_same<Signature, std::remove_pointer_t<detail::lua_CFunction_noexcept>>> meta::neg<std::is_same<Signature, detail::lua_CFunction_noexcept>>,
meta::neg<std::is_same<Signature, std::remove_pointer_t<detail::lua_CFunction_noexcept>>>
#endif // noexcept function types #endif // noexcept function types
>::value>> { >::value>> {
template <typename F> template <typename F>
static int push(lua_State* L, F&& f) { static int push(lua_State* L, F&& f) {
return unqualified_pusher<function_sig<>>{}.push(L, std::forward<F>(f)); function_detail::select<false>(L, std::forward<F>(f));
return 1;
} }
}; };
template <typename... Functions> template <typename... Functions>
struct unqualified_pusher<overload_set<Functions...>> { struct unqualified_pusher<overload_set<Functions...>> {
static int push(lua_State* L, overload_set<Functions...>&& set) { static int push(lua_State* L, overload_set<Functions...>&& set) {
// TODO: yielding using F = function_detail::overloaded_function<0, Functions...>;
typedef function_detail::overloaded_function<0, Functions...> F; function_detail::select_set_fx<false, F>(L, std::move(set.functions));
unqualified_pusher<function_sig<>>{}.set_fx<false, F>(L, std::move(set.functions));
return 1; return 1;
} }
static int push(lua_State* L, const overload_set<Functions...>& set) { static int push(lua_State* L, const overload_set<Functions...>& set) {
// TODO: yielding using F = function_detail::overloaded_function<0, Functions...>;
typedef function_detail::overloaded_function<0, Functions...> F; function_detail::select_set_fx<false, F>(L, set.functions);
unqualified_pusher<function_sig<>>{}.set_fx<false, F>(L, set.functions);
return 1; return 1;
} }
}; };
@ -343,33 +366,30 @@ namespace sol {
}; };
template <typename F, typename G> template <typename F, typename G>
struct unqualified_pusher<property_wrapper<F, G>, std::enable_if_t<!std::is_void<F>::value && !std::is_void<G>::value>> { struct unqualified_pusher<property_wrapper<F, G>> {
static int push(lua_State* L, property_wrapper<F, G>&& pw) { static int push(lua_State* L, property_wrapper<F, G>&& pw) {
return stack::push(L, overload(std::move(pw.read), std::move(pw.write))); if constexpr (std::is_void_v<F>) {
}
static int push(lua_State* L, const property_wrapper<F, G>& pw) {
return stack::push(L, overload(pw.read, pw.write));
}
};
template <typename F>
struct unqualified_pusher<property_wrapper<F, void>> {
static int push(lua_State* L, property_wrapper<F, void>&& pw) {
return stack::push(L, std::move(pw.read));
}
static int push(lua_State* L, const property_wrapper<F, void>& pw) {
return stack::push(L, pw.read);
}
};
template <typename F>
struct unqualified_pusher<property_wrapper<void, F>> {
static int push(lua_State* L, property_wrapper<void, F>&& pw) {
return stack::push(L, std::move(pw.write)); return stack::push(L, std::move(pw.write));
} }
static int push(lua_State* L, const property_wrapper<void, F>& pw) { else if constexpr (std::is_void_v<G>) {
return stack::push(L, std::move(pw.read));
}
else {
return stack::push(L, overload(std::move(pw.read), std::move(pw.write)));
}
}
static int push(lua_State* L, const property_wrapper<F, G>& pw) {
if constexpr (std::is_void_v<F>) {
return stack::push(L, pw.write); return stack::push(L, pw.write);
} }
else if constexpr (std::is_void_v<G>) {
return stack::push(L, pw.read);
}
else {
return stack::push(L, overload(pw.read, pw.write));
}
}
}; };
template <typename T> template <typename T>
@ -385,26 +405,26 @@ namespace sol {
template <typename... Functions> template <typename... Functions>
struct unqualified_pusher<factory_wrapper<Functions...>> { struct unqualified_pusher<factory_wrapper<Functions...>> {
static int push(lua_State* L, const factory_wrapper<Functions...>& fw) { static int push(lua_State* L, const factory_wrapper<Functions...>& fw) {
typedef function_detail::overloaded_function<0, Functions...> F; using F = function_detail::overloaded_function<0, Functions...>;
unqualified_pusher<function_sig<>>{}.set_fx<false, F>(L, fw.functions); function_detail::select_set_fx<false, F>(L, fw.functions);
return 1; return 1;
} }
static int push(lua_State* L, factory_wrapper<Functions...>&& fw) { static int push(lua_State* L, factory_wrapper<Functions...>&& fw) {
typedef function_detail::overloaded_function<0, Functions...> F; using F = function_detail::overloaded_function<0, Functions...>;
unqualified_pusher<function_sig<>>{}.set_fx<false, F>(L, std::move(fw.functions)); function_detail::select_set_fx<false, F>(L, std::move(fw.functions));
return 1; return 1;
} }
static int push(lua_State* L, const factory_wrapper<Functions...>& set, function_detail::call_indicator) { static int push(lua_State* L, const factory_wrapper<Functions...>& fw, function_detail::call_indicator) {
typedef function_detail::overloaded_function<1, Functions...> F; using F = function_detail::overloaded_function<1, Functions...>;
unqualified_pusher<function_sig<>>{}.set_fx<false, F>(L, set.functions); function_detail::select_set_fx<false, F>(L, fw.functions);
return 1; return 1;
} }
static int push(lua_State* L, factory_wrapper<Functions...>&& set, function_detail::call_indicator) { static int push(lua_State* L, factory_wrapper<Functions...>&& fw, function_detail::call_indicator) {
typedef function_detail::overloaded_function<1, Functions...> F; using F = function_detail::overloaded_function<1, Functions...>;
unqualified_pusher<function_sig<>>{}.set_fx<false, F>(L, std::move(set.functions)); function_detail::select_set_fx<false, F>(L, std::move(fw.functions));
return 1; return 1;
} }
}; };

View File

@ -30,7 +30,7 @@
namespace sol { namespace sol {
namespace function_detail { namespace function_detail {
template <int start_skew = 0, typename... Functions> template <int start_skew, typename... Functions>
struct overloaded_function { struct overloaded_function {
typedef std::tuple<Functions...> overload_list; typedef std::tuple<Functions...> overload_list;
typedef std::make_index_sequence<sizeof...(Functions)> indices; typedef std::make_index_sequence<sizeof...(Functions)> indices;
@ -47,7 +47,8 @@ namespace function_detail {
template <typename Fx, std::size_t I, typename... R, typename... Args> template <typename Fx, std::size_t I, typename... R, typename... Args>
static int call(types<Fx>, meta::index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, overload_list& ol) { static int call(types<Fx>, meta::index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, overload_list& ol) {
auto& func = std::get<I>(ol); auto& func = std::get<I>(ol);
return call_detail::call_wrapped<void, true, false, start_skew>(L, func); int nr = call_detail::call_wrapped<void, true, false, start_skew>(L, func);
return nr;
} }
int operator()(lua_State* L) { int operator()(lua_State* L) {

View File

@ -136,6 +136,9 @@ namespace sol {
template <typename T> template <typename T>
struct is_member_object<readonly_wrapper<T>> : std::true_type {}; struct is_member_object<readonly_wrapper<T>> : std::true_type {};
template <typename T>
inline constexpr bool is_member_object_v = is_member_object<T>::value;
} // namespace meta } // namespace meta
} // namespace sol } // namespace sol

View File

@ -523,12 +523,26 @@ namespace sol {
struct supports_op_less<T, void> : std::false_type {}; struct supports_op_less<T, void> : std::false_type {};
template <typename T, typename U = T> template <typename T, typename U = T>
struct supports_op_equal : decltype(meta_detail::supports_op_equal_test(std::declval<T&>(), std::declval<U&>())) {}; struct supports_op_equal : decltype(meta_detail::supports_op_equal_test(std::declval<T&>(), std::declval<U&>())) {};
template <typename T>
struct supports_op_equal<void, T> : std::false_type {};
template <typename T>
struct supports_op_equal<T, void> : std::false_type {};
template <typename T, typename U = T> template <typename T, typename U = T>
struct supports_op_less_equal : decltype(meta_detail::supports_op_less_equal_test(std::declval<T&>(), std::declval<U&>())) {}; struct supports_op_less_equal : decltype(meta_detail::supports_op_less_equal_test(std::declval<T&>(), std::declval<U&>())) {};
template <typename T>
struct supports_op_less_equal<void, T> : std::false_type {};
template <typename T>
struct supports_op_less_equal<T, void> : std::false_type {};
template <typename T, typename U = std::ostream> template <typename T, typename U = std::ostream>
struct supports_ostream_op : decltype(meta_detail::supports_ostream_op(std::declval<T&>(), std::declval<U&>())) {}; struct supports_ostream_op : decltype(meta_detail::supports_ostream_op(std::declval<T&>(), std::declval<U&>())) {};
template <typename T> template <typename T>
struct supports_ostream_op<void, T> : std::false_type {};
template <typename T>
struct supports_ostream_op<T, void> : std::false_type {};
template <typename T>
struct supports_adl_to_string : decltype(meta_detail::supports_adl_to_string(std::declval<T&>())) {}; struct supports_adl_to_string : decltype(meta_detail::supports_adl_to_string(std::declval<T&>())) {};
template <>
struct supports_adl_to_string<void> : std::false_type {};
template <typename T> template <typename T>
using supports_to_string_member = meta::boolean<meta_detail::has_to_string_test<T>::value>; using supports_to_string_member = meta::boolean<meta_detail::has_to_string_test<T>::value>;

View File

@ -44,7 +44,7 @@ namespace sol {
} // namespace detail } // namespace detail
template <typename T> template <typename T>
using unqualified = std::remove_cv<std::remove_reference_t<T>>; struct unqualified : std::remove_cv<std::remove_reference_t<T>> {};
template <typename T> template <typename T>
using unqualified_t = typename unqualified<T>::type; using unqualified_t = typename unqualified<T>::type;

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script. // This file was generated with a script.
// Generated 2019-01-17 06:28:58.332972 UTC // Generated 2019-01-28 16:32:19.530572 UTC
// This header was generated with sol v2.20.6 (revision 88a089c) // This header was generated with sol v2.20.6 (revision ad494bd)
// https://github.com/ThePhD/sol2 // https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP #ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script. // This file was generated with a script.
// Generated 2019-01-17 06:28:58.073560 UTC // Generated 2019-01-28 16:32:19.243332 UTC
// This header was generated with sol v2.20.6 (revision 88a089c) // This header was generated with sol v2.20.6 (revision ad494bd)
// https://github.com/ThePhD/sol2 // https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_HPP #ifndef SOL_SINGLE_INCLUDE_HPP
@ -510,7 +510,7 @@ namespace sol {
} // namespace detail } // namespace detail
template <typename T> template <typename T>
using unqualified = std::remove_cv<std::remove_reference_t<T>>; struct unqualified : std::remove_cv<std::remove_reference_t<T>> {};
template <typename T> template <typename T>
using unqualified_t = typename unqualified<T>::type; using unqualified_t = typename unqualified<T>::type;
@ -1332,11 +1332,8 @@ namespace sol {
template <bool B> template <bool B>
using boolean = std::integral_constant<bool, B>; using boolean = std::integral_constant<bool, B>;
template <typename T> template <bool B>
using invoke_t = typename T::type; constexpr inline bool boolean_v = boolean<B>::value;
template <typename T>
using invoke_v = boolean<T::value>;
template <typename T> template <typename T>
using neg = boolean<!T::value>; using neg = boolean<!T::value>;
@ -1710,29 +1707,35 @@ namespace sol {
struct is_matched_lookup_impl<T, true> : std::is_same<typename T::key_type, typename T::value_type> {}; struct is_matched_lookup_impl<T, true> : std::is_same<typename T::key_type, typename T::value_type> {};
} // namespace meta_detail } // namespace meta_detail
#if defined(_MSC_VER) && _MSC_VER <= 1910
template <typename T, typename U = T> template <typename T, typename U = T>
using supports_op_less = decltype(meta_detail::supports_op_less_test(std::ref(std::declval<T&>()), std::ref(std::declval<U&>()))); struct supports_op_less : decltype(meta_detail::supports_op_less_test(std::declval<T&>(), std::declval<U&>())) {};
template <typename T, typename U = T>
using supports_op_equal = decltype(meta_detail::supports_op_equal_test(std::ref(std::declval<T&>()), std::ref(std::declval<U&>())));
template <typename T, typename U = T>
using supports_op_less_equal = decltype(meta_detail::supports_op_less_equal_test(std::ref(std::declval<T&>()), std::ref(std::declval<U&>())));
template <typename T, typename U = std::ostream>
using supports_ostream_op = decltype(meta_detail::supports_ostream_op(std::ref(std::declval<T&>()), std::ref(std::declval<U&>())));
template <typename T> template <typename T>
using supports_adl_to_string = decltype(meta_detail::supports_adl_to_string(std::ref(std::declval<T&>()))); struct supports_op_less<void, T> : std::false_type {};
#else
template <typename T, typename U = T>
using supports_op_less = decltype(meta_detail::supports_op_less_test(std::declval<T&>(), std::declval<U&>()));
template <typename T, typename U = T>
using supports_op_equal = decltype(meta_detail::supports_op_equal_test(std::declval<T&>(), std::declval<U&>()));
template <typename T, typename U = T>
using supports_op_less_equal = decltype(meta_detail::supports_op_less_equal_test(std::declval<T&>(), std::declval<U&>()));
template <typename T, typename U = std::ostream>
using supports_ostream_op = decltype(meta_detail::supports_ostream_op(std::declval<T&>(), std::declval<U&>()));
template <typename T> template <typename T>
using supports_adl_to_string = decltype(meta_detail::supports_adl_to_string(std::declval<T&>())); struct supports_op_less<T, void> : std::false_type {};
#endif template <typename T, typename U = T>
struct supports_op_equal : decltype(meta_detail::supports_op_equal_test(std::declval<T&>(), std::declval<U&>())) {};
template <typename T>
struct supports_op_equal<void, T> : std::false_type {};
template <typename T>
struct supports_op_equal<T, void> : std::false_type {};
template <typename T, typename U = T>
struct supports_op_less_equal : decltype(meta_detail::supports_op_less_equal_test(std::declval<T&>(), std::declval<U&>())) {};
template <typename T>
struct supports_op_less_equal<void, T> : std::false_type {};
template <typename T>
struct supports_op_less_equal<T, void> : std::false_type {};
template <typename T, typename U = std::ostream>
struct supports_ostream_op : decltype(meta_detail::supports_ostream_op(std::declval<T&>(), std::declval<U&>())) {};
template <typename T>
struct supports_ostream_op<void, T> : std::false_type {};
template <typename T>
struct supports_ostream_op<T, void> : std::false_type {};
template <typename T>
struct supports_adl_to_string : decltype(meta_detail::supports_adl_to_string(std::declval<T&>())) {};
template <>
struct supports_adl_to_string<void> : std::false_type {};
template <typename T> template <typename T>
using supports_to_string_member = meta::boolean<meta_detail::has_to_string_test<T>::value>; using supports_to_string_member = meta::boolean<meta_detail::has_to_string_test<T>::value>;
@ -15360,6 +15363,9 @@ namespace sol {
template <typename T> template <typename T>
struct is_member_object<readonly_wrapper<T>> : std::true_type {}; struct is_member_object<readonly_wrapper<T>> : std::true_type {};
template <typename T>
inline constexpr bool is_member_object_v = is_member_object<T>::value;
} // namespace meta } // namespace meta
} // namespace sol } // namespace sol
@ -16071,6 +16077,14 @@ namespace sol {
} }
}; };
template <typename T, typename Y, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct lua_call_wrapper<T, yielding_t<Y>, is_index, is_variable, checked, boost, clean_stack, C> {
template <typename F>
static int call(lua_State* L, F&& f) {
return lua_call_wrapper<T, meta::unqualified_t<Y>, is_index, is_variable, checked, boost, clean_stack>{}.call(L, f.func);
}
};
template <typename T, typename Sig, typename P, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> template <typename T, typename Sig, typename P, bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct lua_call_wrapper<T, function_arguments<Sig, P>, is_index, is_variable, checked, boost, clean_stack, C> { struct lua_call_wrapper<T, function_arguments<Sig, P>, is_index, is_variable, checked, boost, clean_stack, C> {
template <typename F> template <typename F>
@ -16081,7 +16095,17 @@ namespace sol {
template <typename T, bool is_index, bool is_variable, int boost = 0, bool checked = detail::default_safe_function_calls, bool clean_stack = true, typename Fx, typename... Args> template <typename T, bool is_index, bool is_variable, int boost = 0, bool checked = detail::default_safe_function_calls, bool clean_stack = true, typename Fx, typename... Args>
inline int call_wrapped(lua_State* L, Fx&& fx, Args&&... args) { inline int call_wrapped(lua_State* L, Fx&& fx, Args&&... args) {
return lua_call_wrapper<T, meta::unqualified_t<Fx>, is_index, is_variable, checked, boost, clean_stack> {}.call(L, std::forward<Fx>(fx), std::forward<Args>(args)...); using uFx = meta::unqualified_t<Fx>;
if constexpr(meta::is_specialization_of_v<uFx, yielding_t>) {
using real_fx = meta::unqualified_t<decltype(std::forward<Fx>(fx).func)>;
int nr = lua_call_wrapper<T, real_fx, is_index, is_variable, checked, boost, clean_stack>{}.call(
L, std::forward<Fx>(fx).func, std::forward<Args>(args)...);
return lua_yield(L, nr);
}
else {
return lua_call_wrapper<T, uFx, is_index, is_variable, checked, boost, clean_stack>{}.call(
L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
} }
template <typename T, bool is_index, bool is_variable, typename F, int start = 1, bool checked = detail::default_safe_function_calls, bool clean_stack = true> template <typename T, bool is_index, bool is_variable, typename F, int start = 1, bool checked = detail::default_safe_function_calls, bool clean_stack = true>
@ -16607,7 +16631,7 @@ namespace function_detail {
namespace sol { namespace sol {
namespace function_detail { namespace function_detail {
template <int start_skew = 0, typename... Functions> template <int start_skew, typename... Functions>
struct overloaded_function { struct overloaded_function {
typedef std::tuple<Functions...> overload_list; typedef std::tuple<Functions...> overload_list;
typedef std::make_index_sequence<sizeof...(Functions)> indices; typedef std::make_index_sequence<sizeof...(Functions)> indices;
@ -16624,7 +16648,8 @@ namespace function_detail {
template <typename Fx, std::size_t I, typename... R, typename... Args> template <typename Fx, std::size_t I, typename... R, typename... Args>
static int call(types<Fx>, meta::index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, overload_list& ol) { static int call(types<Fx>, meta::index_value<I>, types<R...>, types<Args...>, lua_State* L, int, int, overload_list& ol) {
auto& func = std::get<I>(ol); auto& func = std::get<I>(ol);
return call_detail::call_wrapped<void, true, false, start_skew>(L, func); int nr = call_detail::call_wrapped<void, true, false, start_skew>(L, func);
return nr;
} }
int operator()(lua_State* L) { int operator()(lua_State* L) {
@ -16789,193 +16814,43 @@ namespace sol {
namespace sol { namespace sol {
namespace function_detail { namespace function_detail {
template <typename T> template <typename T>
struct class_indicator {}; struct class_indicator {
using type = T;
};
struct call_indicator {}; struct call_indicator {};
} // namespace function_detail
namespace stack { template <bool yielding>
template <typename... Sigs> inline int lua_c_wrapper(lua_State* L) {
struct unqualified_pusher<function_sig<Sigs...>> { lua_CFunction cf = lua_tocfunction(L, lua_upvalueindex(2));
template <bool is_yielding, typename... Sig, typename Fx, typename... Args> int nr = cf(L);
static void select_convertible(std::false_type, types<Sig...>, lua_State* L, Fx&& fx, Args&&... args) { if constexpr (yielding) {
typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx; return lua_yield(L, nr);
typedef function_detail::functor_function<clean_fx, is_yielding, true> F; }
set_fx<false, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...); else {
return nr;
}
} }
template <bool is_yielding, typename R, typename... A, typename Fx, typename... Args> template <bool yielding>
static void select_convertible(std::true_type, types<R(A...)>, lua_State* L, Fx&& fx, Args&&... args) { inline int lua_c_noexcept_wrapper(lua_State* L) noexcept {
using fx_ptr_t = R (*)(A...); detail::lua_CFunction_noexcept cf = reinterpret_cast<detail::lua_CFunction_noexcept>(lua_tocfunction(L, lua_upvalueindex(2)));
fx_ptr_t fxptr = detail::unwrap(std::forward<Fx>(fx)); int nr = cf(L);
select_function<is_yielding>(std::true_type(), L, fxptr, std::forward<Args>(args)...); if constexpr (yielding) {
return lua_yield(L, nr);
}
else {
return nr;
}
} }
template <bool is_yielding, typename R, typename... A, typename Fx, typename... Args> struct c_function_invocation {};
static void select_convertible(types<R(A...)> t, lua_State* L, Fx&& fx, Args&&... args) {
typedef std::decay_t<meta::unwrap_unqualified_t<Fx>> raw_fx_t;
typedef R (*fx_ptr_t)(A...);
typedef std::is_convertible<raw_fx_t, fx_ptr_t> is_convertible;
select_convertible<is_yielding>(is_convertible(), t, L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
template <bool is_yielding, typename Fx, typename... Args> template <bool is_yielding, typename Fx, typename... Args>
static void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) { inline void select(lua_State* L, Fx&& fx, Args&&... args);
typedef meta::function_signature_t<meta::unwrap_unqualified_t<Fx>> Sig;
select_convertible<is_yielding>(types<Sig>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
template <bool is_yielding, typename Fx, typename T, typename... Args>
static void select_reference_member_variable(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx;
typedef function_detail::member_variable<meta::unwrap_unqualified_t<T>, clean_fx, is_yielding> F;
set_fx<false, F>(L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
}
template <bool is_yielding, typename Fx, typename T, typename... Args>
static void select_reference_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
typedef std::decay_t<Fx> dFx;
dFx memfxptr(std::forward<Fx>(fx));
auto userptr = detail::ptr(std::forward<T>(obj), std::forward<Args>(args)...);
lua_CFunction freefunc = &function_detail::upvalue_member_variable<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>, is_yielding>::call;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, memfxptr);
upvalues += stack::push(L, static_cast<void const*>(userptr));
stack::push(L, c_closure(freefunc, upvalues));
}
template <bool is_yielding, typename Fx, typename... Args> template <bool is_yielding, typename Fx, typename... Args>
static void select_member_variable(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { inline void select_set_fx(lua_State* L, Args&&... args) {
select_convertible<is_yielding>(types<Sigs...>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
template <bool is_yielding, typename Fx, typename T, typename... Args, meta::disable<meta::is_specialization_of<meta::unqualified_t<T>, function_detail::class_indicator>> = meta::enabler>
static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
typedef meta::boolean<meta::is_specialization_of<meta::unqualified_t<T>, std::reference_wrapper>::value || std::is_pointer<T>::value> is_reference;
select_reference_member_variable<is_yielding>(is_reference(), L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
}
template <bool is_yielding, typename Fx, typename C>
static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator<C>) {
lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx, is_yielding>::call;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, fx);
stack::push(L, c_closure(freefunc, upvalues));
}
template <bool is_yielding, typename Fx>
static void select_member_variable(std::true_type, lua_State* L, Fx&& fx) {
typedef typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type C;
lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx, is_yielding>::call;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, fx);
stack::push(L, c_closure(freefunc, upvalues));
}
template <bool is_yielding, typename Fx, typename T, typename... Args>
static void select_reference_member_function(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
typedef std::decay_t<Fx> clean_fx;
typedef function_detail::member_function<meta::unwrap_unqualified_t<T>, clean_fx, is_yielding> F;
set_fx<false, F>(L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
}
template <bool is_yielding, typename Fx, typename T, typename... Args>
static void select_reference_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
using dFx = std::decay_t<Fx>;
dFx memfxptr(std::forward<Fx>(fx));
auto userptr = detail::ptr(std::forward<T>(obj), std::forward<Args>(args)...);
lua_CFunction freefunc = &function_detail::upvalue_member_function<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>, is_yielding>::call;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::push<user<dFx>>(L, memfxptr);
upvalues += stack::push(L, lightuserdata_value(static_cast<void*>(userptr)));
stack::push(L, c_closure(freefunc, upvalues));
}
template <bool is_yielding, typename Fx, typename... Args>
static void select_member_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) {
select_member_variable<is_yielding>(meta::is_member_object<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
template <bool is_yielding, typename Fx, typename T, typename... Args, meta::disable<meta::is_specialization_of<meta::unqualified_t<T>, function_detail::class_indicator>> = meta::enabler>
static void select_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
typedef meta::boolean<meta::is_specialization_of<meta::unqualified_t<T>, std::reference_wrapper>::value || std::is_pointer<T>::value> is_reference;
select_reference_member_function<is_yielding>(is_reference(), L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
}
template <bool is_yielding, typename Fx, typename C>
static void select_member_function(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator<C>) {
using dFx = std::decay_t<Fx>;
lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, dFx, is_yielding>::call;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::push<user<dFx>>(L, fx);
stack::push(L, c_closure(freefunc, upvalues));
}
template <bool is_yielding, typename Fx>
static void select_member_function(std::true_type, lua_State* L, Fx&& fx) {
using dFx = std::decay_t<Fx>;
typedef typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type C;
lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, dFx, is_yielding>::call;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::push<user<dFx>>(L, fx);
stack::push(L, c_closure(freefunc, upvalues));
}
template <bool is_yielding, typename Fx, typename... Args>
static void select_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) {
select_member_function<is_yielding>(std::is_member_function_pointer<meta::unqualified_t<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
template <bool is_yielding, typename Fx, typename... Args>
static void select_function(std::true_type, lua_State* L, Fx&& fx, Args&&... args) {
std::decay_t<Fx> target(std::forward<Fx>(fx), std::forward<Args>(args)...);
lua_CFunction freefunc = &function_detail::upvalue_free_function<Fx, is_yielding>::call;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, target);
stack::push(L, c_closure(freefunc, upvalues));
}
template <bool is_yielding>
static void select_function(std::true_type, lua_State* L, lua_CFunction f) {
// TODO: support yielding
stack::push(L, f);
}
#if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE
template <bool is_yielding>
static void select_function(std::true_type, lua_State* L, detail::lua_CFunction_noexcept f) {
// TODO: support yielding
stack::push(L, f);
}
#endif // noexcept function type
template <bool is_yielding, typename Fx, typename... Args, meta::disable<is_lua_reference<meta::unqualified_t<Fx>>> = meta::enabler>
static void select(lua_State* L, Fx&& fx, Args&&... args) {
select_function<is_yielding>(std::is_function<std::remove_pointer_t<meta::unqualified_t<Fx>>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
template <bool is_yielding, typename Fx, meta::enable<is_lua_reference<meta::unqualified_t<Fx>>> = meta::enabler>
static void select(lua_State* L, Fx&& fx) {
// TODO: hoist into lambda in this case??
stack::push(L, std::forward<Fx>(fx));
}
template <bool is_yielding, typename Fx, typename... Args>
static void set_fx(lua_State* L, Args&&... args) {
lua_CFunction freefunc = detail::static_trampoline<function_detail::call<meta::unqualified_t<Fx>, 2, is_yielding>>; lua_CFunction freefunc = detail::static_trampoline<function_detail::call<meta::unqualified_t<Fx>, 2, is_yielding>>;
int upvalues = 0; int upvalues = 0;
@ -16984,17 +16859,183 @@ namespace sol {
stack::push(L, c_closure(freefunc, upvalues)); stack::push(L, c_closure(freefunc, upvalues));
} }
template <typename Arg0, typename... Args, meta::disable<std::is_same<detail::yield_tag_t, meta::unqualified_t<Arg0>>> = meta::enabler> template <bool is_yielding, typename R, typename... A, typename Fx, typename... Args>
static int push(lua_State* L, Arg0&& arg0, Args&&... args) { inline void select_convertible(types<R(A...)>, lua_State* L, Fx&& fx, Args&&... args) {
// Set will always place one thing (function) on the stack using dFx = std::decay_t<meta::unwrap_unqualified_t<Fx>>;
select<false>(L, std::forward<Arg0>(arg0), std::forward<Args>(args)...); using fx_ptr_t = R (*)(A...);
return 1; constexpr bool is_convertible = std::is_convertible_v<dFx, fx_ptr_t>;
if constexpr (is_convertible) {
fx_ptr_t fxptr = detail::unwrap(std::forward<Fx>(fx));
select<is_yielding>(L, std::move(fxptr), std::forward<Args>(args)...);
}
else {
using F = function_detail::functor_function<dFx, is_yielding, true>;
select_set_fx<false, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
} }
template <typename... Args> template <bool is_yielding, typename Fx, typename... Args>
static int push(lua_State* L, detail::yield_tag_t, Args&&... args) { inline void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) {
// Set will always place one thing (function) on the stack typedef meta::function_signature_t<meta::unwrap_unqualified_t<Fx>> Sig;
select<true>(L, std::forward<Args>(args)...); select_convertible<is_yielding>(types<Sig>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
template <bool is_yielding, typename Fx, typename... Args>
inline void select_member_variable(lua_State* L, Fx&& fx, Args&&... args) {
using uFx = meta::unqualified_t<Fx>;
if constexpr (sizeof...(Args) < 1) {
using C = typename meta::bind_traits<uFx>::object_type;
lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx, is_yielding>::call;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, fx);
stack::push(L, c_closure(freefunc, upvalues));
}
else if constexpr (sizeof...(Args) < 2) {
using Tu = typename meta::unqualified<Args...>::type;
constexpr bool is_reference = meta::is_specialization_of_v<Tu, std::reference_wrapper> || std::is_pointer_v<Tu>;
if constexpr (meta::is_specialization_of_v<Tu, function_detail::class_indicator>) {
lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<typename Tu::type, Fx, is_yielding>::call;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, fx);
stack::push(L, c_closure(freefunc, upvalues));
}
else if constexpr (is_reference) {
typedef std::decay_t<Fx> dFx;
dFx memfxptr(std::forward<Fx>(fx));
auto userptr = detail::ptr(std::forward<Args>(args)...);
lua_CFunction freefunc
= &function_detail::upvalue_member_variable<std::decay_t<decltype(*userptr)>, meta::unqualified_t<Fx>, is_yielding>::call;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, memfxptr);
upvalues += stack::push(L, static_cast<void const*>(userptr));
stack::push(L, c_closure(freefunc, upvalues));
}
else {
using clean_fx = std::remove_pointer_t<std::decay_t<Fx>>;
using F = function_detail::member_variable<Tu, clean_fx, is_yielding>;
select_set_fx<false, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
}
else {
using C = typename meta::bind_traits<uFx>::object_type;
using clean_fx = std::remove_pointer_t<std::decay_t<Fx>>;
using F = function_detail::member_variable<C, clean_fx, is_yielding>;
select_set_fx<false, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
}
template <bool is_yielding, typename Fx, typename T, typename... Args>
inline void select_member_function_with(lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
using dFx = std::decay_t<Fx>;
using Tu = meta::unqualified_t<T>;
if constexpr (meta::is_specialization_of_v<Tu, function_detail::class_indicator>) {
using C = typename Tu::type;
lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, dFx, is_yielding>::call;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::push<user<dFx>>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
stack::push(L, c_closure(freefunc, upvalues));
}
else {
constexpr bool is_reference = meta::is_specialization_of_v<Tu, std::reference_wrapper> || std::is_pointer_v<Tu>;
if constexpr (is_reference) {
auto userptr = detail::ptr(std::forward<T>(obj));
lua_CFunction freefunc = &function_detail::upvalue_member_function<std::decay_t<decltype(*userptr)>, dFx, is_yielding>::call;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::push<user<dFx>>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
upvalues += stack::push(L, lightuserdata_value(static_cast<void*>(userptr)));
stack::push(L, c_closure(freefunc, upvalues));
}
else {
using F = function_detail::member_function<Tu, dFx, is_yielding>;
select_set_fx<false, F>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
}
}
template <bool is_yielding, typename Fx, typename... Args>
inline void select_member_function(lua_State* L, Fx&& fx, Args&&... args) {
using dFx = std::decay_t<Fx>;
if constexpr (sizeof...(Args) < 1) {
using C = typename meta::bind_traits<meta::unqualified_t<Fx>>::object_type;
lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, dFx, is_yielding>::call;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::push<user<dFx>>(L, std::forward<Fx>(fx));
stack::push(L, c_closure(freefunc, upvalues));
}
else {
select_member_function_with<is_yielding>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
}
template <bool is_yielding, typename Fx, typename... Args>
inline void select(lua_State* L, Fx&& fx, Args&&... args) {
using uFx = meta::unqualified_t<Fx>;
if constexpr (is_lua_reference_v<uFx>) {
// TODO: hoist into lambda in this case for yielding???
stack::push(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
else if constexpr (is_lua_c_function_v<uFx>) {
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::push(L, std::forward<Fx>(fx));
#if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE
if constexpr (std::is_nothrow_invocable_r_v<int, uFx, lua_State*>) {
detail::lua_CFunction_noexcept cf = &lua_c_noexcept_wrapper<is_yielding>;
lua_pushcclosure(L, reinterpret_cast<lua_CFunction>(cf), 2);
}
else {
lua_CFunction cf = &lua_c_wrapper<is_yielding>;
lua_pushcclosure(L, cf, 2);
}
#else
lua_CFunction cf = &function_detail::lua_c_wrapper<is_yielding>;
lua_pushcclosure(L, cf, 2);
#endif
}
else if constexpr (std::is_function_v<std::remove_pointer_t<uFx>>) {
std::decay_t<Fx> target(std::forward<Fx>(fx), std::forward<Args>(args)...);
lua_CFunction freefunc = &function_detail::upvalue_free_function<Fx, is_yielding>::call;
int upvalues = 0;
upvalues += stack::push(L, nullptr);
upvalues += stack::stack_detail::push_as_upvalues(L, target);
stack::push(L, c_closure(freefunc, upvalues));
}
else if constexpr (std::is_member_function_pointer_v<uFx>) {
select_member_function<is_yielding>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
else if constexpr (meta::is_member_object_v<uFx>) {
select_member_variable<is_yielding>(L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
else {
select_convertible<is_yielding>(types<>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
}
}
} // namespace function_detail
namespace stack {
template <typename... Sigs>
struct unqualified_pusher<function_sig<Sigs...>> {
template <typename Arg0, typename... Args>
static int push(lua_State* L, Arg0&& arg0, Args&&... args) {
if constexpr (std::is_same_v<meta::unqualified_t<Arg0>, detail::yield_tag_t>) {
function_detail::select<true>(L, std::forward<Args>(args)...);
}
else {
function_detail::select<false>(L, std::forward<Arg0>(arg0), std::forward<Args>(args)...);
}
return 1; return 1;
} }
}; };
@ -17003,16 +17044,14 @@ namespace sol {
struct unqualified_pusher<yielding_t<T>> { struct unqualified_pusher<yielding_t<T>> {
template <typename... Args> template <typename... Args>
static int push(lua_State* L, const yielding_t<T>& f, Args&&... args) { static int push(lua_State* L, const yielding_t<T>& f, Args&&... args) {
unqualified_pusher<function_sig<>> p{}; function_detail::select<true>(L, f.func, std::forward<Args>(args)...);
(void)p; return 1;
return p.push(L, detail::yield_tag, f.func, std::forward<Args>(args)...);
} }
template <typename... Args> template <typename... Args>
static int push(lua_State* L, yielding_t<T>&& f, Args&&... args) { static int push(lua_State* L, yielding_t<T>&& f, Args&&... args) {
unqualified_pusher<function_sig<>> p{}; function_detail::select<true>(L, std::move(f.func), std::forward<Args>(args)...);
(void)p; return 1;
return p.push(L, detail::yield_tag, f.func, std::forward<Args>(args)...);
} }
}; };
@ -17035,50 +17074,53 @@ namespace sol {
template <typename Signature> template <typename Signature>
struct unqualified_pusher<std::function<Signature>> { struct unqualified_pusher<std::function<Signature>> {
static int push(lua_State* L, const std::function<Signature>& fx) { static int push(lua_State* L, const std::function<Signature>& fx) {
return unqualified_pusher<function_sig<Signature>>{}.push(L, fx); function_detail::select<false>(L, fx);
return 1;
} }
static int push(lua_State* L, std::function<Signature>&& fx) { static int push(lua_State* L, std::function<Signature>&& fx) {
return unqualified_pusher<function_sig<Signature>>{}.push(L, std::move(fx)); function_detail::select<false>(L, std::move(fx));
return 1;
} }
}; };
template <typename Signature> template <typename Signature>
struct unqualified_pusher<Signature, std::enable_if_t<std::is_member_pointer<Signature>::value>> { struct unqualified_pusher<Signature, std::enable_if_t<std::is_member_pointer<Signature>::value>> {
template <typename F, typename... Args> template <typename... Args>
static int push(lua_State* L, F&& f, Args&&... args) { static int push(lua_State* L, Args&&... args) {
unqualified_pusher<function_sig<>> p{}; function_detail::select<false>(L, std::forward<Args>(args)...);
(void)p; return 1;
return p.push(L, std::forward<F>(f), std::forward<Args>(args)...);
} }
}; };
template <typename Signature> template <typename Signature>
struct unqualified_pusher<Signature, std::enable_if_t<meta::all<std::is_function<std::remove_pointer_t<Signature>>, meta::neg<std::is_same<Signature, lua_CFunction>>, meta::neg<std::is_same<Signature, std::remove_pointer_t<lua_CFunction>>> struct unqualified_pusher<Signature,
std::enable_if_t<meta::all<std::is_function<std::remove_pointer_t<Signature>>, meta::neg<std::is_same<Signature, lua_CFunction>>,
meta::neg<std::is_same<Signature, std::remove_pointer_t<lua_CFunction>>>
#if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE #if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE
, ,
meta::neg<std::is_same<Signature, detail::lua_CFunction_noexcept>>, meta::neg<std::is_same<Signature, std::remove_pointer_t<detail::lua_CFunction_noexcept>>> meta::neg<std::is_same<Signature, detail::lua_CFunction_noexcept>>,
meta::neg<std::is_same<Signature, std::remove_pointer_t<detail::lua_CFunction_noexcept>>>
#endif // noexcept function types #endif // noexcept function types
>::value>> { >::value>> {
template <typename F> template <typename F>
static int push(lua_State* L, F&& f) { static int push(lua_State* L, F&& f) {
return unqualified_pusher<function_sig<>>{}.push(L, std::forward<F>(f)); function_detail::select<false>(L, std::forward<F>(f));
return 1;
} }
}; };
template <typename... Functions> template <typename... Functions>
struct unqualified_pusher<overload_set<Functions...>> { struct unqualified_pusher<overload_set<Functions...>> {
static int push(lua_State* L, overload_set<Functions...>&& set) { static int push(lua_State* L, overload_set<Functions...>&& set) {
// TODO: yielding using F = function_detail::overloaded_function<0, Functions...>;
typedef function_detail::overloaded_function<0, Functions...> F; function_detail::select_set_fx<false, F>(L, std::move(set.functions));
unqualified_pusher<function_sig<>>{}.set_fx<false, F>(L, std::move(set.functions));
return 1; return 1;
} }
static int push(lua_State* L, const overload_set<Functions...>& set) { static int push(lua_State* L, const overload_set<Functions...>& set) {
// TODO: yielding using F = function_detail::overloaded_function<0, Functions...>;
typedef function_detail::overloaded_function<0, Functions...> F; function_detail::select_set_fx<false, F>(L, set.functions);
unqualified_pusher<function_sig<>>{}.set_fx<false, F>(L, set.functions);
return 1; return 1;
} }
}; };
@ -17103,33 +17145,30 @@ namespace sol {
}; };
template <typename F, typename G> template <typename F, typename G>
struct unqualified_pusher<property_wrapper<F, G>, std::enable_if_t<!std::is_void<F>::value && !std::is_void<G>::value>> { struct unqualified_pusher<property_wrapper<F, G>> {
static int push(lua_State* L, property_wrapper<F, G>&& pw) { static int push(lua_State* L, property_wrapper<F, G>&& pw) {
return stack::push(L, overload(std::move(pw.read), std::move(pw.write))); if constexpr (std::is_void_v<F>) {
}
static int push(lua_State* L, const property_wrapper<F, G>& pw) {
return stack::push(L, overload(pw.read, pw.write));
}
};
template <typename F>
struct unqualified_pusher<property_wrapper<F, void>> {
static int push(lua_State* L, property_wrapper<F, void>&& pw) {
return stack::push(L, std::move(pw.read));
}
static int push(lua_State* L, const property_wrapper<F, void>& pw) {
return stack::push(L, pw.read);
}
};
template <typename F>
struct unqualified_pusher<property_wrapper<void, F>> {
static int push(lua_State* L, property_wrapper<void, F>&& pw) {
return stack::push(L, std::move(pw.write)); return stack::push(L, std::move(pw.write));
} }
static int push(lua_State* L, const property_wrapper<void, F>& pw) { else if constexpr (std::is_void_v<G>) {
return stack::push(L, std::move(pw.read));
}
else {
return stack::push(L, overload(std::move(pw.read), std::move(pw.write)));
}
}
static int push(lua_State* L, const property_wrapper<F, G>& pw) {
if constexpr (std::is_void_v<F>) {
return stack::push(L, pw.write); return stack::push(L, pw.write);
} }
else if constexpr (std::is_void_v<G>) {
return stack::push(L, pw.read);
}
else {
return stack::push(L, overload(pw.read, pw.write));
}
}
}; };
template <typename T> template <typename T>
@ -17145,26 +17184,26 @@ namespace sol {
template <typename... Functions> template <typename... Functions>
struct unqualified_pusher<factory_wrapper<Functions...>> { struct unqualified_pusher<factory_wrapper<Functions...>> {
static int push(lua_State* L, const factory_wrapper<Functions...>& fw) { static int push(lua_State* L, const factory_wrapper<Functions...>& fw) {
typedef function_detail::overloaded_function<0, Functions...> F; using F = function_detail::overloaded_function<0, Functions...>;
unqualified_pusher<function_sig<>>{}.set_fx<false, F>(L, fw.functions); function_detail::select_set_fx<false, F>(L, fw.functions);
return 1; return 1;
} }
static int push(lua_State* L, factory_wrapper<Functions...>&& fw) { static int push(lua_State* L, factory_wrapper<Functions...>&& fw) {
typedef function_detail::overloaded_function<0, Functions...> F; using F = function_detail::overloaded_function<0, Functions...>;
unqualified_pusher<function_sig<>>{}.set_fx<false, F>(L, std::move(fw.functions)); function_detail::select_set_fx<false, F>(L, std::move(fw.functions));
return 1; return 1;
} }
static int push(lua_State* L, const factory_wrapper<Functions...>& set, function_detail::call_indicator) { static int push(lua_State* L, const factory_wrapper<Functions...>& fw, function_detail::call_indicator) {
typedef function_detail::overloaded_function<1, Functions...> F; using F = function_detail::overloaded_function<1, Functions...>;
unqualified_pusher<function_sig<>>{}.set_fx<false, F>(L, set.functions); function_detail::select_set_fx<false, F>(L, fw.functions);
return 1; return 1;
} }
static int push(lua_State* L, factory_wrapper<Functions...>&& set, function_detail::call_indicator) { static int push(lua_State* L, factory_wrapper<Functions...>&& fw, function_detail::call_indicator) {
typedef function_detail::overloaded_function<1, Functions...> F; using F = function_detail::overloaded_function<1, Functions...>;
unqualified_pusher<function_sig<>>{}.set_fx<false, F>(L, std::move(set.functions)); function_detail::select_set_fx<false, F>(L, std::move(fw.functions));
return 1; return 1;
} }
}; };

View File

@ -25,9 +25,70 @@
#include <catch.hpp> #include <catch.hpp>
struct coro_h {
int x = 500;
int func() {
x += 1;
return x;
}
};
struct coro_test {
std::string identifier;
sol::reference obj;
coro_test(sol::this_state L, std::string id) : identifier(id), obj(L, sol::lua_nil) {
}
void store(sol::table ref) {
// must be explicit
obj = sol::reference(obj.lua_state(), ref);
}
void copy_store(sol::table ref) {
// must be explicit
obj = sol::reference(obj.lua_state(), ref);
}
sol::reference get() {
return obj;
}
~coro_test() {
}
};
struct coro_test_implicit {
std::string identifier;
sol::main_reference obj;
coro_test_implicit(sol::this_state L, std::string id) : identifier(id), obj(L, sol::lua_nil) {
}
void store(sol::table ref) {
// main_reference does the state shift implicitly
obj = std::move(ref);
lua_State* Lmain = sol::main_thread(ref.lua_state());
REQUIRE(obj.lua_state() == Lmain);
}
void copy_store(sol::table ref) {
// main_reference does the state shift implicitly
obj = ref;
lua_State* Lmain = sol::main_thread(ref.lua_state());
REQUIRE(obj.lua_state() == Lmain);
}
sol::reference get() {
return obj;
}
~coro_test_implicit() {
}
};
TEST_CASE("coroutines/coroutine.yield", "ensure calling a coroutine works") { TEST_CASE("coroutines/coroutine.yield", "ensure calling a coroutine works") {
const auto& script = R"(counter = 20 const auto& script = R"(counter = 20
function loop() function loop()
while counter ~= 30 while counter ~= 30
do do
@ -55,7 +116,6 @@ end
TEST_CASE("coroutines/new thread coroutines", "ensure calling a coroutine works when the work is put on a different thread") { TEST_CASE("coroutines/new thread coroutines", "ensure calling a coroutine works when the work is put on a different thread") {
const auto& code = R"(counter = 20 const auto& code = R"(counter = 20
function loop() function loop()
while counter ~= 30 while counter ~= 30
do do
@ -145,10 +205,10 @@ TEST_CASE("coroutines/explicit transfer", "check that the xmove constructors shi
-- co - L2 -- co - L2
-- co2 - L3 -- co2 - L3
x = co_test.new("x") x = coro_test.new("x")
local co = coroutine.wrap( local co = coroutine.wrap(
function() function()
local t = co_test.new("t") local t = coro_test.new("t")
local co2 = coroutine.wrap( local co2 = coroutine.wrap(
function() function()
local t2 = { "SOME_TABLE" } local t2 = { "SOME_TABLE" }
@ -171,45 +231,19 @@ collectgarbage()
co = nil co = nil
)"; )";
struct co_test {
std::string identifier;
sol::reference obj;
co_test(sol::this_state L, std::string id)
: identifier(id), obj(L, sol::lua_nil) {
}
void store(sol::table ref) {
// must be explicit
obj = sol::reference(obj.lua_state(), ref);
}
void copy_store(sol::table ref) {
// must be explicit
obj = sol::reference(obj.lua_state(), ref);
}
sol::reference get() {
return obj;
}
~co_test() {
}
};
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::coroutine, sol::lib::base); lua.open_libraries(sol::lib::coroutine, sol::lib::base);
lua.new_usertype<co_test>("co_test", lua.new_usertype<coro_test>("coro_test",
sol::constructors<co_test(sol::this_state, std::string)>(), sol::constructors<coro_test(sol::this_state, std::string)>(),
"store", &co_test::store, "store", &coro_test::store,
"copy_store", &co_test::copy_store, "copy_store", &coro_test::copy_store,
"get", &co_test::get); "get", &coro_test::get);
auto r = lua.safe_script(code, sol::script_pass_on_error); auto r = lua.safe_script(code, sol::script_pass_on_error);
REQUIRE(r.valid()); REQUIRE(r.valid());
co_test& ct = lua["x"]; coro_test& ct = lua["x"];
lua_State* Lmain1 = lua.lua_state(); lua_State* Lmain1 = lua.lua_state();
lua_State* Lmain2 = sol::main_thread(lua); lua_State* Lmain2 = sol::main_thread(lua);
@ -229,10 +263,10 @@ TEST_CASE("coroutines/implicit transfer", "check that copy and move assignment c
-- co - L2 -- co - L2
-- co2 - L3 -- co2 - L3
x = co_test.new("x") x = coro_test.new("x")
local co = coroutine.wrap( local co = coroutine.wrap(
function() function()
local t = co_test.new("t") local t = coro_test.new("t")
local co2 = coroutine.wrap( local co2 = coroutine.wrap(
function() function()
local t2 = { "SOME_TABLE" } local t2 = { "SOME_TABLE" }
@ -255,11 +289,11 @@ collectgarbage()
co = nil co = nil
)"; )";
struct co_test_implicit { struct coro_test_implicit {
std::string identifier; std::string identifier;
sol::reference obj; sol::reference obj;
co_test_implicit(sol::this_state L, std::string id) coro_test_implicit(sol::this_state L, std::string id)
: identifier(id), obj(L, sol::lua_nil) { : identifier(id), obj(L, sol::lua_nil) {
} }
@ -277,23 +311,23 @@ co = nil
return obj; return obj;
} }
~co_test_implicit() { ~coro_test_implicit() {
} }
}; };
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::coroutine, sol::lib::base); lua.open_libraries(sol::lib::coroutine, sol::lib::base);
lua.new_usertype<co_test_implicit>("co_test", lua.new_usertype<coro_test_implicit>("coro_test",
sol::constructors<co_test_implicit(sol::this_state, std::string)>(), sol::constructors<coro_test_implicit(sol::this_state, std::string)>(),
"store", &co_test_implicit::store, "store", &coro_test_implicit::store,
"copy_store", &co_test_implicit::copy_store, "copy_store", &coro_test_implicit::copy_store,
"get", &co_test_implicit::get); "get", &coro_test_implicit::get);
auto r = lua.safe_script(code, sol::script_pass_on_error); auto r = lua.safe_script(code, sol::script_pass_on_error);
REQUIRE(r.valid()); REQUIRE(r.valid());
co_test_implicit& ct = lua["x"]; coro_test_implicit& ct = lua["x"];
lua_State* Lmain1 = lua.lua_state(); lua_State* Lmain1 = lua.lua_state();
lua_State* Lmain2 = sol::main_thread(lua); lua_State* Lmain2 = sol::main_thread(lua);
@ -313,10 +347,10 @@ TEST_CASE("coroutines/main transfer", "check that copy and move assignment const
-- co - L2 -- co - L2
-- co2 - L3 -- co2 - L3
x = co_test.new("x") x = coro_test.new("x")
local co = coroutine.wrap( local co = coroutine.wrap(
function() function()
local t = co_test.new("t") local t = coro_test.new("t")
local co2 = coroutine.wrap( local co2 = coroutine.wrap(
function() function()
local t2 = { "SOME_TABLE" } local t2 = { "SOME_TABLE" }
@ -338,49 +372,19 @@ co = nil
collectgarbage() collectgarbage()
)"; )";
struct co_test_implicit {
std::string identifier;
sol::main_reference obj;
co_test_implicit(sol::this_state L, std::string id)
: identifier(id), obj(L, sol::lua_nil) {
}
void store(sol::table ref) {
// main_reference does the state shift implicitly
obj = std::move(ref);
lua_State* Lmain = sol::main_thread(ref.lua_state());
REQUIRE(obj.lua_state() == Lmain);
}
void copy_store(sol::table ref) {
// main_reference does the state shift implicitly
obj = ref;
lua_State* Lmain = sol::main_thread(ref.lua_state());
REQUIRE(obj.lua_state() == Lmain);
}
sol::reference get() {
return obj;
}
~co_test_implicit() {
}
};
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::coroutine, sol::lib::base); lua.open_libraries(sol::lib::coroutine, sol::lib::base);
lua.new_usertype<co_test_implicit>("co_test", lua.new_usertype<coro_test_implicit>("coro_test",
sol::constructors<co_test_implicit(sol::this_state, std::string)>(), sol::constructors<coro_test_implicit(sol::this_state, std::string)>(),
"store", &co_test_implicit::store, "store", &coro_test_implicit::store,
"copy_store", &co_test_implicit::copy_store, "copy_store", &coro_test_implicit::copy_store,
"get", &co_test_implicit::get); "get", &coro_test_implicit::get);
auto r = lua.safe_script(code, sol::script_pass_on_error); auto r = lua.safe_script(code, sol::script_pass_on_error);
REQUIRE(r.valid()); REQUIRE(r.valid());
co_test_implicit& ct = lua["x"]; coro_test_implicit& ct = lua["x"];
lua_State* Lmain1 = lua.lua_state(); lua_State* Lmain1 = lua.lua_state();
lua_State* Lmain2 = sol::main_thread(lua); lua_State* Lmain2 = sol::main_thread(lua);
@ -532,6 +536,7 @@ end
} }
TEST_CASE("coroutines/yielding", "test that a sol2 bound function can yield when marked yieldable") { TEST_CASE("coroutines/yielding", "test that a sol2 bound function can yield when marked yieldable") {
SECTION("regular functions") {
sol::state lua; sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::coroutine); lua.open_libraries(sol::lib::base, sol::lib::coroutine);
@ -541,16 +546,11 @@ TEST_CASE("coroutines/yielding", "test that a sol2 bound function can yield when
return i; return i;
}; };
struct h { coro_h hobj{};
int x = 500;
int func() const {
return x;
}
} hobj{};
lua["f"] = sol::yielding(func); lua["f"] = sol::yielding(func);
lua["g"] = sol::yielding([]() { return 300; }); lua["g"] = sol::yielding([]() { return 300; });
lua["h"] = sol::yielding(&h::func); lua["h"] = sol::yielding(&coro_h::func);
lua["hobj"] = &hobj; lua["hobj"] = &hobj;
sol::string_view code = R"( sol::string_view code = R"(
@ -564,7 +564,7 @@ TEST_CASE("coroutines/yielding", "test that a sol2 bound function can yield when
success3, value3 = coroutine.resume(co3) success3, value3 = coroutine.resume(co3)
)"; )";
auto result = lua.safe_script(code); auto result = lua.safe_script(code, sol::script_pass_on_error);
REQUIRE(result.valid()); REQUIRE(result.valid());
bool success1 = lua["success1"]; bool success1 = lua["success1"];
@ -580,5 +580,51 @@ TEST_CASE("coroutines/yielding", "test that a sol2 bound function can yield when
bool success3 = lua["success3"]; bool success3 = lua["success3"];
int value3 = lua["value3"]; int value3 = lua["value3"];
REQUIRE(success3); REQUIRE(success3);
REQUIRE(value3 == 500); REQUIRE(value3 == 501);
REQUIRE(hobj.x == 501);
}
SECTION("usertypes") {
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::coroutine);
coro_h hobj;
lua["hobj"] = &hobj;
lua.new_usertype<coro_h>("coro_h",
"h", sol::yielding(&coro_h::func)
);
sol::string_view code = R"(
co4 = coroutine.create(function()
hobj:h()
hobj.h(hobj)
coro_h.h(hobj)
end)
success4, value4 = coroutine.resume(co4)
success5, value5 = coroutine.resume(co4)
success6, value6 = coroutine.resume(co4)
)";
auto result = lua.safe_script(code, sol::script_pass_on_error);
REQUIRE(result.valid());
bool success4 = lua["success4"];
int value4 = lua["value4"];
REQUIRE(success4);
REQUIRE(value4 == 501);
bool success5 = lua["success5"];
int value5 = lua["value5"];
REQUIRE(success5);
REQUIRE(value5 == 502);
bool success6 = lua["success6"];
int value6 = lua["value6"];
REQUIRE(success6);
REQUIRE(value6 == 503);
REQUIRE(hobj.x == 503);
}
} }