diff --git a/.gitignore b/.gitignore index a932d0c0..dc3ecdc1 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,4 @@ main.ninja luajit-2.0.3/ .dropbox* desktop.ini +lua-5.3.0/ diff --git a/sol/default_construct.hpp b/sol/default_construct.hpp index 90ad3264..73165ba1 100644 --- a/sol/default_construct.hpp +++ b/sol/default_construct.hpp @@ -33,6 +33,23 @@ struct default_construct { alloc.construct(obj, std::forward(args)...); } }; + +template +struct placement_construct { + T obj; + + template + placement_construct( Args&&... args ) : obj(std::forward(args)...) { + + } + + template + void operator()(Args&&... args) const { + std::allocator> alloc{}; + alloc.construct(obj, std::forward(args)...); + } +}; + } // sol #endif // SOL_DEFAULT_CONSTRUCTOR_HPP diff --git a/sol/function.hpp b/sol/function.hpp index cbdf5109..abe9d656 100644 --- a/sol/function.hpp +++ b/sol/function.hpp @@ -39,24 +39,31 @@ private: lua_call(state(), static_cast(argcount), static_cast(resultcount)); } - template - std::tuple invoke(types, std::size_t n) const { + template + std::tuple invoke(indices, types, std::size_t n) const { luacall(n, sizeof...(Ret)); - return stack::pop_reverse_call(state(), std::make_tuple, types()); + const int nreturns = static_cast(sizeof...(Ret)); + const int stacksize = lua_gettop(state()); + const int firstreturn = std::max(0, stacksize - nreturns) + 1; + auto r = std::make_tuple(stack::get(state(), firstreturn + I)...); + lua_pop(state(), nreturns); + return r; } - template - Ret invoke(types, std::size_t n) const { + template + Ret invoke(indices, types, std::size_t n) const { luacall(n, 1); return stack::pop(state()); } - void invoke(types, std::size_t n) const { + template + void invoke(indices, types, std::size_t n) const { luacall(n, 0); } - void invoke(types<>, std::size_t n) const { - luacall(n, 0); + void invoke(indices<>, types<>, std::size_t n) const { + auto tr = types(); + invoke(tr, tr, n); } public: @@ -80,8 +87,9 @@ public: template typename return_type::type call(Args&&... args) const { push(); - stack::push_args(state(), std::forward(args)...); - return invoke(types(), sizeof...(Args)); + int pushcount = stack::push_args(state(), std::forward(args)...); + auto tr = types(); + return invoke(tr, tr, pushcount); } }; @@ -175,8 +183,8 @@ struct pusher> { lua_CFunction freefunc = &static_member_function, Fx>::call; int upvalues = stack::detail::push_as_upvalues(L, memfxptr); - stack::push(L, userobjdata); - ++upvalues; + upvalues += stack::push(L, userobjdata); + stack::push(L, freefunc, upvalues); } @@ -209,15 +217,17 @@ struct pusher> { } template - static void push(lua_State* L, Args&&... args) { + static int push(lua_State* L, Args&&... args) { + // Set will always place one thing (function) on the stack set(L, std::forward(args)...); + return 1; } }; template struct pusher> { - static void push(lua_State* L, std::function fx) { - pusher{}.push(L, std::move(fx)); + static int push(lua_State* L, std::function fx) { + return pusher{}.push(L, std::move(fx)); } }; diff --git a/sol/function_types.hpp b/sol/function_types.hpp index 0fd4f7d6..1da7dc80 100644 --- a/sol/function_types.hpp +++ b/sol/function_types.hpp @@ -46,6 +46,10 @@ struct functor { template functor(FxArgs&&... fxargs): item(nullptr), invocation(std::forward(fxargs)...) {} + bool check () const { + return invocation != nullptr; + } + template void call(types, Args&&... args) { T& member = *item; @@ -59,7 +63,7 @@ struct functor { } template - auto operator()(Args&&... args) -> decltype(this->call(types{}, std::forward(args)...)) { + auto operator()(Args&&... args) -> decltype(std::declval().call(types{}, std::forward(args)...)) { return this->call(types{}, std::forward(args)...); } }; @@ -75,15 +79,24 @@ struct functor functor(FxArgs&&... fxargs): item(nullptr), invocation(std::forward(fxargs)...) {} + bool check () const { + return this->fx.invocation != nullptr; + } + template - void operator()(Arg&& arg) { + void call(types, Arg&& arg) { T& member = *item; (member.*invocation) = std::forward(arg); } - return_type operator()() { - T& member = *item; - return (member.*invocation); + return_type call(types) { + T& member = *item; + return (member.*invocation); + } + + template + auto operator()(Args&&... args) -> decltype(std::declval().call(types{}, std::forward(args)...)) { + return this->call(types{}, std::forward(args)...); } }; @@ -96,9 +109,24 @@ struct functor::value || T* item; function_type invocation; +private: + bool check(std::false_type) const { + return true; + } + + bool check(std::true_type) const { + return this->invocation != nullptr; + } + +public: + template functor(FxArgs&&... fxargs): item(nullptr), invocation(std::forward(fxargs)...) {} + bool check () const { + return this->check(std::is_function()); + } + template void call(types, Args&&... args) { T& member = *item; @@ -112,7 +140,7 @@ struct functor::value || } template - auto operator()(Args&&... args) -> decltype(this->call(types{}, std::forward(args)...)) { + auto operator()(Args&&... args) -> decltype(std::declval().call(types{}, std::forward(args)...)) { return this->call(types{}, std::forward(args)...); } }; @@ -125,8 +153,8 @@ struct static_function { typedef function_traits traits_type; template - static int typed_call(types, types t, function_type* fx, lua_State* L) { - stack::get_call(L, fx, t); + static int typed_call(types tr, types ta, function_type* fx, lua_State* L) { + stack::call(L, 0, tr, ta, fx); std::ptrdiff_t nargs = sizeof...(Args); lua_pop(L, nargs); return 0; @@ -138,13 +166,12 @@ struct static_function { } template - static int typed_call(types, types t, function_type* fx, lua_State* L) { + static int typed_call(types, types ta, function_type* fx, lua_State* L) { typedef typename return_type::type return_type; - return_type r = stack::get_call(L, fx, t); - std::ptrdiff_t nargs = sizeof...(Args); + return_type r = stack::call(L, 0, types(), ta, fx); + int nargs = static_cast(sizeof...(Args)); lua_pop(L, nargs); - stack::push(L, detail::return_forward{}(r)); - return sizeof...(Ret); + return stack::push(L, detail::return_forward{}(r)); } static int call(lua_State* L) { @@ -165,10 +192,10 @@ struct static_member_function { typedef function_traits traits_type; template - static int typed_call(types, types, T& item, function_type& ifx, lua_State* L) { + static int typed_call(types tr, types ta, T& item, function_type& ifx, lua_State* L) { auto fx = [&item, &ifx](Args&&... args) -> void { (item.*ifx)(std::forward(args)...); }; - stack::get_call(L, fx, types()); - std::ptrdiff_t nargs = sizeof...(Args); + stack::call(L, 0, tr, ta, fx); + int nargs = static_cast(sizeof...(Args)); lua_pop(L, nargs); return 0; } @@ -179,14 +206,13 @@ struct static_member_function { } template - static int typed_call(types, types, T& item, function_type& ifx, lua_State* L) { + static int typed_call(types tr, types ta, T& item, function_type& ifx, lua_State* L) { typedef typename return_type::type return_type; auto fx = [&item, &ifx](Args&&... args) -> return_type { return (item.*ifx)(std::forward(args)...); }; - return_type r = stack::get_call(L, fx, types()); - std::ptrdiff_t nargs = sizeof...(Args); + return_type r = stack::call(L, 0, tr, ta, fx); + int nargs = static_cast(sizeof...(Args)); lua_pop(L, nargs); - stack::push(L, detail::return_forward{}(r)); - return sizeof...(Ret); + return stack::push(L, detail::return_forward{}(r)); } static int call(lua_State* L) { @@ -238,12 +264,12 @@ struct base_function { } static int call(lua_State* L) { - void** pinheritancedata = static_cast(stack::get(L, 1).value); + void** pinheritancedata = static_cast(stack::get(L, 1).value); return base_call(L, *pinheritancedata); } static int gc(lua_State* L) { - void** pudata = static_cast(stack::get(L, 1).value); + void** pudata = static_cast(stack::get(L, 1).value); return base_gc(L, *pudata); } @@ -251,11 +277,11 @@ struct base_function { struct usertype { static int call(lua_State* L) { // Zero-based template parameter, but upvalues start at 1 - return base_call(L, stack::get(L, I + 1)); + return base_call(L, stack::get(L, I + 1)); } static int ref_call(lua_State* L) { - return ref_base_call(L, stack::get(L, I + 1)); + return ref_base_call(L, stack::get(L, I + 1)); } template @@ -267,7 +293,7 @@ struct base_function { static void func_gc (std::false_type, lua_State* L) { // Shut up clang tautological error without throwing out std::size_t for(std::size_t i = 0; i < limit; ++i) { - upvalue_t up = stack::get(L, i + 1); + upvalue up = stack::get(L, i + 1); base_function* obj = static_cast(up.value); std::allocator alloc{}; alloc.destroy(obj); @@ -303,9 +329,9 @@ struct functor_function : public base_function { functor_function(FxArgs&&... fxargs): fx(std::forward(fxargs)...) {} template - int operator()(types, types t, lua_State* L) { - stack::get_call(L, fx, t); - std::ptrdiff_t nargs = sizeof...(Args); + int operator()(types r, types t, lua_State* L) { + stack::call(L, 0, r, t, fx); + int nargs = static_cast(sizeof...(Args)); lua_pop(L, nargs); return 0; } @@ -316,12 +342,11 @@ struct functor_function : public base_function { } template - int operator()(types, types t, lua_State* L) { - return_type r = stack::get_call(L, fx, t); - std::ptrdiff_t nargs = sizeof...(Args); + int operator()(types tr, types ta, lua_State* L) { + return_type r = stack::call(L, 0, tr, ta, fx); + int nargs = static_cast(sizeof...(Args)); lua_pop(L, nargs); - stack::push(L, r); - return sizeof...(Ret); + return stack::push(L, r); } virtual int operator()(lua_State* L) override { @@ -355,8 +380,8 @@ struct member_function : public base_function { member_function(Tm&& m, FxArgs&&... fxargs): fx(std::forward(m), std::forward(fxargs)...) {} template - int operator()(types, types t, lua_State* L) { - stack::get_call(L, fx, t); + int operator()(types tr, types ta, lua_State* L) { + stack::call(L, 0, tr, ta, fx); return 0; } @@ -366,12 +391,11 @@ struct member_function : public base_function { } template - int operator()(types, types t, lua_State* L) { - return_type r = stack::get_call(L, fx, t); - std::ptrdiff_t nargs = sizeof...(Args); + int operator()(types tr, types ta, lua_State* L) { + return_type r = stack::call(L, 0, tr, ta, fx); + int nargs = static_cast(sizeof...(Args)); lua_pop(L, nargs); - stack::push(L, std::move(r)); - return sizeof...(Ret); + return stack::push(L, detail::return_forward{}(r)); } virtual int operator()(lua_State* L) override { @@ -398,7 +422,7 @@ struct usertype_function_core : public base_function { usertype_function_core(FxArgs&&... fxargs): fx(std::forward(fxargs)...) {} template> - typename std::enable_if::value, void>::type push(lua_State* L, Return&& r) { + typename std::enable_if::value, int>::type push(lua_State* L, Return&& r) { if(detail::get_ptr(r) == fx.item) { // push nothing // note that pushing nothing with the ':' @@ -408,37 +432,42 @@ struct usertype_function_core : public base_function { // and naturally lua returns that. // It's an "easy" way to return *this, // without allocating an extra userdata, apparently! - return; + return 1; } - stack::push(L, std::forward(r)); + return stack::push(L, std::forward(r)); } template> - typename std::enable_if::value, void>::type push(lua_State* L, Return&& r) { - stack::push(L, std::forward(r)); + typename std::enable_if::value, int>::type push(lua_State* L, Return&& r) { + return stack::push(L, std::forward(r)); } template - int operator()(types, types t, lua_State* L) { - static const std::size_t skew = static_cast(std::is_member_object_pointer::value); - stack::get_call(L, 2 + skew, fx, t); - std::ptrdiff_t nargs = sizeof...(Args); + int call(types r, types t, lua_State* L) { + //static const std::size_t skew = static_cast(std::is_member_object_pointer::value); + stack::call(L, 0, r, t, fx); + int nargs = static_cast(sizeof...(Args)); lua_pop(L, nargs); return 0; } - template - int operator()(types, types t, lua_State* L) { - return_type r = stack::get_call(L, 2, fx, t); - std::ptrdiff_t nargs = sizeof...(Args); - lua_pop(L, nargs); - push(L, detail::return_forward{}(r)); - return sizeof...(Ret); + template + int call(types<>, types t, lua_State* L) { + return this->call(types(), t, L); } - template - int operator()(types<>, types t, lua_State* L) { - return (*this)(types(), t, L); + template + int call(types tr, types ta, lua_State* L) { + return_type r = stack::call(L, 0, tr, ta, fx); + int nargs = static_cast(sizeof...(Args)); + lua_pop(L, nargs); + int pushcount = push(L, detail::return_forward{}(r)); + return pushcount; + } + + template + int operator()(types r, types t, lua_State* L) { + return this->call(r, t, L); } }; @@ -530,7 +559,7 @@ struct usertype_indexing_function : public usertype_function_core auto function = functions.find(accessor); if(function != functions.end()) { if(function->second.second) { - stack::push(L, function->second.first.get()); + stack::push(L, function->second.first.get()); if(std::is_same::value) { stack::push(L, &base_function::usertype<0>::ref_call, 1); } @@ -546,7 +575,7 @@ struct usertype_indexing_function : public usertype_function_core return (*function->second.first)(L); } } - if(this->fx.invocation == nullptr) { + if (!this->fx.check()) { throw error("invalid indexing \"" + accessor + "\" on type: " + name); } this->fx.item = detail::get_ptr(stack::get(L, 1)); @@ -564,4 +593,4 @@ struct usertype_indexing_function : public usertype_function_core } // sol -#endif // SOL_FUNCTION_TYPES_HPP \ No newline at end of file +#endif // SOL_FUNCTION_TYPES_HPP diff --git a/sol/object.hpp b/sol/object.hpp index 6e1c9feb..2d6ccba0 100644 --- a/sol/object.hpp +++ b/sol/object.hpp @@ -34,16 +34,16 @@ public: template auto as() const -> decltype(stack::get(state())) { push(); - type_assert(state(), -1, type_of()); - return stack::get(state()); + type actual = stack::get(state()); + type_assert(state(), -1, type_of(), actual); + return stack::pop(state()); } template bool is() const { - push(); auto expected = type_of(); - auto actual = lua_type(state(), -1); - return (static_cast(expected) == actual) || (expected == type::poly); + auto actual = get_type(); + return (expected == actual) || (expected == type::poly); } explicit operator bool() const { diff --git a/sol/reference.hpp b/sol/reference.hpp index 8ccdad50..6e081e5c 100644 --- a/sol/reference.hpp +++ b/sol/reference.hpp @@ -79,7 +79,7 @@ public: return *this; } - type get_type() { + type get_type() const { push(); int result = lua_type(L, -1); lua_pop(L, 1); diff --git a/sol/stack.hpp b/sol/stack.hpp index 4b8ec1f1..d526968d 100644 --- a/sol/stack.hpp +++ b/sol/stack.hpp @@ -75,18 +75,99 @@ struct return_forward { namespace stack { namespace detail { template -inline void push_userdata(lua_State* L, Key&& metatablekey, Args&&... args) { +inline int push_userdata(lua_State* L, Key&& metatablekey, Args&&... args) { T* pdatum = static_cast(lua_newuserdata(L, sizeof(T))); std::allocator alloc{}; alloc.construct(pdatum, std::forward(args)...); luaL_getmetatable(L, std::addressof(metatablekey[0])); lua_setmetatable(L, -2); + return 1; } } // detail -template + +template struct getter; -template +template struct pusher; +template::value, typename = void> +struct checker; + +template +inline int push(lua_State* L, T&& t, Args&&... args) { + return pusher>{}.push(L, std::forward(t), std::forward(args)...); +} + +template +inline int push_tuple(lua_State* L, indices, T&& tuplen) { + using swallow = char[1 + sizeof...(I)]; + int pushcount = 0; + swallow {'\0', (pushcount += sol::stack::push(L, std::get(tuplen)), '\0')... }; + return pushcount; +} + +// overload allows to use a pusher of a specific type, but pass in any kind of args +template +inline int push(lua_State* L, Arg&& arg, Args&&... args) { + return pusher>{}.push(L, std::forward(arg), std::forward(args)...); +} + +inline int push_args(lua_State*) { + // do nothing + return 0; +} + +template +inline int push_args(lua_State* L, T&& t, Args&&... args) { + int pushcount = push(L, std::forward(t)); + using swallow = char[]; + void(swallow{'\0', (pushcount += push(L, std::forward(args)), '\0')... }); + return pushcount; +} + +template> +inline auto get(lua_State* L, int index = -1) -> decltype(getter{}.get(L, index)) { + return getter{}.get(L, index); +} + +template +auto pop(lua_State* L) -> decltype(get(L)) { + typedef decltype(get(L)) ret_t; + ret_t r = get(L); + lua_pop(L, 1); + return r; +} + +template +struct get_return { + typedef decltype(get(nullptr)) type; +}; + +template +struct checker { + template + static bool check (lua_State* L, int index, const Handler& handler) { + const type indextype = type_of(L, index); + bool success = expected == indextype; + if (!success) { + // expected type, actual type + handler(L, index, expected, indextype); + } + return success; + } +}; + +template +bool check(lua_State* L, int index, Handler&& handler) { + typedef Unqualified Tu; + checker c; + return c.check(L, index, std::forward(handler)); +} + +template +bool check(lua_State* L, int index) { + auto handler = type_panic; + return check(L, index, handler); +} template struct getter { @@ -97,12 +178,13 @@ struct getter { template, std::is_signed> = 0> static U get(lua_State* L, int index = -1) { - return static_cast(lua_tounsigned(L, index)); + return static_cast(lua_tointeger(L, index)); } template, std::is_unsigned> = 0> static U get(lua_State* L, int index = -1) { - return static_cast(lua_tointeger(L, index)); + typedef typename std::make_signed::type signed_int; + return static_cast(stack::get(L, index)); } template> = 0> @@ -184,22 +266,22 @@ struct getter { }; template<> -struct getter { - static userdata_t get(lua_State* L, int index = -1) { +struct getter { + static userdata get(lua_State* L, int index = -1) { return{ lua_touserdata(L, index) }; } }; template<> -struct getter { - static lightuserdata_t get(lua_State* L, int index = 1) { +struct getter { + static light_userdata get(lua_State* L, int index = 1) { return{ lua_touserdata(L, index) }; } }; template<> -struct getter { - static upvalue_t get(lua_State* L, int index = 1) { +struct getter { + static upvalue get(lua_State* L, int index = 1) { return{ lua_touserdata(L, lua_upvalueindex(index)) }; } }; @@ -214,22 +296,25 @@ struct getter { template struct pusher { template> = 0> - static void push(lua_State* L, const T& value) { + static int push(lua_State* L, const T& value) { lua_pushnumber(L, value); + return 1; } template, std::is_signed> = 0> - static void push(lua_State* L, const T& value) { + static int push(lua_State* L, const T& value) { lua_pushinteger(L, value); + return 1; } template, std::is_unsigned> = 0> - static void push(lua_State* L, const T& value) { - lua_pushunsigned(L, value); + static int push(lua_State* L, const T& value) { + typedef typename std::make_signed::type signed_int; + return stack::push(L, static_cast(value)); } template, Not>> = 0> - static void push(lua_State* L, const T& cont) { + static int push(lua_State* L, const T& cont) { lua_createtable(L, cont.size(), 0); unsigned index = 1; for(auto&& i : cont) { @@ -240,154 +325,139 @@ struct pusher { // set the table lua_settable(L, -3); } + return 1; } template, has_key_value_pair> = 0> - static void push(lua_State* L, const T& cont) { + static int push(lua_State* L, const T& cont) { lua_createtable(L, cont.size(), 0); for(auto&& pair : cont) { pusher>{}.push(L, pair.first); pusher>{}.push(L, pair.second); lua_settable(L, -3); } + return 1; } template> = 0> - static void push(lua_State*, T& ref) { - ref.push(); + static int push(lua_State*, T& ref) { + return ref.push(); } template, EnableIf>, Not>, Not>, Not>> = 0> - static void push(lua_State* L, T& t) { - detail::push_userdata(L, usertype_traits::metatable, t); + static int push(lua_State* L, T& t) { + return detail::push_userdata(L, usertype_traits::metatable, t); } template, EnableIf>, Not>, Not>, Not>> = 0> - static void push(lua_State* L, T&& t) { - detail::push_userdata(L, usertype_traits::metatable, std::move(t)); + static int push(lua_State* L, T&& t) { + return detail::push_userdata(L, usertype_traits::metatable, std::move(t)); } }; template struct pusher { - static void push(lua_State* L, T* obj) { - detail::push_userdata(L, usertype_traits::metatable, obj); + static int push(lua_State* L, T* obj) { + return detail::push_userdata(L, usertype_traits::metatable, obj); } }; template struct pusher> { - static void push(lua_State* L, const std::reference_wrapper& t) { - pusher{}.push(L, std::addressof(t.get())); + static int push(lua_State* L, const std::reference_wrapper& t) { + return stack::push(L, std::addressof(t.get())); } }; template<> struct pusher { - static void push(lua_State* L, const bool& b) { + static int push(lua_State* L, const bool& b) { lua_pushboolean(L, b); + return 1; } }; template<> struct pusher { - static void push(lua_State* L, const nil_t&) { + static int push(lua_State* L, const nil_t&) { lua_pushnil(L); + return 1; } }; template<> struct pusher { - static void push(lua_State* L, lua_CFunction func, int n = 0) { + static int push(lua_State* L, lua_CFunction func, int n = 0) { lua_pushcclosure(L, func, n); + return 1; } }; template<> struct pusher { - static void push(lua_State* L, void* userdata) { + static int push(lua_State* L, void* userdata) { lua_pushlightuserdata(L, userdata); + return 1; } }; template<> -struct pusher { - static void push(lua_State* L, upvalue_t upvalue) { +struct pusher { + static int push(lua_State* L, upvalue upvalue) { lua_pushlightuserdata(L, upvalue); + return 1; } }; template<> -struct pusher { - static void push(lua_State* L, lightuserdata_t userdata) { +struct pusher { + static int push(lua_State* L, light_userdata userdata) { lua_pushlightuserdata(L, userdata); + return 1; } }; template<> -struct pusher { +struct pusher { template> - static void push(lua_State* L, T&& data) { + static int push(lua_State* L, T&& data) { U* userdata = static_cast(lua_newuserdata(L, sizeof(U))); new(userdata)U(std::forward(data)); + return 1; } }; template<> struct pusher { - static void push(lua_State* L, const char* str) { + static int push(lua_State* L, const char* str) { lua_pushlstring(L, str, std::char_traits::length(str)); + return 1; } }; template struct pusher { - static void push(lua_State* L, const char (&str)[N]) { + static int push(lua_State* L, const char (&str)[N]) { lua_pushlstring(L, str, N - 1); + return 1; } }; template<> struct pusher { - static void push(lua_State* L, const std::string& str) { + static int push(lua_State* L, const std::string& str) { lua_pushlstring(L, str.c_str(), str.size()); + return 1; } }; -template -inline void push(lua_State* L, T&& t, Args&&... args) { - pusher>{}.push(L, std::forward(t), std::forward(args)...); -} - -// overload allows to use a pusher of a specific type, but pass in any kind of args -template -inline void push(lua_State* L, Arg&& arg, Args&&... args) { - pusher>{}.push(L, std::forward(arg), std::forward(args)...); -} - -inline void push_args(lua_State*) { - // do nothing -} - -template -inline void push_args(lua_State* L, T&& t, Args&&... args) { - pusher>{}.push(L, std::forward(t)); - using swallow = char[]; - void(swallow{'\0', (pusher>{}.push(L, std::forward(args)), '\0')... }); -} - -template> -inline auto get(lua_State* L, int index = -1) -> decltype(getter{}.get(L, index)) { - return getter{}.get(L, index); -} - -template -auto pop(lua_State* L) -> decltype(get(L)) { - typedef decltype(get(L)) ret_t; - ret_t r = get(L); - lua_pop(L, 1); - return r; -} +template +struct pusher> { + template + static int push(lua_State* L, Tuple&& tuplen) { + return push_tuple(L, build_indices(), std::forward(tuplen)); + } +}; namespace detail { template @@ -401,10 +471,11 @@ inline int push_as_upvalues(lua_State* L, T& item) { data_t data{{}}; std::memcpy(std::addressof(data[0]), std::addressof(item), itemsize); + int pushcount = 0; for(auto&& v : data) { - push(L, upvalue_t(v)); + pushcount += push(L, upvalue(v)); } - return data_t_count; + return pushcount; } template @@ -413,105 +484,84 @@ inline std::pair get_as_upvalues(lua_State* L, int index = 1) { typedef std::array data_t; data_t voiddata{ {} }; for(std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof(void*)) { - voiddata[i] = get(L, index++); + voiddata[i] = get(L, index++); } return std::pair(*reinterpret_cast(static_cast(voiddata.data())), index); } -template -inline void push_tuple(lua_State* L, indices, T&& tuplen) { - using swallow = char[1 + sizeof...(I)]; - swallow {'\0', (sol::stack::push(L, std::get(tuplen)), '\0')... }; -} - -template -inline auto ltr_get(lua_State*, int, F&& f, types, types<>, Vs&&... vs) -> decltype(f(std::forward(vs)...)) { - return f(std::forward(vs)...); -} -template -inline auto ltr_get(lua_State* L, int index, F&& f, types, types, Vs&&... vs) -> decltype(f(std::declval()...)) { - return ltr_get(L, index + 1, std::forward(f), types(), types(), std::forward(vs)..., stack::get(L, index)); -} - -template -inline auto ltr_pop(lua_State*, F&& f, types, types<>, Vs&&... vs) -> decltype(f(std::forward(vs)...)) { - return f(std::forward(vs)...); -} -template -inline 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)..., stack::pop(L)); -} - -template -inline auto rtl_pop(lua_State*, F&& f, types, types<>, Vs&&... vs) -> decltype(f(std::forward(vs)...)) { - return f(std::forward(vs)...); -} -template -inline 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(), stack::pop(L), std::forward(vs)...); -} -} // detail - -template -struct pusher> { - static void push(lua_State* L, const std::tuple& tuplen) { - detail::push_tuple(L, build_indices(), tuplen); - } - - static void push(lua_State* L, std::tuple&& tuplen) { - detail::push_tuple(L, build_indices(), std::move(tuplen)); +template +struct check_arguments { + template + static bool check(lua_State* L, int firstargument, indices, types) { + bool checks = true; + using swallow = int[sizeof...(Args)+2]; + (void)swallow { + 0, (checks &= stack::check(L, firstargument + I))..., 0 + }; + return checks; } }; -template -inline void push_reverse(lua_State* L, T&& item) { - push(L, std::forward(item)); +template <> +struct check_arguments { + template + static bool check(lua_State*, int, indices, types) { + return true; + } +}; + +template ::value>::type> +inline R call(lua_State* L, int start, indices, types, types ta, Fx&& fx, FxArgs&&... args) { + const int stacksize = lua_gettop(L); + const int firstargument = start + stacksize - std::max(sizeof...(Args)-1, static_cast(0)); + + detail::check_arguments{}.check(L, firstargument, ta, ta); + + return fx(std::forward(args)..., stack::get(L, firstargument + I)...); } -template -inline void push_reverse(lua_State* L, const std::tuple& tuplen) { - detail::push_tuple(L, build_reverse_indices(), tuplen); +template +inline void call(lua_State* L, int start, indices, types, types ta, Fx&& fx, FxArgs&&... args) { + const int stacksize = lua_gettop(L); + const int firstargument = start + stacksize - std::max(sizeof...(Args)-1, static_cast(0)); + + bool checks = detail::check_arguments{}.check(L, firstargument, ta, ta); + if ( !checks ) + throw error("Arguments not of the proper types for this function call"); + + fx(std::forward(args)..., stack::get(L, firstargument + I)...); +} +} // detail + +template ::value>::type> +inline R call(lua_State* L, int start, types tr, types ta, Fx&& fx, FxArgs&&... args) { + return detail::call(L, start, ta, tr, ta, std::forward(fx), std::forward(args)...); } -template -inline void push_reverse(lua_State* L, std::tuple&& tuplen) { - detail::push_tuple(L, build_reverse_indices(), std::move(tuplen)); +template ::value>::type> +inline R call(lua_State* L, types tr, types ta, Fx&& fx, FxArgs&&... args) { + return call(L, 0, ta, tr, ta, std::forward(fx), std::forward(args)...); } -template -inline auto get_call(lua_State* L, int index, TFx&& fx, types t, Vs&&... vs) -> decltype(detail::ltr_get(L, index, std::forward(fx), t, t, std::forward(vs)...)) { - return detail::ltr_get(L, index, std::forward(fx), t, t, std::forward(vs)...); +template +inline void call(lua_State* L, int start, types tr, types ta, Fx&& fx, FxArgs&&... args) { + detail::call(L, start, ta, tr, ta, std::forward(fx), std::forward(args)...); } -template -inline auto get_call(lua_State* L, TFx&& fx, types t, Vs&&... vs) -> decltype(get_call(L, 1, std::forward(fx), t, std::forward(vs)...)) { - return get_call(L, 1, std::forward(fx), t, std::forward(vs)...); -} - -template -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()); +template +inline void call(lua_State* L, types tr, types ta, Fx&& fx, FxArgs&&... args) { + call(L, 0, ta, tr, ta, std::forward(fx), std::forward(args)...); } inline call_syntax get_call_syntax(lua_State* L, const std::string& meta) { - if(get(L, 1) == type::table) { - if(luaL_newmetatable(L, meta.c_str()) == 0) { + if (get(L, 1) == type::table) { + if (luaL_newmetatable(L, meta.c_str()) == 0) { lua_settop(L, -2); return call_syntax::colon; } } return call_syntax::dot; } - -template -struct get_return { - typedef decltype(get(nullptr)) type; -}; } // stack } // sol diff --git a/sol/state.hpp b/sol/state.hpp index bed5b8c8..82470000 100644 --- a/sol/state.hpp +++ b/sol/state.hpp @@ -138,8 +138,8 @@ public: template auto get(Keys&&... keys) const - -> decltype(global.get(types(), std::forward(keys)...)) { - return global.get(types(), std::forward(keys)...); + -> decltype(global.get(std::forward(keys)...)) { + return global.get(std::forward(keys)...); } template diff --git a/sol/table.hpp b/sol/table.hpp index df2aa70a..6a4967d6 100644 --- a/sol/table.hpp +++ b/sol/table.hpp @@ -41,27 +41,16 @@ class table : public reference { return result; } - template - typename std::tuple_element::type...>>::type element_get(types, Tup&& key) const { - typedef typename std::tuple_element>::type T; - return single_get(std::get(key)); + template + typename return_type::type...>::type tuple_get(types, indices, Keys&& keys) const { + return std::make_tuple(single_get(std::get(keys))...); } - template - typename return_type::type...>::type tuple_get(types t, indices, Tup&& tup) const { - return std::make_tuple(element_get(t, std::forward(tup))...); + template + typename stack::get_return::type tuple_get(types, indices<0>, Keys&& keys) const { + return single_get(std::get<0>(keys)); } - template - typename stack::get_return::type tuple_get(types t, indices<0>, Tup&& tup) const { - return element_get<0>(t, std::forward(tup)); - } - - template - typename return_type::type...>::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) { @@ -70,7 +59,8 @@ public: template typename return_type::type...>::type get(Keys&&... keys) const { - return get(types(), std::forward(keys)...); + types tr; + return tuple_get(tr, tr, std::make_tuple(std::forward(keys)...)); } template diff --git a/sol/traits.hpp b/sol/traits.hpp index ff5056b7..b9fcc2d4 100644 --- a/sol/traits.hpp +++ b/sol/traits.hpp @@ -120,9 +120,10 @@ struct return_type { template<> struct return_type<> : types<>{ typedef void type; -}; +}; + +namespace detail { -namespace detail { template>::value> struct is_function_impl : std::is_function::type> {}; @@ -146,10 +147,11 @@ struct is_function_impl { template struct check_deducible_signature { + struct nat {}; template static auto test(int) -> decltype(&G::operator(), void()); template - static auto test(...) -> struct nat; + static auto test(...) -> nat; using type = std::is_void(0))>; }; @@ -312,6 +314,7 @@ template Unwrap unwrapper(std::reference_wrapper arg) { return arg.get(); } + } // sol #endif // SOL_TRAITS_HPP diff --git a/sol/types.hpp b/sol/types.hpp index 31439924..676ef316 100644 --- a/sol/types.hpp +++ b/sol/types.hpp @@ -29,28 +29,31 @@ namespace sol { struct nil_t {}; const nil_t nil {}; -struct void_type {}; +inline bool operator==(nil_t, nil_t) { return true; } +inline bool operator!=(nil_t, nil_t) { return false; } + +struct void_type : types {}; // This is important because it allows myobject.call( Void, ... ) to work const void_type Void {}; template struct function_sig_t {}; using function_t = function_sig_t<>; -struct upvalue_t { +struct upvalue { void* value; - upvalue_t(void* data) : value(data) {} + upvalue(void* data) : value(data) {} operator void*() const { return value; } }; -struct lightuserdata_t { +struct light_userdata { void* value; - lightuserdata_t(void* data) : value(data) {} + light_userdata(void* data) : value(data) {} operator void*() const { return value; } }; -struct userdata_t { +struct userdata { void* value; - userdata_t(void* data) : value(data) {} + userdata(void* data) : value(data) {} operator void*() const { return value; } }; @@ -74,10 +77,29 @@ enum class type : int { table | boolean | function | userdata | lightuserdata }; +inline int type_panic(lua_State* L, int index, type expected, type actual) { + return luaL_error(L, "stack index %d, expected %s, received %s", index, lua_typename(L, static_cast(expected)), lua_typename(L, static_cast(actual))); +} + +// Specify this function as the handler for lua::check if you know there's nothing wrong +inline int no_panic(lua_State*, int, type, type) { + return 0; +} + inline void type_error(lua_State* L, int expected, int actual) { luaL_error(L, "expected %s, received %s", lua_typename(L, expected), lua_typename(L, actual)); } +inline void type_error(lua_State* L, type expected, type actual) { + type_error(L, static_cast(expected), static_cast(actual)); +} + +inline void type_assert(lua_State* L, int index, type expected, type actual) { + if (expected != type::poly && expected != actual) { + type_panic(L, index, expected, actual); + } +} + inline void type_assert(lua_State* L, int index, type expected) { int actual = lua_type(L, index); if(expected != type::poly && static_cast(expected) != actual) { @@ -95,70 +117,82 @@ class table; class function; class object; -namespace detail { -template -inline type arithmetic(std::true_type) { - return type::number; -} +template +struct lua_type_of : std::integral_constant { -template -inline type arithmetic(std::false_type) { - return type::userdata; -} -} // detail +}; + +template <> +struct lua_type_of : std::integral_constant { + +}; + +template +struct lua_type_of : std::integral_constant { + +}; + +template <> +struct lua_type_of : std::integral_constant { + +}; + +template <> +struct lua_type_of : std::integral_constant { + +}; + +template <> +struct lua_type_of : std::integral_constant { + +}; + +template <> +struct lua_type_of : std::integral_constant { + +}; + +template <> +struct lua_type_of : std::integral_constant { + +}; + +template <> +struct lua_type_of : std::integral_constant { + +}; + +template <> +struct lua_type_of : std::integral_constant { + +}; + +template +struct lua_type_of : std::integral_constant { + +}; + +template +struct lua_type_of::value>::type> : std::integral_constant { + +}; template inline type type_of() { - return detail::arithmetic(std::is_arithmetic{}); + return lua_type_of>::value; } -template<> -inline type type_of
() { - return type::table; +inline type type_of(lua_State* L, int index) { + return static_cast(lua_type(L, index)); } -template<> -inline type type_of() { - return type::function; -} +// All enumerations are given and taken from lua +// as numbers as well +template +struct lua_type_of::value>::type> : std::integral_constant { -template<> -inline type type_of() { - return type::poly; -} +}; -template<> -inline type type_of() { - return type::string; -} - -template<> -inline type type_of() { - return type::string; -} - -template<> -inline type type_of() { - return type::nil; -} - -template<> -inline type type_of() { - return type::boolean; -} - -template<> -inline type type_of() { - return type::lightuserdata; -} - -template<> -inline type type_of() { - return type::userdata; -} - -inline bool operator==(nil_t, nil_t) { return true; } -inline bool operator!=(nil_t, nil_t) { return false; } } // sol #endif // SOL_TYPES_HPP diff --git a/sol/usertype.hpp b/sol/usertype.hpp index e2316029..f7ebea3f 100644 --- a/sol/usertype.hpp +++ b/sol/usertype.hpp @@ -104,7 +104,7 @@ private: template static void do_constructor(lua_State* L, T* obj, call_syntax syntax, int, types) { default_construct fx{}; - stack::get_call(L, 1 + static_cast(syntax), fx, types(), obj); + stack::call(L, -1 + static_cast(syntax), types(), types(), fx, obj); } static void match_constructor(lua_State*, T*, call_syntax, int) { @@ -143,7 +143,7 @@ private: struct destructor { static int destruct(lua_State* L) { - userdata_t udata = stack::get(L, 1); + userdata udata = stack::get(L, 1); T* obj = static_cast(udata.value); std::allocator alloc{}; alloc.destroy(obj); @@ -352,7 +352,7 @@ public: ptrmetafunctiontable.push_back({ nullptr, nullptr }); } - void push(lua_State* L) { + int push(lua_State* L) { // push pointer tables first, // but leave the regular T table on last // so it can be linked to a type for usage with `.new(...)` or `:new(...)` @@ -363,6 +363,7 @@ public: push_metatable(L, usertype_traits::metatable, metafunctions, metafunctiontable); set_global_deleter(L); + return 1; } private: @@ -394,10 +395,10 @@ private: int n = 0; for(auto& c : cont) { if(release) { - stack::push(L, c.release()); + stack::push(L, c.release()); } else { - stack::push(L, c.get()); + stack::push(L, c.get()); } ++n; } @@ -405,14 +406,11 @@ private: } }; -template -using userdata = typename detail::deprecate_type>::type; - namespace stack { template struct pusher> { - static void push(lua_State* L, usertype& user) { - user.push(L); + static int push(lua_State* L, usertype& user) { + return user.push(L); } }; } // stack diff --git a/tests.cpp b/tests.cpp index feec805f..ffa2ccab 100644 --- a/tests.cpp +++ b/tests.cpp @@ -582,7 +582,7 @@ TEST_CASE("tables/usertype", "Show that we can create classes from usertype and sol::object a = lua.get("a"); sol::object b = lua.get("b"); sol::object c = lua.get("c"); - REQUIRE((a.is())); + REQUIRE((a.is())); auto atype = a.get_type(); auto btype = b.get_type(); auto ctype = c.get_type(); @@ -650,7 +650,7 @@ TEST_CASE("tables/usertype utility", "Show internal management of classes regist sol::object a = lua.get("a"); sol::object b = lua.get("b"); sol::object c = lua.get("c"); - REQUIRE((a.is())); + REQUIRE((a.is())); auto atype = a.get_type(); auto btype = b.get_type(); auto ctype = c.get_type(); @@ -750,16 +750,16 @@ TEST_CASE("tables/issue-number-twenty-five", "Using pointers and references from return *this; } - int fun(int x) { - return x * 10; + int fun(int xa) { + return xa * 10; } }; sol::state lua; lua.open_libraries(sol::lib::base); lua.new_usertype("test", "set", &test::set, "get", &test::get, "pointer_get", &test::pget, "fun", &test::fun, "create_get", &test::create_get); - REQUIRE_NOTHROW(lua.script("x = test.new()\n" - "x:set():get()")); + REQUIRE_NOTHROW(lua.script("x = test.new()")); + REQUIRE_NOTHROW(lua.script("assert(x:set():get() == 10)")); REQUIRE_NOTHROW(lua.script("y = x:pointer_get()")); REQUIRE_NOTHROW(lua.script("y:set():get()")); REQUIRE_NOTHROW(lua.script("y:fun(10)"));