From ff7326ed96a927d98efb5b76308cf80ed8afe2e7 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Fri, 9 May 2014 10:48:55 -0400 Subject: [PATCH] We now have the ability to get a userdata that has been created C++ style out of lua Using `auto` and `decltype` in more places that MSVC can handle it -- using type traits in other places to avoid VC++'s chokes More flexibility, woo! --- sol/stack.hpp | 149 ++++++++++++++++++++++++++----------------------- sol/state.hpp | 3 +- sol/table.hpp | 22 +++----- sol/traits.hpp | 5 ++ sol/types.hpp | 10 ++++ tests.cpp | 4 +- 6 files changed, 106 insertions(+), 87 deletions(-) diff --git a/sol/stack.hpp b/sol/stack.hpp index 8f93c2a3..c4c9fc13 100644 --- a/sol/stack.hpp +++ b/sol/stack.hpp @@ -33,110 +33,112 @@ namespace sol { namespace stack { namespace detail { +inline nil_t get(types, lua_State* L, int index = -1) { + if (lua_isnil(L, index) == 0) + throw sol::sol_error("not nil"); + return nil_t{ }; +} + +inline lightuserdata_t get(types, lua_State* L, int index = -1) { + return{ lua_touserdata(L, lua_upvalueindex(index)) }; +} + +inline userdata_t get(types, lua_State* L, int index = -1) { + return{ lua_touserdata(L, index) }; +} + +inline std::string get(types, lua_State* L, int index = -1) { + std::string::size_type len; + auto str = lua_tolstring(L, index, &len); + return{ str, len }; +} + +inline const char* get(types, lua_State* L, int index = -1) { + return lua_tostring(L, index); +} + +inline type get(types, lua_State* L, int index = -1) { + return static_cast(lua_type(L, index)); +} + +template +inline T& get(types>, lua_State* L, int index = -1) { + userdata_t udata = get(types{}, L, index); + T* obj = static_cast(udata.value); + return *obj; +} + +template +inline T get(types, lua_State* L, int index = -1) { + return T(L, index); +} + template -inline T get_unsigned(lua_State* L, std::true_type, int index = -1) { +inline T get_unsigned(std::true_type, lua_State* L, int index = -1) { return lua_tounsigned(L, index); } template -inline T get_unsigned(lua_State* L, std::false_type, int index = -1) { +inline T get_unsigned(std::false_type, lua_State* L, int index = -1) { return static_cast(lua_tointeger(L, index)); } template -inline T get_arithmetic(lua_State* L, std::false_type, int index = -1) { +inline T get_arithmetic(std::false_type, lua_State* L, int index = -1) { // T is a floating point return static_cast(lua_tonumber(L, index)); } template -inline T get_arithmetic(lua_State* L, std::true_type, int index = -1) { +inline T get_arithmetic(std::true_type, lua_State* L, int index = -1) { // T is an integral - return get_unsigned(L, std::is_unsigned{}, index); + return get_unsigned(std::is_unsigned{}, L, index); } template -inline T get_nil(lua_State* L, std::true_type, int index = -1) { - if (lua_isnil(L, index) == 0) - throw sol::sol_error("not nil"); - return nil_t{}; -} - -template -inline T get_nil(lua_State* L, std::false_type, int index = -1) { - // T is a class type - return T(L, index); -} - -template -inline T get_helper(lua_State* L, std::true_type, int index = -1) { - return get_nil(L, std::is_same(), index); -} - -template -inline T get_helper(lua_State* L, std::false_type, int index = -1) { +inline T get_helper(std::true_type, lua_State* L, int index = -1) { // T is a fundamental type - return get_arithmetic(L, std::is_integral{}, index); + return get_arithmetic(std::is_integral{}, L, index); +} + +template<> +inline bool get_helper(std::true_type, lua_State* L, int index) { + return lua_toboolean(L, index) != 0; } template -inline void push_unsigned(lua_State* L, T x, std::true_type) { +inline auto get_helper(std::false_type, lua_State* L, int index = -1) { + // T is a class + return get(types(), L, index); +} + +template +inline void push_unsigned(std::true_type, lua_State* L, T x) { lua_pushunsigned(L, x); } template -inline void push_unsigned(lua_State* L, T x, std::false_type) { +inline void push_unsigned(std::false_type, lua_State* L, T x) { lua_pushinteger(L, x); } template -inline void push_arithmetic(lua_State* L, T x, std::true_type) { +inline void push_arithmetic(std::true_type, lua_State* L, T x) { // T is an integral type - push_unsigned(L, x, std::is_unsigned{}); + push_unsigned(std::is_unsigned{}, L, x); } template -inline void push_arithmetic(lua_State* L, T x, std::false_type) { +inline void push_arithmetic(std::false_type, lua_State* L, T x) { // T is an floating point type lua_pushnumber(L, x); } } // detail template -inline T get(lua_State* L, int index = -1) { - return detail::get_helper(L, std::is_class{}, index); -} - -template<> -inline bool get(lua_State* L, int index) { - return lua_toboolean(L, index) != 0; -} - -template<> -inline lightuserdata_t get(lua_State* L, int index) { - return {lua_touserdata(L, lua_upvalueindex(index))}; -} - -template<> -inline userdata_t get(lua_State* L, int index) { - return {lua_touserdata(L, index)}; -} - -template<> -inline std::string get(lua_State* L, int index) { - std::string::size_type len; - auto str = lua_tolstring(L, index, &len); - return { str, len }; -} - -template<> -inline const char* get(lua_State* L, int index) { - return lua_tostring(L, index); -} - -template<> -inline type get(lua_State* L, int index) { - return static_cast(lua_type(L, index)); +inline auto get(lua_State* L, int index = -1) +-> decltype(detail::get_helper(std::is_arithmetic{}, L, index)) { + return detail::get_helper(std::is_arithmetic{}, L, index); } template @@ -151,15 +153,16 @@ inline std::pair get_user(lua_State* L, int index = 1) { } template -inline T pop(lua_State* L) { - auto r = get(L); +auto pop(lua_State* L) +-> decltype(get(L)) { + auto&& r = get(L); lua_pop(L, 1); return r; } template inline EnableIf> push(lua_State* L, T arithmetic) { - detail::push_arithmetic(L, arithmetic, std::is_integral{}); + detail::push_arithmetic(std::is_integral{}, L, arithmetic); } inline void push(lua_State*, reference& ref) { @@ -245,7 +248,7 @@ inline auto ltr_get(lua_State*, int, F&& f, types, types<>, Vs&&... vs) } template inline auto ltr_get(lua_State* L, int index, F&& f, types t, types, Vs&&... vs) -> decltype(f(std::declval()...)) { - return ltr_get(L, index + 1, std::forward(f), t, types(), std::forward(vs)..., get(L, index)); + return ltr_get(L, index + 1, std::forward(f), t, types(), std::forward(vs)..., stack::get(L, index)); } template @@ -254,7 +257,7 @@ inline auto ltr_pop(lua_State*, F&& f, types, types<>, Vs&&... vs) -> d } 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)..., pop(L)); + return ltr_pop(L, std::forward(f), t, types(), std::forward(vs)..., stack::pop(L)); } template @@ -263,7 +266,7 @@ inline auto rtl_pop(lua_State*, F&& f, types, types<>, Vs&&... vs) -> d } 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(), pop(L), std::forward(vs)...); + return rtl_pop(L, std::forward(f), t, types(), stack::pop(L), std::forward(vs)...); } } // detail @@ -338,6 +341,12 @@ inline std::string dump_types(lua_State* L) { } return visual; } + +template +struct get_return { + typedef decltype(get(nullptr)) type; +}; + } // stack } // sol diff --git a/sol/state.hpp b/sol/state.hpp index 954991fa..d33cb807 100644 --- a/sol/state.hpp +++ b/sol/state.hpp @@ -129,7 +129,8 @@ public: } template - typename return_type::type get(Keys&&... keys) const { + auto get(Keys&&... keys) const + -> decltype(global.get(types(), std::forward(keys)...)) { return global.get(types(), std::forward(keys)...); } diff --git a/sol/table.hpp b/sol/table.hpp index 81b0eddd..0cde0b83 100644 --- a/sol/table.hpp +++ b/sol/table.hpp @@ -43,40 +43,34 @@ T* get_ptr(T* val) { class table : public reference { friend class state; template - T single_get(U&& key) const { + typename stack::get_return::type single_get(U&& key) const { push(); stack::push(state(), std::forward(key)); lua_gettable(state(), -2); type_assert(state(), -1, type_of()); - auto result = stack::pop(state()); + auto&& result = stack::pop(state()); lua_pop(state(), 1); return result; } template - typename std::tuple_element>::type element_get(types, Tup&& key) const { + typename std::tuple_element::type...>>::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; + return single_get(std::get(key)); } template - typename return_type::type tuple_get(types t, indices, Tup&& tup) const { + typename return_type::type...>::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 { + 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 get(types t, Keys&&... keys) const { + 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)...)); } @@ -87,7 +81,7 @@ public: } template - typename return_type::type get(Keys&&... keys) const { + typename return_type::type...>::type get(Keys&&... keys) const { return get(types(), std::forward(keys)...); } diff --git a/sol/traits.hpp b/sol/traits.hpp index 980acf25..acf8d55d 100644 --- a/sol/traits.hpp +++ b/sol/traits.hpp @@ -53,6 +53,11 @@ struct return_type<> : types<>{ typedef void type; }; +template class Templ> +struct is_specialization_of : std::false_type { }; +template class Templ> +struct is_specialization_of, Templ> : std::true_type { }; + template using Bool = std::integral_constant; diff --git a/sol/types.hpp b/sol/types.hpp index 476a8708..7c448910 100644 --- a/sol/types.hpp +++ b/sol/types.hpp @@ -92,6 +92,16 @@ inline type arithmetic(std::true_type) { template inline type arithmetic(std::false_type) { + return usertype(is_specialization_of{}); +} + +template +inline type usertype(std::true_type) { + return type::userdata; +} + +template +inline type usertype(std::false_type) { return type::none; } } // detail diff --git a/tests.cpp b/tests.cpp index 0c76980c..89de8659 100644 --- a/tests.cpp +++ b/tests.cpp @@ -254,7 +254,7 @@ TEST_CASE("tables/functions_variables", "Check if tables and function calls work std::cout << "stateless lambda()" << std::endl; return "test"; } - ); + ); REQUIRE_NOTHROW(run_script(lua)); lua.get("os").set_function("fun", &free_function); @@ -272,7 +272,7 @@ TEST_CASE("tables/functions_variables", "Check if tables and function calls work std::cout << "stateless lambda()" << std::endl; return "test"; } - ); + ); REQUIRE_NOTHROW(run_script(lua)); // r-value, cannot optimise