Fixed a bug with the return order and added tests to make sure it works.

Added the ability to get mutiple values when doing `table.get` or `state.get`.
Lua is hard. :c
This commit is contained in:
ThePhD 2013-12-15 22:09:06 -05:00
parent e0bcf5a11e
commit f8cfb80a45
6 changed files with 92 additions and 61 deletions

View File

@ -69,18 +69,19 @@ struct static_lua_func {
return 0;
}
template<typename... Ret, typename... Args>
static int typed_call(types<Ret...>, types<Args...> 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<typename... Args>
static int typed_call(types<>, types<Args...> t, fx_t* fx, lua_State* L) {
return typed_call(types<void>(), t, fx, L);
}
template<typename... Ret, typename... Args>
static int typed_call(types<Ret...>, types<Args...> t, fx_t* fx, lua_State* L) {
typedef typename multi_return<Ret...>::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) {
int upvalue = 1;
fx_t* fx;
@ -99,7 +100,6 @@ struct static_object_lua_func {
typedef typename std::decay<TFx>::type fx_t;
typedef function_traits<fx_t> fx_traits;
template<typename... Args>
static int typed_call(types<void>, types<Args...>, T& item, fx_t& ifx, lua_State* L) {
auto fx = [&item, &ifx](Args&&... args) { (item.*ifx)(std::forward<Args>(args)...); };
@ -107,29 +107,20 @@ struct static_object_lua_func {
return 0;
}
template<typename Ret, typename... Args>
static int typed_call(types<Ret>, types<Args...>, T& item, fx_t& ifx, lua_State* L) {
auto fx = [&item, &ifx](Args&&... args) -> Ret {
return (item.*ifx)(std::forward<Args>(args)...);
};
auto r = stack::pop_call(L, fx, types<Args...>());
stack::push(L, std::move(r));
return 1;
template<typename... Args>
static int typed_call(types<>, types<Args...> t, T& item, fx_t& ifx, lua_State* L) {
return typed_call(types<void>(), t, item, ifx, L);
}
template<typename... Ret, typename... Args>
static int typed_call(types<Ret...>, types<Args...>, T& item, fx_t& ifx, lua_State* L) {
auto fx = [&item, &ifx](Args&&... args) -> std::tuple<Ret...> { return (item.*ifx)(std::forward<Args>(args)...); };
auto r = stack::pop_call(L, fx, types<Args...>());
stack::push_reverse(L, std::move(r));
typedef typename multi_return<Ret...>::type return_type;
auto fx = [&item, &ifx](Args&&... args) -> return_type { return (item.*ifx)(std::forward<Args>(args)...); };
return_type r = stack::pop_call(L, fx, types<Args...>());
stack::push(L, std::move(r));
return sizeof...(Ret);
}
template<typename... Args>
static int typed_call(types<>, types<Args...>, T& item, fx_t& ifx, lua_State* L) {
return typed_call(types<void>(), 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<void*, data_t_count> data_t;
@ -193,22 +184,22 @@ struct lambda_lua_func : public lua_func {
return (*this)(tuple_types<typename fx_traits::return_type>(), typename fx_traits::args_type(), L);
}
template<typename... Args>
int operator()(types<>, types<Args...> t, lua_State* L) {
stack::pop_call(L, fx, t);
return 0;
}
template<typename... Args>
int operator()(types<void>, types<Args...> t, lua_State* L) {
stack::pop_call(L, fx, t);
return 0;
}
template<typename... Args>
int operator()(types<>, types<Args...> t, lua_State* L) {
return (*this)(types<void>(), t, L);
}
template<typename... Ret, typename... Args>
int operator()(types<Ret...>, types<Args...> t, lua_State* L) {
auto r = stack::pop_call(L, fx, t);
stack::push_reverse(L, r);
typedef typename multi_return<Ret...>::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<typename... FxArgs>
explicit_lua_func(FxArgs&&... fxargs): fx(std::forward<FxArgs>(fxargs)...) {}
template<typename... Args>
int operator()(types<>, types<Args...> t, lua_State* L) {
return (*this)(types<void>(), t, L);
}
template<typename... Args>
int operator()(types<void>, types<Args...> t, lua_State* L) {
stack::pop_call(L, fx, t);
return 0;
}
template<typename... Args>
int operator()(types<>, types<Args...> t, lua_State* L) {
return (*this)(types<void>(), t, L);
}
template<typename... Ret, typename... Args>
int operator()(types<Ret...>, types<Args...> t, lua_State* L) {
auto r = stack::pop_call(L, fx, t);
stack::push_reverse(L, std::move(r));
typedef typename multi_return<Ret...>::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<TFx, T, true> : public lua_func {
template<typename... Ret, typename... Args>
int operator()(types<Ret...>, types<Args...> t, lua_State* L) {
auto r = stack::pop_call(L, fx, t);
stack::push_reverse(L, std::move(r));
typedef typename multi_return<Ret...>::type return_type;
return_type r = stack::pop_call(L, fx, t);
stack::push(L, std::move(r));
return sizeof...(Ret);
}

View File

@ -127,9 +127,9 @@ public:
}
}
template<typename T, typename U>
T get(U&& key) const {
return global.get<T>(std::forward<U>(key));
template<typename... Args, typename... Keys>
typename multi_return<Args...>::type get(Keys&&... keys) const {
return global.get(types<Args...>(), std::forward<Keys>(keys)...);
}
template<typename T, typename U>

View File

@ -41,15 +41,11 @@ T* get_ptr(T* val) {
} // detail
class table : public reference {
friend class state;
template<typename Table, typename T> struct proxy;
public:
table() noexcept : reference() {}
table(lua_State* L, int index = -1) : reference(L, index) {
type_assert(L, index, type::table);
}
template<typename T, typename U>
T get(U&& key) const {
T single_get(U&& key) const {
push();
stack::push(state(), std::forward<U>(key));
lua_gettable(state(), -2);
@ -59,6 +55,45 @@ public:
return result;
}
template<std::size_t I, typename Tup, typename... Ret>
typename std::tuple_element<I, std::tuple<Ret...>>::type element_get(types<Ret...>, Tup&& key) const {
typedef typename std::tuple_element<I, std::tuple<Ret...>>::type T;
typedef typename std::tuple_element<I, Tup>::type U;
push();
stack::push(state(), std::get<I>(key));
lua_gettable(state(), -2);
type_assert(state(), -1, type_of<T>());
T result = stack::pop<T>(state());
lua_pop(state(), 1);
return result;
}
template<typename Tup, typename... Ret, std::size_t... I>
typename multi_return<Ret...>::type tuple_get(types<Ret...> t, indices<I...>, Tup&& tup) const {
return std::make_tuple(element_get<I>(t, std::forward<Tup>(tup))...);
}
template<typename Tup, typename Ret>
Ret tuple_get(types<Ret> t, indices<0>, Tup&& tup) const {
return element_get<0>(t, std::forward<Tup>(tup));
}
template<typename... Ret, typename... Keys>
typename multi_return<Ret...>::type get(types<Ret...> 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>(keys)...));
}
public:
table() noexcept : reference() {}
table(lua_State* L, int index = -1) : reference(L, index) {
type_assert(L, index, type::table);
}
template<typename... Ret, typename... Keys>
typename multi_return<Ret...>::type get(Keys&&... keys) const {
return get(types<Ret...>(), std::forward<Keys>(keys)...);
}
template<typename T, typename U>
table& set(T&& key, U&& value) {
push();

View File

@ -226,13 +226,16 @@ TEST_CASE("functions/return _order", "Check if return order is in the same readi
lua.set_function( "f", [ ] {
return std::make_tuple( 10, 11, 12 );
} );
lua.script( "function g() return 10, 11, 12 end" );
auto tcpp = lua.get<sol::function>( "f" ).call<int, int, int>( );
auto tlua = lua.get<sol::function>( "g" ).call<int, int, int>( );
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<sol::function>("f").call<int, int, int>();
auto tlua = lua.get<sol::function>("g").call<int, int, int>();
auto tluaget = lua.get<int, int, int>("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<int>("x") << ',' << lua.get<int>("y") << ',' << lua.get<int>("z") << std::endl;
REQUIRE(tcpp == triple);
REQUIRE(tlua == triple);
REQUIRE(tluaget == triple);
}
TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works properly") {