From ee13a7812f7b43cb6f9a044a57892b9a40d1c840 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Sat, 9 Mar 2019 20:57:49 -0500 Subject: [PATCH] Full fixes for everything. --- examples/CMakeLists.txt | 1 + examples/source/any_return.cpp | 2 + examples/source/customization_multiple.cpp | 6 +- include/sol/forward.hpp | 8 + include/sol/proxy.hpp | 37 +- include/sol/stack_check_get_qualified.hpp | 37 +- include/sol/stack_check_get_unqualified.hpp | 164 +- include/sol/stack_check_qualified.hpp | 97 +- include/sol/stack_check_unqualified.hpp | 732 +++---- include/sol/stack_core.hpp | 142 +- include/sol/stack_get_qualified.hpp | 72 - include/sol/stack_get_unqualified.hpp | 227 +- include/sol/stack_push.hpp | 388 ++-- include/sol/state_handling.hpp | 6 +- include/sol/traits.hpp | 119 +- include/sol/types.hpp | 65 +- include/sol/usertype_container.hpp | 13 +- include/sol/usertype_container_launch.hpp | 34 +- single/include/sol/forward.hpp | 12 +- single/include/sol/sol.hpp | 2145 +++++++++---------- 20 files changed, 1960 insertions(+), 2347 deletions(-) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index f2f61fa7..e366a0bf 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -85,6 +85,7 @@ function (MAKE_EXAMPLE example_source_file example_suffix target_sol) else() target_compile_options(${example_name} PRIVATE -std=c++1z + -ftemplate-backtrace-limit=0 -Wall -Wpedantic -Werror -pedantic -pedantic-errors -Wno-noexcept-type -Wno-unknown-warning -Wno-unknown-warning-option) diff --git a/examples/source/any_return.cpp b/examples/source/any_return.cpp index 222e6731..04e98f5c 100644 --- a/examples/source/any_return.cpp +++ b/examples/source/any_return.cpp @@ -44,4 +44,6 @@ int main() { std::cout << "result2: " << result2 << std::endl; std::cout << "result3: " << result3 << std::endl; std::cout << std::endl; + + return 0; } \ No newline at end of file diff --git a/examples/source/customization_multiple.cpp b/examples/source/customization_multiple.cpp index 9a8d1321..796349e9 100644 --- a/examples/source/customization_multiple.cpp +++ b/examples/source/customization_multiple.cpp @@ -10,7 +10,7 @@ struct two_things { }; template -bool check(sol::types, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking) { +bool sol_lua_check(sol::types, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking) { // indices can be negative to count backwards from the top of the stack, // rather than the bottom up // to deal with this, we adjust the index to @@ -22,7 +22,7 @@ bool check(sol::types, lua_State* L, int index, Handler&& handler, s return success; } -two_things get(sol::types, lua_State* L, int index, sol::stack::record& tracking) { +two_things sol_lua_get(sol::types, lua_State* L, int index, sol::stack::record& tracking) { int absolute_index = lua_absindex(L, index); // Get the first element int a = sol::stack::get(L, absolute_index); @@ -34,7 +34,7 @@ two_things get(sol::types, lua_State* L, int index, sol::stack::reco return two_things{ a, b }; } -int push(sol::types, lua_State* L, const two_things& things) { +int sol_lua_push(sol::types, lua_State* L, const two_things& things) { int amount = sol::stack::push(L, things.a); // amount will be 1: int pushes 1 item amount += sol::stack::push(L, things.b); diff --git a/include/sol/forward.hpp b/include/sol/forward.hpp index cc3ed05f..4829fce5 100644 --- a/include/sol/forward.hpp +++ b/include/sol/forward.hpp @@ -29,6 +29,14 @@ #include #include +#if defined(SOL_USING_CXX_LUA) && SOL_USING_CXX_LUA +struct lua_State; +#else +extern "C" { + struct lua_State; +} +#endif // C++ Mangling for Lua vs. Not + namespace sol { template diff --git a/include/sol/proxy.hpp b/include/sol/proxy.hpp index 3da63b2b..7b3f2aa1 100644 --- a/include/sol/proxy.hpp +++ b/include/sol/proxy.hpp @@ -46,14 +46,14 @@ namespace sol { } auto setup_table(std::true_type) { - auto p = stack::probe_get_field, global_table>::value>(lua_state(), key, tbl.stack_index()); + auto p = stack::probe_get_field, global_table>>(lua_state(), key, tbl.stack_index()); lua_pop(lua_state(), p.levels); return p; } bool is_valid(std::false_type) { auto pp = stack::push_pop(tbl); - auto p = stack::probe_get_field, global_table>::value>(lua_state(), key, lua_gettop(lua_state())); + auto p = stack::probe_get_field, global_table>>(lua_state(), key, lua_gettop(lua_state())); lua_pop(lua_state(), p.levels); return p; } @@ -69,7 +69,7 @@ namespace sol { template proxy& set(T&& item) { - tuple_set(std::make_index_sequence>::value>(), std::forward(item)); + tuple_set(std::make_index_sequence>>(), std::forward(item)); return *this; } @@ -79,14 +79,15 @@ namespace sol { return *this; } - template >>, meta::is_callable>> = meta::enabler> + template proxy& operator=(U&& other) { - return set_function(std::forward(other)); - } - - template >>, meta::is_callable>> = meta::enabler> - proxy& operator=(U&& other) { - return set(std::forward(other)); + using uTu = meta::unwrap_unqualified_t; + if constexpr (!is_lua_reference_or_proxy_v && meta::is_callable_v) { + return set_function(std::forward(other)); + } + else { + return set(std::forward(other)); + } } template @@ -193,26 +194,26 @@ namespace sol { template inline bool operator==(T&& left, const proxy& right) { - typedef decltype(stack::get(nullptr, 0)) U; - return right.template get>() == left; + using G = decltype(stack::get(nullptr, 0)); + return right.template get>() == left; } template inline bool operator==(const proxy& right, T&& left) { - typedef decltype(stack::get(nullptr, 0)) U; - return right.template get>() == left; + using G = decltype(stack::get(nullptr, 0)); + return right.template get>() == left; } template inline bool operator!=(T&& left, const proxy& right) { - typedef decltype(stack::get(nullptr, 0)) U; - return right.template get>() != left; + using G = decltype(stack::get(nullptr, 0)); + return right.template get>() != left; } template inline bool operator!=(const proxy& right, T&& left) { - typedef decltype(stack::get(nullptr, 0)) U; - return right.template get>() != left; + using G = decltype(stack::get(nullptr, 0)); + return right.template get>() != left; } template diff --git a/include/sol/stack_check_get_qualified.hpp b/include/sol/stack_check_get_qualified.hpp index 5f9866a0..c4fec817 100644 --- a/include/sol/stack_check_get_qualified.hpp +++ b/include/sol/stack_check_get_qualified.hpp @@ -35,28 +35,25 @@ namespace sol { namespace stack { template static optional get(lua_State* L, int index, Handler&& handler, record& tracking) { - if (!check(L, index, std::forward(handler))) { - tracking.use(static_cast(!lua_isnone(L, index))); - return nullopt; + if constexpr (is_lua_reference_v) { + // actually check if it's none here, otherwise + // we'll have a none object inside an optional! + bool success = lua_isnoneornil(L, index) == 0 && stack::check(L, index, no_panic); + if (!success) { + // expected type, actual type + tracking.use(static_cast(success)); + handler(L, index, type::poly, type_of(L, index), ""); + return nullopt; + } + return stack_detail::unchecked_get(L, index, tracking); } - return stack_detail::unchecked_get(L, index, tracking); - } - }; - - template - struct qualified_check_getter::value>> { - template - static optional get(lua_State* L, int index, Handler&& handler, record& tracking) { - // actually check if it's none here, otherwise - // we'll have a none object inside an optional! - bool success = lua_isnoneornil(L, index) == 0 && stack::check(L, index, no_panic); - if (!success) { - // expected type, actual type - tracking.use(static_cast(success)); - handler(L, index, type::poly, type_of(L, index), ""); - return nullopt; + else { + if (!check(L, index, std::forward(handler))) { + tracking.use(static_cast(!lua_isnone(L, index))); + return nullopt; + } + return stack_detail::unchecked_get(L, index, tracking); } - return stack_detail::unchecked_get(L, index, tracking); } }; diff --git a/include/sol/stack_check_get_unqualified.hpp b/include/sol/stack_check_get_unqualified.hpp index e36c35b1..124ec31a 100644 --- a/include/sol/stack_check_get_unqualified.hpp +++ b/include/sol/stack_check_get_unqualified.hpp @@ -45,100 +45,94 @@ namespace stack { template static optional get(lua_State* L, int index, Handler&& handler, record& tracking) { - if (!unqualified_check(L, index, std::forward(handler))) { - tracking.use(static_cast(!lua_isnone(L, index))); - return nullopt; - } - return stack_detail::unchecked_unqualified_get(L, index, tracking); - } - }; - - template - struct unqualified_check_getter::value>> { - template - static optional get(lua_State* L, int index, Handler&& handler, record& tracking) { - // actually check if it's none here, otherwise - // we'll have a none object inside an optional! - bool success = lua_isnoneornil(L, index) == 0 && stack::check(L, index, no_panic); - if (!success) { - // expected type, actual type - tracking.use(static_cast(success)); - handler(L, index, type::poly, type_of(L, index), ""); - return nullopt; - } - return stack_detail::unchecked_get(L, index, tracking); - } - }; - - template - struct unqualified_check_getter::value && lua_type_of::value == type::number>> { - template - static optional get(lua_State* L, int index, Handler&& handler, record& tracking) { -#if SOL_LUA_VERSION >= 503 - if (lua_isinteger(L, index) != 0) { - tracking.use(1); - return static_cast(lua_tointeger(L, index)); - } -#endif - int isnum = 0; - const lua_Number value = lua_tonumberx(L, index, &isnum); - if (isnum != 0) { -#if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) - const auto integer_value = llround(value); - if (static_cast(integer_value) == value) { - tracking.use(1); - return static_cast(integer_value); + if constexpr (!meta::meta_detail::is_adl_sol_lua_check_v && !meta::meta_detail::is_adl_sol_lua_get_v) { + if constexpr (is_lua_reference_v) { + // actually check if it's none here, otherwise + // we'll have a none object inside an optional! + bool success = lua_isnoneornil(L, index) == 0 && stack::check(L, index, no_panic); + if (!success) { + // expected type, actual type + tracking.use(static_cast(success)); + handler(L, index, type::poly, type_of(L, index), ""); + return nullopt; + } + return stack_detail::unchecked_get(L, index, tracking); + } + else if constexpr (std::is_same_v) { + return lua_toboolean(L, index) != 0; + } + else if constexpr (std::is_integral_v && !std::is_same_v) { + #if SOL_LUA_VERSION >= 503 + if (lua_isinteger(L, index) != 0) { + tracking.use(1); + return static_cast(lua_tointeger(L, index)); + } + #endif + int isnum = 0; + const lua_Number value = lua_tonumberx(L, index, &isnum); + if (isnum != 0) { + #if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) + const auto integer_value = llround(value); + if (static_cast(integer_value) == value) { + tracking.use(1); + return static_cast(integer_value); + } + #else + tracking.use(1); + return static_cast(value); + #endif + } + const type t = type_of(L, index); + tracking.use(static_cast(t != type::none)); + handler(L, index, type::number, t, "not an integer"); + return nullopt; + } + else if constexpr(std::is_floating_point_v) { + int isnum = 0; + lua_Number value = lua_tonumberx(L, index, &isnum); + if (isnum == 0) { + type t = type_of(L, index); + tracking.use(static_cast(t != type::none)); + handler(L, index, type::number, t, "not a valid floating point number"); + return nullopt; + } + tracking.use(1); + return static_cast(value); + } + else if constexpr (std::is_enum_v && !meta::any_same_v) { + int isnum = 0; + lua_Integer value = lua_tointegerx(L, index, &isnum); + if (isnum == 0) { + type t = type_of(L, index); + tracking.use(static_cast(t != type::none)); + handler(L, index, type::number, t, "not a valid enumeration value"); + return nullopt; + } + tracking.use(1); + return static_cast(value); + } + else { + if (!unqualified_check(L, index, std::forward(handler))) { + tracking.use(static_cast(!lua_isnone(L, index))); + return nullopt; + } + return stack_detail::unchecked_unqualified_get(L, index, tracking); } -#else - tracking.use(1); - return static_cast(value); -#endif } - const type t = type_of(L, index); - tracking.use(static_cast(t != type::none)); - handler(L, index, type::number, t, "not an integer"); - return nullopt; - } - }; - - template - struct unqualified_check_getter::value && !meta::any_same::value>> { - template - static optional get(lua_State* L, int index, Handler&& handler, record& tracking) { - int isnum = 0; - lua_Integer value = lua_tointegerx(L, index, &isnum); - if (isnum == 0) { - type t = type_of(L, index); - tracking.use(static_cast(t != type::none)); - handler(L, index, type::number, t, "not a valid enumeration value"); - return nullopt; + else { + if (!unqualified_check(L, index, std::forward(handler))) { + tracking.use(static_cast(!lua_isnone(L, index))); + return nullopt; + } + return stack_detail::unchecked_unqualified_get(L, index, tracking); } - tracking.use(1); - return static_cast(value); - } - }; - - template - struct unqualified_check_getter::value>> { - template - static optional get(lua_State* L, int index, Handler&& handler, record& tracking) { - int isnum = 0; - lua_Number value = lua_tonumberx(L, index, &isnum); - if (isnum == 0) { - type t = type_of(L, index); - tracking.use(static_cast(t != type::none)); - handler(L, index, type::number, t, "not a valid floating point number"); - return nullopt; - } - tracking.use(1); - return static_cast(value); } }; template struct unqualified_getter> { static decltype(auto) get(lua_State* L, int index, record& tracking) { - return check_get(L, index, no_panic, tracking); + return stack::unqualified_check_get(L, index, no_panic, tracking); } }; diff --git a/include/sol/stack_check_qualified.hpp b/include/sol/stack_check_qualified.hpp index 9aa28f00..0d6090ab 100644 --- a/include/sol/stack_check_qualified.hpp +++ b/include/sol/stack_check_qualified.hpp @@ -29,64 +29,55 @@ namespace sol { namespace stack { - template - struct qualified_checker::value - && !std::is_reference::value - >> { - typedef unique_usertype_traits> u_traits; - typedef typename u_traits::type T; - typedef typename u_traits::template rebind_base rebind_t; - + template + struct qualified_checker { template - static bool check(std::false_type, lua_State* L, int index, Handler&& handler, record& tracking) { - return stack::unqualified_check(L, index, std::forward(handler), tracking); - } - - template - static bool check(std::true_type, lua_State* L, int index, Handler&& handler, record& tracking) { - // we have a unique pointer type that can be - // rebound to a base/derived type - const type indextype = type_of(L, index); - tracking.use(1); - if (indextype != type::userdata) { - handler(L, index, type::userdata, indextype, "value is not a userdata"); - return false; - } - void* memory = lua_touserdata(L, index); - memory = detail::align_usertype_unique_destructor(memory); - detail::unique_destructor& pdx = *static_cast(memory); - if (&detail::usertype_unique_alloc_destroy == pdx) { - return true; - } - if constexpr (derive::value) { - memory = detail::align_usertype_unique_tag(memory); - detail::unique_tag& ic = *reinterpret_cast(memory); - string_view ti = usertype_traits::qualified_name(); - string_view rebind_ti = usertype_traits::qualified_name(); - if (ic(nullptr, nullptr, ti, rebind_ti) != 0) { - return true; + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + if constexpr (!std::is_reference_v && is_unique_usertype_v) { + using u_traits = unique_usertype_traits>; + using T = typename u_traits::type; + using rebind_t = typename u_traits::template rebind_base; + if constexpr (!std::is_void_v) { + // we have a unique pointer type that can be + // rebound to a base/derived type + const type indextype = type_of(L, index); + tracking.use(1); + if (indextype != type::userdata) { + handler(L, index, type::userdata, indextype, "value is not a userdata"); + return false; + } + void* memory = lua_touserdata(L, index); + memory = detail::align_usertype_unique_destructor(memory); + detail::unique_destructor& pdx = *static_cast(memory); + if (&detail::usertype_unique_alloc_destroy == pdx) { + return true; + } + if constexpr (derive::value) { + memory = detail::align_usertype_unique_tag(memory); + detail::unique_tag& ic = *reinterpret_cast(memory); + string_view ti = usertype_traits::qualified_name(); + string_view rebind_ti = usertype_traits::qualified_name(); + if (ic(nullptr, nullptr, ti, rebind_ti) != 0) { + return true; + } + } + handler(L, index, type::userdata, indextype, "value is a userdata but is not the correct unique usertype"); + return false; + } + else { + return stack::unqualified_check(L, index, std::forward(handler), tracking); } } - handler(L, index, type::userdata, indextype, "value is a userdata but is not the correct unique usertype"); - return false; - } - - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - return check(meta::neg>(), L, index, std::forward(handler), tracking); - } - }; - - template - struct qualified_checker>::value && !std::is_reference::value>> { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - if (type_of(L, index) == type::userdata) { - return stack::unqualified_check(L, index, std::forward(handler), tracking); + else if constexpr (!std::is_reference_v && is_container_v) { + if (type_of(L, index) == type::userdata) { + return stack::unqualified_check(L, index, std::forward(handler), tracking); + } + else { + return stack::unqualified_check>(L, index, std::forward(handler), tracking); + } } else { - return stack::unqualified_check>(L, index, std::forward(handler), tracking); + return stack::unqualified_check(L, index, std::forward(handler), tracking); } } }; diff --git a/include/sol/stack_check_unqualified.hpp b/include/sol/stack_check_unqualified.hpp index e77a3d6f..3386aaa1 100644 --- a/include/sol/stack_check_unqualified.hpp +++ b/include/sol/stack_check_unqualified.hpp @@ -90,367 +90,317 @@ namespace sol { namespace stack { struct unqualified_checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - tracking.use(1); - const type indextype = type_of(L, index); - bool success = expected == indextype; - if (!success) { - // expected type, actual type, message - handler(L, index, expected, indextype, ""); - } - return success; - } - }; - - template - struct qualified_checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - return stack::unqualified_check(L, index, std::forward(handler), tracking); - } - }; - - template - struct unqualified_checker::value>> { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - tracking.use(1); -#if SOL_LUA_VERSION >= 503 -#if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS - int isnum = 0; - lua_tointegerx(L, index, &isnum); - const bool success = isnum != 0; - if (!success) { - // expected type, actual type - handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string"); - } -#elif (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) - // this check is precise, does not convert - if (lua_isinteger(L, index) == 1) { - return true; - } - const bool success = false; - if (!success) { - // expected type, actual type - handler(L, index, type::number, type_of(L, index), "not a numeric (integral) type"); - } -#else - type t = type_of(L, index); - const bool success = t == type::number; -#endif // If numbers are enabled, use the imprecise check - if (!success) { - // expected type, actual type - handler(L, index, type::number, type_of(L, index), "not a numeric type"); - } - return success; -#else -#if !defined(SOL_STRINGS_ARE_NUMBERS) || !SOL_STRINGS_ARE_NUMBERS - // must pre-check, because it will convert - type t = type_of(L, index); - if (t != type::number) { - // expected type, actual type - handler(L, index, type::number, t, "not a numeric type"); - return false; - } -#endif // Do not allow strings to be numbers -#if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) - int isnum = 0; - const lua_Number v = lua_tonumberx(L, index, &isnum); - const bool success = isnum != 0 && static_cast(llround(v)) == v; -#else - const bool success = true; -#endif // Safe numerics and number precision checking - if (!success) { - // expected type, actual type -#if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS - handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string"); -#else - handler(L, index, type::number, t, "not a numeric type"); -#endif - } - return success; -#endif // Lua Version 5.3 versus others - } - }; - - template - struct unqualified_checker::value>> { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - tracking.use(1); -#if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS - bool success = lua_isnumber(L, index) == 1; - if (!success) { - // expected type, actual type - handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string"); - } - return success; -#else - type t = type_of(L, index); - bool success = t == type::number; - if (!success) { - // expected type, actual type - handler(L, index, type::number, t, "not a numeric type"); - } - return success; -#endif // Strings are Numbers - } - }; - - template - struct unqualified_checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - bool success = lua_isnil(L, index); - if (success) { + if constexpr (std::is_same_v) { tracking.use(1); + bool success = lua_isboolean(L, index) == 1; + if (!success) { + // expected type, actual type + handler(L, index, expected, type_of(L, index), ""); + } return success; } - tracking.use(0); - success = lua_isnone(L, index); - if (!success) { - // expected type, actual type - handler(L, index, expected, type_of(L, index), ""); + else if constexpr (std::is_integral_v && !std::is_same_v) { + tracking.use(1); +#if SOL_LUA_VERSION >= 503 +#if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS + int isnum = 0; + lua_tointegerx(L, index, &isnum); + const bool success = isnum != 0; + if (!success) { + // expected type, actual type + handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string"); + } +#elif (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) + // this check is precise, does not convert + if (lua_isinteger(L, index) == 1) { + return true; + } + const bool success = false; + if (!success) { + // expected type, actual type + handler(L, index, type::number, type_of(L, index), "not a numeric (integral) type"); + } +#else + type t = type_of(L, index); + const bool success = t == type::number; +#endif // If numbers are enabled, use the imprecise check + if (!success) { + // expected type, actual type + handler(L, index, type::number, type_of(L, index), "not a numeric type"); + } + return success; +#else +#if !defined(SOL_STRINGS_ARE_NUMBERS) || !SOL_STRINGS_ARE_NUMBERS + // must pre-check, because it will convert + type t = type_of(L, index); + if (t != type::number) { + // expected type, actual type + handler(L, index, type::number, t, "not a numeric type"); + return false; + } +#endif // Do not allow strings to be numbers +#if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) + int isnum = 0; + const lua_Number v = lua_tonumberx(L, index, &isnum); + const bool success = isnum != 0 && static_cast(llround(v)) == v; +#else + const bool success = true; +#endif // Safe numerics and number precision checking + if (!success) { + // expected type, actual type +#if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS + handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string"); +#else + handler(L, index, type::number, t, "not a numeric type"); +#endif + } + return success; +#endif // Lua Version 5.3 versus others } - return success; - } - }; - - template - struct unqualified_checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - return !stack::unqualified_check(L, index, std::forward(handler), tracking); - } - }; - - template - struct unqualified_checker : unqualified_checker {}; - - template - struct unqualified_checker { - template - static bool check(lua_State*, int, Handler&&, record& tracking) { - tracking.use(0); - return true; - } - }; - - template - struct unqualified_checker { - template - static bool check(lua_State*, int, Handler&&, record& tracking) { - tracking.use(0); - return true; - } - }; - - template - struct unqualified_checker { - template - static bool check(lua_State*, int, Handler&&, record& tracking) { - tracking.use(0); - return true; - } - }; - - template - struct unqualified_checker { - template - static bool check(lua_State*, int, Handler&&, record& tracking) { - tracking.use(0); - return true; - } - }; - - template - struct unqualified_checker { - template - static bool check(lua_State*, int, Handler&&, record& tracking) { - tracking.use(0); - return true; - } - }; - - template - struct unqualified_checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - tracking.use(1); - bool success = is_lua_reference::value || !lua_isnone(L, index); - if (!success) { - // expected type, actual type - handler(L, index, type::poly, type_of(L, index), ""); + else if constexpr (std::is_floating_point_v) { + tracking.use(1); +#if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS + bool success = lua_isnumber(L, index) == 1; + if (!success) { + // expected type, actual type + handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string"); + } + return success; +#else + type t = type_of(L, index); + bool success = t == type::number; + if (!success) { + // expected type, actual type + handler(L, index, type::number, t, "not a numeric type"); + } + return success; +#endif // Strings are Numbers } - return success; - } - }; - - template - struct unqualified_checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - tracking.use(1); - type t = type_of(L, index); - bool success = t == type::userdata || t == type::lightuserdata; - if (!success) { - // expected type, actual type - handler(L, index, type::lightuserdata, t, ""); - } - return success; - } - }; - - template - struct unqualified_checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - tracking.use(1); - type t = type_of(L, index); - bool success = t == type::userdata; - if (!success) { - // expected type, actual type - handler(L, index, type::userdata, t, ""); - } - return success; - } - }; - - template - struct unqualified_checker, type::userdata, C> { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - return stack::check(L, index, std::forward(handler), tracking); - } - }; - - template - struct unqualified_checker, type::userdata, C> : unqualified_checker, type::lightuserdata, C> {}; - - template - struct unqualified_checker, type::userdata, C> : unqualified_checker::value, C> {}; - - template - struct unqualified_checker : stack_detail::basic_check {}; - template - struct unqualified_checker, type::function, C> : unqualified_checker {}; - template - struct unqualified_checker : unqualified_checker {}; - - template - struct unqualified_checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - tracking.use(1); - type t = type_of(L, index); - if (t == type::lua_nil || t == type::none || t == type::function) { - // allow for lua_nil to be returned + else if constexpr(meta::any_same_v) { + tracking.use(0); return true; } - if (t != type::userdata && t != type::table) { - handler(L, index, type::function, t, "must be a function or table or a userdata"); - return false; - } - // Do advanced check for call-style userdata? - static const auto& callkey = to_string(meta_function::call); - if (lua_getmetatable(L, index) == 0) { - // No metatable, no __call key possible - handler(L, index, type::function, t, "value is not a function and does not have overriden metatable"); - return false; - } - if (lua_isnoneornil(L, -1)) { + else if constexpr (is_unique_usertype_v) { + using proper_T = typename unique_usertype_traits::type; + const type indextype = type_of(L, index); + tracking.use(1); + if (indextype != type::userdata) { + handler(L, index, type::userdata, indextype, "value is not a userdata"); + return false; + } + if (lua_getmetatable(L, index) == 0) { + return true; + } + int metatableindex = lua_gettop(L); + if (stack_detail::check_metatable>(L, metatableindex)) { + void* memory = lua_touserdata(L, index); + memory = detail::align_usertype_unique_destructor(memory); + detail::unique_destructor& pdx = *static_cast(memory); + bool success = &detail::usertype_unique_alloc_destroy == pdx; + if (!success) { + memory = detail::align_usertype_unique_tag(memory); +#if 0 + // New version +#else + const char*& name_tag = *static_cast(memory); + success = usertype_traits::qualified_name() == name_tag; +#endif + if (!success) { + handler(L, index, type::userdata, indextype, "value is a userdata but is not the correct unique usertype"); + } + } + return success; + } lua_pop(L, 1); - handler(L, index, type::function, t, "value is not a function and does not have valid metatable"); + handler(L, index, type::userdata, indextype, "unrecognized userdata (not pushed by sol?)"); return false; } - lua_getfield(L, -1, &callkey[0]); - if (lua_isnoneornil(L, -1)) { - lua_pop(L, 2); - handler(L, index, type::function, t, "value's metatable does not have __call overridden in metatable, cannot call this type"); - return false; + else if constexpr (meta::any_same_v) { + bool success = lua_isnil(L, index); + if (success) { + tracking.use(1); + return success; + } + tracking.use(0); + success = lua_isnone(L, index); + if (!success) { + // expected type, actual type + handler(L, index, expected, type_of(L, index), ""); + } + return success; + } + else if constexpr (std::is_same_v) { + tracking.use(1); + type t = type_of(L, index); + if (t == type::table || t == type::none || t == type::lua_nil || t == type::userdata) { + return true; + } + handler(L, index, type::table, t, "value cannot not have a valid environment"); + return true; + } + else if constexpr (std::is_same_v) { + return !stack::unqualified_check(L, index, std::forward(handler), tracking); + } + else if constexpr(meta::is_specialization_of_v) { + tracking.use(1); + if (lua_getmetatable(L, index) == 0) { + return true; + } + type t = type_of(L, -1); + if (t == type::table || t == type::none || t == type::lua_nil) { + lua_pop(L, 1); + return true; + } + if (t != type::userdata) { + lua_pop(L, 1); + handler(L, index, type::table, t, "value does not have a valid metatable"); + return false; + } + return true; + } + else if constexpr (std::is_same_v) { + tracking.use(1); + if (lua_getmetatable(L, index) == 0) { + return true; + } + type t = type_of(L, -1); + if (t == type::table || t == type::none || t == type::lua_nil) { + lua_pop(L, 1); + return true; + } + if (t != type::userdata) { + lua_pop(L, 1); + handler(L, index, expected, t, "value does not have a valid metatable"); + return false; + } + return true; + } + else if constexpr (expected == type::userdata) { + if constexpr (meta::any_same_v || meta::is_specialization_of_v) { + tracking.use(1); + type t = type_of(L, index); + bool success = t == type::userdata; + if (!success) { + // expected type, actual type + handler(L, index, type::userdata, t, ""); + } + return success; + } + else if constexpr (meta::is_specialization_of_v) { + unqualified_checker c; + (void)c; + return c.check(L, index, std::forward(handler), tracking); + } + else { + if constexpr (std::is_pointer_v) { + return check_usertype(L, index, std::forward(handler), tracking); + } + else if constexpr (meta::is_specialization_of_v) { + using T_internal = typename T::type; + return stack::check(L, index, std::forward(handler), tracking); + } + else { + return check_usertype(L, index, std::forward(handler), tracking); + } + } + } + else if constexpr (expected == type::poly) { + tracking.use(1); + bool success = is_lua_reference_v || !lua_isnone(L, index); + if (!success) { + // expected type, actual type + handler(L, index, type::poly, type_of(L, index), ""); + } + return success; + } + else if constexpr (expected == type::lightuserdata) { + tracking.use(1); + type t = type_of(L, index); + bool success = t == type::userdata || t == type::lightuserdata; + if (!success) { + // expected type, actual type + handler(L, index, type::lightuserdata, t, ""); + } + return success; + } + else if constexpr (expected == type::function) { + if constexpr (meta::any_same_v, c_closure>) { + tracking.use(1); + bool success = lua_iscfunction(L, index) == 1; + if (!success) { + // expected type, actual type + handler(L, index, expected, type_of(L, index), ""); + } + return success; + } + else { + tracking.use(1); + type t = type_of(L, index); + if (t == type::lua_nil || t == type::none || t == type::function) { + // allow for lua_nil to be returned + return true; + } + if (t != type::userdata && t != type::table) { + handler(L, index, type::function, t, "must be a function or table or a userdata"); + return false; + } + // Do advanced check for call-style userdata? + static const auto& callkey = to_string(meta_function::call); + if (lua_getmetatable(L, index) == 0) { + // No metatable, no __call key possible + handler(L, index, type::function, t, "value is not a function and does not have overriden metatable"); + return false; + } + if (lua_isnoneornil(L, -1)) { + lua_pop(L, 1); + handler(L, index, type::function, t, "value is not a function and does not have valid metatable"); + return false; + } + lua_getfield(L, -1, &callkey[0]); + if (lua_isnoneornil(L, -1)) { + lua_pop(L, 2); + handler(L, index, type::function, t, "value's metatable does not have __call overridden in metatable, cannot call this type"); + return false; + } + // has call, is definitely a function + lua_pop(L, 2); + return true; + } + } + else if constexpr (expected == type::table) { + tracking.use(1); + type t = type_of(L, index); + if (t == type::table) { + return true; + } + if (t != type::userdata) { + handler(L, index, type::table, t, "value is not a table or a userdata that can behave like one"); + return false; + } + return true; + } + else { + tracking.use(1); + const type indextype = type_of(L, index); + bool success = expected == indextype; + if (!success) { + // expected type, actual type, message + handler(L, index, expected, indextype, ""); + } + return success; } - // has call, is definitely a function - lua_pop(L, 2); - return true; } }; - template - struct unqualified_checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - tracking.use(1); - type t = type_of(L, index); - if (t == type::table) { - return true; - } - if (t != type::userdata) { - handler(L, index, type::table, t, "value is not a table or a userdata that can behave like one"); - return false; - } - return true; - } - }; + template + struct unqualified_checker, type::userdata> : unqualified_checker> {}; - template - struct unqualified_checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - tracking.use(1); - if (lua_getmetatable(L, index) == 0) { - return true; - } - type t = type_of(L, -1); - if (t == type::table || t == type::none || t == type::lua_nil) { - lua_pop(L, 1); - return true; - } - if (t != type::userdata) { - lua_pop(L, 1); - handler(L, index, expected, t, "value does not have a valid metatable"); - return false; - } - return true; - } - }; - - template - struct unqualified_checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - tracking.use(1); - type t = type_of(L, index); - if (t == type::table || t == type::none || t == type::lua_nil || t == type::userdata) { - return true; - } - handler(L, index, type::table, t, "value cannot not have a valid environment"); - return true; - } - }; - - template - struct unqualified_checker, type::poly, C> { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - tracking.use(1); - if (lua_getmetatable(L, index) == 0) { - return true; - } - type t = type_of(L, -1); - if (t == type::table || t == type::none || t == type::lua_nil) { - lua_pop(L, 1); - return true; - } - if (t != type::userdata) { - lua_pop(L, 1); - handler(L, index, type::table, t, "value does not have a valid metatable"); - return false; - } - return true; - } - }; - - template - struct unqualified_checker, type::userdata, C> { + template + struct unqualified_checker, type::userdata> { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { const type indextype = type_of(L, index); @@ -507,8 +457,8 @@ namespace sol { namespace stack { } }; - template - struct unqualified_checker, type::userdata, C> { + template + struct unqualified_checker, type::userdata> { template static bool check(lua_State* L, int index, type indextype, Handler&& handler, record& tracking) { if (indextype == type::lua_nil) { @@ -525,88 +475,24 @@ namespace sol { namespace stack { } }; - template - struct unqualified_checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - return check_usertype(L, index, std::forward(handler), tracking); - } - }; - - template - struct unqualified_checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - return check_usertype(L, index, std::forward(handler), tracking); - } - }; - - template - struct unqualified_checker::value>> { - typedef typename unique_usertype_traits::type T; - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - const type indextype = type_of(L, index); - tracking.use(1); - if (indextype != type::userdata) { - handler(L, index, type::userdata, indextype, "value is not a userdata"); - return false; - } - if (lua_getmetatable(L, index) == 0) { - return true; - } - int metatableindex = lua_gettop(L); - if (stack_detail::check_metatable>(L, metatableindex)) { - void* memory = lua_touserdata(L, index); - memory = detail::align_usertype_unique_destructor(memory); - detail::unique_destructor& pdx = *static_cast(memory); - bool success = &detail::usertype_unique_alloc_destroy == pdx; - if (!success) { - memory = detail::align_usertype_unique_tag(memory); -#if 0 - // New version -#else - const char*& name_tag = *static_cast(memory); - success = usertype_traits::qualified_name() == name_tag; -#endif - if (!success) { - handler(L, index, type::userdata, indextype, "value is a userdata but is not the correct unique usertype"); - } - } - return success; - } - lua_pop(L, 1); - handler(L, index, type::userdata, indextype, "unrecognized userdata (not pushed by sol?)"); - return false; - } - }; - - template - struct unqualified_checker, type::userdata, C> { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - return stack::check(L, index, std::forward(handler), tracking); - } - }; - - template - struct unqualified_checker, type::poly, C> { + template + struct unqualified_checker, type::poly> { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { return stack::multi_check(L, index, std::forward(handler), tracking); } }; - template - struct unqualified_checker, type::poly, C> { + template + struct unqualified_checker, type::poly> { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { return stack::multi_check(L, index, std::forward(handler), tracking); } }; - template - struct unqualified_checker, type::poly, C> { + template + struct unqualified_checker, type::poly> { template static bool check(lua_State* L, int index, Handler&&, record& tracking) { type t = type_of(L, index); @@ -618,14 +504,14 @@ namespace sol { namespace stack { tracking.use(1); return true; } - return stack::check(L, index, no_panic, tracking); + return stack::unqualified_check(L, index, no_panic, tracking); } }; #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES - template - struct unqualified_checker, type::poly, C> { + template + struct unqualified_checker, type::poly> { template static bool check(lua_State* L, int index, Handler&&, record& tracking) { type t = type_of(L, index); @@ -643,8 +529,8 @@ namespace sol { namespace stack { #if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT - template - struct unqualified_checker, type::poly, C> { + template + struct unqualified_checker, type::poly> { typedef std::variant V; typedef std::variant_size V_size; typedef std::integral_constant V_is_empty; diff --git a/include/sol/stack_core.hpp b/include/sol/stack_core.hpp index 84c5fa85..e1eaeba2 100644 --- a/include/sol/stack_core.hpp +++ b/include/sol/stack_core.hpp @@ -594,15 +594,11 @@ namespace sol { struct popper; template struct unqualified_pusher; - template ::value, typename = void> + template , typename C = void> struct unqualified_checker; - template ::value, typename = void> + template , typename C = void> struct qualified_checker; template - struct qualified_interop_checker; - template - struct unqualified_interop_checker; - template struct unqualified_check_getter; template struct qualified_check_getter; @@ -634,116 +630,50 @@ namespace sol { } // namespace stack namespace meta { namespace meta_detail { - template - struct is_adl_sol_lua_get { - private: - template - static meta::sfinae_yes_t test( - std::remove_reference_t(), static_cast(nullptr), -1, std::declval()))>*); - template - static meta::sfinae_no_t test(...); - - public: - static constexpr bool value = std::is_same_v(nullptr)), meta::sfinae_yes_t>; - }; template - struct is_adl_sol_lua_interop_get { - private: - template - static meta::sfinae_yes_t test( - std::remove_reference_t(), static_cast(nullptr), -1, static_cast(nullptr), std::declval()))>*); - template - static meta::sfinae_no_t test(...); - - public: - static constexpr bool value = std::is_same_v(nullptr)), meta::sfinae_yes_t>; - }; + using adl_sol_lua_get_test_t = decltype(sol_lua_get(types(), static_cast(nullptr), -1, std::declval())); template - struct is_adl_sol_lua_check { - private: - template - static meta::sfinae_yes_t test(std::remove_reference_t(), static_cast(nullptr), -1, no_panic, std::declval()))>*); - template - static meta::sfinae_no_t test(...); - - public: - static constexpr bool value = std::is_same_v(nullptr)), meta::sfinae_yes_t>; - }; + using adl_sol_lua_interop_get_test_t + = decltype(sol_lua_interop_get(types(), static_cast(nullptr), -1, static_cast(nullptr), std::declval())); template - struct is_adl_sol_lua_interop_check { - private: - template - static meta::sfinae_yes_t test(std::remove_reference_t(), static_cast(nullptr), -1, type::none, no_panic, std::declval()))>*); - template - static meta::sfinae_no_t test(...); - - public: - static constexpr bool value = std::is_same_v(nullptr)), meta::sfinae_yes_t>; - }; + using adl_sol_lua_check_test_t = decltype(sol_lua_check(types(), static_cast(nullptr), -1, no_panic, std::declval())); template - struct is_adl_sol_lua_check_get { - private: - template - static meta::sfinae_yes_t test(std::remove_reference_t(), static_cast(nullptr), -1, no_panic, std::declval()))>*); - template - static meta::sfinae_no_t test(...); + using adl_sol_lua_interop_check_test_t + = decltype(sol_lua_interop_check(types(), static_cast(nullptr), -1, type::none, no_panic, std::declval())); - public: - static constexpr bool value = std::is_same_v(nullptr)), meta::sfinae_yes_t>; - }; + template + using adl_sol_lua_check_get_test_t = decltype(sol_lua_check_get(types(), static_cast(nullptr), -1, no_panic, std::declval())); template - struct is_adl_sol_lua_push { - private: - template - static meta::sfinae_yes_t test(std::remove_reference_t(nullptr), std::declval()...))>*); - template - static meta::sfinae_no_t test(...); - - public: - static constexpr bool value = std::is_same_v(nullptr)), meta::sfinae_yes_t>; - }; + using adl_sol_lua_push_test_t = decltype(sol_lua_push(static_cast(nullptr), std::declval()...)); template - struct is_adl_sol_lua_push_exact { - private: - template - static meta::sfinae_yes_t test( - std::remove_reference_t(), static_cast(nullptr), std::declval()...))>*); - template - static meta::sfinae_no_t test(...); - - public: - static constexpr bool value = std::is_same_v(nullptr)), meta::sfinae_yes_t>; - }; + using adl_sol_lua_push_exact_test_t = decltype(sol_lua_push(types(), static_cast(nullptr), std::declval()...)); template - inline constexpr bool is_adl_sol_lua_get_v = is_adl_sol_lua_get::value; + inline constexpr bool is_adl_sol_lua_get_v = meta::is_detected_v; template - inline constexpr bool is_adl_sol_lua_interop_get_v = is_adl_sol_lua_interop_get::value; + inline constexpr bool is_adl_sol_lua_interop_get_v = meta::is_detected_v; template - inline constexpr bool is_adl_sol_lua_check_v = is_adl_sol_lua_check::value; + inline constexpr bool is_adl_sol_lua_check_v = meta::is_detected_v; template - inline constexpr bool is_adl_sol_lua_interop_check_v = is_adl_sol_lua_interop_check::value; + inline constexpr bool is_adl_sol_lua_interop_check_v = meta::is_detected_v; template - inline constexpr bool is_adl_sol_lua_check_get_v = is_adl_sol_lua_check_get::value; + inline constexpr bool is_adl_sol_lua_check_get_v = meta::is_detected_v; template - inline constexpr bool is_adl_sol_lua_push_v = is_adl_sol_lua_push::value; + inline constexpr bool is_adl_sol_lua_push_v = meta::is_detected_v; template - inline constexpr bool is_adl_sol_lua_push_exact_v = is_adl_sol_lua_push_exact::value; + inline constexpr bool is_adl_sol_lua_push_exact_v = meta::is_detected_v; }} // namespace meta::meta_detail @@ -791,7 +721,7 @@ namespace sol { using strip_extensible_t = typename strip_extensible::type; template - static int get_size_hint(const C& c) { + static int get_size_hint(C& c) { return static_cast(c.size()); } @@ -833,9 +763,12 @@ namespace sol { return sol_lua_interop_get(types(), L, index, unadjusted_pointer, tracking); } else { - unqualified_interop_getter g{}; - (void)g; - return g.get(L, index, unadjusted_pointer, tracking); + (void)L; + (void)index; + (void)unadjusted_pointer; + (void)tracking; + using Ti = stack_detail::strip_extensible_t; + return std::pair{ false, nullptr }; } } @@ -845,9 +778,7 @@ namespace sol { return sol_lua_interop_get(types(), L, index, unadjusted_pointer, tracking); } else { - qualified_interop_getter g{}; - (void)g; - return g.get(L, index, unadjusted_pointer, tracking); + return unqualified_interop_get(L, index, unadjusted_pointer, tracking); } } @@ -858,10 +789,12 @@ namespace sol { return sol_lua_interop_check(types(), L, index, index_type, std::forward(handler), tracking); } else { - unqualified_interop_checker c; - // VC++ has a bad warning here: shut it up - (void)c; - return c.check(L, index, index_type, std::forward(handler), tracking); + (void)L; + (void)index; + (void)index_type; + (void)handler; + (void)tracking; + return false; } } @@ -871,10 +804,7 @@ namespace sol { return sol_lua_interop_check(types(), L, index, index_type, std::forward(handler), tracking); } else { - qualified_interop_checker c; - // VC++ has a bad warning here: shut it up - (void)c; - return c.check(L, index, index_type, std::forward(handler), tracking); + return unqualified_interop_check(L, index, index_type, std::forward(handler), tracking); } } } // namespace stack_detail @@ -1435,11 +1365,11 @@ namespace sol { return stack::push(L, false); } else { - auto maybel = stack::unqualified_check_get(L, 1); + auto maybel = stack::unqualified_check_get(L, 1); if (!maybel) { return stack::push(L, false); } - auto mayber = stack::unqualified_check_get(L, 2); + auto mayber = stack::unqualified_check_get(L, 2); if (!mayber) { return stack::push(L, false); } diff --git a/include/sol/stack_get_qualified.hpp b/include/sol/stack_get_qualified.hpp index 57b1f947..702f1882 100644 --- a/include/sol/stack_get_qualified.hpp +++ b/include/sol/stack_get_qualified.hpp @@ -29,78 +29,6 @@ namespace sol { namespace stack { - template - struct qualified_getter::value - && is_unique_usertype>::value - && !std::is_void>::template rebind_base>::value - >> { - typedef unique_usertype_traits> u_traits; - typedef typename u_traits::type T; - typedef typename u_traits::actual_type Real; - typedef typename u_traits::template rebind_base rebind_t; - - static Real get(lua_State* L, int index, record& tracking) { - tracking.use(1); - void* memory = lua_touserdata(L, index); - memory = detail::align_usertype_unique_destructor(memory); - detail::unique_destructor& pdx = *static_cast(memory); - if (&detail::usertype_unique_alloc_destroy == pdx) { - memory = detail::align_usertype_unique_tag(memory); - memory = detail::align_usertype_unique(memory); - Real* mem = static_cast(memory); - return *mem; - } - Real r(nullptr); - if constexpr (!derive::value) { - // TODO: abort / terminate, maybe only in debug modes? - return r; - } - else { - memory = detail::align_usertype_unique_tag(memory); - detail::unique_tag& ic = *reinterpret_cast(memory); - memory = detail::align_usertype_unique(memory); - string_view ti = usertype_traits::qualified_name(); - string_view rebind_ti = usertype_traits::qualified_name(); - int cast_operation = ic(memory, &r, ti, rebind_ti); - switch (cast_operation) { - case 1: { - // it's a perfect match, - // alias memory directly - Real* mem = static_cast(memory); - return *mem; - } - case 2: - // it's a base match, return the - // aliased creation - return std::move(r); - default: - // uh oh.. - break; - } - // TODO: abort / terminate, maybe only in debug modes? - return r; - } - } - }; - - template - struct qualified_getter::value - && is_container>::value - && std::is_default_constructible>::value - && !is_lua_primitive::value - && !is_transparent_argument::value - >> { - static T get(lua_State* L, int index, record& tracking) { - if (type_of(L, index) == type::userdata) { - return stack_detail::unchecked_unqualified_get(L, index, tracking); - } - else { - return stack_detail::unchecked_unqualified_get>(L, index, tracking); - } - } - }; } } // namespace sol::stack diff --git a/include/sol/stack_get_unqualified.hpp b/include/sol/stack_get_unqualified.hpp index ad3c91c5..f898a002 100644 --- a/include/sol/stack_get_unqualified.hpp +++ b/include/sol/stack_get_unqualified.hpp @@ -118,60 +118,110 @@ namespace sol { namespace stack { template struct unqualified_getter { - static T& get(lua_State* L, int index, record& tracking) { - return unqualified_getter>{}.get(L, index, tracking); + static decltype(auto) get(lua_State* L, int index, record& tracking) { + if constexpr (std::is_same_v) { + tracking.use(1); + return lua_toboolean(L, index) != 0; + } + else if constexpr (std::is_enum_v) { + tracking.use(1); + return static_cast(lua_tointegerx(L, index, nullptr)); + } + else if constexpr (std::is_integral_v) { + tracking.use(1); +#if SOL_LUA_VERSION >= 503 + if (lua_isinteger(L, index) != 0) { + return static_cast(lua_tointeger(L, index)); + } +#endif + return static_cast(llround(lua_tonumber(L, index))); + } + else if constexpr (std::is_floating_point_v) { + tracking.use(1); + return static_cast(lua_tonumber(L, index)); + } + else if constexpr (is_lua_reference_v) { + tracking.use(1); + return T(L, index); + } + else if constexpr (is_unique_usertype_v) { + using Real = typename unique_usertype_traits::actual_type; + + tracking.use(1); + void* memory = lua_touserdata(L, index); + memory = detail::align_usertype_unique(memory); + Real* mem = static_cast(memory); + return *mem; + } + else { + return stack_detail::unchecked_unqualified_get>(L, index, tracking); + } } }; - template + template struct qualified_getter { static decltype(auto) get(lua_State* L, int index, record& tracking) { - return stack::unqualified_get(L, index, tracking); - } - }; - - template - struct unqualified_interop_getter { - using T = stack_detail::strip_extensible_t; - - static std::pair get(lua_State*, int, void*, record&) { - return { false, nullptr }; - } - }; - - template - struct qualified_interop_getter { - static decltype(auto) get(lua_State* L, int index, void* unadjusted_pointer, record& tracking) { - return stack_detail::unqualified_interop_get(L, index, unadjusted_pointer, tracking); - } - }; - - template - struct unqualified_getter::value>> { - static T get(lua_State* L, int index, record& tracking) { - tracking.use(1); - return static_cast(lua_tonumber(L, index)); - } - }; - - template - struct unqualified_getter::value>> { - static T get(lua_State* L, int index, record& tracking) { - tracking.use(1); -#if SOL_LUA_VERSION >= 503 - if (lua_isinteger(L, index) != 0) { - return static_cast(lua_tointeger(L, index)); + using Tu = meta::unqualified_t; + if constexpr (!std::is_reference_v && is_container_v + && std::is_default_constructible_v && !is_lua_primitive_v && !is_transparent_argument_v) { + if (type_of(L, index) == type::userdata) { + return static_cast(stack_detail::unchecked_unqualified_get(L, index, tracking)); + } + else { + return stack_detail::unchecked_unqualified_get>(L, index, tracking); + } + } + else if constexpr (!std::is_reference_v && is_unique_usertype_v + && !std::is_void_v::template rebind_base>) { + using u_traits = unique_usertype_traits; + using T = typename u_traits::type; + using Real = typename u_traits::actual_type; + using rebind_t = typename u_traits::template rebind_base; + tracking.use(1); + void* memory = lua_touserdata(L, index); + memory = detail::align_usertype_unique_destructor(memory); + detail::unique_destructor& pdx = *static_cast(memory); + if (&detail::usertype_unique_alloc_destroy == pdx) { + memory = detail::align_usertype_unique_tag(memory); + memory = detail::align_usertype_unique(memory); + Real* mem = static_cast(memory); + return static_cast(*mem); + } + Real r(nullptr); + if constexpr (!derive::value) { + // TODO: abort / terminate, maybe only in debug modes? + return static_cast(r); + } + else { + memory = detail::align_usertype_unique_tag(memory); + detail::unique_tag& ic = *reinterpret_cast(memory); + memory = detail::align_usertype_unique(memory); + string_view ti = usertype_traits::qualified_name(); + string_view rebind_ti = usertype_traits::qualified_name(); + int cast_operation = ic(memory, &r, ti, rebind_ti); + switch (cast_operation) { + case 1: { + // it's a perfect match, + // alias memory directly + Real* mem = static_cast(memory); + return static_cast(*mem); + } + case 2: + // it's a base match, return the + // aliased creation + return static_cast(std::move(r)); + default: + // uh oh.. + break; + } + // TODO: abort / terminate, maybe only in debug modes? + return static_cast(r); + } + } + else { + return stack::unqualified_get(L, index, tracking); } -#endif - return static_cast(llround(lua_tonumber(L, index))); - } - }; - - template - struct unqualified_getter::value>> { - static T get(lua_State* L, int index, record& tracking) { - tracking.use(1); - return static_cast(lua_tointegerx(L, index, nullptr)); } }; @@ -487,44 +537,47 @@ namespace sol { namespace stack { }; template - struct unqualified_getter, std::enable_if_t::value>> { + struct unqualified_getter> { static T get(lua_State* L, int index, record& tracking) { - unqualified_getter g; - // VC++ has a bad warning here: shut it up - (void)g; - return g.get(L, index, tracking); - } - }; - - template - struct unqualified_getter, std::enable_if_t::value>> { - using Tu = meta::unqualified_t; - - static T get(lua_State* L, int index, record& tracking) { - if constexpr(meta::is_associative::value) { - typedef typename T::value_type P; - typedef typename P::first_type K; - typedef typename P::second_type V; - unqualified_getter> g; - // VC++ has a bad warning here: shut it up - (void)g; - return g.get(types>(), L, index, tracking); + using Tu = meta::unqualified_t; + if constexpr (is_container_v) { + if constexpr (meta::is_associative::value) { + typedef typename T::value_type P; + typedef typename P::first_type K; + typedef typename P::second_type V; + unqualified_getter> g; + // VC++ has a bad warning here: shut it up + (void)g; + return g.get(types>(), L, index, tracking); + } + else { + typedef typename T::value_type V; + unqualified_getter> g; + // VC++ has a bad warning here: shut it up + (void)g; + return g.get(types>(), L, index, tracking); + } } else { - typedef typename T::value_type V; - unqualified_getter> g; + unqualified_getter g; // VC++ has a bad warning here: shut it up (void)g; - return g.get(types>(), L, index, tracking); + return g.get(L, index, tracking); } } }; template - struct unqualified_getter::value>> { - static T get(lua_State* L, int index, record& tracking) { - tracking.use(1); - return T(L, index); + struct unqualified_getter> { + static decltype(auto) get(lua_State* L, int index, record& tracking) { + return stack::unqualified_get(L, index, tracking); + } + }; + + template + struct unqualified_getter*> { + static decltype(auto) get(lua_State* L, int index, record& tracking) { + return stack::unqualified_get(L, index, tracking); } }; @@ -581,14 +634,6 @@ namespace sol { namespace stack { } }; - template <> - struct unqualified_getter { - static bool get(lua_State* L, int index, record& tracking) { - tracking.use(1); - return lua_toboolean(L, index) != 0; - } - }; - template <> struct unqualified_getter { static std::string get(lua_State* L, int index, record& tracking) { @@ -894,20 +939,6 @@ namespace sol { namespace stack { } }; - template - struct unqualified_getter::value>> { - typedef typename unique_usertype_traits::type P; - typedef typename unique_usertype_traits::actual_type Real; - - static Real& get(lua_State* L, int index, record& tracking) { - tracking.use(1); - void* memory = lua_touserdata(L, index); - memory = detail::align_usertype_unique(memory); - Real* mem = static_cast(memory); - return *mem; - } - }; - template struct unqualified_getter> { typedef std::tuple(nullptr, 0))...> R; diff --git a/include/sol/stack_push.hpp b/include/sol/stack_push.hpp index 82b45697..78d52ea2 100644 --- a/include/sol/stack_push.hpp +++ b/include/sol/stack_push.hpp @@ -49,7 +49,7 @@ namespace sol { namespace stack_detail { template inline bool integer_value_fits(const T& value) { - if constexpr (sizeof(T) < sizeof(lua_Integer) || (std::is_signed::value && sizeof(T) == sizeof(lua_Integer))) { + if constexpr (sizeof(T) < sizeof(lua_Integer) || (std::is_signed_v && sizeof(T) == sizeof(lua_Integer))) { (void)value; return true; } @@ -61,6 +61,21 @@ namespace sol { return (u_min <= t_min || value >= static_cast(u_min)) && (u_max >= t_max || value <= static_cast(u_max)); } } + + template + int msvc_is_ass_with_if_constexpr_push_enum(std::true_type, lua_State* L, const T& value) { + if constexpr (std::is_same_v, char>) { + return stack::push(L, static_cast(value)); + } + else { + return stack::push(L, static_cast>(value)); + } + } + + template + int msvc_is_ass_with_if_constexpr_push_enum(std::false_type, lua_State*, const T&) { + return 0; + } } inline int push_environment_of(lua_State* L, int index = -1) { @@ -112,19 +127,19 @@ namespace sol { return push_fx(L, fx, std::forward(args)...); } - template , detail::with_function_tag>>> + template static int push(lua_State* L, Arg&& arg, Args&&... args) { - return push_keyed(L, usertype_traits::metatable(), std::forward(arg), std::forward(args)...); + if constexpr (std::is_same_v, detail::with_function_tag>) { + return push_fx(L, std::forward(args)...); + } + else { + return push_keyed(L, usertype_traits::metatable(), std::forward(arg), std::forward(args)...); + } } static int push(lua_State* L) { return push_keyed(L, usertype_traits::metatable()); } - - template - static int push(lua_State* L, detail::with_function_tag, Args&&... args) { - return push_fx(L, std::forward(args)...); - } }; template @@ -150,14 +165,14 @@ namespace sol { return push_fx(L, fx, obj); } - template , detail::with_function_tag>>> + template static int push(lua_State* L, Arg&& arg, Args&&... args) { - return push_keyed(L, usertype_traits::metatable(), std::forward(arg), std::forward(args)...); - } - - template - static int push(lua_State* L, detail::with_function_tag, Args&&... args) { - return push_fx(L, std::forward(args)...); + if constexpr (std::is_same_v, detail::with_function_tag>) { + return push_fx(L, std::forward(args)...); + } + else { + return push_keyed(L, usertype_traits::metatable(), std::forward(arg), std::forward(args)...); + } } }; @@ -169,67 +184,118 @@ namespace sol { } }; + namespace stack_detail { + template + struct uu_pusher { + using u_traits = unique_usertype_traits; + using P = typename u_traits::type; + using Real = typename u_traits::actual_type; + using rebind_t = typename u_traits::template rebind_base; + + template + static int push(lua_State* L, Arg&& arg, Args&&... args) { + if constexpr (std::is_base_of_v>) { + if (u_traits::is_null(arg)) { + return stack::push(L, lua_nil); + } + return push_deep(L, std::forward(arg), std::forward(args)...); + } + else { + return push_deep(L, std::forward(arg), std::forward(args)...); + } + } + + template + static int push_deep(lua_State* L, Args&&... args) { + #if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); + #endif // make sure stack doesn't overflow + P** pref = nullptr; + detail::unique_destructor* fx = nullptr; + detail::unique_tag* id = nullptr; + Real* mem = detail::usertype_unique_allocate(L, pref, fx, id); + *fx = detail::usertype_unique_alloc_destroy; + *id = &detail::inheritance

::template type_unique_cast; + detail::default_construct::construct(mem, std::forward(args)...); + *pref = unique_usertype_traits::get(*mem); + if (luaL_newmetatable(L, &usertype_traits>>::metatable()[0]) == 1) { + detail::lua_reg_table l{}; + int index = 0; + detail::indexed_insert insert_fx(l, index); + detail::insert_default_registrations

(insert_fx, detail::property_always_true); + l[index] = { to_string(meta_function::garbage_collect).c_str(), detail::make_destructor() }; + luaL_setfuncs(L, l, 0); + } + lua_setmetatable(L, -2); + return 1; + } + }; + } // namespace stack_detail + template struct unqualified_pusher { template static int push(lua_State* L, Args&&... args) { - return stack::push>(L, std::forward(args)...); - } - }; - - template - struct unqualified_pusher>, std::is_function>, - is_lua_reference>>::value>> { - template - static int push(lua_State* L, Args&&... args) { - return stack::push>(L, std::forward(args)...); - } - }; - - template - struct unqualified_pusher::value>> { - typedef unique_usertype_traits u_traits; - typedef typename u_traits::type P; - typedef typename u_traits::actual_type Real; - typedef typename u_traits::template rebind_base rebind_t; - - template >> = meta::enabler> - static int push(lua_State* L, Arg&& arg) { - if (unique_usertype_traits::is_null(arg)) { - return stack::push(L, lua_nil); + using Tu = meta::unqualified_t; + if constexpr (is_lua_reference_v) { + using int_arr = int[]; + int_arr p{ (std::forward(args).push(L))... }; + return p[0]; } - return push_deep(L, std::forward(arg)); - } - - template - static int push(lua_State* L, Arg0&& arg0, Arg0&& arg1, Args&&... args) { - return push_deep(L, std::forward(arg0), std::forward(arg1), std::forward(args)...); - } - - template - static int push_deep(lua_State* L, Args&&... args) { + else if constexpr (std::is_same_v) { #if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_userdata); + luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); #endif // make sure stack doesn't overflow - P** pref = nullptr; - detail::unique_destructor* fx = nullptr; - detail::unique_tag* id = nullptr; - Real* mem = detail::usertype_unique_allocate(L, pref, fx, id); - *fx = detail::usertype_unique_alloc_destroy; - *id = &detail::inheritance

