From 219d10b0b4948463905579d92d8ef0067b1ebded Mon Sep 17 00:00:00 2001 From: ThePhD Date: Sun, 19 Jul 2015 10:26:11 -0400 Subject: [PATCH] Thanks to LUA_MULTRET, we can have normal function call syntax with `sol::function` that doesn't require the user to pass the arguments in directly with `.call( ... )` function result is meant to be transient, and therefore should not be regularly storeable by the user... but there is no way to make a "and you can't have anything but a temporary to this" type, as far as I can tell. --- .gitignore | 1 + sol/function.hpp | 64 +++++++++++++++++++++++++++++++++++++++--------- sol/stack.hpp | 8 +++--- sol/table.hpp | 2 +- 4 files changed, 59 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 9706a40b..cda6f552 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,4 @@ lua-5.3.0/ .vs/ lua-5.1.5/ luajit-2.0.4/ +*.creator.user.* diff --git a/sol/function.hpp b/sol/function.hpp index e9433732..4a2fd911 100644 --- a/sol/function.hpp +++ b/sol/function.hpp @@ -33,14 +33,52 @@ #include namespace sol { +class function_result { +private: + lua_State* L; + int index; + int returncount; + + template + T get(types, indices) const { + return stack::get(L, index); + } + + template + std::tuple get(types, indices) const { + auto r = std::make_tuple(stack::get(L, index + I)...); + return r; + } + +public: + function_result() = default; + function_result(lua_State* L, int index = -1, int returncount = 0): L(L), index(index), returncount(returncount) { + + } + function_result(const function_result&) = default; + function_result& operator=(const function_result&) = default; + function_result(function_result&&) = default; + function_result& operator=(function_result&&) = default; + + template + operator T () const { + auto tr = tuple_types(); + return get(tr, tr); + } + + ~function_result() { + lua_pop(L, returncount); + } +}; + class function : public reference { private: - void luacall(std::size_t argcount, std::size_t resultcount) const { - lua_call(state(), static_cast(argcount), static_cast(resultcount)); + void luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount) const { + lua_call(state(), static_cast(argcount), static_cast(resultcount)); } template - std::tuple invoke(indices, types, std::size_t n) const { + std::tuple invoke(indices, types, std::ptrdiff_t n) const { luacall(n, sizeof...(Ret)); const int nreturns = static_cast(sizeof...(Ret)); const int stacksize = lua_gettop(state()); @@ -51,19 +89,23 @@ private: } template - Ret invoke(indices, types, std::size_t n) const { + Ret invoke(indices, types, std::ptrdiff_t n) const { luacall(n, 1); return stack::pop(state()); } template - void invoke(indices, types, std::size_t n) const { + void invoke(indices, types, std::ptrdiff_t n) const { luacall(n, 0); } - void invoke(indices<>, types<>, std::size_t n) const { - auto tr = types(); - invoke(tr, tr, n); + function_result invoke(indices<>, types<>, std::ptrdiff_t n) const { + const int stacksize = lua_gettop(state()); + const int firstreturn = std::max(0, stacksize - static_cast(n) - 1); + luacall(n, LUA_MULTRET); + const int poststacksize = lua_gettop(state()); + const int returncount = poststacksize - firstreturn; + return function_result(state(), firstreturn + 1, returncount); } public: @@ -75,8 +117,8 @@ public: function& operator=(const function&) = default; template - void operator()(Args&&... args) const { - call<>(std::forward(args)...); + function_result operator()(Args&&... args) const { + return call<>(std::forward(args)...); } template @@ -85,7 +127,7 @@ public: } template - ReturnType call(Args&&... args) const { + auto call(Args&&... args) const -> decltype(invoke(types(), types(), 0)) { push(); int pushcount = stack::push_args(state(), std::forward(args)...); auto tr = types(); diff --git a/sol/stack.hpp b/sol/stack.hpp index 5fdc5ca6..b08b2b9f 100644 --- a/sol/stack.hpp +++ b/sol/stack.hpp @@ -113,9 +113,9 @@ inline int push_args(lua_State* L, T&& t, Args&&... args) { return pushcount; } -template> -inline auto get(lua_State* L, int index = -1) -> decltype(getter{}.get(L, index)) { - return getter{}.get(L, index); +template +inline auto get(lua_State* L, int index = -1) -> decltype(getter>{}.get(L, index)) { + return getter>{}.get(L, index); } template @@ -619,7 +619,7 @@ inline void call(lua_State* L, types tr, types ta, Fx&& fx, FxArg } inline call_syntax get_call_syntax(lua_State* L, const std::string& meta) { - if (get(L, 1) == type::table) { + if (sol::stack::get(L, 1) == type::table) { if (luaL_newmetatable(L, meta.c_str()) == 0) { lua_settop(L, -2); return call_syntax::colon; diff --git a/sol/table.hpp b/sol/table.hpp index f1a42146..b58d69d4 100644 --- a/sol/table.hpp +++ b/sol/table.hpp @@ -31,7 +31,7 @@ namespace sol { class table : public reference { friend class state; template - typename stack::get_return::type single_get(U&& key) const { + auto single_get(U&& key) const -> decltype(stack::get(nullptr, 0)) { push(); stack::push(state(), std::forward(key)); lua_gettable(state(), -2);