diff --git a/sol/function.hpp b/sol/function.hpp index 1f60a257..91da5d18 100644 --- a/sol/function.hpp +++ b/sol/function.hpp @@ -35,8 +35,8 @@ private: template std::tuple invoke(types, std::size_t n) { - luacall(n, sizeof...(Ret)); - return stack::pop_call(state(), std::make_tuple, types()); + luacall(n, sizeof...(Ret)); + return stack::pop_reverse_call(state(), std::make_tuple, types()); } template diff --git a/sol/lua_function.hpp b/sol/lua_function.hpp index 89c56614..ba3df646 100644 --- a/sol/lua_function.hpp +++ b/sol/lua_function.hpp @@ -62,18 +62,24 @@ template struct static_lua_func { typedef typename std::remove_pointer::type>::type fx_t; typedef function_traits fx_traits; - + template static int typed_call(types, types t, fx_t* fx, lua_State* L) { stack::pop_call(L, fx, t); return 0; } - template - static int typed_call(types, types t, fx_t* fx, lua_State* L) { - auto r = stack::pop_call(L, fx, t); + template + static int typed_call(types<>, types t, fx_t* fx, lua_State* L) { + return typed_call(types(), t, fx, L); + } + + template + static int typed_call(types, types t, fx_t* fx, lua_State* L) { + typedef typename multi_return::type return_type; + return_type r = stack::pop_call(L, fx, t); stack::push(L, std::move(r)); - return sizeof...(TRn); + return sizeof...(Ret); } static int call(lua_State* L) { @@ -101,22 +107,18 @@ struct static_object_lua_func { return 0; } - template - static int typed_call(types, types, T& item, fx_t& ifx, lua_State* L) { - auto fx = [&item, &ifx](Args&&... args) -> TR { - return (item.*ifx)(std::forward(args)...); - }; - auto r = stack::pop_call(L, fx, types()); - stack::push(L, std::move(r)); - return 1; + template + static int typed_call(types<>, types t, T& item, fx_t& ifx, lua_State* L) { + return typed_call(types(), t, item, ifx, L); } - template - static int typed_call(types, types, T& item, fx_t& ifx, lua_State* L) { - auto fx = [&item, &ifx](Args&&... args) -> std::tuple { return (item.*ifx)(std::forward(args)...); }; - auto r = stack::pop_call(L, fx, types()); + template + static int typed_call(types, types, T& item, fx_t& ifx, lua_State* L) { + typedef typename multi_return::type return_type; + auto fx = [&item, &ifx](Args&&... args) -> return_type { return (item.*ifx)(std::forward(args)...); }; + return_type r = stack::pop_call(L, fx, types()); stack::push(L, std::move(r)); - return sizeof...(TRn); + return sizeof...(Ret); } static int call(lua_State* L) { @@ -188,11 +190,17 @@ struct lambda_lua_func : public lua_func { return 0; } - template - int operator()(types, types t, lua_State* L) { - auto r = stack::pop_call(L, fx, t); + template + int operator()(types<>, types t, lua_State* L) { + return (*this)(types(), t, L); + } + + template + int operator()(types, types t, lua_State* L) { + typedef typename multi_return::type return_type; + return_type r = stack::pop_call(L, fx, t); stack::push(L, r); - return sizeof...(TRn); + return sizeof...(Ret); } }; @@ -205,21 +213,27 @@ struct explicit_lua_func : public lua_func { template explicit_lua_func(FxArgs&&... fxargs): fx(std::forward(fxargs)...) {} - virtual int operator()(lua_State* L) override { - return (*this)(tuple_types(), typename fx_traits::args_type(), L); - } - template int operator()(types, types t, lua_State* L) { stack::pop_call(L, fx, t); return 0; } - template - int operator()(types, types t, lua_State* L) { - auto r = stack::pop_call(L, fx, t); + template + int operator()(types<>, types t, lua_State* L) { + return (*this)(types(), t, L); + } + + template + int operator()(types, types t, lua_State* L) { + typedef typename multi_return::type return_type; + return_type r = stack::pop_call(L, fx, t); stack::push(L, std::move(r)); - return sizeof...(TRn); + return sizeof...(Ret); + } + + virtual int operator()(lua_State* L) override { + return (*this)(tuple_types(), typename fx_traits::args_type(), L); } }; @@ -243,21 +257,27 @@ struct explicit_lua_func : public lua_func { template explicit_lua_func(T m, FxArgs&&... fxargs): fx(std::move(m), std::forward(fxargs)...) {} - virtual int operator()(lua_State* L) override { - return (*this)(tuple_types(), typename fx_traits::args_type(), L); - } - template int operator()(types, types t, lua_State* L) { stack::pop_call(L, fx, t); return 0; } - template - int operator()(types, types t, lua_State* L) { - auto r = stack::pop_call(L, fx, t); - stack::push(L, r); - return sizeof...(TRn); + template + int operator()(types<>, types t, lua_State* L) { + return (*this)(types(), t, L); + } + + template + int operator()(types, types t, lua_State* L) { + typedef typename multi_return::type return_type; + return_type r = stack::pop_call(L, fx, t); + stack::push(L, std::move(r)); + return sizeof...(Ret); + } + + virtual int operator()(lua_State* L) override { + return (*this)(tuple_types(), typename fx_traits::args_type(), L); } }; diff --git a/sol/stack.hpp b/sol/stack.hpp index 782bd98d..6bb1608f 100644 --- a/sol/stack.hpp +++ b/sol/stack.hpp @@ -212,33 +212,58 @@ inline void push_tuple(lua_State* L, indices, T&& tuplen) { swallow {'\0', (sol::stack::push(L, std::get(tuplen)), '\0')... }; } -template -auto ltr_pop(lua_State*, F&& f, types<>, Vs&&... vs) -> decltype(f(std::forward(vs)...)) { +template +auto ltr_pop(lua_State*, F&& f, types, types<>, Vs&&... vs) -> decltype(f(std::forward(vs)...)) { return f(std::forward(vs)...); } -template -auto ltr_pop(lua_State* L, F&& f, types, Vs&&... vs) -> decltype(ltr_pop(L, std::forward(f), types<>(), std::forward(vs)..., pop(L))) { - return ltr_pop(L, std::forward(f), types<>(), std::forward(vs)..., pop(L)); +template +auto ltr_pop(lua_State* L, F&& f, types t, types, Vs&&... vs) -> decltype(f(std::declval()...)) { + return ltr_pop(L, std::forward(f), t, types(), std::forward(vs)..., pop(L)); } -template -auto ltr_pop(lua_State* L, F&& f, types, Vs&&... vs) -> decltype(f(std::forward(vs)..., std::declval(), std::declval()...)) { - return ltr_pop(L, std::forward(f), types(), std::forward(vs)..., pop(L)); + +template +auto rtl_pop(lua_State*, F&& f, types, types<>, Vs&&... vs) -> decltype(f(std::forward(vs)...)) { + return f(std::forward(vs)...); +} +template +auto rtl_pop(lua_State* L, F&& f, types t, types, Vs&&... vs) -> decltype(f(std::declval()...)) { + return rtl_pop(L, std::forward(f), t, types(), pop(L), std::forward(vs)...); } } // detail template inline void push(lua_State* L, const std::tuple& tuplen) { - detail::push_tuple(L, build_reverse_indices(), tuplen); + detail::push_tuple(L, build_indices(), tuplen); } template inline void push(lua_State* L, std::tuple&& tuplen) { + detail::push_tuple(L, build_indices(), std::move(tuplen)); +} + +template +inline void push_reverse(lua_State* L, T&& item) { + push(L, std::forward(item)); +} + +template +inline void push_reverse(lua_State* L, const std::tuple& tuplen) { + detail::push_tuple(L, build_reverse_indices(), tuplen); +} + +template +inline void push_reverse(lua_State* L, std::tuple&& tuplen) { detail::push_tuple(L, build_reverse_indices(), std::move(tuplen)); } template -inline auto pop_call(lua_State* L, TFx&& fx, types) -> decltype(detail::ltr_pop(L, std::forward(fx), types())) { - return detail::ltr_pop(L, std::forward(fx), types()); +inline auto pop_call(lua_State* L, TFx&& fx, types t) -> decltype(detail::ltr_pop(L, std::forward(fx), t, t)) { + return detail::ltr_pop(L, std::forward(fx), t, t); +} + +template +inline auto pop_reverse_call(lua_State* L, TFx&& fx, types t) -> decltype(detail::rtl_pop(L, std::forward(fx), t, reversed())) { + return detail::rtl_pop(L, std::forward(fx), t, reversed()); } void push_args(lua_State*) { diff --git a/sol/state.hpp b/sol/state.hpp index 9cac52e4..aebb136b 100644 --- a/sol/state.hpp +++ b/sol/state.hpp @@ -127,9 +127,9 @@ public: } } - template - T get(U&& key) const { - return global.get(std::forward(key)); + template + typename multi_return::type get(Keys&&... keys) const { + return global.get(types(), std::forward(keys)...); } template diff --git a/sol/table.hpp b/sol/table.hpp index b5c44a79..5ab57618 100644 --- a/sol/table.hpp +++ b/sol/table.hpp @@ -41,15 +41,11 @@ T* get_ptr(T* val) { } // detail class table : public reference { + friend class state; template struct proxy; -public: - table() noexcept : reference() {} - table(lua_State* L, int index = -1) : reference(L, index) { - type_assert(L, index, type::table); - } template - T get(U&& key) const { + T single_get(U&& key) const { push(); stack::push(state(), std::forward(key)); lua_gettable(state(), -2); @@ -59,6 +55,44 @@ public: return result; } + template + typename std::tuple_element>::type element_get(types, Tup&& key) const { + typedef typename std::tuple_element>::type T; + push(); + stack::push(state(), std::get(key)); + lua_gettable(state(), -2); + type_assert(state(), -1, type_of()); + T result = stack::pop(state()); + lua_pop(state(), 1); + return result; + } + + template + typename multi_return::type tuple_get(types t, indices, Tup&& tup) const { + return std::make_tuple(element_get(t, std::forward(tup))...); + } + + template + Ret tuple_get(types t, indices<0>, Tup&& tup) const { + return element_get<0>(t, std::forward(tup)); + } + + template + typename multi_return::type get(types t, Keys&&... keys) const { + static_assert(sizeof...(Keys) == sizeof...(Ret), "Must have same number of keys as return values"); + return tuple_get(t, t, std::make_tuple(std::forward(keys)...)); + } +public: + table() noexcept : reference() {} + table(lua_State* L, int index = -1) : reference(L, index) { + type_assert(L, index, type::table); + } + + template + typename multi_return::type get(Keys&&... keys) const { + return get(types(), std::forward(keys)...); + } + template table& set(T&& key, U&& value) { push(); diff --git a/sol/tuple.hpp b/sol/tuple.hpp index 31285b04..cecaa3e8 100644 --- a/sol/tuple.hpp +++ b/sol/tuple.hpp @@ -57,7 +57,16 @@ template struct build_reverse_indices<0, Ns...> : indices {}; template -struct types : build_indices {}; +struct types : build_indices { typedef types type; }; + +template +struct reversed_ : Acc{}; + +template +struct reversed_, Arg, Args...> : reversed_, Args...>{}; + +template +struct reversed : reversed_, Args...>{}; template struct tuple_types : types, std::false_type {}; diff --git a/tests.cpp b/tests.cpp index 5b020278..c986f73c 100644 --- a/tests.cpp +++ b/tests.cpp @@ -220,6 +220,24 @@ TEST_CASE("tables/functions_variables", "Check if tables and function calls work REQUIRE_NOTHROW(run_script(lua)); } +TEST_CASE("functions/return_order_and_multi_get", "Check if return order is in the same reading order specified in Lua" ) { + const static std::tuple triple = std::make_tuple(10, 11, 12); + sol::state lua; + lua.set_function( "f", [ ] { + return std::make_tuple( 10, 11, 12 ); + } ); + lua.script("function g() return 10, 11, 12 end\nx,y,z = g()"); + auto tcpp = lua.get("f").call(); + auto tlua = lua.get("g").call(); + auto tluaget = lua.get("x", "y", "z"); + std::cout << "cpp: " << std::get<0>(tcpp) << ',' << std::get<1>(tcpp) << ',' << std::get<2>(tcpp) << std::endl; + std::cout << "lua: " << std::get<0>(tlua) << ',' << std::get<1>(tlua) << ',' << std::get<2>(tlua) << std::endl; + std::cout << "lua.xyz: " << lua.get("x") << ',' << lua.get("y") << ',' << lua.get("z") << std::endl; + REQUIRE(tcpp == triple); + REQUIRE(tlua == triple); + REQUIRE(tluaget == triple); +} + TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works properly") { sol::state lua; lua.open_libraries(sol::lib::base);