From e1f3e5f009ee0e972e8743b856a0a6a5e764eb41 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Mon, 28 Jan 2019 11:32:32 -0500 Subject: [PATCH] cull a good chunk of SFINAE, see what results... --- include/sol/function_types.hpp | 436 +++++++++--------- include/sol/function_types_overloaded.hpp | 5 +- include/sol/property.hpp | 3 + include/sol/traits.hpp | 16 +- include/sol/tuple.hpp | 2 +- single/include/sol/forward.hpp | 4 +- single/include/sol/sol.hpp | 537 ++++++++++++---------- tests/runtime_tests/source/coroutines.cpp | 298 +++++++----- 8 files changed, 712 insertions(+), 589 deletions(-) diff --git a/include/sol/function_types.hpp b/include/sol/function_types.hpp index affb8558..a6ce9537 100644 --- a/include/sol/function_types.hpp +++ b/include/sol/function_types.hpp @@ -1,4 +1,4 @@ -// sol3 +// sol3 // The MIT License (MIT) @@ -35,51 +35,101 @@ namespace sol { namespace function_detail { template - struct class_indicator {}; + struct class_indicator { + using type = T; + }; struct call_indicator {}; - } // namespace function_detail - namespace stack { - template - struct unqualified_pusher> { - template - static void select_convertible(types t, lua_State* L, Fx&& fx, Args&&... args) { - typedef std::decay_t> raw_fx_t; - typedef R (*fx_ptr_t)(A...); - constexpr bool is_convertible = std::is_convertible_v; - if constexpr (is_convertible) { - using fx_ptr_t = R (*)(A...); - fx_ptr_t fxptr = detail::unwrap(std::forward(fx)); - select_function(std::true_type(), L, fxptr, std::forward(args)...); + template + inline int lua_c_wrapper(lua_State* L) { + lua_CFunction cf = lua_tocfunction(L, lua_upvalueindex(2)); + int nr = cf(L); + if constexpr (yielding) { + return lua_yield(L, nr); + } + else { + return nr; + } + } + + template + inline int lua_c_noexcept_wrapper(lua_State* L) noexcept { + detail::lua_CFunction_noexcept cf = reinterpret_cast(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 + inline void select(lua_State* L, Fx&& fx, Args&&... args); + + template + inline void select_set_fx(lua_State* L, Args&&... args) { + lua_CFunction freefunc = detail::static_trampoline, 2, is_yielding>>; + + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push>(L, std::forward(args)...); + stack::push(L, c_closure(freefunc, upvalues)); + } + + template + inline void select_convertible(types, lua_State* L, Fx&& fx, Args&&... args) { + using dFx = std::decay_t>; + using fx_ptr_t = R (*)(A...); + constexpr bool is_convertible = std::is_convertible_v; + if constexpr (is_convertible) { + fx_ptr_t fxptr = detail::unwrap(std::forward(fx)); + select(L, std::move(fxptr), std::forward(args)...); + } + else { + using F = function_detail::functor_function; + select_set_fx(L, std::forward(fx), std::forward(args)...); + } + } + + template + inline void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) { + typedef meta::function_signature_t> Sig; + select_convertible(types(), L, std::forward(fx), std::forward(args)...); + } + + template + inline void select_member_variable(lua_State* L, Fx&& fx, Args&&... args) { + using uFx = meta::unqualified_t; + if constexpr (sizeof...(Args) < 1) { + using C = typename meta::bind_traits::object_type; + lua_CFunction freefunc = &function_detail::upvalue_this_member_variable::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::type; + constexpr bool is_reference = meta::is_specialization_of_v || std::is_pointer_v; + if constexpr (meta::is_specialization_of_v) { + lua_CFunction freefunc = &function_detail::upvalue_this_member_variable::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 { - typedef std::remove_pointer_t> clean_fx; - typedef function_detail::functor_function F; - set_fx(L, std::forward(fx), std::forward(args)...); - } - } - - template - static void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) { - typedef meta::function_signature_t> Sig; - select_convertible(types(), L, std::forward(fx), std::forward(args)...); - } - - template - static void select_member_variable(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { - select_convertible(types(), L, std::forward(fx), std::forward(args)...); - } - - template , function_detail::class_indicator>> = meta::enabler> - static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { - constexpr bool is_reference = meta::is_specialization_of_v, std::reference_wrapper> || std::is_pointer_v; - if constexpr(is_reference) { + else if constexpr (is_reference) { typedef std::decay_t dFx; dFx memfxptr(std::forward(fx)); - auto userptr = detail::ptr(std::forward(obj), std::forward(args)...); + auto userptr = detail::ptr(std::forward(args)...); lua_CFunction freefunc - = &function_detail::upvalue_member_variable, meta::unqualified_t, is_yielding>::call; + = &function_detail::upvalue_member_variable, meta::unqualified_t, is_yielding>::call; int upvalues = 0; upvalues += stack::push(L, nullptr); @@ -89,94 +139,93 @@ namespace sol { } else { using clean_fx = std::remove_pointer_t>; - using F = function_detail::member_variable, clean_fx, is_yielding>; - set_fx(L, std::forward(fx), std::forward(obj), std::forward(args)...); + using F = function_detail::member_variable; + select_set_fx(L, std::forward(fx), std::forward(args)...); } } - - template - static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator) { - lua_CFunction freefunc = &function_detail::upvalue_this_member_variable::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 { + using C = typename meta::bind_traits::object_type; + using clean_fx = std::remove_pointer_t>; + using F = function_detail::member_variable; + select_set_fx(L, std::forward(fx), std::forward(args)...); } + } - template - static void select_member_variable(std::true_type, lua_State* L, Fx&& fx) { - typedef typename meta::bind_traits>::object_type C; - lua_CFunction freefunc = &function_detail::upvalue_this_member_variable::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 - static void select_reference_member_function(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { - typedef std::decay_t clean_fx; - typedef function_detail::member_function, clean_fx, is_yielding> F; - set_fx(L, std::forward(fx), std::forward(obj), std::forward(args)...); - } - - template - static void select_reference_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { - using dFx = std::decay_t; - dFx memfxptr(std::forward(fx)); - auto userptr = detail::ptr(std::forward(obj), std::forward(args)...); - lua_CFunction freefunc = &function_detail::upvalue_member_function, meta::unqualified_t, is_yielding>::call; - - int upvalues = 0; - upvalues += stack::push(L, nullptr); - upvalues += stack::push>(L, memfxptr); - upvalues += stack::push(L, lightuserdata_value(static_cast(userptr))); - stack::push(L, c_closure(freefunc, upvalues)); - } - - template - static void select_member_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { - select_member_variable(meta::is_member_object>(), L, std::forward(fx), std::forward(args)...); - } - - template , 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, std::reference_wrapper>::value || std::is_pointer::value> is_reference; - select_reference_member_function(is_reference(), L, std::forward(fx), std::forward(obj), std::forward(args)...); - } - - template - static void select_member_function(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator) { - using dFx = std::decay_t; + template + inline void select_member_function_with(lua_State* L, Fx&& fx, T&& obj, Args&&... args) { + using dFx = std::decay_t; + using Tu = meta::unqualified_t; + if constexpr (meta::is_specialization_of_v) { + using C = typename Tu::type; lua_CFunction freefunc = &function_detail::upvalue_this_member_function::call; - + int upvalues = 0; upvalues += stack::push(L, nullptr); - upvalues += stack::push>(L, fx); + upvalues += stack::push>(L, std::forward(fx), std::forward(args)...); stack::push(L, c_closure(freefunc, upvalues)); } + else { + constexpr bool is_reference = meta::is_specialization_of_v || std::is_pointer_v; + if constexpr (is_reference) { + auto userptr = detail::ptr(std::forward(obj)); + lua_CFunction freefunc = &function_detail::upvalue_member_function, dFx, is_yielding>::call; - template - static void select_member_function(std::true_type, lua_State* L, Fx&& fx) { - using dFx = std::decay_t; - typedef typename meta::bind_traits>::object_type C; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push>(L, std::forward(fx), std::forward(args)...); + upvalues += stack::push(L, lightuserdata_value(static_cast(userptr))); + stack::push(L, c_closure(freefunc, upvalues)); + } + else { + using F = function_detail::member_function; + select_set_fx(L, std::forward(fx), std::forward(args)...); + } + } + } + + template + inline void select_member_function(lua_State* L, Fx&& fx, Args&&... args) { + using dFx = std::decay_t; + if constexpr (sizeof...(Args) < 1) { + using C = typename meta::bind_traits>::object_type; lua_CFunction freefunc = &function_detail::upvalue_this_member_function::call; - + int upvalues = 0; upvalues += stack::push(L, nullptr); - upvalues += stack::push>(L, fx); + upvalues += stack::push>(L, std::forward(fx)); stack::push(L, c_closure(freefunc, upvalues)); } - - template - static void select_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { - select_member_function(std::is_member_function_pointer>(), L, std::forward(fx), std::forward(args)...); + else { + select_member_function_with(L, std::forward(fx), std::forward(args)...); } + } - template - static void select_function(std::true_type, lua_State* L, Fx&& fx, Args&&... args) { + template + inline void select(lua_State* L, Fx&& fx, Args&&... args) { + using uFx = meta::unqualified_t; + if constexpr (is_lua_reference_v) { + // TODO: hoist into lambda in this case for yielding??? + stack::push(L, std::forward(fx), std::forward(args)...); + } + else if constexpr (is_lua_c_function_v) { + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push(L, std::forward(fx)); +#if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE + if constexpr (std::is_nothrow_invocable_r_v) { + detail::lua_CFunction_noexcept cf = &lua_c_noexcept_wrapper; + lua_pushcclosure(L, reinterpret_cast(cf), 2); + } + else { + lua_CFunction cf = &lua_c_wrapper; + lua_pushcclosure(L, cf, 2); + } +#else + lua_CFunction cf = &function_detail::lua_c_wrapper; + lua_pushcclosure(L, cf, 2); +#endif + } + else if constexpr (std::is_function_v>) { std::decay_t target(std::forward(fx), std::forward(args)...); lua_CFunction freefunc = &function_detail::upvalue_free_function::call; @@ -185,74 +234,45 @@ namespace sol { upvalues += stack::stack_detail::push_as_upvalues(L, target); stack::push(L, c_closure(freefunc, upvalues)); } - - template - static void select_function(std::true_type, lua_State* L, lua_CFunction f) { - // TODO: support yielding - stack::push(L, f); + else if constexpr (std::is_member_function_pointer_v) { + select_member_function(L, std::forward(fx), std::forward(args)...); } - -#if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE - template - static void select_function(std::true_type, lua_State* L, detail::lua_CFunction_noexcept f) { - // TODO: support yielding - stack::push(L, f); + else if constexpr (meta::is_member_object_v) { + select_member_variable(L, std::forward(fx), std::forward(args)...); } -#endif // noexcept function type - - template >> = meta::enabler> - static void select(lua_State* L, Fx&& fx, Args&&... args) { - select_function(std::is_function>>(), L, std::forward(fx), std::forward(args)...); - } - - template >> = meta::enabler> - static void select(lua_State* L, Fx&& fx) { - // TODO: hoist into lambda in this case?? - stack::push(L, std::forward(fx)); - } - - template - static void set_fx(lua_State* L, Args&&... args) { - lua_CFunction freefunc = detail::static_trampoline, 2, is_yielding>>; - - int upvalues = 0; - upvalues += stack::push(L, nullptr); - upvalues += stack::push>(L, std::forward(args)...); - stack::push(L, c_closure(freefunc, upvalues)); + else { + select_convertible(types<>(), L, std::forward(fx), std::forward(args)...); } + } + } // namespace function_detail + namespace stack { + template + struct unqualified_pusher> { template static int push(lua_State* L, Arg0&& arg0, Args&&... args) { - if constexpr(std::is_same_v, detail::yield_tag_t>) { - select(L, std::forward(args)...); + if constexpr (std::is_same_v, detail::yield_tag_t>) { + function_detail::select(L, std::forward(args)...); } else { - select(L, std::forward(arg0), std::forward(args)...); + function_detail::select(L, std::forward(arg0), std::forward(args)...); } return 1; } - - template - 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 struct unqualified_pusher> { template static int push(lua_State* L, const yielding_t& f, Args&&... args) { - unqualified_pusher> p{}; - (void)p; - return p.push(L, detail::yield_tag, f.func, std::forward(args)...); + function_detail::select(L, f.func, std::forward(args)...); + return 1; } template static int push(lua_State* L, yielding_t&& f, Args&&... args) { - unqualified_pusher> p{}; - (void)p; - return p.push(L, detail::yield_tag, std::move(f.func), std::forward(args)...); + function_detail::select(L, std::move(f.func), std::forward(args)...); + return 1; } }; @@ -275,50 +295,53 @@ namespace sol { template struct unqualified_pusher> { static int push(lua_State* L, const std::function& fx) { - return unqualified_pusher>{}.push(L, fx); + function_detail::select(L, fx); + return 1; } static int push(lua_State* L, std::function&& fx) { - return unqualified_pusher>{}.push(L, std::move(fx)); + function_detail::select(L, std::move(fx)); + return 1; } }; template struct unqualified_pusher::value>> { - template - static int push(lua_State* L, F&& f, Args&&... args) { - unqualified_pusher> p{}; - (void)p; - return p.push(L, std::forward(f), std::forward(args)...); + template + static int push(lua_State* L, Args&&... args) { + function_detail::select(L, std::forward(args)...); + return 1; } }; template - struct unqualified_pusher>, meta::neg>, meta::neg>> + struct unqualified_pusher>, meta::neg>, + meta::neg>> #if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE - , - meta::neg>, meta::neg>> + , + meta::neg>, + meta::neg>> #endif // noexcept function types - >::value>> { + >::value>> { template static int push(lua_State* L, F&& f) { - return unqualified_pusher>{}.push(L, std::forward(f)); + function_detail::select(L, std::forward(f)); + return 1; } }; template struct unqualified_pusher> { static int push(lua_State* L, overload_set&& set) { - // TODO: yielding - typedef function_detail::overloaded_function<0, Functions...> F; - unqualified_pusher>{}.set_fx(L, std::move(set.functions)); + using F = function_detail::overloaded_function<0, Functions...>; + function_detail::select_set_fx(L, std::move(set.functions)); return 1; } static int push(lua_State* L, const overload_set& set) { - // TODO: yielding - typedef function_detail::overloaded_function<0, Functions...> F; - unqualified_pusher>{}.set_fx(L, set.functions); + using F = function_detail::overloaded_function<0, Functions...>; + function_detail::select_set_fx(L, set.functions); return 1; } }; @@ -343,32 +366,29 @@ namespace sol { }; template - struct unqualified_pusher, std::enable_if_t::value && !std::is_void::value>> { + struct unqualified_pusher> { static int push(lua_State* L, property_wrapper&& pw) { - return stack::push(L, overload(std::move(pw.read), std::move(pw.write))); + if constexpr (std::is_void_v) { + return stack::push(L, std::move(pw.write)); + } + else if constexpr (std::is_void_v) { + 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& pw) { - return stack::push(L, overload(pw.read, pw.write)); - } - }; - - template - struct unqualified_pusher> { - static int push(lua_State* L, property_wrapper&& pw) { - return stack::push(L, std::move(pw.read)); - } - static int push(lua_State* L, const property_wrapper& pw) { - return stack::push(L, pw.read); - } - }; - - template - struct unqualified_pusher> { - static int push(lua_State* L, property_wrapper&& pw) { - return stack::push(L, std::move(pw.write)); - } - static int push(lua_State* L, const property_wrapper& pw) { - return stack::push(L, pw.write); + if constexpr (std::is_void_v) { + return stack::push(L, pw.write); + } + else if constexpr (std::is_void_v) { + return stack::push(L, pw.read); + } + else { + return stack::push(L, overload(pw.read, pw.write)); + } } }; @@ -385,26 +405,26 @@ namespace sol { template struct unqualified_pusher> { static int push(lua_State* L, const factory_wrapper& fw) { - typedef function_detail::overloaded_function<0, Functions...> F; - unqualified_pusher>{}.set_fx(L, fw.functions); + using F = function_detail::overloaded_function<0, Functions...>; + function_detail::select_set_fx(L, fw.functions); return 1; } static int push(lua_State* L, factory_wrapper&& fw) { - typedef function_detail::overloaded_function<0, Functions...> F; - unqualified_pusher>{}.set_fx(L, std::move(fw.functions)); + using F = function_detail::overloaded_function<0, Functions...>; + function_detail::select_set_fx(L, std::move(fw.functions)); return 1; } - static int push(lua_State* L, const factory_wrapper& set, function_detail::call_indicator) { - typedef function_detail::overloaded_function<1, Functions...> F; - unqualified_pusher>{}.set_fx(L, set.functions); + static int push(lua_State* L, const factory_wrapper& fw, function_detail::call_indicator) { + using F = function_detail::overloaded_function<1, Functions...>; + function_detail::select_set_fx(L, fw.functions); return 1; } - static int push(lua_State* L, factory_wrapper&& set, function_detail::call_indicator) { - typedef function_detail::overloaded_function<1, Functions...> F; - unqualified_pusher>{}.set_fx(L, std::move(set.functions)); + static int push(lua_State* L, factory_wrapper&& fw, function_detail::call_indicator) { + using F = function_detail::overloaded_function<1, Functions...>; + function_detail::select_set_fx(L, std::move(fw.functions)); return 1; } }; diff --git a/include/sol/function_types_overloaded.hpp b/include/sol/function_types_overloaded.hpp index 062aebc5..6a5e61ff 100644 --- a/include/sol/function_types_overloaded.hpp +++ b/include/sol/function_types_overloaded.hpp @@ -30,7 +30,7 @@ namespace sol { namespace function_detail { - template + template struct overloaded_function { typedef std::tuple overload_list; typedef std::make_index_sequence indices; @@ -47,7 +47,8 @@ namespace function_detail { template static int call(types, meta::index_value, types, types, lua_State* L, int, int, overload_list& ol) { auto& func = std::get(ol); - return call_detail::call_wrapped(L, func); + int nr = call_detail::call_wrapped(L, func); + return nr; } int operator()(lua_State* L) { diff --git a/include/sol/property.hpp b/include/sol/property.hpp index 8a07907d..4534e54b 100644 --- a/include/sol/property.hpp +++ b/include/sol/property.hpp @@ -136,6 +136,9 @@ namespace sol { template struct is_member_object> : std::true_type {}; + + template + inline constexpr bool is_member_object_v = is_member_object::value; } // namespace meta } // namespace sol diff --git a/include/sol/traits.hpp b/include/sol/traits.hpp index d97701b2..4e4982d5 100644 --- a/include/sol/traits.hpp +++ b/include/sol/traits.hpp @@ -523,13 +523,27 @@ namespace sol { struct supports_op_less : std::false_type {}; template struct supports_op_equal : decltype(meta_detail::supports_op_equal_test(std::declval(), std::declval())) {}; + template + struct supports_op_equal : std::false_type {}; + template + struct supports_op_equal : std::false_type {}; template struct supports_op_less_equal : decltype(meta_detail::supports_op_less_equal_test(std::declval(), std::declval())) {}; + template + struct supports_op_less_equal : std::false_type {}; + template + struct supports_op_less_equal : std::false_type {}; template struct supports_ostream_op : decltype(meta_detail::supports_ostream_op(std::declval(), std::declval())) {}; template + struct supports_ostream_op : std::false_type {}; + template + struct supports_ostream_op : std::false_type {}; + template struct supports_adl_to_string : decltype(meta_detail::supports_adl_to_string(std::declval())) {}; - + template <> + struct supports_adl_to_string : std::false_type {}; + template using supports_to_string_member = meta::boolean::value>; diff --git a/include/sol/tuple.hpp b/include/sol/tuple.hpp index 3775176c..6f1e9f62 100644 --- a/include/sol/tuple.hpp +++ b/include/sol/tuple.hpp @@ -44,7 +44,7 @@ namespace sol { } // namespace detail template - using unqualified = std::remove_cv>; + struct unqualified : std::remove_cv> {}; template using unqualified_t = typename unqualified::type; diff --git a/single/include/sol/forward.hpp b/single/include/sol/forward.hpp index 5925ffc1..25ae8e9d 100644 --- a/single/include/sol/forward.hpp +++ b/single/include/sol/forward.hpp @@ -20,8 +20,8 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // This file was generated with a script. -// Generated 2019-01-17 06:28:58.332972 UTC -// This header was generated with sol v2.20.6 (revision 88a089c) +// Generated 2019-01-28 16:32:19.530572 UTC +// This header was generated with sol v2.20.6 (revision ad494bd) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP diff --git a/single/include/sol/sol.hpp b/single/include/sol/sol.hpp index b1e0f08d..15e77f2e 100644 --- a/single/include/sol/sol.hpp +++ b/single/include/sol/sol.hpp @@ -20,8 +20,8 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // This file was generated with a script. -// Generated 2019-01-17 06:28:58.073560 UTC -// This header was generated with sol v2.20.6 (revision 88a089c) +// Generated 2019-01-28 16:32:19.243332 UTC +// This header was generated with sol v2.20.6 (revision ad494bd) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -510,7 +510,7 @@ namespace sol { } // namespace detail template - using unqualified = std::remove_cv>; + struct unqualified : std::remove_cv> {}; template using unqualified_t = typename unqualified::type; @@ -1332,11 +1332,8 @@ namespace sol { template using boolean = std::integral_constant; - template - using invoke_t = typename T::type; - - template - using invoke_v = boolean; + template + constexpr inline bool boolean_v = boolean::value; template using neg = boolean; @@ -1710,29 +1707,35 @@ namespace sol { struct is_matched_lookup_impl : std::is_same {}; } // namespace meta_detail -#if defined(_MSC_VER) && _MSC_VER <= 1910 template - using supports_op_less = decltype(meta_detail::supports_op_less_test(std::ref(std::declval()), std::ref(std::declval()))); - template - using supports_op_equal = decltype(meta_detail::supports_op_equal_test(std::ref(std::declval()), std::ref(std::declval()))); - template - using supports_op_less_equal = decltype(meta_detail::supports_op_less_equal_test(std::ref(std::declval()), std::ref(std::declval()))); - template - using supports_ostream_op = decltype(meta_detail::supports_ostream_op(std::ref(std::declval()), std::ref(std::declval()))); + struct supports_op_less : decltype(meta_detail::supports_op_less_test(std::declval(), std::declval())) {}; template - using supports_adl_to_string = decltype(meta_detail::supports_adl_to_string(std::ref(std::declval()))); -#else - template - using supports_op_less = decltype(meta_detail::supports_op_less_test(std::declval(), std::declval())); - template - using supports_op_equal = decltype(meta_detail::supports_op_equal_test(std::declval(), std::declval())); - template - using supports_op_less_equal = decltype(meta_detail::supports_op_less_equal_test(std::declval(), std::declval())); - template - using supports_ostream_op = decltype(meta_detail::supports_ostream_op(std::declval(), std::declval())); + struct supports_op_less : std::false_type {}; template - using supports_adl_to_string = decltype(meta_detail::supports_adl_to_string(std::declval())); -#endif + struct supports_op_less : std::false_type {}; + template + struct supports_op_equal : decltype(meta_detail::supports_op_equal_test(std::declval(), std::declval())) {}; + template + struct supports_op_equal : std::false_type {}; + template + struct supports_op_equal : std::false_type {}; + template + struct supports_op_less_equal : decltype(meta_detail::supports_op_less_equal_test(std::declval(), std::declval())) {}; + template + struct supports_op_less_equal : std::false_type {}; + template + struct supports_op_less_equal : std::false_type {}; + template + struct supports_ostream_op : decltype(meta_detail::supports_ostream_op(std::declval(), std::declval())) {}; + template + struct supports_ostream_op : std::false_type {}; + template + struct supports_ostream_op : std::false_type {}; + template + struct supports_adl_to_string : decltype(meta_detail::supports_adl_to_string(std::declval())) {}; + template <> + struct supports_adl_to_string : std::false_type {}; + template using supports_to_string_member = meta::boolean::value>; @@ -15360,6 +15363,9 @@ namespace sol { template struct is_member_object> : std::true_type {}; + + template + inline constexpr bool is_member_object_v = is_member_object::value; } // namespace meta } // namespace sol @@ -16071,17 +16077,35 @@ namespace sol { } }; + template + struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { + template + static int call(lua_State* L, F&& f) { + return lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack>{}.call(L, f.func); + } + }; + template struct lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack, C> { template static int call(lua_State* L, F&& f) { - return lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack> {}.call(L, std::get<0>(f.arguments)); + return lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack>{}.call(L, std::get<0>(f.arguments)); } }; template inline int call_wrapped(lua_State* L, Fx&& fx, Args&&... args) { - return lua_call_wrapper, is_index, is_variable, checked, boost, clean_stack> {}.call(L, std::forward(fx), std::forward(args)...); + using uFx = meta::unqualified_t; + if constexpr(meta::is_specialization_of_v) { + using real_fx = meta::unqualified_t(fx).func)>; + int nr = lua_call_wrapper{}.call( + L, std::forward(fx).func, std::forward(args)...); + return lua_yield(L, nr); + } + else { + return lua_call_wrapper{}.call( + L, std::forward(fx), std::forward(args)...); + } } template @@ -16607,7 +16631,7 @@ namespace function_detail { namespace sol { namespace function_detail { - template + template struct overloaded_function { typedef std::tuple overload_list; typedef std::make_index_sequence indices; @@ -16624,7 +16648,8 @@ namespace function_detail { template static int call(types, meta::index_value, types, types, lua_State* L, int, int, overload_list& ol) { auto& func = std::get(ol); - return call_detail::call_wrapped(L, func); + int nr = call_detail::call_wrapped(L, func); + return nr; } int operator()(lua_State* L) { @@ -16789,157 +16814,197 @@ namespace sol { namespace sol { namespace function_detail { template - struct class_indicator {}; + struct class_indicator { + using type = T; + }; struct call_indicator {}; - } // namespace function_detail - namespace stack { - template - struct unqualified_pusher> { - template - static void select_convertible(std::false_type, types, lua_State* L, Fx&& fx, Args&&... args) { - typedef std::remove_pointer_t> clean_fx; - typedef function_detail::functor_function F; - set_fx(L, std::forward(fx), std::forward(args)...); + template + inline int lua_c_wrapper(lua_State* L) { + lua_CFunction cf = lua_tocfunction(L, lua_upvalueindex(2)); + int nr = cf(L); + if constexpr (yielding) { + return lua_yield(L, nr); } + else { + return nr; + } + } - template - static void select_convertible(std::true_type, types, lua_State* L, Fx&& fx, Args&&... args) { - using fx_ptr_t = R (*)(A...); + template + inline int lua_c_noexcept_wrapper(lua_State* L) noexcept { + detail::lua_CFunction_noexcept cf = reinterpret_cast(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 + inline void select(lua_State* L, Fx&& fx, Args&&... args); + + template + inline void select_set_fx(lua_State* L, Args&&... args) { + lua_CFunction freefunc = detail::static_trampoline, 2, is_yielding>>; + + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push>(L, std::forward(args)...); + stack::push(L, c_closure(freefunc, upvalues)); + } + + template + inline void select_convertible(types, lua_State* L, Fx&& fx, Args&&... args) { + using dFx = std::decay_t>; + using fx_ptr_t = R (*)(A...); + constexpr bool is_convertible = std::is_convertible_v; + if constexpr (is_convertible) { fx_ptr_t fxptr = detail::unwrap(std::forward(fx)); - select_function(std::true_type(), L, fxptr, std::forward(args)...); + select(L, std::move(fxptr), std::forward(args)...); } - - template - static void select_convertible(types t, lua_State* L, Fx&& fx, Args&&... args) { - typedef std::decay_t> raw_fx_t; - typedef R (*fx_ptr_t)(A...); - typedef std::is_convertible is_convertible; - select_convertible(is_convertible(), t, L, std::forward(fx), std::forward(args)...); + else { + using F = function_detail::functor_function; + select_set_fx(L, std::forward(fx), std::forward(args)...); } + } - template - static void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) { - typedef meta::function_signature_t> Sig; - select_convertible(types(), L, std::forward(fx), std::forward(args)...); - } + template + inline void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) { + typedef meta::function_signature_t> Sig; + select_convertible(types(), L, std::forward(fx), std::forward(args)...); + } - template - static void select_reference_member_variable(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { - typedef std::remove_pointer_t> clean_fx; - typedef function_detail::member_variable, clean_fx, is_yielding> F; - set_fx(L, std::forward(fx), std::forward(obj), std::forward(args)...); - } - - template - static void select_reference_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { - typedef std::decay_t dFx; - dFx memfxptr(std::forward(fx)); - auto userptr = detail::ptr(std::forward(obj), std::forward(args)...); - lua_CFunction freefunc = &function_detail::upvalue_member_variable, meta::unqualified_t, 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(userptr)); - stack::push(L, c_closure(freefunc, upvalues)); - } - - template - static void select_member_variable(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { - select_convertible(types(), L, std::forward(fx), std::forward(args)...); - } - - template , 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, std::reference_wrapper>::value || std::is_pointer::value> is_reference; - select_reference_member_variable(is_reference(), L, std::forward(fx), std::forward(obj), std::forward(args)...); - } - - template - static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator) { + template + inline void select_member_variable(lua_State* L, Fx&& fx, Args&&... args) { + using uFx = meta::unqualified_t; + if constexpr (sizeof...(Args) < 1) { + using C = typename meta::bind_traits::object_type; lua_CFunction freefunc = &function_detail::upvalue_this_member_variable::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::type; + constexpr bool is_reference = meta::is_specialization_of_v || std::is_pointer_v; + if constexpr (meta::is_specialization_of_v) { + lua_CFunction freefunc = &function_detail::upvalue_this_member_variable::call; - template - static void select_member_variable(std::true_type, lua_State* L, Fx&& fx) { - typedef typename meta::bind_traits>::object_type C; - lua_CFunction freefunc = &function_detail::upvalue_this_member_variable::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)); + 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 dFx; + dFx memfxptr(std::forward(fx)); + auto userptr = detail::ptr(std::forward(args)...); + lua_CFunction freefunc + = &function_detail::upvalue_member_variable, meta::unqualified_t, 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(userptr)); + stack::push(L, c_closure(freefunc, upvalues)); + } + else { + using clean_fx = std::remove_pointer_t>; + using F = function_detail::member_variable; + select_set_fx(L, std::forward(fx), std::forward(args)...); + } } - - template - static void select_reference_member_function(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { - typedef std::decay_t clean_fx; - typedef function_detail::member_function, clean_fx, is_yielding> F; - set_fx(L, std::forward(fx), std::forward(obj), std::forward(args)...); + else { + using C = typename meta::bind_traits::object_type; + using clean_fx = std::remove_pointer_t>; + using F = function_detail::member_variable; + select_set_fx(L, std::forward(fx), std::forward(args)...); } + } - template - static void select_reference_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) { - using dFx = std::decay_t; - dFx memfxptr(std::forward(fx)); - auto userptr = detail::ptr(std::forward(obj), std::forward(args)...); - lua_CFunction freefunc = &function_detail::upvalue_member_function, meta::unqualified_t, is_yielding>::call; - - int upvalues = 0; - upvalues += stack::push(L, nullptr); - upvalues += stack::push>(L, memfxptr); - upvalues += stack::push(L, lightuserdata_value(static_cast(userptr))); - stack::push(L, c_closure(freefunc, upvalues)); - } - - template - static void select_member_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { - select_member_variable(meta::is_member_object>(), L, std::forward(fx), std::forward(args)...); - } - - template , 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, std::reference_wrapper>::value || std::is_pointer::value> is_reference; - select_reference_member_function(is_reference(), L, std::forward(fx), std::forward(obj), std::forward(args)...); - } - - template - static void select_member_function(std::true_type, lua_State* L, Fx&& fx, function_detail::class_indicator) { - using dFx = std::decay_t; + template + inline void select_member_function_with(lua_State* L, Fx&& fx, T&& obj, Args&&... args) { + using dFx = std::decay_t; + using Tu = meta::unqualified_t; + if constexpr (meta::is_specialization_of_v) { + using C = typename Tu::type; lua_CFunction freefunc = &function_detail::upvalue_this_member_function::call; - + int upvalues = 0; upvalues += stack::push(L, nullptr); - upvalues += stack::push>(L, fx); + upvalues += stack::push>(L, std::forward(fx), std::forward(args)...); stack::push(L, c_closure(freefunc, upvalues)); } + else { + constexpr bool is_reference = meta::is_specialization_of_v || std::is_pointer_v; + if constexpr (is_reference) { + auto userptr = detail::ptr(std::forward(obj)); + lua_CFunction freefunc = &function_detail::upvalue_member_function, dFx, is_yielding>::call; - template - static void select_member_function(std::true_type, lua_State* L, Fx&& fx) { - using dFx = std::decay_t; - typedef typename meta::bind_traits>::object_type C; + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push>(L, std::forward(fx), std::forward(args)...); + upvalues += stack::push(L, lightuserdata_value(static_cast(userptr))); + stack::push(L, c_closure(freefunc, upvalues)); + } + else { + using F = function_detail::member_function; + select_set_fx(L, std::forward(fx), std::forward(args)...); + } + } + } + + template + inline void select_member_function(lua_State* L, Fx&& fx, Args&&... args) { + using dFx = std::decay_t; + if constexpr (sizeof...(Args) < 1) { + using C = typename meta::bind_traits>::object_type; lua_CFunction freefunc = &function_detail::upvalue_this_member_function::call; - + int upvalues = 0; upvalues += stack::push(L, nullptr); - upvalues += stack::push>(L, fx); + upvalues += stack::push>(L, std::forward(fx)); stack::push(L, c_closure(freefunc, upvalues)); } - - template - static void select_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) { - select_member_function(std::is_member_function_pointer>(), L, std::forward(fx), std::forward(args)...); + else { + select_member_function_with(L, std::forward(fx), std::forward(args)...); } + } - template - static void select_function(std::true_type, lua_State* L, Fx&& fx, Args&&... args) { + template + inline void select(lua_State* L, Fx&& fx, Args&&... args) { + using uFx = meta::unqualified_t; + if constexpr (is_lua_reference_v) { + // TODO: hoist into lambda in this case for yielding??? + stack::push(L, std::forward(fx), std::forward(args)...); + } + else if constexpr (is_lua_c_function_v) { + int upvalues = 0; + upvalues += stack::push(L, nullptr); + upvalues += stack::push(L, std::forward(fx)); +#if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE + if constexpr (std::is_nothrow_invocable_r_v) { + detail::lua_CFunction_noexcept cf = &lua_c_noexcept_wrapper; + lua_pushcclosure(L, reinterpret_cast(cf), 2); + } + else { + lua_CFunction cf = &lua_c_wrapper; + lua_pushcclosure(L, cf, 2); + } +#else + lua_CFunction cf = &function_detail::lua_c_wrapper; + lua_pushcclosure(L, cf, 2); +#endif + } + else if constexpr (std::is_function_v>) { std::decay_t target(std::forward(fx), std::forward(args)...); lua_CFunction freefunc = &function_detail::upvalue_free_function::call; @@ -16948,53 +17013,29 @@ namespace sol { upvalues += stack::stack_detail::push_as_upvalues(L, target); stack::push(L, c_closure(freefunc, upvalues)); } - - template - static void select_function(std::true_type, lua_State* L, lua_CFunction f) { - // TODO: support yielding - stack::push(L, f); + else if constexpr (std::is_member_function_pointer_v) { + select_member_function(L, std::forward(fx), std::forward(args)...); } - -#if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE - template - static void select_function(std::true_type, lua_State* L, detail::lua_CFunction_noexcept f) { - // TODO: support yielding - stack::push(L, f); + else if constexpr (meta::is_member_object_v) { + select_member_variable(L, std::forward(fx), std::forward(args)...); } -#endif // noexcept function type - - template >> = meta::enabler> - static void select(lua_State* L, Fx&& fx, Args&&... args) { - select_function(std::is_function>>(), L, std::forward(fx), std::forward(args)...); + else { + select_convertible(types<>(), L, std::forward(fx), std::forward(args)...); } + } + } // namespace function_detail - template >> = meta::enabler> - static void select(lua_State* L, Fx&& fx) { - // TODO: hoist into lambda in this case?? - stack::push(L, std::forward(fx)); - } - - template - static void set_fx(lua_State* L, Args&&... args) { - lua_CFunction freefunc = detail::static_trampoline, 2, is_yielding>>; - - int upvalues = 0; - upvalues += stack::push(L, nullptr); - upvalues += stack::push>(L, std::forward(args)...); - stack::push(L, c_closure(freefunc, upvalues)); - } - - template >> = meta::enabler> + namespace stack { + template + struct unqualified_pusher> { + template static int push(lua_State* L, Arg0&& arg0, Args&&... args) { - // Set will always place one thing (function) on the stack - select(L, std::forward(arg0), std::forward(args)...); - return 1; - } - - template - static int push(lua_State* L, detail::yield_tag_t, Args&&... args) { - // Set will always place one thing (function) on the stack - select(L, std::forward(args)...); + if constexpr (std::is_same_v, detail::yield_tag_t>) { + function_detail::select(L, std::forward(args)...); + } + else { + function_detail::select(L, std::forward(arg0), std::forward(args)...); + } return 1; } }; @@ -17003,16 +17044,14 @@ namespace sol { struct unqualified_pusher> { template static int push(lua_State* L, const yielding_t& f, Args&&... args) { - unqualified_pusher> p{}; - (void)p; - return p.push(L, detail::yield_tag, f.func, std::forward(args)...); + function_detail::select(L, f.func, std::forward(args)...); + return 1; } template static int push(lua_State* L, yielding_t&& f, Args&&... args) { - unqualified_pusher> p{}; - (void)p; - return p.push(L, detail::yield_tag, f.func, std::forward(args)...); + function_detail::select(L, std::move(f.func), std::forward(args)...); + return 1; } }; @@ -17035,50 +17074,53 @@ namespace sol { template struct unqualified_pusher> { static int push(lua_State* L, const std::function& fx) { - return unqualified_pusher>{}.push(L, fx); + function_detail::select(L, fx); + return 1; } static int push(lua_State* L, std::function&& fx) { - return unqualified_pusher>{}.push(L, std::move(fx)); + function_detail::select(L, std::move(fx)); + return 1; } }; template struct unqualified_pusher::value>> { - template - static int push(lua_State* L, F&& f, Args&&... args) { - unqualified_pusher> p{}; - (void)p; - return p.push(L, std::forward(f), std::forward(args)...); + template + static int push(lua_State* L, Args&&... args) { + function_detail::select(L, std::forward(args)...); + return 1; } }; template - struct unqualified_pusher>, meta::neg>, meta::neg>> + struct unqualified_pusher>, meta::neg>, + meta::neg>> #if defined(SOL_NOEXCEPT_FUNCTION_TYPE) && SOL_NOEXCEPT_FUNCTION_TYPE - , - meta::neg>, meta::neg>> + , + meta::neg>, + meta::neg>> #endif // noexcept function types - >::value>> { + >::value>> { template static int push(lua_State* L, F&& f) { - return unqualified_pusher>{}.push(L, std::forward(f)); + function_detail::select(L, std::forward(f)); + return 1; } }; template struct unqualified_pusher> { static int push(lua_State* L, overload_set&& set) { - // TODO: yielding - typedef function_detail::overloaded_function<0, Functions...> F; - unqualified_pusher>{}.set_fx(L, std::move(set.functions)); + using F = function_detail::overloaded_function<0, Functions...>; + function_detail::select_set_fx(L, std::move(set.functions)); return 1; } static int push(lua_State* L, const overload_set& set) { - // TODO: yielding - typedef function_detail::overloaded_function<0, Functions...> F; - unqualified_pusher>{}.set_fx(L, set.functions); + using F = function_detail::overloaded_function<0, Functions...>; + function_detail::select_set_fx(L, set.functions); return 1; } }; @@ -17103,32 +17145,29 @@ namespace sol { }; template - struct unqualified_pusher, std::enable_if_t::value && !std::is_void::value>> { + struct unqualified_pusher> { static int push(lua_State* L, property_wrapper&& pw) { - return stack::push(L, overload(std::move(pw.read), std::move(pw.write))); + if constexpr (std::is_void_v) { + return stack::push(L, std::move(pw.write)); + } + else if constexpr (std::is_void_v) { + 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& pw) { - return stack::push(L, overload(pw.read, pw.write)); - } - }; - - template - struct unqualified_pusher> { - static int push(lua_State* L, property_wrapper&& pw) { - return stack::push(L, std::move(pw.read)); - } - static int push(lua_State* L, const property_wrapper& pw) { - return stack::push(L, pw.read); - } - }; - - template - struct unqualified_pusher> { - static int push(lua_State* L, property_wrapper&& pw) { - return stack::push(L, std::move(pw.write)); - } - static int push(lua_State* L, const property_wrapper& pw) { - return stack::push(L, pw.write); + if constexpr (std::is_void_v) { + return stack::push(L, pw.write); + } + else if constexpr (std::is_void_v) { + return stack::push(L, pw.read); + } + else { + return stack::push(L, overload(pw.read, pw.write)); + } } }; @@ -17145,26 +17184,26 @@ namespace sol { template struct unqualified_pusher> { static int push(lua_State* L, const factory_wrapper& fw) { - typedef function_detail::overloaded_function<0, Functions...> F; - unqualified_pusher>{}.set_fx(L, fw.functions); + using F = function_detail::overloaded_function<0, Functions...>; + function_detail::select_set_fx(L, fw.functions); return 1; } static int push(lua_State* L, factory_wrapper&& fw) { - typedef function_detail::overloaded_function<0, Functions...> F; - unqualified_pusher>{}.set_fx(L, std::move(fw.functions)); + using F = function_detail::overloaded_function<0, Functions...>; + function_detail::select_set_fx(L, std::move(fw.functions)); return 1; } - static int push(lua_State* L, const factory_wrapper& set, function_detail::call_indicator) { - typedef function_detail::overloaded_function<1, Functions...> F; - unqualified_pusher>{}.set_fx(L, set.functions); + static int push(lua_State* L, const factory_wrapper& fw, function_detail::call_indicator) { + using F = function_detail::overloaded_function<1, Functions...>; + function_detail::select_set_fx(L, fw.functions); return 1; } - static int push(lua_State* L, factory_wrapper&& set, function_detail::call_indicator) { - typedef function_detail::overloaded_function<1, Functions...> F; - unqualified_pusher>{}.set_fx(L, std::move(set.functions)); + static int push(lua_State* L, factory_wrapper&& fw, function_detail::call_indicator) { + using F = function_detail::overloaded_function<1, Functions...>; + function_detail::select_set_fx(L, std::move(fw.functions)); return 1; } }; diff --git a/tests/runtime_tests/source/coroutines.cpp b/tests/runtime_tests/source/coroutines.cpp index 758bc32c..b010dc8d 100644 --- a/tests/runtime_tests/source/coroutines.cpp +++ b/tests/runtime_tests/source/coroutines.cpp @@ -25,9 +25,70 @@ #include +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") { const auto& script = R"(counter = 20 - function loop() while counter ~= 30 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") { const auto& code = R"(counter = 20 - function loop() while counter ~= 30 do @@ -145,10 +205,10 @@ TEST_CASE("coroutines/explicit transfer", "check that the xmove constructors shi -- co - L2 -- co2 - L3 -x = co_test.new("x") +x = coro_test.new("x") local co = coroutine.wrap( function() - local t = co_test.new("t") + local t = coro_test.new("t") local co2 = coroutine.wrap( function() local t2 = { "SOME_TABLE" } @@ -171,45 +231,19 @@ collectgarbage() 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; lua.open_libraries(sol::lib::coroutine, sol::lib::base); - lua.new_usertype("co_test", - sol::constructors(), - "store", &co_test::store, - "copy_store", &co_test::copy_store, - "get", &co_test::get); + lua.new_usertype("coro_test", + sol::constructors(), + "store", &coro_test::store, + "copy_store", &coro_test::copy_store, + "get", &coro_test::get); auto r = lua.safe_script(code, sol::script_pass_on_error); REQUIRE(r.valid()); - co_test& ct = lua["x"]; + coro_test& ct = lua["x"]; lua_State* Lmain1 = lua.lua_state(); 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 -- co2 - L3 -x = co_test.new("x") +x = coro_test.new("x") local co = coroutine.wrap( function() - local t = co_test.new("t") + local t = coro_test.new("t") local co2 = coroutine.wrap( function() local t2 = { "SOME_TABLE" } @@ -255,11 +289,11 @@ collectgarbage() co = nil )"; - struct co_test_implicit { + struct coro_test_implicit { std::string identifier; 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) { } @@ -277,23 +311,23 @@ co = nil return obj; } - ~co_test_implicit() { + ~coro_test_implicit() { } }; sol::state lua; lua.open_libraries(sol::lib::coroutine, sol::lib::base); - lua.new_usertype("co_test", - sol::constructors(), - "store", &co_test_implicit::store, - "copy_store", &co_test_implicit::copy_store, - "get", &co_test_implicit::get); + lua.new_usertype("coro_test", + sol::constructors(), + "store", &coro_test_implicit::store, + "copy_store", &coro_test_implicit::copy_store, + "get", &coro_test_implicit::get); auto r = lua.safe_script(code, sol::script_pass_on_error); REQUIRE(r.valid()); - co_test_implicit& ct = lua["x"]; + coro_test_implicit& ct = lua["x"]; lua_State* Lmain1 = lua.lua_state(); 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 -- co2 - L3 -x = co_test.new("x") +x = coro_test.new("x") local co = coroutine.wrap( function() - local t = co_test.new("t") + local t = coro_test.new("t") local co2 = coroutine.wrap( function() local t2 = { "SOME_TABLE" } @@ -338,49 +372,19 @@ co = nil 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; lua.open_libraries(sol::lib::coroutine, sol::lib::base); - lua.new_usertype("co_test", - sol::constructors(), - "store", &co_test_implicit::store, - "copy_store", &co_test_implicit::copy_store, - "get", &co_test_implicit::get); + lua.new_usertype("coro_test", + sol::constructors(), + "store", &coro_test_implicit::store, + "copy_store", &coro_test_implicit::copy_store, + "get", &coro_test_implicit::get); auto r = lua.safe_script(code, sol::script_pass_on_error); REQUIRE(r.valid()); - co_test_implicit& ct = lua["x"]; + coro_test_implicit& ct = lua["x"]; lua_State* Lmain1 = lua.lua_state(); lua_State* Lmain2 = sol::main_thread(lua); @@ -532,53 +536,95 @@ end } TEST_CASE("coroutines/yielding", "test that a sol2 bound function can yield when marked yieldable") { - sol::state lua; - lua.open_libraries(sol::lib::base, sol::lib::coroutine); + SECTION("regular functions") { + sol::state lua; + lua.open_libraries(sol::lib::base, sol::lib::coroutine); - int i = 0; - auto func = [&i]() { - ++i; - return i; - }; + int i = 0; + auto func = [&i]() { + ++i; + return i; + }; - struct h { - int x = 500; - int func() const { - return x; - } - } hobj{}; + coro_h hobj{}; - lua["f"] = sol::yielding(func); - lua["g"] = sol::yielding([]() { return 300; }); - lua["h"] = sol::yielding(&h::func); - lua["hobj"] = &hobj; + lua["f"] = sol::yielding(func); + lua["g"] = sol::yielding([]() { return 300; }); + lua["h"] = sol::yielding(&coro_h::func); + lua["hobj"] = &hobj; - sol::string_view code = R"( - co1 = coroutine.create(function () return f() end) - success1, value1 = coroutine.resume(co1) - co2 = coroutine.create(function () return g() end) - success2, value2 = coroutine.resume(co2) - co3 = coroutine.create(function() - h(hobj) - end) - success3, value3 = coroutine.resume(co3) - )"; + sol::string_view code = R"( + co1 = coroutine.create(function () return f() end) + success1, value1 = coroutine.resume(co1) + co2 = coroutine.create(function () return g() end) + success2, value2 = coroutine.resume(co2) + co3 = coroutine.create(function() + h(hobj) + end) + success3, value3 = coroutine.resume(co3) + )"; - auto result = lua.safe_script(code); - REQUIRE(result.valid()); + auto result = lua.safe_script(code, sol::script_pass_on_error); + REQUIRE(result.valid()); - bool success1 = lua["success1"]; - int value1 = lua["value1"]; - REQUIRE(success1); - REQUIRE(value1 == 1); + bool success1 = lua["success1"]; + int value1 = lua["value1"]; + REQUIRE(success1); + REQUIRE(value1 == 1); - bool success2 = lua["success2"]; - int value2 = lua["value2"]; - REQUIRE(success2); - REQUIRE(value2 == 300); + bool success2 = lua["success2"]; + int value2 = lua["value2"]; + REQUIRE(success2); + REQUIRE(value2 == 300); - bool success3 = lua["success3"]; - int value3 = lua["value3"]; - REQUIRE(success3); - REQUIRE(value3 == 500); + bool success3 = lua["success3"]; + int value3 = lua["value3"]; + REQUIRE(success3); + 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", + "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); + } }