::template type_unique_cast; - detail::default_construct::construct(mem, std::forward(args)...); - *pref = unique_usertype_traits::get(*mem); - if (luaL_newmetatable(L, &usertype_traits>>::metatable()[0]) == 1) { - detail::lua_reg_table l{}; - int index = 0; - detail::indexed_insert insert_fx(l, index); - detail::insert_default_registrations

(insert_fx, detail::property_always_true); - l[index] = { to_string(meta_function::garbage_collect).c_str(), detail::make_destructor() }; - luaL_setfuncs(L, l, 0); + lua_pushboolean(L, std::forward(args)...); + return 1; + } + else if constexpr (std::is_integral_v) { + const Tu& value(std::forward(args)...); +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_integral); +#endif // make sure stack doesn't overflow +#if SOL_LUA_VERSION >= 503 + if (stack_detail::integer_value_fits(value)) { + lua_pushinteger(L, static_cast(value)); + return 1; + } +#endif // Lua 5.3 and above +#if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) + if (static_cast(llround(static_cast(value))) != value) { +#if defined(SOL_NO_EXCEPTIONS) && SOL_NO_EXCEPTIONS + // Is this really worth it? + assert(false && "integer value will be misrepresented in lua"); + lua_pushnumber(L, static_cast(std::forward(args)...)); + return 1; +#else + throw error(detail::direct_error, "integer value will be misrepresented in lua"); +#endif // No Exceptions + } +#endif // Safe Numerics and Number Precision Check + lua_pushnumber(L, static_cast(value)); + return 1; + } + else if constexpr (std::is_floating_point_v) { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, detail::not_enough_stack_space_floating); +#endif // make sure stack doesn't overflow + lua_pushnumber(L, std::forward(args)...); + return 1; + } + else if constexpr (std::is_enum_v) { + return stack_detail::msvc_is_ass_with_if_constexpr_push_enum(std::true_type(), L, std::forward(args)...); + } + else if constexpr (std::is_pointer_v) { + return stack::push>>(L, std::forward(args)...); + } + else if constexpr (is_unique_usertype_v) { + stack_detail::uu_pusher p; + (void)p; + return p.push(L, std::forward(args)...); + } + else { + return stack::push>(L, std::forward(args)...); } - lua_setmetatable(L, -2); - return 1; } }; @@ -240,70 +306,19 @@ namespace sol { } }; - template - struct unqualified_pusher::value>> { - static int push(lua_State* L, const T& value) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_floating); -#endif // make sure stack doesn't overflow - lua_pushnumber(L, value); - return 1; - } - }; - - template - struct unqualified_pusher::value>> { - static int push(lua_State* L, const T& value) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_integral); -#endif // make sure stack doesn't overflow -#if SOL_LUA_VERSION >= 503 - if (stack_detail::integer_value_fits(value)) { - lua_pushinteger(L, static_cast(value)); - return 1; - } -#endif // Lua 5.3 and above -#if (defined(SOL_SAFE_NUMERICS) && SOL_SAFE_NUMERICS) && !(defined(SOL_NO_CHECK_NUMBER_PRECISION) && SOL_NO_CHECK_NUMBER_PRECISION) - if (static_cast(llround(static_cast(value))) != value) { -#if defined(SOL_NO_EXCEPTIONS) && SOL_NO_EXCEPTIONS - // Is this really worth it? - assert(false && "integer value will be misrepresented in lua"); - lua_pushnumber(L, static_cast(value)); - return 1; -#else - throw error(detail::direct_error, "integer value will be misrepresented in lua"); -#endif // No Exceptions - } -#endif // Safe Numerics and Number Precision Check - lua_pushnumber(L, static_cast(value)); - return 1; - } - }; - - template - struct unqualified_pusher::value>> { - static int push(lua_State* L, const T& value) { - if (std::is_same>::value) { - return stack::push(L, static_cast(value)); - } - return stack::push(L, static_cast>(value)); - } - }; - template struct unqualified_pusher> { + using has_kvp = meta::has_key_value_pair>>; + static int push(lua_State* L, const T& tablecont) { - typedef meta::has_key_value_pair>> has_kvp; return push(has_kvp(), std::false_type(), L, tablecont); } static int push(std::true_type, lua_State* L, const T& tablecont) { - typedef meta::has_key_value_pair>> has_kvp; return push(has_kvp(), std::true_type(), L, tablecont); } static int push(std::false_type, lua_State* L, const T& tablecont) { - typedef meta::has_key_value_pair>> has_kvp; return push(has_kvp(), std::false_type(), L, tablecont); } @@ -368,36 +383,28 @@ namespace sol { }; template - struct unqualified_pusher, std::enable_if_t>>::value>> { - static int push(lua_State* L, const T& tablecont) { - return stack::push>(L, tablecont); - } - }; - - template - struct unqualified_pusher, std::enable_if_t>>::value>> { + struct unqualified_pusher> { static int push(lua_State* L, const T& v) { - return stack::push(L, v); + using inner_t = std::remove_pointer_t>; + if constexpr (is_container_v) { + return stack::push>(L, v); + } + else { + return stack::push(L, v); + } } }; template - struct unqualified_pusher, std::enable_if_t>>::value>> { + struct unqualified_pusher> { static int push(lua_State* L, const T& tablecont) { - unqualified_pusher> p{}; - // silence annoying VC++ warning - (void)p; - return p.push(std::true_type(), L, tablecont); - } - }; - - template - struct unqualified_pusher, std::enable_if_t>>::value>> { - static int push(lua_State* L, const T& tablecont) { - unqualified_pusher> p{}; - // silence annoying VC++ warning - (void)p; - return p.push(L, tablecont); + using inner_t = std::remove_pointer_t>; + if constexpr (is_container_v) { + return stack::push>(L, tablecont); + } + else { + return stack::push(L, tablecont); + } } }; @@ -411,28 +418,6 @@ namespace sol { } }; - template - struct unqualified_pusher::value>> { - static int push(lua_State* L, const T& ref) { - return ref.push(L); - } - - static int push(lua_State* L, T&& ref) { - return ref.push(L); - } - }; - - template <> - struct unqualified_pusher { - static int push(lua_State* L, bool b) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_generic); -#endif // make sure stack doesn't overflow - lua_pushboolean(L, b); - return 1; - } - }; - template <> struct unqualified_pusher { static int push(lua_State* L, lua_nil_t) { @@ -604,22 +589,20 @@ namespace sol { return 1; } - template , no_metatable_t, metatable_key_t>> = meta::enabler> + template static int push(lua_State* L, Arg&& arg, Args&&... args) { - const auto name = &usertype_traits>::user_gc_metatable()[0]; - return push_with(L, name, std::forward(arg), std::forward(args)...); - } - - template - static int push(lua_State* L, no_metatable_t, Args&&... args) { - const auto name = &usertype_traits>::user_gc_metatable()[0]; - return push_with(L, name, std::forward(args)...); - } - - template - static int push(lua_State* L, metatable_key_t, Key&& key, Args&&... args) { - const auto name = &key[0]; - return push_with(L, name, std::forward(args)...); + if constexpr (std::is_same_v, metatable_key_t>) { + const auto name = &arg[0]; + return push_with(L, name, std::forward(args)...); + } + else if constexpr (std::is_same_v, no_metatable_t>) { + const auto name = &usertype_traits>::user_gc_metatable()[0]; + return push_with(L, name, std::forward(args)...); + } + else { + const auto name = &usertype_traits>::user_gc_metatable()[0]; + return push_with(L, name, std::forward(arg), std::forward(args)...); + } } static int push(lua_State* L, const user& u) { @@ -734,22 +717,32 @@ namespace sol { } }; - template - struct unqualified_pusher> { - static int push(lua_State* L, const std::basic_string& str) { + template + struct unqualified_pusher> { + static int push(lua_State* L, const std::basic_string& str) { + if constexpr (!std::is_same_v) { + return stack::push(str.data(), str.size()); + } + else { #if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_string); + luaL_checkstack(L, 1, detail::not_enough_stack_space_string); #endif // make sure stack doesn't overflow - lua_pushlstring(L, str.c_str(), str.size()); - return 1; + lua_pushlstring(L, str.c_str(), str.size()); + return 1; + } } - static int push(lua_State* L, const std::basic_string& str, std::size_t sz) { + static int push(lua_State* L, const std::basic_string& str, std::size_t sz) { + if constexpr (!std::is_same_v) { + return stack::push(str.data(), sz); + } + else { #if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, detail::not_enough_stack_space_string); + luaL_checkstack(L, 1, detail::not_enough_stack_space_string); #endif // make sure stack doesn't overflow - lua_pushlstring(L, str.c_str(), sz); - return 1; + lua_pushlstring(L, str.c_str(), sz); + return 1; + } } }; @@ -1066,17 +1059,6 @@ namespace sol { } }; - template - struct unqualified_pusher, std::enable_if_t::value>> { - static int push(lua_State* L, const std::basic_string& wstr) { - return push(L, wstr, wstr.size()); - } - - static int push(lua_State* L, const std::basic_string& wstr, std::size_t sz) { - return stack::push(L, wstr.data(), wstr.data() + sz); - } - }; - template struct unqualified_pusher> { template diff --git a/include/sol/state_handling.hpp b/include/sol/state_handling.hpp index fcfec6cc..d6b39bdf 100644 --- a/include/sol/state_handling.hpp +++ b/include/sol/state_handling.hpp @@ -72,13 +72,13 @@ namespace sol { inline int default_traceback_error_handler(lua_State* L) { std::string msg = "An unknown error has triggered the default error handler"; - optional maybetopmsg = stack::check_get(L, 1); + optional maybetopmsg = stack::unqualified_check_get(L, 1, no_panic); if (maybetopmsg) { const string_view& topmsg = maybetopmsg.value(); msg.assign(topmsg.data(), topmsg.size()); } luaL_traceback(L, L, msg.c_str(), 1); - optional maybetraceback = stack::check_get(L, -1); + optional maybetraceback = stack::unqualified_check_get(L, -1, no_panic); if (maybetraceback) { const string_view& traceback = maybetraceback.value(); msg.assign(traceback.data(), traceback.size()); @@ -141,7 +141,7 @@ namespace sol { #endif // serialize exception information if possible if (t == type::string) { err += ": "; - string_view serr = stack::get(L, result.stack_index()); + string_view serr = stack::unqualified_get(L, result.stack_index()); err.append(serr.data(), serr.size()); } #if defined(SOL_PRINT_ERRORS) && SOL_PRINT_ERRORS diff --git a/include/sol/traits.hpp b/include/sol/traits.hpp index cab8d8ff..4be5e162 100644 --- a/include/sol/traits.hpp +++ b/include/sol/traits.hpp @@ -47,6 +47,23 @@ namespace sol { using sfinae_yes_t = std::true_type; using sfinae_no_t = std::false_type; + template + using void_t = void; + + namespace meta_detail { + template