diff --git a/sol/function.hpp b/sol/function.hpp index aac52037..91da5d18 100644 --- a/sol/function.hpp +++ b/sol/function.hpp @@ -35,7 +35,7 @@ private: template std::tuple invoke(types, std::size_t n) { - luacall(n, sizeof...(Ret)); + luacall(n, sizeof...(Ret)); return stack::pop_reverse_call(state(), std::make_tuple, types()); } diff --git a/sol/lua_function.hpp b/sol/lua_function.hpp index 6a120d62..ba3df646 100644 --- a/sol/lua_function.hpp +++ b/sol/lua_function.hpp @@ -69,16 +69,17 @@ struct static_lua_func { return 0; } - template - static int typed_call(types, types t, fx_t* fx, lua_State* L) { - auto r = stack::pop_call(L, fx, t); - stack::push_reverse(L, std::move(r)); - return sizeof...(Ret); - } - template static int typed_call(types<>, types t, fx_t* fx, lua_State* L) { - return typed_call(types(), t, fx, 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...(Ret); } static int call(lua_State* L) { @@ -99,7 +100,6 @@ struct static_object_lua_func { typedef typename std::decay::type fx_t; typedef function_traits fx_traits; - template static int typed_call(types, types, T& item, fx_t& ifx, lua_State* L) { auto fx = [&item, &ifx](Args&&... args) { (item.*ifx)(std::forward(args)...); }; @@ -107,29 +107,20 @@ 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) -> Ret { - 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()); - stack::push_reverse(L, std::move(r)); + 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...(Ret); } - template - static int typed_call(types<>, types, T& item, fx_t& ifx, lua_State* L) { - return typed_call(types(), item, ifx, L); - } - static int call(lua_State* L) { const static std::size_t data_t_count = (sizeof(fx_t)+(sizeof(void*)-1)) / sizeof(void*); typedef std::array data_t; @@ -193,22 +184,22 @@ struct lambda_lua_func : public lua_func { 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) { stack::pop_call(L, fx, t); return 0; } + template + int operator()(types<>, types t, lua_State* L) { + return (*this)(types(), t, L); + } + template int operator()(types, types t, lua_State* L) { - auto r = stack::pop_call(L, fx, t); - stack::push_reverse(L, r); + typedef typename multi_return::type return_type; + return_type r = stack::pop_call(L, fx, t); + stack::push(L, r); return sizeof...(Ret); } }; @@ -222,21 +213,22 @@ struct explicit_lua_func : public lua_func { template explicit_lua_func(FxArgs&&... fxargs): fx(std::forward(fxargs)...) {} - template - int operator()(types<>, types t, lua_State* L) { - return (*this)(types(), t, 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) { + return (*this)(types(), t, L); + } + template int operator()(types, types t, lua_State* L) { - auto r = stack::pop_call(L, fx, t); - stack::push_reverse(L, std::move(r)); + 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); } @@ -278,8 +270,9 @@ struct explicit_lua_func : public lua_func { template int operator()(types, types t, lua_State* L) { - auto r = stack::pop_call(L, fx, t); - stack::push_reverse(L, std::move(r)); + 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); } diff --git a/sol/stack.hpp b/sol/stack.hpp index 5866d6f5..06381641 100644 --- a/sol/stack.hpp +++ b/sol/stack.hpp @@ -227,7 +227,7 @@ auto rtl_pop(lua_State*, F&& f, types, types<>, Vs&&... vs) -> decltype } 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)...); + return rtl_pop(L, std::forward(f), t, types(), pop(L), std::forward(vs)...); } } // detail 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..09421897 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,45 @@ public: return result; } + template + typename std::tuple_element>::type element_get(types, Tup&& key) const { + typedef typename std::tuple_element>::type T; + typedef typename std::tuple_element::type U; + 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/tests.cpp b/tests.cpp index d9749f9b..940b95fd 100644 --- a/tests.cpp +++ b/tests.cpp @@ -224,15 +224,18 @@ TEST_CASE("functions/return _order", "Check if return order is in the same readi 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 ); + return std::make_tuple( 10, 11, 12 ); } ); - lua.script( "function g() return 10, 11, 12 end" ); - auto tcpp = lua.get( "f" ).call( ); - auto tlua = lua.get( "g" ).call( ); - std::cout << std::get<0>( tcpp ) << ',' << std::get<1>( tcpp ) << ',' << std::get<2>( tcpp ) << std::endl; - std::cout << std::get<0>( tlua ) << ',' << std::get<1>( tlua ) << ',' << std::get<2>( tlua ) << std::endl; - REQUIRE( tcpp == triple ); - REQUIRE( tlua == triple ); + 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") {