From 88cafb281f6c74eb20de159ddd8a128812ee5533 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Fri, 21 Dec 2018 01:07:05 -0500 Subject: [PATCH] improve all tests, fix all tests, and improve metatable for GCC builds --- cmake/Modules/FindLuaBuild/LuaJIT.cmake | 34 +- .../custom_global_transparent_argument.cpp | 75 +- examples/source/customization.cpp | 2 +- .../source/customization_convert_on_get.cpp | 54 +- examples/source/metatable_customization.cpp | 4 +- examples/source/usertype.cpp | 7 +- include/sol/config.hpp | 2 +- include/sol/container_traits.hpp | 83 +- include/sol/object.hpp | 3 - include/sol/sol.hpp | 1 + include/sol/stack_check_unqualified.hpp | 74 +- include/sol/stack_core.hpp | 4 +- include/sol/stack_push.hpp | 2 - include/sol/traits.hpp | 33 +- include/sol/usertype_container.hpp | 11 +- include/sol/usertype_core.hpp | 4 +- include/sol/usertype_storage.hpp | 31 +- single/include/sol/forward.hpp | 4 +- single/include/sol/sol.hpp | 1289 +++++++++-------- .../source/compatibility/compat-5.3.cpp | 2 +- .../source/compatibility/version.cpp | 2 +- tests/runtime_tests/source/common_classes.hpp | 1 + .../source/container_semantics.cpp | 54 + tests/runtime_tests/source/customizations.cpp | 686 ++++----- .../source/customizations_private.cpp | 169 +++ tests/runtime_tests/source/utility.cpp | 4 +- 26 files changed, 1394 insertions(+), 1241 deletions(-) create mode 100644 tests/runtime_tests/source/customizations_private.cpp diff --git a/cmake/Modules/FindLuaBuild/LuaJIT.cmake b/cmake/Modules/FindLuaBuild/LuaJIT.cmake index 6584acf3..d7c35cdb 100644 --- a/cmake/Modules/FindLuaBuild/LuaJIT.cmake +++ b/cmake/Modules/FindLuaBuild/LuaJIT.cmake @@ -230,11 +230,11 @@ file(TO_CMAKE_PATH "${LUA_JIT_SOURCE_DIR}/${LUA_JIT_PREBUILT_EXE}" LUA_JIT_SOURC file(TO_CMAKE_PATH "${LUA_JIT_SOURCE_DIR}/${LUA_JIT_PREBUILT_DLL}" LUA_JIT_SOURCE_LUA_DLL) file(TO_CMAKE_PATH "${LUA_JIT_SOURCE_DIR}/${LUA_JIT_PREBUILT_EXP}" LUA_JIT_SOURCE_LUA_LIB_EXP) +file(TO_CMAKE_PATH "${LUA_JIT_LIB_FILE}" LUA_JIT_DESTINATION_LUA_LIB) +file(TO_CMAKE_PATH "${LUA_JIT_IMP_LIB_FILE}" LUA_JIT_DESTINATION_LUA_IMP_LIB) +file(TO_CMAKE_PATH "${LUA_JIT_EXE_FILE}" LUA_JIT_DESTINATION_LUA_INTERPRETER) file(TO_CMAKE_PATH "${LUA_JIT_DLL_FILE}" LUA_JIT_DESTINATION_LUA_DLL) file(TO_CMAKE_PATH "${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/${LUA_JIT_LIB_EXP_FILENAME}" LUA_JIT_DESTINATION_LUA_LIB_EXP) -file(TO_CMAKE_PATH "${LUA_JIT_IMP_LIB_FILE}" LUA_JIT_DESTINATION_LUA_IMP_LIB) -file(TO_CMAKE_PATH "${LUA_JIT_LIB_FILE}" LUA_JIT_DESTINATION_LUA_LIB) -file(TO_CMAKE_PATH "${LUA_JIT_EXE_FILE}" LUA_JIT_DESTINATION_LUA_INTERPRETER) if (WIN32 AND NOT MSVC) string(COMPARE EQUAL ${LUA_JIT_VERSION} ${LUA_JIT_2.0_LATEST_VERSION} lua_jit_same_version_20) @@ -247,14 +247,21 @@ elseif(LUA_JIT_NORMALIZED_LUA_VERSION MATCHES "latest") set(LUA_JIT_PULL_LATEST TRUE) endif() -set(LUA_JIT_BYPRODUCTS "${LUA_JIT_SOURCE_LUA_LIB}" "${LUA_JIT_SOURCE_LUA_LIB_EXP}" +set(LUA_JIT_BYPRODUCTS "${LUA_JIT_SOURCE_LUA_LIB}" "${LUA_JIT_SOURCE_LUA_DLL}" "${LUA_JIT_SOURCE_LUA_INTERPRETER}") -set(LUA_JIT_INSTALL_BYPRODUCTS "${LUA_JIT_DESTINATION_LUA_LIB}" "${LUA_JIT_DESTINATION_LUA_LIB_EXP}" +set(LUA_JIT_INSTALL_BYPRODUCTS "${LUA_JIT_DESTINATION_LUA_LIB}" "${LUA_JIT_DESTINATION_LUA_DLL}" "${LUA_JIT_DESTINATION_LUA_INTERPRETER}") +if (MSVC) + set(LUA_JIT_BYPRODUCTS "${LUA_JIT_BYPRODUCTS}" "${LUA_JIT_SOURCE_LUA_LIB_EXP}") + set(LUA_JIT_INSTALL_BYPRODUCTS "${LUA_JIT_INSTALL_BYPRODUCTS}" "${LUA_JIT_DESTINATION_LUA_LIB_EXP}") +endif() + if (CMAKE_IMPORT_LIBRARY_SUFFIX) - set(LUA_JIT_BYPRODUCTS "${LUA_JIT_BYPRODUCTS}" "${LUA_JIT_SOURCE_LUA_IMP_LIB}") + if (NOT MSVC) + set(LUA_JIT_BYPRODUCTS "${LUA_JIT_BYPRODUCTS}" "${LUA_JIT_SOURCE_LUA_IMP_LIB}") + endif() set(LUA_JIT_INSTALL_BYPRODUCTS "${LUA_JIT_INSTALL_BYPRODUCTS}" "${LUA_JIT_DESTINATION_LUA_IMP_LIB}") endif() @@ -300,7 +307,7 @@ if (LUA_JIT_GIT_COMMIT OR LUA_JIT_PULL_LATEST) ${LUA_JIT_BUILD_COMMAND} INSTALL_COMMAND "" TEST_COMMAND "" - BUILD_BYPRODUCTS ${LUA_JIT_BYPRODUCTS}) + BUILD_BYPRODUCTS "${LUA_JIT_BYPRODUCTS}") else() ExternalProject_Add(LUA_JIT BUILD_IN_SOURCE TRUE @@ -320,23 +327,24 @@ else() ${LUA_JIT_BUILD_COMMAND} INSTALL_COMMAND "" TEST_COMMAND "" - BUILD_BYPRODUCTS ${LUA_JIT_BYPRODUCTS}) + BUILD_BYPRODUCTS "${LUA_JIT_BYPRODUCTS}") endif() # # MAYBE?: # Add additional post-build step to move all necessary headers/lua files # for now, we just point directly to the `src` directory... -add_custom_command(TARGET LUA_JIT - POST_BUILD +add_custom_target(luajit_postbuild ${LUA_JIT_POSTBUILD_COMMANDS} COMMENT ${LUA_JIT_POSTBUILD_COMMENTS} - BYPRODUCTS ${LUA_JIT_INSTALL_BYPRODUCTS}) + DEPENDS "${LUA_JIT_BYPRODUCTS}" +) + # # Lua Library add_library(${lualib} ${LUA_BUILD_LIBRARY_TYPE} IMPORTED) # make sure the library we export really does depend on Lua JIT's external project -add_dependencies(${lualib} LUA_JIT) +add_dependencies(${lualib} luajit_postbuild) # Configure properties if (BUILD_LUA_AS_DLL) if (MSVC) @@ -372,7 +380,7 @@ add_executable(${luainterpreter} IMPORTED) set_target_properties(${luainterpreter} PROPERTIES IMPORTED_LOCATION "${LUA_JIT_DESTINATION_LUA_INTERPRETER}") -add_dependencies(${luainterpreter} LUA_JIT) +add_dependencies(${luainterpreter} luajit_postbuild) # # set externally-visible target indicator set(LUA_LIBRARIES ${lualib}) diff --git a/examples/source/custom_global_transparent_argument.cpp b/examples/source/custom_global_transparent_argument.cpp index 94f73e9a..3ebdfae4 100644 --- a/examples/source/custom_global_transparent_argument.cpp +++ b/examples/source/custom_global_transparent_argument.cpp @@ -8,49 +8,38 @@ struct GlobalResource { int value = 2; }; -// Customize sol2 to handle this type -namespace sol { - template <> - struct lua_type_of : std::integral_constant {}; - - namespace stack { - template <> - struct checker { - template - static bool check(lua_State* L, int /*index*/, Handler&& handler, record& tracking) { - tracking.use(0); - // get the field from global storage - stack::get_field(L, script_key); - // verify type - type t = static_cast(lua_type(L, -1)); - lua_pop(L, 1); - if (t != type::lightuserdata) { - handler(L, 0, type::lightuserdata, t, "global resource is not present"); - return false; - } - return true; - } - }; - - template <> - struct unqualified_getter { - static GlobalResource* get(lua_State* L, int /*index*/, record& tracking) { - // retrieve the (light) userdata for this type - tracking.use(0); // not actually pulling anything off the stack - stack::get_field(L, script_key); - GlobalResource* ls = static_cast(lua_touserdata(L, -1)); - lua_pop(L, 1); // clean up stack value returned by `get_field` - return ls; - }; - }; - template <> - struct pusher { - static int push(lua_State* L, GlobalResource* ls) { - // push light userdata - return stack::push(L, make_light(ls));; - } - }; +template +bool sol_lua_check(sol::types, lua_State* L, int /*index*/, Handler&& handler, sol::stack::record& tracking) { + // not actually taking anything off the stack + tracking.use(0); + // get the field from global storage + sol::stack::get_field(L, script_key); + // verify type + sol::type t = static_cast(lua_type(L, -1)); + lua_pop(L, 1); + if (t != sol::type::lightuserdata) { + handler(L, 0, sol::type::lightuserdata, t, "global resource is not present as a light userdata"); + return false; } + return true; +} + +GlobalResource* sol_lua_get(sol::types, lua_State* L, int /*index*/, sol::stack::record& tracking) { + // retrieve the (light) userdata for this type + + // not actually pulling anything off the stack + tracking.use(0); + sol::stack::get_field(L, script_key); + GlobalResource* ls = static_cast(lua_touserdata(L, -1)); + + // clean up stack value returned by `get_field` + lua_pop(L, 1); + return ls; +} + +int sol_lua_push(lua_State* L, GlobalResource* ls) { + // push light userdata + return sol::stack::push(L, static_cast(ls)); } int main() { @@ -67,7 +56,7 @@ int main() { lua.set(script_key, &instance); // note only 1 argument, - // despite being 2 + // despite f having 2 arguments to recieve lua.script("assert(f(1) == 3)"); return 0; diff --git a/examples/source/customization.cpp b/examples/source/customization.cpp index 30215f5d..32832c11 100644 --- a/examples/source/customization.cpp +++ b/examples/source/customization.cpp @@ -25,7 +25,7 @@ namespace sol { namespace stack { template <> - struct checker { + struct unqualified_checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { // indices can be negative to count backwards from the top of the stack, diff --git a/examples/source/customization_convert_on_get.cpp b/examples/source/customization_convert_on_get.cpp index 605d85e1..77df4fc7 100644 --- a/examples/source/customization_convert_on_get.cpp +++ b/examples/source/customization_convert_on_get.cpp @@ -9,41 +9,27 @@ struct number_shim { double num = 0; }; -namespace sol { +template +bool sol_lua_check(sol::types, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking) { + // check_usertype is a backdoor for directly checking sol2 usertypes + if (!sol::stack::check_usertype(L, index) + && !sol::stack::check(L, index)) { + handler(L, index, sol::type_of(L, index), sol::type::userdata, "expected a number_shim or a number"); + return false; + } + tracking.use(1); + return true; +} - template <> - struct lua_type_of : std::integral_constant {}; - - namespace stack { - template <> - struct checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - // check_usertype is a backdoor for directly checking sol2 usertypes - if (!check_usertype(L, index) && !stack::check(L, index)) { - handler(L, index, type_of(L, index), type::userdata, "expected a number_shim or a number"); - return false; - } - tracking.use(1); - return true; - } - }; - - template <> - struct unqualified_getter { - static number_shim get(lua_State* L, int index, record& tracking) { - if (check_usertype(L, index)) { - number_shim& ns = get_usertype(L, index, tracking); - return ns; - } - number_shim ns{}; - ns.num = stack::get(L, index, tracking); - return ns; - } - }; - - } // namespace stack -} // namespace sol +number_shim sol_lua_get(sol::types, lua_State* L, int index, sol::stack::record& tracking) { + if (sol::stack::check_usertype(L, index)) { + number_shim& ns = sol::stack::get_usertype(L, index, tracking); + return ns; + } + number_shim ns{}; + ns.num = sol::stack::get(L, index, tracking); + return ns; +} int main() { sol::state lua; diff --git a/examples/source/metatable_customization.cpp b/examples/source/metatable_customization.cpp index 348920ec..01bd518e 100644 --- a/examples/source/metatable_customization.cpp +++ b/examples/source/metatable_customization.cpp @@ -34,7 +34,7 @@ void register_thing_type(sol::state& lua) { if (!source.is()) { return luaL_error(L, "given an incorrect object for this call"); } - sol::optional maybe_svkey = key.as(); + sol::optional maybe_svkey = key.as>(); if (maybe_svkey) { { // functions are different from variables @@ -77,7 +77,7 @@ void register_thing_type(sol::state& lua) { return luaL_error(L, "given an incorrect object for this call"); } // write to member variables, etc. etc... - sol::optional maybe_svkey = key.as(); + sol::optional maybe_svkey = key.as>(); if (maybe_svkey) { { // variables are different than funtions diff --git a/examples/source/usertype.cpp b/examples/source/usertype.cpp index f53a94c3..56674b04 100644 --- a/examples/source/usertype.cpp +++ b/examples/source/usertype.cpp @@ -55,7 +55,9 @@ int main() { // you must make sure that the name of the function // goes before the member function pointer - lua.new_usertype("foo", "print", &foo::print, "test", &foo::test); + lua.new_usertype("foo", sol::constructors(), + "print", &foo::print, + "test", &foo::test); // making the class from lua is simple // same with calling member functions @@ -83,7 +85,7 @@ int main() { sol::usertype utype = lua.new_usertype("vector", ctor); // add to it as much as you like - lua["is_unit"] = &vector::is_unit; + utype["is_unit"] = &vector::is_unit; // You can throw away the usertype after // you set it: you do NOT // have to keep it around @@ -111,4 +113,5 @@ int main() { std::cout << std::endl; + return 0; } diff --git a/include/sol/config.hpp b/include/sol/config.hpp index 47c6196e..499ba775 100644 --- a/include/sol/config.hpp +++ b/include/sol/config.hpp @@ -191,7 +191,7 @@ // Interop allows userdata from external systems // with external memory layout and metatable names // to be registered. It costs something to perform -// the checker / differentiation for sol2 usertypes versus +// the unqualified_checker / differentiation for sol2 usertypes versus // external ones however, so this is off by default #if !defined(SOL_ENABLE_INTEROP) // off by default here diff --git a/include/sol/container_traits.hpp b/include/sol/container_traits.hpp index 5a44b235..708493ce 100644 --- a/include/sol/container_traits.hpp +++ b/include/sol/container_traits.hpp @@ -26,8 +26,8 @@ #include "traits.hpp" #include "stack.hpp" -#include "map.hpp" #include "object.hpp" +#include "map.hpp" namespace sol { @@ -496,15 +496,16 @@ namespace sol { template struct container_traits_default>, meta::has_value_type>>, meta::has_iterator>>>::value>> { private: - typedef std::remove_pointer_t>> T; + using T = std::remove_pointer_t>>; private: - typedef container_traits deferred_traits; - typedef meta::is_associative is_associative; - typedef meta::is_lookup is_lookup; - typedef meta::is_matched_lookup is_matched_lookup; - typedef typename T::iterator iterator; - typedef typename T::value_type value_type; + using deferred_traits = container_traits; + using is_associative = meta::is_associative; + using is_lookup = meta::is_lookup; + using is_ordered = meta::is_ordered; + using is_matched_lookup = meta::is_matched_lookup; + using iterator = typename T::iterator; + using value_type = typename T::value_type; typedef std::conditional_t, std::conditional_t static detail::error_result find_has_associative_lookup(std::true_type, lua_State* L, T& self) { - decltype(auto) key = stack::unqualified_get(L, 2); - auto it = self.find(key); - if (it == deferred_traits::end(L, self)) { - return stack::push(L, lua_nil); - } - if constexpr (idx_of) { - return stack::push(L, std::distance(deferred_traits::begin(L, self), it)); + if constexpr (!is_ordered::value && idx_of) { + (void)L; + (void)self; + return detail::error_result("cannot perform an 'index_of': '%s's is not an ordered container", detail::demangle().data()); } else { - return get_associative(is_associative(), L, it); + decltype(auto) key = stack::unqualified_get(L, 2); + auto it = self.find(key); + if (it == deferred_traits::end(L, self)) { + return stack::push(L, lua_nil); + } + if constexpr (idx_of) { + auto dist = std::distance(deferred_traits::begin(L, self), it); + dist -= deferred_traits::index_adjustment(L, self); + return stack::push(L, dist); + } + else { + return get_associative(is_associative(), L, it); + } } } template static detail::error_result find_has_associative_lookup(std::false_type, lua_State* L, T& self) { - decltype(auto) value = stack::unqualified_get(L, 2); - auto it = self.find(value); - if (it == deferred_traits::end(L, self)) { - return stack::push(L, lua_nil); - } - if constexpr (idx_of) { - return stack::push(L, std::distance(deferred_traits::begin(L, self), it)); + if constexpr (!is_ordered::value && idx_of) { + (void)L; + (void)self; + return detail::error_result("cannot perform an 'index_of': '%s's is not an ordered container", detail::demangle().data()); } else { - return get_associative(is_associative(), L, it); + decltype(auto) value = stack::unqualified_get(L, 2); + auto it = self.find(value); + if (it == deferred_traits::end(L, self)) { + return stack::push(L, lua_nil); + } + if constexpr (idx_of) { + auto dist = std::distance(deferred_traits::begin(L, self), it); + dist -= deferred_traits::index_adjustment(L, self); + return stack::push(L, dist); + } + else { + return get_associative(is_associative(), L, it); + } } } @@ -797,12 +816,13 @@ namespace sol { return find_has_associative_lookup(meta::any(), L, self); } - static detail::error_result find_associative_lookup(std::true_type, lua_State* L, iterator& it, std::size_t) { + static detail::error_result find_associative_lookup(std::true_type, lua_State* L, T&, iterator& it, std::size_t) { return get_associative(is_associative(), L, it); } - static detail::error_result find_associative_lookup(std::false_type, lua_State* L, iterator&, std::size_t index) { - return stack::push(L, index); + static detail::error_result find_associative_lookup(std::false_type, lua_State* L, T& self, iterator&, std::size_t idx) { + idx -= deferred_traits::index_adjustment(L, self); + return stack::push(L, idx); } template @@ -815,8 +835,8 @@ namespace sol { decltype(auto) value = stack::unqualified_get(L, 2); auto it = deferred_traits::begin(L, self); auto e = deferred_traits::end(L, self); - std::size_t index = 1; - for (;; ++it, ++index) { + std::size_t idx = 0; + for (;; ++it, ++idx) { if (it == e) { return stack::push(L, lua_nil); } @@ -824,7 +844,7 @@ namespace sol { break; } } - return find_associative_lookup(meta::any>(), L, it, index); + return find_associative_lookup(meta::all, meta::any>(), L, self, it, idx); } template @@ -1306,7 +1326,8 @@ namespace sol { for (std::size_t idx = 0; idx < N; ++idx) { const auto& v = self[idx]; if (v == value) { - return stack::push(L, idx + 1); + idx -= deferred_traits::index_adjustment(L, self); + return stack::push(L, idx); } } return stack::push(L, lua_nil); diff --git a/include/sol/object.hpp b/include/sol/object.hpp index b39be53c..1fe1000e 100644 --- a/include/sol/object.hpp +++ b/include/sol/object.hpp @@ -28,9 +28,6 @@ #include "reference.hpp" #include "stack.hpp" #include "object_base.hpp" -#include "as_args.hpp" -#include "variadic_args.hpp" -#include "optional.hpp" namespace sol { diff --git a/include/sol/sol.hpp b/include/sol/sol.hpp index a7b3d10f..5965dffd 100644 --- a/include/sol/sol.hpp +++ b/include/sol/sol.hpp @@ -60,6 +60,7 @@ #include "thread.hpp" #include "userdata.hpp" #include "metatable.hpp" +#include "as_args.hpp" #include "variadic_args.hpp" #include "variadic_results.hpp" diff --git a/include/sol/stack_check_unqualified.hpp b/include/sol/stack_check_unqualified.hpp index 753fa5cb..6f9cc746 100644 --- a/include/sol/stack_check_unqualified.hpp +++ b/include/sol/stack_check_unqualified.hpp @@ -80,7 +80,7 @@ namespace stack { }; template - struct checker { + struct unqualified_checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -95,10 +95,10 @@ namespace stack { }; template - struct qualified_checker : checker, lua_type_of>::value, C> {}; + struct qualified_checker : unqualified_checker, lua_type_of>::value, C> {}; template - struct checker::value>> { + struct unqualified_checker::value>> { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -161,7 +161,7 @@ namespace stack { }; template - struct checker::value>> { + struct unqualified_checker::value>> { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -185,7 +185,7 @@ namespace stack { }; template - struct checker { + struct unqualified_checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { bool success = lua_isnil(L, index); @@ -204,7 +204,7 @@ namespace stack { }; template - struct checker { + 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); @@ -212,10 +212,10 @@ namespace stack { }; template - struct checker : checker {}; + struct unqualified_checker : unqualified_checker {}; template - struct checker { + struct unqualified_checker { template static bool check(lua_State*, int, Handler&&, record& tracking) { tracking.use(0); @@ -224,7 +224,7 @@ namespace stack { }; template - struct checker { + struct unqualified_checker { template static bool check(lua_State*, int, Handler&&, record& tracking) { tracking.use(0); @@ -233,7 +233,7 @@ namespace stack { }; template - struct checker { + struct unqualified_checker { template static bool check(lua_State*, int, Handler&&, record& tracking) { tracking.use(0); @@ -242,7 +242,7 @@ namespace stack { }; template - struct checker { + struct unqualified_checker { template static bool check(lua_State*, int, Handler&&, record& tracking) { tracking.use(0); @@ -251,7 +251,7 @@ namespace stack { }; template - struct checker { + struct unqualified_checker { template static bool check(lua_State*, int, Handler&&, record& tracking) { tracking.use(0); @@ -260,7 +260,7 @@ namespace stack { }; template - struct checker { + struct unqualified_checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -274,7 +274,7 @@ namespace stack { }; template - struct checker { + struct unqualified_checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -289,7 +289,7 @@ namespace stack { }; template - struct checker { + struct unqualified_checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -304,7 +304,7 @@ namespace stack { }; template - struct checker, type::userdata, C> { + 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); @@ -312,20 +312,20 @@ namespace stack { }; template - struct checker, type::userdata, C> : checker, type::lightuserdata, C> {}; + struct unqualified_checker, type::userdata, C> : unqualified_checker, type::lightuserdata, C> {}; template - struct checker, type::userdata, C> : checker::value, C> {}; + struct unqualified_checker, type::userdata, C> : unqualified_checker::value, C> {}; template - struct checker : stack_detail::basic_check {}; + struct unqualified_checker : stack_detail::basic_check {}; template - struct checker, type::function, C> : checker {}; + struct unqualified_checker, type::function, C> : unqualified_checker {}; template - struct checker : checker {}; + struct unqualified_checker : unqualified_checker {}; template - struct checker { + struct unqualified_checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -363,7 +363,7 @@ namespace stack { }; template - struct checker { + struct unqualified_checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -380,7 +380,7 @@ namespace stack { }; template - struct checker { + struct unqualified_checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -402,7 +402,7 @@ namespace stack { }; template - struct checker { + struct unqualified_checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -416,7 +416,7 @@ namespace stack { }; template - struct checker, type::poly, C> { + struct unqualified_checker, type::poly, C> { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -438,7 +438,7 @@ namespace stack { }; template - struct checker, type::userdata, C> { + struct unqualified_checker, type::userdata, C> { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { const type indextype = type_of(L, index); @@ -497,7 +497,7 @@ namespace stack { }; template - struct checker, type::userdata, C> { + struct unqualified_checker, type::userdata, C> { template static bool check(lua_State* L, int index, type indextype, Handler&& handler, record& tracking) { if (indextype == type::lua_nil) { @@ -515,7 +515,7 @@ namespace stack { }; template - struct checker { + 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); @@ -523,7 +523,7 @@ namespace stack { }; template - struct checker { + 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); @@ -531,7 +531,7 @@ namespace stack { }; template - struct checker::value>> { + struct unqualified_checker::value>> { typedef typename unique_usertype_traits::type T; template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { @@ -571,7 +571,7 @@ namespace stack { }; template - struct checker, type::userdata, C> { + 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); @@ -579,7 +579,7 @@ namespace stack { }; template - struct checker, type::poly, C> { + struct unqualified_checker, type::poly, C> { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { return stack::multi_check(L, index, std::forward(handler), tracking); @@ -587,7 +587,7 @@ namespace stack { }; template - struct checker, type::poly, C> { + struct unqualified_checker, type::poly, C> { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { return stack::multi_check(L, index, std::forward(handler), tracking); @@ -595,7 +595,7 @@ namespace stack { }; template - struct checker, type::poly, C> { + struct unqualified_checker, type::poly, C> { template static bool check(lua_State* L, int index, Handler&&, record& tracking) { type t = type_of(L, index); @@ -614,7 +614,7 @@ namespace stack { #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES template - struct checker, type::poly, C> { + struct unqualified_checker, type::poly, C> { template static bool check(lua_State* L, int index, Handler&&, record& tracking) { type t = type_of(L, index); @@ -633,7 +633,7 @@ namespace stack { #if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT template - struct checker, type::poly, C> { + struct unqualified_checker, type::poly, C> { 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 4f054f7d..465f592b 100644 --- a/include/sol/stack_core.hpp +++ b/include/sol/stack_core.hpp @@ -572,7 +572,7 @@ namespace sol { template struct pusher; template ::value, typename = void> - struct checker; + struct unqualified_checker; template ::value, typename = void> struct qualified_checker; template @@ -919,7 +919,7 @@ namespace sol { return sol_lua_check(types(), L, index, std::forward(handler), tracking); } else { - checker c; + unqualified_checker c; // VC++ has a bad warning here: shut it up (void)c; return c.check(L, index, std::forward(handler), tracking); diff --git a/include/sol/stack_push.hpp b/include/sol/stack_push.hpp index d546504b..9d9eedc3 100644 --- a/include/sol/stack_push.hpp +++ b/include/sol/stack_push.hpp @@ -862,7 +862,6 @@ namespace sol { } static int push(lua_State* L, const char16_t* strb, const char16_t* stre) { - // TODO: use new unicode methods char sbo[SOL_STACK_STRING_OPTIMIZATION_SIZE]; // if our max string space is small enough, use SBO // right off the bat @@ -940,7 +939,6 @@ namespace sol { } static int push(lua_State* L, const char32_t* strb, const char32_t* stre) { - // TODO: use new unicode methods char sbo[SOL_STACK_STRING_OPTIMIZATION_SIZE]; // if our max string space is small enough, use SBO // right off the bat diff --git a/include/sol/traits.hpp b/include/sol/traits.hpp index b3d79075..7013b0ed 100644 --- a/include/sol/traits.hpp +++ b/include/sol/traits.hpp @@ -355,8 +355,24 @@ namespace sol { static std::false_type test(...); }; + struct has_key_comp_impl { + template >().key_comp())> + static std::true_type test(int); + + template + static std::false_type test(...); + }; + + struct has_load_factor_impl { + template >().load_factor())> + static std::true_type test(int); + + template + static std::false_type test(...); + }; + struct has_mapped_type_impl { - template , typename V = typename U::mapped_type> + template ::mapped_type> static std::true_type test(int); template @@ -364,7 +380,7 @@ namespace sol { }; struct has_value_type_impl { - template , typename V = typename U::value_type> + template ::value_type> static std::true_type test(int); template @@ -372,7 +388,7 @@ namespace sol { }; struct has_iterator_impl { - template , typename V = typename U::iterator> + template ::iterator> static std::true_type test(int); template @@ -540,6 +556,12 @@ namespace sol { template struct has_key_type : decltype(meta_detail::has_key_type_impl::test(0)) {}; + template + struct has_key_comp : decltype(meta_detail::has_key_comp_impl::test(0)) {}; + + template + struct has_load_factor : decltype(meta_detail::has_load_factor_impl::test(0)) {}; + template struct has_mapped_type : decltype(meta_detail::has_mapped_type_impl::test(0)) {}; @@ -571,7 +593,10 @@ namespace sol { using is_lookup = meta::all, has_value_type>; template - struct is_matched_lookup : meta_detail::is_matched_lookup_impl::value> {}; + using is_ordered = meta::all, meta::neg>>; + + template + using is_matched_lookup = meta_detail::is_matched_lookup_impl::value>; template using is_string_like = any, std::basic_string>, diff --git a/include/sol/usertype_container.hpp b/include/sol/usertype_container.hpp index 49e46156..9bd7dcb4 100644 --- a/include/sol/usertype_container.hpp +++ b/include/sol/usertype_container.hpp @@ -338,7 +338,9 @@ namespace sol { std::remove_pointer_t>> meta_usertype_container; static const char* metakey = is_shim ? &usertype_traits>>::metatable()[0] : &usertype_traits::metatable()[0]; - static const std::array reg = { { { "__pairs", &meta_usertype_container::pairs_call }, + static const std::array reg = { { + // clang-format off + { "__pairs", &meta_usertype_container::pairs_call }, { "__ipairs", &meta_usertype_container::ipairs_call }, { "__len", &meta_usertype_container::length_call }, { "__index", &meta_usertype_container::index_call }, @@ -354,9 +356,12 @@ namespace sol { { "insert", &meta_usertype_container::insert_call }, { "add", &meta_usertype_container::add_call }, { "find", &meta_usertype_container::find_call }, + { "index_of", &meta_usertype_container::index_of_call }, { "erase", &meta_usertype_container::erase_call }, std::is_pointer::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ "__gc", &detail::usertype_alloc_destruct }, - { nullptr, nullptr } } }; + { nullptr, nullptr } + // clang-format on + } }; if (luaL_newmetatable(L, metakey) == 1) { luaL_setfuncs(L, reg.data(), 0); @@ -434,7 +439,7 @@ namespace sol { }; template - struct checker, type::userdata, C> { + 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); diff --git a/include/sol/usertype_core.hpp b/include/sol/usertype_core.hpp index 649c8407..27975ac4 100644 --- a/include/sol/usertype_core.hpp +++ b/include/sol/usertype_core.hpp @@ -34,6 +34,7 @@ #include "deprecate.hpp" #include "object.hpp" #include "function_types.hpp" +#include "usertype_container.hpp" #include #include @@ -140,8 +141,7 @@ namespace sol { ifx(meta_function::equal_to, f); } if (fx(meta_function::pairs)) { - // TODO: fix this - //ifx(meta_function::pairs, &usertype_container>::pairs_call); + ifx(meta_function::pairs, &usertype_container>::pairs_call); } if (fx(meta_function::length)) { if constexpr (meta::has_size::value || meta::has_size::value) { diff --git a/include/sol/usertype_storage.hpp b/include/sol/usertype_storage.hpp index 3b65c152..b74529b8 100644 --- a/include/sol/usertype_storage.hpp +++ b/include/sol/usertype_storage.hpp @@ -591,23 +591,8 @@ namespace sol { namespace u_detail { // and other amenities return; } - if (is_destruction - && (smt == submetatable_type::reference || smt == submetatable_type::const_reference || smt == submetatable_type::named - || smt == submetatable_type::unique)) { - // gc does not apply to us here - // for reference types (raw T*, std::ref) - // for the named metatable itself, - // or for unique_usertypes, which do their own custom destruction - return; - } int fast_index_table_push = fast_index_table.push(); stack_reference t(L, -fast_index_table_push); - if constexpr (is_lua_c_function_v || is_lua_reference_or_proxy::value) { - stack::set_field(L, s, b.data_, t.stack_index()); - } - else { - stack::set_field(L, s, make_closure(&b.template call, nullptr, ics.binding_data), t.stack_index()); - } if (poison_indexing) { change_indexing(L, smt, @@ -618,6 +603,22 @@ namespace sol { namespace u_detail { &usertype_storage::meta_index_call, &usertype_storage::meta_new_index_call); } + if (is_destruction + && (smt == submetatable_type::reference || smt == submetatable_type::const_reference || smt == submetatable_type::named + || smt == submetatable_type::unique)) { + // gc does not apply to us here + // for reference types (raw T*, std::ref) + // for the named metatable itself, + // or for unique_usertypes, which do their own custom destruction + t.pop(); + return; + } + if constexpr (is_lua_c_function_v || is_lua_reference_or_proxy::value) { + stack::set_field(L, s, b.data_, t.stack_index()); + } + else { + stack::set_field(L, s, make_closure(&b.template call, nullptr, ics.binding_data), t.stack_index()); + } t.pop(); }; if (is_index) { diff --git a/single/include/sol/forward.hpp b/single/include/sol/forward.hpp index 42fa0432..1ec77882 100644 --- a/single/include/sol/forward.hpp +++ b/single/include/sol/forward.hpp @@ -20,8 +20,8 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // This file was generated with a script. -// Generated 2018-12-19 18:01:44.554823 UTC -// This header was generated with sol v2.20.6 (revision 9b29277) +// Generated 2018-12-21 06:03:11.681784 UTC +// This header was generated with sol v2.20.6 (revision c35c66b) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP diff --git a/single/include/sol/sol.hpp b/single/include/sol/sol.hpp index 64a3a963..85151e88 100644 --- a/single/include/sol/sol.hpp +++ b/single/include/sol/sol.hpp @@ -20,8 +20,8 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // This file was generated with a script. -// Generated 2018-12-19 18:01:43.480660 UTC -// This header was generated with sol v2.20.6 (revision 9b29277) +// Generated 2018-12-21 06:03:11.212386 UTC +// This header was generated with sol v2.20.6 (revision c35c66b) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -4118,8 +4118,24 @@ namespace sol { static std::false_type test(...); }; + struct has_key_comp_impl { + template >().key_comp())> + static std::true_type test(int); + + template + static std::false_type test(...); + }; + + struct has_load_factor_impl { + template >().load_factor())> + static std::true_type test(int); + + template + static std::false_type test(...); + }; + struct has_mapped_type_impl { - template , typename V = typename U::mapped_type> + template ::mapped_type> static std::true_type test(int); template @@ -4127,7 +4143,7 @@ namespace sol { }; struct has_value_type_impl { - template , typename V = typename U::value_type> + template ::value_type> static std::true_type test(int); template @@ -4135,7 +4151,7 @@ namespace sol { }; struct has_iterator_impl { - template , typename V = typename U::iterator> + template ::iterator> static std::true_type test(int); template @@ -4303,6 +4319,12 @@ namespace sol { template struct has_key_type : decltype(meta_detail::has_key_type_impl::test(0)) {}; + template + struct has_key_comp : decltype(meta_detail::has_key_comp_impl::test(0)) {}; + + template + struct has_load_factor : decltype(meta_detail::has_load_factor_impl::test(0)) {}; + template struct has_mapped_type : decltype(meta_detail::has_mapped_type_impl::test(0)) {}; @@ -4334,7 +4356,10 @@ namespace sol { using is_lookup = meta::all, has_value_type>; template - struct is_matched_lookup : meta_detail::is_matched_lookup_impl::value> {}; + using is_ordered = meta::all, meta::neg>>; + + template + using is_matched_lookup = meta_detail::is_matched_lookup_impl::value>; template using is_string_like = any, std::basic_string>, @@ -7925,7 +7950,7 @@ namespace sol { template struct pusher; template ::value, typename = void> - struct checker; + struct unqualified_checker; template ::value, typename = void> struct qualified_checker; template @@ -8271,7 +8296,7 @@ namespace sol { return sol_lua_check(types(), L, index, std::forward(handler), tracking); } else { - checker c; + unqualified_checker c; // VC++ has a bad warning here: shut it up (void)c; return c.check(L, index, std::forward(handler), tracking); @@ -8771,7 +8796,7 @@ namespace stack { }; template - struct checker { + struct unqualified_checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -8786,10 +8811,10 @@ namespace stack { }; template - struct qualified_checker : checker, lua_type_of>::value, C> {}; + struct qualified_checker : unqualified_checker, lua_type_of>::value, C> {}; template - struct checker::value>> { + struct unqualified_checker::value>> { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -8852,7 +8877,7 @@ namespace stack { }; template - struct checker::value>> { + struct unqualified_checker::value>> { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -8876,7 +8901,7 @@ namespace stack { }; template - struct checker { + struct unqualified_checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { bool success = lua_isnil(L, index); @@ -8895,7 +8920,7 @@ namespace stack { }; template - struct checker { + 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); @@ -8903,10 +8928,10 @@ namespace stack { }; template - struct checker : checker {}; + struct unqualified_checker : unqualified_checker {}; template - struct checker { + struct unqualified_checker { template static bool check(lua_State*, int, Handler&&, record& tracking) { tracking.use(0); @@ -8915,7 +8940,7 @@ namespace stack { }; template - struct checker { + struct unqualified_checker { template static bool check(lua_State*, int, Handler&&, record& tracking) { tracking.use(0); @@ -8924,7 +8949,7 @@ namespace stack { }; template - struct checker { + struct unqualified_checker { template static bool check(lua_State*, int, Handler&&, record& tracking) { tracking.use(0); @@ -8933,7 +8958,7 @@ namespace stack { }; template - struct checker { + struct unqualified_checker { template static bool check(lua_State*, int, Handler&&, record& tracking) { tracking.use(0); @@ -8942,7 +8967,7 @@ namespace stack { }; template - struct checker { + struct unqualified_checker { template static bool check(lua_State*, int, Handler&&, record& tracking) { tracking.use(0); @@ -8951,7 +8976,7 @@ namespace stack { }; template - struct checker { + struct unqualified_checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -8965,7 +8990,7 @@ namespace stack { }; template - struct checker { + struct unqualified_checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -8980,7 +9005,7 @@ namespace stack { }; template - struct checker { + struct unqualified_checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -8995,7 +9020,7 @@ namespace stack { }; template - struct checker, type::userdata, C> { + 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); @@ -9003,20 +9028,20 @@ namespace stack { }; template - struct checker, type::userdata, C> : checker, type::lightuserdata, C> {}; + struct unqualified_checker, type::userdata, C> : unqualified_checker, type::lightuserdata, C> {}; template - struct checker, type::userdata, C> : checker::value, C> {}; + struct unqualified_checker, type::userdata, C> : unqualified_checker::value, C> {}; template - struct checker : stack_detail::basic_check {}; + struct unqualified_checker : stack_detail::basic_check {}; template - struct checker, type::function, C> : checker {}; + struct unqualified_checker, type::function, C> : unqualified_checker {}; template - struct checker : checker {}; + struct unqualified_checker : unqualified_checker {}; template - struct checker { + struct unqualified_checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -9054,7 +9079,7 @@ namespace stack { }; template - struct checker { + struct unqualified_checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -9071,7 +9096,7 @@ namespace stack { }; template - struct checker { + struct unqualified_checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -9093,7 +9118,7 @@ namespace stack { }; template - struct checker { + struct unqualified_checker { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -9107,7 +9132,7 @@ namespace stack { }; template - struct checker, type::poly, C> { + struct unqualified_checker, type::poly, C> { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); @@ -9129,7 +9154,7 @@ namespace stack { }; template - struct checker, type::userdata, C> { + struct unqualified_checker, type::userdata, C> { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { const type indextype = type_of(L, index); @@ -9188,7 +9213,7 @@ namespace stack { }; template - struct checker, type::userdata, C> { + struct unqualified_checker, type::userdata, C> { template static bool check(lua_State* L, int index, type indextype, Handler&& handler, record& tracking) { if (indextype == type::lua_nil) { @@ -9206,7 +9231,7 @@ namespace stack { }; template - struct checker { + 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); @@ -9214,7 +9239,7 @@ namespace stack { }; template - struct checker { + 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); @@ -9222,7 +9247,7 @@ namespace stack { }; template - struct checker::value>> { + struct unqualified_checker::value>> { typedef typename unique_usertype_traits::type T; template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { @@ -9262,7 +9287,7 @@ namespace stack { }; template - struct checker, type::userdata, C> { + 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); @@ -9270,7 +9295,7 @@ namespace stack { }; template - struct checker, type::poly, C> { + struct unqualified_checker, type::poly, C> { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { return stack::multi_check(L, index, std::forward(handler), tracking); @@ -9278,7 +9303,7 @@ namespace stack { }; template - struct checker, type::poly, C> { + struct unqualified_checker, type::poly, C> { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { return stack::multi_check(L, index, std::forward(handler), tracking); @@ -9286,7 +9311,7 @@ namespace stack { }; template - struct checker, type::poly, C> { + struct unqualified_checker, type::poly, C> { template static bool check(lua_State* L, int index, Handler&&, record& tracking) { type t = type_of(L, index); @@ -9305,7 +9330,7 @@ namespace stack { #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES template - struct checker, type::poly, C> { + struct unqualified_checker, type::poly, C> { template static bool check(lua_State* L, int index, Handler&&, record& tracking) { type t = type_of(L, index); @@ -9324,7 +9349,7 @@ namespace stack { #if defined(SOL_STD_VARIANT) && SOL_STD_VARIANT template - struct checker, type::poly, C> { + struct unqualified_checker, type::poly, C> { typedef std::variant V; typedef std::variant_size V_size; typedef std::integral_constant V_is_empty; @@ -11788,7 +11813,6 @@ namespace sol { } static int push(lua_State* L, const char16_t* strb, const char16_t* stre) { - // TODO: use new unicode methods char sbo[SOL_STACK_STRING_OPTIMIZATION_SIZE]; // if our max string space is small enough, use SBO // right off the bat @@ -11866,7 +11890,6 @@ namespace sol { } static int push(lua_State* L, const char32_t* strb, const char32_t* stre) { - // TODO: use new unicode methods char sbo[SOL_STACK_STRING_OPTIMIZATION_SIZE]; // if our max string space is small enough, use SBO // right off the bat @@ -12763,40 +12786,115 @@ namespace sol { // end of sol/object_base.hpp -// beginning of sol/as_args.hpp - namespace sol { - template - struct as_args_t { - T src; + + template + class basic_object : public basic_object_base { + private: + typedef basic_object_base base_t; + + template + basic_object(std::integral_constant, lua_State* L, int index = -1) noexcept + : base_t(L, index) { + if (invert_and_pop) { + lua_pop(L, -index); + } + } + + public: + basic_object() noexcept = default; + template , basic_object>>, meta::neg>, is_lua_reference>> = meta::enabler> + basic_object(T&& r) + : base_t(std::forward(r)) { + } + template >> = meta::enabler> + basic_object(lua_State* L, T&& r) + : base_t(L, std::forward(r)) { + } + basic_object(lua_nil_t r) + : base_t(r) { + } + basic_object(const basic_object&) = default; + basic_object(basic_object&&) = default; + basic_object(const stack_reference& r) noexcept + : basic_object(r.lua_state(), r.stack_index()) { + } + basic_object(stack_reference&& r) noexcept + : basic_object(r.lua_state(), r.stack_index()) { + } + template + basic_object(const proxy_base& r) noexcept + : basic_object(r.operator basic_object()) { + } + template + basic_object(proxy_base&& r) noexcept + : basic_object(r.operator basic_object()) { + } + basic_object(lua_State* L, lua_nil_t r) noexcept + : base_t(L, r) { + } + basic_object(lua_State* L, int index = -1) noexcept + : base_t(L, index) { + } + basic_object(lua_State* L, absolute_index index) noexcept + : base_t(L, index) { + } + basic_object(lua_State* L, raw_index index) noexcept + : base_t(L, index) { + } + basic_object(lua_State* L, ref_index index) noexcept + : base_t(L, index) { + } + template + basic_object(lua_State* L, in_place_type_t, Args&&... args) noexcept + : basic_object(std::integral_constant::value>(), L, -stack::push(L, std::forward(args)...)) { + } + template + basic_object(lua_State* L, in_place_t, T&& arg, Args&&... args) noexcept + : basic_object(L, in_place_type, std::forward(arg), std::forward(args)...) { + } + basic_object& operator=(const basic_object&) = default; + basic_object& operator=(basic_object&&) = default; + basic_object& operator=(const base_type& b) { + base_t::operator=(b); + return *this; + } + basic_object& operator=(base_type&& b) { + base_t::operator=(std::move(b)); + return *this; + } + template + basic_object& operator=(const proxy_base& r) { + this->operator=(r.operator basic_object()); + return *this; + } + template + basic_object& operator=(proxy_base&& r) { + this->operator=(r.operator basic_object()); + return *this; + } }; - template - auto as_args(Source&& source) { - return as_args_t { std::forward(source) }; + template + object make_object(lua_State* L, T&& value) { + return make_reference(L, std::forward(value)); } - namespace stack { - template - struct pusher> { - int push(lua_State* L, const as_args_t& e) { - int p = 0; - for (const auto& i : e.src) { - p += stack::push(L, i); - } - return p; - } - }; - } // namespace stack + template + object make_object(lua_State* L, Args&&... args) { + return make_reference(L, std::forward(args)...); + } } // namespace sol -// end of sol/as_args.hpp +// end of sol/object.hpp -// beginning of sol/variadic_args.hpp +// beginning of sol/function.hpp -// beginning of sol/stack_proxy.hpp +// beginning of sol/unsafe_function.hpp -// beginning of sol/stack_proxy_base.hpp +// beginning of sol/function_result.hpp + +// beginning of sol/protected_function_result.hpp // beginning of sol/proxy_base.hpp @@ -12831,114 +12929,6 @@ namespace sol { // end of sol/proxy_base.hpp -namespace sol { - struct stack_proxy_base : public proxy_base { - private: - lua_State* L; - int index; - - public: - stack_proxy_base() - : L(nullptr), index(0) { - } - stack_proxy_base(lua_State* L, int index) - : L(L), index(index) { - } - - template - decltype(auto) get() const { - return stack::get(L, stack_index()); - } - - template - bool is() const { - return stack::check(L, stack_index()); - } - - template - decltype(auto) as() const { - return get(); - } - - type get_type() const noexcept { - return type_of(lua_state(), stack_index()); - } - - int push() const { - return push(L); - } - - int push(lua_State* Ls) const { - lua_pushvalue(Ls, index); - return 1; - } - - lua_State* lua_state() const { - return L; - } - int stack_index() const { - return index; - } - }; - - namespace stack { - template <> - struct unqualified_getter { - static stack_proxy_base get(lua_State* L, int index = -1) { - return stack_proxy_base(L, index); - } - }; - - template <> - struct pusher { - static int push(lua_State*, const stack_proxy_base& ref) { - return ref.push(); - } - }; - } // namespace stack - -} // namespace sol - -// end of sol/stack_proxy_base.hpp - -namespace sol { - struct stack_proxy : public stack_proxy_base { - public: - stack_proxy() - : stack_proxy_base() { - } - stack_proxy(lua_State* L, int index) - : stack_proxy_base(L, index) { - } - - template - decltype(auto) call(Args&&... args); - - template - decltype(auto) operator()(Args&&... args) { - return call<>(std::forward(args)...); - } - }; - - namespace stack { - template <> - struct unqualified_getter { - static stack_proxy get(lua_State* L, int index = -1) { - return stack_proxy(L, index); - } - }; - - template <> - struct pusher { - static int push(lua_State*, const stack_proxy& ref) { - return ref.push(); - } - }; - } // namespace stack -} // namespace sol - -// end of sol/stack_proxy.hpp - // beginning of sol/stack_iterator.hpp namespace sol { @@ -13067,268 +13057,117 @@ namespace sol { // end of sol/stack_iterator.hpp +// beginning of sol/stack_proxy.hpp + +// beginning of sol/stack_proxy_base.hpp + namespace sol { - struct variadic_args { + struct stack_proxy_base : public proxy_base { private: lua_State* L; int index; - int stacktop; public: - typedef stack_proxy reference_type; - typedef stack_proxy value_type; - typedef stack_proxy* pointer; - typedef std::ptrdiff_t difference_type; - typedef std::size_t size_type; - typedef stack_iterator iterator; - typedef stack_iterator const_iterator; - typedef std::reverse_iterator reverse_iterator; - typedef std::reverse_iterator const_reverse_iterator; - - variadic_args() = default; - variadic_args(lua_State* luastate, int stackindex = -1) - : L(luastate), index(lua_absindex(luastate, stackindex)), stacktop(lua_gettop(luastate)) { + stack_proxy_base() + : L(nullptr), index(0) { } - variadic_args(lua_State* luastate, int stackindex, int lastindex) - : L(luastate), index(lua_absindex(luastate, stackindex)), stacktop(lastindex) { - } - variadic_args(const variadic_args&) = default; - variadic_args& operator=(const variadic_args&) = default; - variadic_args(variadic_args&& o) - : L(o.L), index(o.index), stacktop(o.stacktop) { - // Must be manual, otherwise destructor will screw us - // return count being 0 is enough to keep things clean - // but will be thorough - o.L = nullptr; - o.index = 0; - o.stacktop = 0; - } - variadic_args& operator=(variadic_args&& o) { - L = o.L; - index = o.index; - stacktop = o.stacktop; - // Must be manual, otherwise destructor will screw us - // return count being 0 is enough to keep things clean - // but will be thorough - o.L = nullptr; - o.index = 0; - o.stacktop = 0; - return *this; + stack_proxy_base(lua_State* L, int index) + : L(L), index(index) { } - iterator begin() { - return iterator(L, index, stacktop + 1); - } - iterator end() { - return iterator(L, stacktop + 1, stacktop + 1); - } - const_iterator begin() const { - return const_iterator(L, index, stacktop + 1); - } - const_iterator end() const { - return const_iterator(L, stacktop + 1, stacktop + 1); - } - const_iterator cbegin() const { - return begin(); - } - const_iterator cend() const { - return end(); + template + decltype(auto) get() const { + return stack::get(L, stack_index()); } - reverse_iterator rbegin() { - return std::reverse_iterator(begin()); + template + bool is() const { + return stack::check(L, stack_index()); } - reverse_iterator rend() { - return std::reverse_iterator(end()); + + template + decltype(auto) as() const { + return get(); } - const_reverse_iterator rbegin() const { - return std::reverse_iterator(begin()); - } - const_reverse_iterator rend() const { - return std::reverse_iterator(end()); - } - const_reverse_iterator crbegin() const { - return std::reverse_iterator(cbegin()); - } - const_reverse_iterator crend() const { - return std::reverse_iterator(cend()); + + type get_type() const noexcept { + return type_of(lua_state(), stack_index()); } int push() const { return push(L); } - int push(lua_State* target) const { - int pushcount = 0; - for (int i = index; i <= stacktop; ++i) { - lua_pushvalue(L, i); - pushcount += 1; - } - if (target != L) { - lua_xmove(L, target, pushcount); - } - return pushcount; - } - - template - decltype(auto) get(difference_type index_offset = 0) const { - return stack::get(L, index + static_cast(index_offset)); - } - - type get_type(difference_type index_offset = 0) const noexcept { - return type_of(L, index + static_cast(index_offset)); - } - - stack_proxy operator[](difference_type index_offset) const { - return stack_proxy(L, index + static_cast(index_offset)); + int push(lua_State* Ls) const { + lua_pushvalue(Ls, index); + return 1; } lua_State* lua_state() const { return L; - }; + } int stack_index() const { return index; - }; - int leftover_count() const { - return stacktop - (index - 1); - } - std::size_t size() const { - return static_cast(leftover_count()); - } - int top() const { - return stacktop; } }; namespace stack { template <> - struct unqualified_getter { - static variadic_args get(lua_State* L, int index, record& tracking) { - tracking.last = 0; - return variadic_args(L, index); + struct unqualified_getter { + static stack_proxy_base get(lua_State* L, int index = -1) { + return stack_proxy_base(L, index); } }; template <> - struct pusher { - static int push(lua_State* L, const variadic_args& ref) { - return ref.push(L); + struct pusher { + static int push(lua_State*, const stack_proxy_base& ref) { + return ref.push(); + } + }; + } // namespace stack + +} // namespace sol + +// end of sol/stack_proxy_base.hpp + +namespace sol { + struct stack_proxy : public stack_proxy_base { + public: + stack_proxy() + : stack_proxy_base() { + } + stack_proxy(lua_State* L, int index) + : stack_proxy_base(L, index) { + } + + template + decltype(auto) call(Args&&... args); + + template + decltype(auto) operator()(Args&&... args) { + return call<>(std::forward(args)...); + } + }; + + namespace stack { + template <> + struct unqualified_getter { + static stack_proxy get(lua_State* L, int index = -1) { + return stack_proxy(L, index); + } + }; + + template <> + struct pusher { + static int push(lua_State*, const stack_proxy& ref) { + return ref.push(); } }; } // namespace stack } // namespace sol -// end of sol/variadic_args.hpp - -namespace sol { - - template - class basic_object : public basic_object_base { - private: - typedef basic_object_base base_t; - - template - basic_object(std::integral_constant, lua_State* L, int index = -1) noexcept - : base_t(L, index) { - if (invert_and_pop) { - lua_pop(L, -index); - } - } - - public: - basic_object() noexcept = default; - template , basic_object>>, meta::neg>, is_lua_reference>> = meta::enabler> - basic_object(T&& r) - : base_t(std::forward(r)) { - } - template >> = meta::enabler> - basic_object(lua_State* L, T&& r) - : base_t(L, std::forward(r)) { - } - basic_object(lua_nil_t r) - : base_t(r) { - } - basic_object(const basic_object&) = default; - basic_object(basic_object&&) = default; - basic_object(const stack_reference& r) noexcept - : basic_object(r.lua_state(), r.stack_index()) { - } - basic_object(stack_reference&& r) noexcept - : basic_object(r.lua_state(), r.stack_index()) { - } - template - basic_object(const proxy_base& r) noexcept - : basic_object(r.operator basic_object()) { - } - template - basic_object(proxy_base&& r) noexcept - : basic_object(r.operator basic_object()) { - } - basic_object(lua_State* L, lua_nil_t r) noexcept - : base_t(L, r) { - } - basic_object(lua_State* L, int index = -1) noexcept - : base_t(L, index) { - } - basic_object(lua_State* L, absolute_index index) noexcept - : base_t(L, index) { - } - basic_object(lua_State* L, raw_index index) noexcept - : base_t(L, index) { - } - basic_object(lua_State* L, ref_index index) noexcept - : base_t(L, index) { - } - template - basic_object(lua_State* L, in_place_type_t, Args&&... args) noexcept - : basic_object(std::integral_constant::value>(), L, -stack::push(L, std::forward(args)...)) { - } - template - basic_object(lua_State* L, in_place_t, T&& arg, Args&&... args) noexcept - : basic_object(L, in_place_type, std::forward(arg), std::forward(args)...) { - } - basic_object& operator=(const basic_object&) = default; - basic_object& operator=(basic_object&&) = default; - basic_object& operator=(const base_type& b) { - base_t::operator=(b); - return *this; - } - basic_object& operator=(base_type&& b) { - base_t::operator=(std::move(b)); - return *this; - } - template - basic_object& operator=(const proxy_base& r) { - this->operator=(r.operator basic_object()); - return *this; - } - template - basic_object& operator=(proxy_base&& r) { - this->operator=(r.operator basic_object()); - return *this; - } - }; - - template - object make_object(lua_State* L, T&& value) { - return make_reference(L, std::forward(value)); - } - - template - object make_object(lua_State* L, Args&&... args) { - return make_reference(L, std::forward(args)...); - } -} // namespace sol - -// end of sol/object.hpp - -// beginning of sol/function.hpp - -// beginning of sol/unsafe_function.hpp - -// beginning of sol/function_result.hpp - -// beginning of sol/protected_function_result.hpp +// end of sol/stack_proxy.hpp namespace sol { struct protected_function_result : public proxy_base { @@ -17017,176 +16856,6 @@ namespace detail { // end of sol/deprecate.hpp -namespace sol { - namespace u_detail { - constexpr const lua_Integer toplevel_magic = static_cast(0xCCC2CCC1); - - constexpr const int environment_index = 1; - constexpr const int usertype_storage_index = 2; - constexpr const int usertype_storage_base_index = 3; - constexpr const int exact_function_index = 4; - constexpr const int magic_index = 5; - - constexpr const int simple_usertype_storage_index = 2; - constexpr const int index_function_index = 3; - constexpr const int new_index_function_index = 4; - - constexpr const int base_walking_failed_index = -32467; - constexpr const int lookup_failed_index = -42469; - - enum class submetatable_type { - // must be sequential - value, - reference, - unique, - const_reference, - const_value, - // must be LAST! - named - }; - - inline auto make_string_view(string_view s) { - return s; - } - - inline auto make_string_view(call_construction) { - return string_view(to_string(meta_function::call_function)); - } - - inline auto make_string_view(meta_function mf) { - return string_view(to_string(mf)); - } - - inline auto make_string_view(base_classes_tag) { - return string_view(detail::base_class_cast_key()); - } - - template - inline std::string make_string(Arg&& arg) { - string_view s = make_string_view(arg); - return std::string(s.data(), s.size()); - } - - inline int is_indexer(string_view s) { - if (s == to_string(meta_function::index)) { - return 1; - } - else if (s == to_string(meta_function::new_index)) { - return 2; - } - return 0; - } - - inline int is_indexer(meta_function mf) { - if (mf == meta_function::index) { - return 1; - } - else if (mf == meta_function::new_index) { - return 2; - } - return 0; - } - - inline int is_indexer(call_construction) { - return 0; - } - } // namespace u_detail - - namespace detail { - - template - inline void insert_default_registrations(IFx&& ifx, Fx&& fx) { - if constexpr (is_automagical::value) { - if (fx(meta_function::less_than)) { - if constexpr (meta::supports_op_less::value) { - lua_CFunction f = &comparsion_operator_wrap>; - ifx(meta_function::less_than, f); - } - } - if (fx(meta_function::less_than_or_equal_to)) { - if constexpr (meta::supports_op_less_equal::value) { - lua_CFunction f = &comparsion_operator_wrap>; - ifx(meta_function::less_than_or_equal_to, f); - } - } - if (fx(meta_function::equal_to)) { - if constexpr (meta::supports_op_equal::value) { - lua_CFunction f = &comparsion_operator_wrap>; - ifx(meta_function::equal_to, f); - } - else { - lua_CFunction f = &comparsion_operator_wrap; - ifx(meta_function::equal_to, f); - } - if (fx(meta_function::pairs)) { - // TODO: fix this - //ifx(meta_function::pairs, &usertype_container>::pairs_call); - } - if (fx(meta_function::length)) { - if constexpr (meta::has_size::value || meta::has_size::value) { - auto f = &default_size; - ifx(meta_function::length, f); - } - } - if (fx(meta_function::to_string)) { - if constexpr (is_to_stringable::value) { - auto f = &detail::static_trampoline<&default_to_string>; - ifx(meta_function::to_string, f); - } - } - if (fx(meta_function::call_function)) { - if constexpr (meta::has_deducible_signature::value) { - auto f = &c_call; - ifx(meta_function::call_function, f); - } - } - } - } - } - } // namespace detail - - namespace stack { namespace stack_detail { - template - struct undefined_metatable { - typedef meta::all>, std::is_destructible> is_destructible; - typedef std::remove_pointer_t P; - lua_State* L; - const char* key; - - undefined_metatable(lua_State* l, const char* k) - : L(l), key(k) { - } - - void operator()() const { - if (luaL_newmetatable(L, key) == 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); - if constexpr (!std::is_pointer_v) { - l[index] = luaL_Reg{ to_string(meta_function::garbage_collect).c_str(), detail::make_destructor

() }; - } - luaL_setfuncs(L, l, 0); - - // __type table - lua_createtable(L, 0, 2); - const std::string& name = detail::demangle(); - lua_pushlstring(L, name.c_str(), name.size()); - lua_setfield(L, -2, "name"); - lua_CFunction is_func = &detail::is_check; - lua_pushcclosure(L, is_func, 0); - lua_setfield(L, -2, "is"); - lua_setfield(L, -2, to_string(meta_function::type).c_str()); - } - lua_setmetatable(L, -2); - } - }; - } - } // namespace stack::stack_detail -} // namespace sol - -// end of sol/usertype_core.hpp - // beginning of sol/usertype_container.hpp // beginning of sol/container_traits.hpp @@ -17683,15 +17352,16 @@ namespace sol { template struct container_traits_default>, meta::has_value_type>>, meta::has_iterator>>>::value>> { private: - typedef std::remove_pointer_t>> T; + using T = std::remove_pointer_t>>; private: - typedef container_traits deferred_traits; - typedef meta::is_associative is_associative; - typedef meta::is_lookup is_lookup; - typedef meta::is_matched_lookup is_matched_lookup; - typedef typename T::iterator iterator; - typedef typename T::value_type value_type; + using deferred_traits = container_traits; + using is_associative = meta::is_associative; + using is_lookup = meta::is_lookup; + using is_ordered = meta::is_ordered; + using is_matched_lookup = meta::is_matched_lookup; + using iterator = typename T::iterator; + using value_type = typename T::value_type; typedef std::conditional_t, std::conditional_t static detail::error_result find_has_associative_lookup(std::true_type, lua_State* L, T& self) { - decltype(auto) key = stack::unqualified_get(L, 2); - auto it = self.find(key); - if (it == deferred_traits::end(L, self)) { - return stack::push(L, lua_nil); - } - if constexpr (idx_of) { - return stack::push(L, std::distance(deferred_traits::begin(L, self), it)); + if constexpr (!is_ordered::value && idx_of) { + (void)L; + (void)self; + return detail::error_result("cannot perform an 'index_of': '%s's is not an ordered container", detail::demangle().data()); } else { - return get_associative(is_associative(), L, it); + decltype(auto) key = stack::unqualified_get(L, 2); + auto it = self.find(key); + if (it == deferred_traits::end(L, self)) { + return stack::push(L, lua_nil); + } + if constexpr (idx_of) { + auto dist = std::distance(deferred_traits::begin(L, self), it); + dist -= deferred_traits::index_adjustment(L, self); + return stack::push(L, dist); + } + else { + return get_associative(is_associative(), L, it); + } } } template static detail::error_result find_has_associative_lookup(std::false_type, lua_State* L, T& self) { - decltype(auto) value = stack::unqualified_get(L, 2); - auto it = self.find(value); - if (it == deferred_traits::end(L, self)) { - return stack::push(L, lua_nil); - } - if constexpr (idx_of) { - return stack::push(L, std::distance(deferred_traits::begin(L, self), it)); + if constexpr (!is_ordered::value && idx_of) { + (void)L; + (void)self; + return detail::error_result("cannot perform an 'index_of': '%s's is not an ordered container", detail::demangle().data()); } else { - return get_associative(is_associative(), L, it); + decltype(auto) value = stack::unqualified_get(L, 2); + auto it = self.find(value); + if (it == deferred_traits::end(L, self)) { + return stack::push(L, lua_nil); + } + if constexpr (idx_of) { + auto dist = std::distance(deferred_traits::begin(L, self), it); + dist -= deferred_traits::index_adjustment(L, self); + return stack::push(L, dist); + } + else { + return get_associative(is_associative(), L, it); + } } } @@ -17984,12 +17672,13 @@ namespace sol { return find_has_associative_lookup(meta::any(), L, self); } - static detail::error_result find_associative_lookup(std::true_type, lua_State* L, iterator& it, std::size_t) { + static detail::error_result find_associative_lookup(std::true_type, lua_State* L, T&, iterator& it, std::size_t) { return get_associative(is_associative(), L, it); } - static detail::error_result find_associative_lookup(std::false_type, lua_State* L, iterator&, std::size_t index) { - return stack::push(L, index); + static detail::error_result find_associative_lookup(std::false_type, lua_State* L, T& self, iterator&, std::size_t idx) { + idx -= deferred_traits::index_adjustment(L, self); + return stack::push(L, idx); } template @@ -18002,8 +17691,8 @@ namespace sol { decltype(auto) value = stack::unqualified_get(L, 2); auto it = deferred_traits::begin(L, self); auto e = deferred_traits::end(L, self); - std::size_t index = 1; - for (;; ++it, ++index) { + std::size_t idx = 0; + for (;; ++it, ++idx) { if (it == e) { return stack::push(L, lua_nil); } @@ -18011,7 +17700,7 @@ namespace sol { break; } } - return find_associative_lookup(meta::any>(), L, it, index); + return find_associative_lookup(meta::all, meta::any>(), L, self, it, idx); } template @@ -18493,7 +18182,8 @@ namespace sol { for (std::size_t idx = 0; idx < N; ++idx) { const auto& v = self[idx]; if (v == value) { - return stack::push(L, idx + 1); + idx -= deferred_traits::index_adjustment(L, self); + return stack::push(L, idx); } } return stack::push(L, lua_nil); @@ -18941,7 +18631,9 @@ namespace sol { std::remove_pointer_t>> meta_usertype_container; static const char* metakey = is_shim ? &usertype_traits>>::metatable()[0] : &usertype_traits::metatable()[0]; - static const std::array reg = { { { "__pairs", &meta_usertype_container::pairs_call }, + static const std::array reg = { { + // clang-format off + { "__pairs", &meta_usertype_container::pairs_call }, { "__ipairs", &meta_usertype_container::ipairs_call }, { "__len", &meta_usertype_container::length_call }, { "__index", &meta_usertype_container::index_call }, @@ -18957,9 +18649,12 @@ namespace sol { { "insert", &meta_usertype_container::insert_call }, { "add", &meta_usertype_container::add_call }, { "find", &meta_usertype_container::find_call }, + { "index_of", &meta_usertype_container::index_of_call }, { "erase", &meta_usertype_container::erase_call }, std::is_pointer::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ "__gc", &detail::usertype_alloc_destruct }, - { nullptr, nullptr } } }; + { nullptr, nullptr } + // clang-format on + } }; if (luaL_newmetatable(L, metakey) == 1) { luaL_setfuncs(L, reg.data(), 0); @@ -19037,7 +18732,7 @@ namespace sol { }; template - struct checker, type::userdata, C> { + 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); @@ -19063,6 +18758,175 @@ namespace sol { // end of sol/usertype_container.hpp +namespace sol { + namespace u_detail { + constexpr const lua_Integer toplevel_magic = static_cast(0xCCC2CCC1); + + constexpr const int environment_index = 1; + constexpr const int usertype_storage_index = 2; + constexpr const int usertype_storage_base_index = 3; + constexpr const int exact_function_index = 4; + constexpr const int magic_index = 5; + + constexpr const int simple_usertype_storage_index = 2; + constexpr const int index_function_index = 3; + constexpr const int new_index_function_index = 4; + + constexpr const int base_walking_failed_index = -32467; + constexpr const int lookup_failed_index = -42469; + + enum class submetatable_type { + // must be sequential + value, + reference, + unique, + const_reference, + const_value, + // must be LAST! + named + }; + + inline auto make_string_view(string_view s) { + return s; + } + + inline auto make_string_view(call_construction) { + return string_view(to_string(meta_function::call_function)); + } + + inline auto make_string_view(meta_function mf) { + return string_view(to_string(mf)); + } + + inline auto make_string_view(base_classes_tag) { + return string_view(detail::base_class_cast_key()); + } + + template + inline std::string make_string(Arg&& arg) { + string_view s = make_string_view(arg); + return std::string(s.data(), s.size()); + } + + inline int is_indexer(string_view s) { + if (s == to_string(meta_function::index)) { + return 1; + } + else if (s == to_string(meta_function::new_index)) { + return 2; + } + return 0; + } + + inline int is_indexer(meta_function mf) { + if (mf == meta_function::index) { + return 1; + } + else if (mf == meta_function::new_index) { + return 2; + } + return 0; + } + + inline int is_indexer(call_construction) { + return 0; + } + } // namespace u_detail + + namespace detail { + + template + inline void insert_default_registrations(IFx&& ifx, Fx&& fx) { + if constexpr (is_automagical::value) { + if (fx(meta_function::less_than)) { + if constexpr (meta::supports_op_less::value) { + lua_CFunction f = &comparsion_operator_wrap>; + ifx(meta_function::less_than, f); + } + } + if (fx(meta_function::less_than_or_equal_to)) { + if constexpr (meta::supports_op_less_equal::value) { + lua_CFunction f = &comparsion_operator_wrap>; + ifx(meta_function::less_than_or_equal_to, f); + } + } + if (fx(meta_function::equal_to)) { + if constexpr (meta::supports_op_equal::value) { + lua_CFunction f = &comparsion_operator_wrap>; + ifx(meta_function::equal_to, f); + } + else { + lua_CFunction f = &comparsion_operator_wrap; + ifx(meta_function::equal_to, f); + } + if (fx(meta_function::pairs)) { + ifx(meta_function::pairs, &usertype_container>::pairs_call); + } + if (fx(meta_function::length)) { + if constexpr (meta::has_size::value || meta::has_size::value) { + auto f = &default_size; + ifx(meta_function::length, f); + } + } + if (fx(meta_function::to_string)) { + if constexpr (is_to_stringable::value) { + auto f = &detail::static_trampoline<&default_to_string>; + ifx(meta_function::to_string, f); + } + } + if (fx(meta_function::call_function)) { + if constexpr (meta::has_deducible_signature::value) { + auto f = &c_call; + ifx(meta_function::call_function, f); + } + } + } + } + } + } // namespace detail + + namespace stack { namespace stack_detail { + template + struct undefined_metatable { + typedef meta::all>, std::is_destructible> is_destructible; + typedef std::remove_pointer_t P; + lua_State* L; + const char* key; + + undefined_metatable(lua_State* l, const char* k) + : L(l), key(k) { + } + + void operator()() const { + if (luaL_newmetatable(L, key) == 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); + if constexpr (!std::is_pointer_v) { + l[index] = luaL_Reg{ to_string(meta_function::garbage_collect).c_str(), detail::make_destructor

() }; + } + luaL_setfuncs(L, l, 0); + + // __type table + lua_createtable(L, 0, 2); + const std::string& name = detail::demangle(); + lua_pushlstring(L, name.c_str(), name.size()); + lua_setfield(L, -2, "name"); + lua_CFunction is_func = &detail::is_check; + lua_pushcclosure(L, is_func, 0); + lua_setfield(L, -2, "is"); + lua_setfield(L, -2, to_string(meta_function::type).c_str()); + } + lua_setmetatable(L, -2); + } + }; + } + } // namespace stack::stack_detail +} // namespace sol + +// end of sol/usertype_core.hpp + // beginning of sol/usertype_storage.hpp namespace sol { namespace u_detail { @@ -19626,23 +19490,8 @@ namespace sol { namespace u_detail { // and other amenities return; } - if (is_destruction - && (smt == submetatable_type::reference || smt == submetatable_type::const_reference || smt == submetatable_type::named - || smt == submetatable_type::unique)) { - // gc does not apply to us here - // for reference types (raw T*, std::ref) - // for the named metatable itself, - // or for unique_usertypes, which do their own custom destruction - return; - } int fast_index_table_push = fast_index_table.push(); stack_reference t(L, -fast_index_table_push); - if constexpr (is_lua_c_function_v || is_lua_reference_or_proxy::value) { - stack::set_field(L, s, b.data_, t.stack_index()); - } - else { - stack::set_field(L, s, make_closure(&b.template call, nullptr, ics.binding_data), t.stack_index()); - } if (poison_indexing) { change_indexing(L, smt, @@ -19653,6 +19502,22 @@ namespace sol { namespace u_detail { &usertype_storage::meta_index_call, &usertype_storage::meta_new_index_call); } + if (is_destruction + && (smt == submetatable_type::reference || smt == submetatable_type::const_reference || smt == submetatable_type::named + || smt == submetatable_type::unique)) { + // gc does not apply to us here + // for reference types (raw T*, std::ref) + // for the named metatable itself, + // or for unique_usertypes, which do their own custom destruction + t.pop(); + return; + } + if constexpr (is_lua_c_function_v || is_lua_reference_or_proxy::value) { + stack::set_field(L, s, b.data_, t.stack_index()); + } + else { + stack::set_field(L, s, make_closure(&b.template call, nullptr, ics.binding_data), t.stack_index()); + } t.pop(); }; if (is_index) { @@ -22540,6 +22405,190 @@ namespace sol { // end of sol/userdata.hpp +// beginning of sol/as_args.hpp + +namespace sol { + template + struct as_args_t { + T src; + }; + + template + auto as_args(Source&& source) { + return as_args_t { std::forward(source) }; + } + + namespace stack { + template + struct pusher> { + int push(lua_State* L, const as_args_t& e) { + int p = 0; + for (const auto& i : e.src) { + p += stack::push(L, i); + } + return p; + } + }; + } // namespace stack +} // namespace sol + +// end of sol/as_args.hpp + +// beginning of sol/variadic_args.hpp + +namespace sol { + struct variadic_args { + private: + lua_State* L; + int index; + int stacktop; + + public: + typedef stack_proxy reference_type; + typedef stack_proxy value_type; + typedef stack_proxy* pointer; + typedef std::ptrdiff_t difference_type; + typedef std::size_t size_type; + typedef stack_iterator iterator; + typedef stack_iterator const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + variadic_args() = default; + variadic_args(lua_State* luastate, int stackindex = -1) + : L(luastate), index(lua_absindex(luastate, stackindex)), stacktop(lua_gettop(luastate)) { + } + variadic_args(lua_State* luastate, int stackindex, int lastindex) + : L(luastate), index(lua_absindex(luastate, stackindex)), stacktop(lastindex) { + } + variadic_args(const variadic_args&) = default; + variadic_args& operator=(const variadic_args&) = default; + variadic_args(variadic_args&& o) + : L(o.L), index(o.index), stacktop(o.stacktop) { + // Must be manual, otherwise destructor will screw us + // return count being 0 is enough to keep things clean + // but will be thorough + o.L = nullptr; + o.index = 0; + o.stacktop = 0; + } + variadic_args& operator=(variadic_args&& o) { + L = o.L; + index = o.index; + stacktop = o.stacktop; + // Must be manual, otherwise destructor will screw us + // return count being 0 is enough to keep things clean + // but will be thorough + o.L = nullptr; + o.index = 0; + o.stacktop = 0; + return *this; + } + + iterator begin() { + return iterator(L, index, stacktop + 1); + } + iterator end() { + return iterator(L, stacktop + 1, stacktop + 1); + } + const_iterator begin() const { + return const_iterator(L, index, stacktop + 1); + } + const_iterator end() const { + return const_iterator(L, stacktop + 1, stacktop + 1); + } + const_iterator cbegin() const { + return begin(); + } + const_iterator cend() const { + return end(); + } + + reverse_iterator rbegin() { + return std::reverse_iterator(begin()); + } + reverse_iterator rend() { + return std::reverse_iterator(end()); + } + const_reverse_iterator rbegin() const { + return std::reverse_iterator(begin()); + } + const_reverse_iterator rend() const { + return std::reverse_iterator(end()); + } + const_reverse_iterator crbegin() const { + return std::reverse_iterator(cbegin()); + } + const_reverse_iterator crend() const { + return std::reverse_iterator(cend()); + } + + int push() const { + return push(L); + } + + int push(lua_State* target) const { + int pushcount = 0; + for (int i = index; i <= stacktop; ++i) { + lua_pushvalue(L, i); + pushcount += 1; + } + if (target != L) { + lua_xmove(L, target, pushcount); + } + return pushcount; + } + + template + decltype(auto) get(difference_type index_offset = 0) const { + return stack::get(L, index + static_cast(index_offset)); + } + + type get_type(difference_type index_offset = 0) const noexcept { + return type_of(L, index + static_cast(index_offset)); + } + + stack_proxy operator[](difference_type index_offset) const { + return stack_proxy(L, index + static_cast(index_offset)); + } + + lua_State* lua_state() const { + return L; + }; + int stack_index() const { + return index; + }; + int leftover_count() const { + return stacktop - (index - 1); + } + std::size_t size() const { + return static_cast(leftover_count()); + } + int top() const { + return stacktop; + } + }; + + namespace stack { + template <> + struct unqualified_getter { + static variadic_args get(lua_State* L, int index, record& tracking) { + tracking.last = 0; + return variadic_args(L, index); + } + }; + + template <> + struct pusher { + static int push(lua_State* L, const variadic_args& ref) { + return ref.push(L); + } + }; + } // namespace stack +} // namespace sol + +// end of sol/variadic_args.hpp + // beginning of sol/variadic_results.hpp // beginning of sol/as_returns.hpp diff --git a/tests/compile_tests/source/compatibility/compat-5.3.cpp b/tests/compile_tests/source/compatibility/compat-5.3.cpp index 7a64333a..dacb831f 100644 --- a/tests/compile_tests/source/compatibility/compat-5.3.cpp +++ b/tests/compile_tests/source/compatibility/compat-5.3.cpp @@ -23,4 +23,4 @@ #include "../sol_defines.hpp" -#include +#include diff --git a/tests/compile_tests/source/compatibility/version.cpp b/tests/compile_tests/source/compatibility/version.cpp index d074bbae..0cefa7d5 100644 --- a/tests/compile_tests/source/compatibility/version.cpp +++ b/tests/compile_tests/source/compatibility/version.cpp @@ -23,4 +23,4 @@ #include "../sol_defines.hpp" -#include +#include diff --git a/tests/runtime_tests/source/common_classes.hpp b/tests/runtime_tests/source/common_classes.hpp index 46dad13d..0f6aae1b 100644 --- a/tests/runtime_tests/source/common_classes.hpp +++ b/tests/runtime_tests/source/common_classes.hpp @@ -27,6 +27,7 @@ #include struct non_copyable { + non_copyable() = default; non_copyable(non_copyable&& other) noexcept = default; non_copyable& operator=(non_copyable&& other) noexcept = default; non_copyable(const non_copyable& other) noexcept = delete; diff --git a/tests/runtime_tests/source/container_semantics.cpp b/tests/runtime_tests/source/container_semantics.cpp index 2d572700..285aff85 100644 --- a/tests/runtime_tests/source/container_semantics.cpp +++ b/tests/runtime_tests/source/container_semantics.cpp @@ -158,6 +158,12 @@ end auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error); REQUIRE(r2.valid()); }; + auto findex_of = [&]() { + auto r1 = lua.safe_script("io1 = c:index_of(12)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("io2 = c:index_of(13)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + }; auto fget = [&]() { auto r1 = lua.safe_script("v1 = c:get(1)", sol::script_pass_on_error); REQUIRE(r1.valid()); @@ -195,6 +201,7 @@ end REQUIRE(r.valid()); }; REQUIRE_NOTHROW(ffind()); + REQUIRE_NOTHROW(findex_of()); REQUIRE_NOTHROW(fget()); REQUIRE_NOTHROW(fset()); REQUIRE_NOTHROW(ferase()); @@ -219,6 +226,8 @@ end const int& last = *backit; std::size_t i1 = lua["i1"]; std::size_t i2 = lua["i2"]; + std::size_t io1 = lua["io1"]; + std::size_t io2 = lua["io2"]; std::size_t s1 = lua["s1"]; std::size_t s2 = lua["s2"]; std::size_t s3 = lua["s3"]; @@ -244,6 +253,8 @@ end REQUIRE((last == 18)); REQUIRE((i1 == 1)); REQUIRE((i2 == 4)); + REQUIRE((io1 == 2)); + REQUIRE((io2 == 3)); REQUIRE((v1 == 11)); REQUIRE((v2 == 13)); REQUIRE((v3 == 18)); @@ -268,6 +279,12 @@ end auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error); REQUIRE(r2.valid()); }; + auto findex_of = [&]() { + auto r1 = lua.safe_script("io1 = c:index_of(12)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("io2 = c:index_of(13)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + }; auto fget = [&]() { auto r1 = lua.safe_script("v1 = c:get(11)", sol::script_pass_on_error); REQUIRE(r1.valid()); @@ -305,6 +322,7 @@ end REQUIRE(r.valid()); }; REQUIRE_NOTHROW(ffind()); + REQUIRE_NOTHROW(findex_of()); REQUIRE_NOTHROW(fget()); REQUIRE_NOTHROW(fset()); REQUIRE_NOTHROW(ferase()); @@ -329,6 +347,8 @@ end const int& last = *backit; int i1 = lua["i1"]; int i2 = lua["i2"]; + int io1 = lua["io1"]; + int io2 = lua["io2"]; std::size_t s1 = lua["s1"]; std::size_t s2 = lua["s2"]; std::size_t s3 = lua["s3"]; @@ -354,6 +374,8 @@ end REQUIRE((last == 20)); REQUIRE((i1 == 11)); REQUIRE((i2 == 14)); + REQUIRE((io1 == 2)); + REQUIRE((io2 == 3)); REQUIRE((v1 == 11)); REQUIRE((v2 == 13)); REQUIRE((v3 == 20)); @@ -368,6 +390,12 @@ void unordered_container_check(sol::state& lua, T& items) { auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error); REQUIRE(r2.valid()); }; + auto findex_of = [&]() { + auto r1 = lua.safe_script("io1 = c:index_of(12)", sol::script_pass_on_error); + REQUIRE_FALSE(r1.valid()); + auto r2 = lua.safe_script("io2 = c:index_of(13)", sol::script_pass_on_error); + REQUIRE_FALSE(r2.valid()); + }; auto fget = [&]() { auto r1 = lua.safe_script("v1 = c:get(11)", sol::script_pass_on_error); REQUIRE(r1.valid()); @@ -405,6 +433,7 @@ void unordered_container_check(sol::state& lua, T& items) { REQUIRE(r.valid()); }; REQUIRE_NOTHROW(ffind()); + REQUIRE_NOTHROW(findex_of()); REQUIRE_NOTHROW(fget()); REQUIRE_NOTHROW(fset()); REQUIRE_NOTHROW(ferase()); @@ -461,6 +490,12 @@ end auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error); REQUIRE(r2.valid()); }; + auto findex_of = [&]() { + auto r1 = lua.safe_script("io1 = c:index_of(12)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("io2 = c:index_of(13)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + }; auto fget = [&]() { auto r1 = lua.safe_script("v1 = c:get(11)", sol::script_pass_on_error); REQUIRE(r1.valid()); @@ -500,6 +535,7 @@ end REQUIRE(r.valid()); }; REQUIRE_NOTHROW(ffind()); + REQUIRE_NOTHROW(findex_of()); REQUIRE_NOTHROW(fget()); REQUIRE_NOTHROW(fset()); REQUIRE_NOTHROW(ferase()); @@ -524,6 +560,8 @@ end const std::pair& last = *backit; int i1 = lua["i1"]; int i2 = lua["i2"]; + int io1 = lua["io1"]; + int io2 = lua["io2"]; std::size_t s1 = lua["s1"]; std::size_t s2 = lua["s2"]; std::size_t s3 = lua["s3"]; @@ -557,6 +595,8 @@ end REQUIRE((last.second == 30)); REQUIRE((i1 == 21)); REQUIRE((i2 == 24)); + REQUIRE((io1 == 2)); + REQUIRE((io2 == 3)); REQUIRE((v1 == 21)); REQUIRE((v2 == 23)); REQUIRE((v3 == 30)); @@ -571,6 +611,12 @@ void associative_unordered_container_check(sol::state& lua, T& items) { auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error); REQUIRE(r2.valid()); }; + auto findex_of = [&]() { + auto r1 = lua.safe_script("io1 = c:index_of(12)", sol::script_pass_on_error); + REQUIRE_FALSE(r1.valid()); + auto r2 = lua.safe_script("io2 = c:index_of(13)", sol::script_pass_on_error); + REQUIRE_FALSE(r2.valid()); + }; auto fget = [&]() { auto r1 = lua.safe_script("v1 = c:get(11)", sol::script_pass_on_error); REQUIRE(r1.valid()); @@ -610,6 +656,7 @@ void associative_unordered_container_check(sol::state& lua, T& items) { REQUIRE(r.valid()); }; REQUIRE_NOTHROW(ffind()); + REQUIRE_NOTHROW(findex_of()); REQUIRE_NOTHROW(fget()); REQUIRE_NOTHROW(fset()); REQUIRE_NOTHROW(ferase()); @@ -694,6 +741,12 @@ end auto r2 = lua.safe_script("i2 = c:find(14)", sol::script_pass_on_error); REQUIRE(r2.valid()); }; + auto findex_of = [&]() { + auto r1 = lua.safe_script("io1 = c:index_of(11)", sol::script_pass_on_error); + REQUIRE(r1.valid()); + auto r2 = lua.safe_script("io2 = c:index_of(14)", sol::script_pass_on_error); + REQUIRE(r2.valid()); + }; auto fget = [&]() { auto r1 = lua.safe_script("v1 = c:get(2)", sol::script_pass_on_error); REQUIRE(r1.valid()); @@ -731,6 +784,7 @@ end REQUIRE(r.valid()); }; REQUIRE_NOTHROW(ffind()); + REQUIRE_NOTHROW(findex_of()); REQUIRE_NOTHROW(fget()); REQUIRE_NOTHROW(fset()); REQUIRE_NOTHROW(ferase()); diff --git a/tests/runtime_tests/source/customizations.cpp b/tests/runtime_tests/source/customizations.cpp index c3610158..ea750e31 100644 --- a/tests/runtime_tests/source/customizations.cpp +++ b/tests/runtime_tests/source/customizations.cpp @@ -1,419 +1,267 @@ -// sol3 - -// The MIT License (MIT) - -// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors - -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -#include "sol_test.hpp" - -#include - -#include -#include - -struct two_things { - int a; - bool b; -}; - -struct number_shim { - double num = 0; -}; - -namespace sol { - - // First, the expected size - // Specialization of a struct - template <> - struct lua_size : std::integral_constant {}; - - // Then, the expected type - template <> - struct lua_type_of : std::integral_constant {}; - - // do note specialize size for this because it is our type - template <> - struct lua_type_of : std::integral_constant {}; - - // Now, specialize various stack structures - namespace stack { - - template <> - struct checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - // Check first and second second index for being the proper types - bool success = stack::check(L, index, handler) && stack::check(L, index + 1, handler); - tracking.use(2); - return success; - } - }; - - template <> - struct unqualified_getter { - static two_things get(lua_State* L, int index, record& tracking) { - // Get the first element - int a = stack::get(L, index); - // Get the second element, - // in the +1 position from the first - bool b = stack::get(L, index + 1); - // we use 2 slots, each of the previous takes 1 - tracking.use(2); - return two_things{ a, b }; - } - }; - - template <> - struct pusher { - static int push(lua_State* L, const two_things& things) { - int amount = stack::push(L, things.a); - amount += stack::push(L, things.b); - // Return 2 things - return amount; - } - }; - - template <> - struct checker { - template - static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { - // check_usertype is a backdoor for directly checking sol2 usertypes - if (!check_usertype(L, index) && !stack::check(L, index)) { - handler(L, index, type_of(L, index), type::userdata, "expected a number_shim or a number"); - return false; - } - tracking.use(1); - return true; - } - }; - - template <> - struct unqualified_getter { - static number_shim get(lua_State* L, int index, record& tracking) { - if (check_usertype(L, index)) { - number_shim& ns = get_usertype(L, index, tracking); - return ns; - } - number_shim ns{}; - ns.num = stack::get(L, index, tracking); - return ns; - } - }; - - } // namespace stack -} // namespace sol - -struct custom { - int bweh; - - static int get_calls; - static int check_calls; - static int check_get_calls; - static int push_calls; - static int exact_push_calls; -}; - -int custom::get_calls = 0; -int custom::check_calls = 0; -int custom::check_get_calls = 0; -int custom::push_calls = 0; -int custom::exact_push_calls = 0; - -custom sol_lua_get(sol::types, lua_State* L, int index, sol::stack::record& tracking) { - ++custom::get_calls; - return { sol::stack::get(L, index, tracking) }; -} - -template -bool sol_lua_check(sol::types, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking) { - ++custom::check_calls; - return sol::stack::check(L, index, std::forward(handler), tracking); -} - -template -sol::optional sol_lua_check_get(sol::types type_tag, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking) { - ++custom::check_get_calls; - if (sol_lua_check(type_tag, L, index, std::forward(handler), tracking)) { - return sol_lua_get(type_tag, L, index, tracking); - } - return sol::nullopt; -} - -int sol_lua_push(lua_State* L, const custom& c) { - ++custom::push_calls; - // ensure there's enough space for 1 more thing on the stack - lua_checkstack(L, 1); - // tell Lua we've left something on - // the stack: return what comes from pushing an integer - return sol::stack::push(L, c.bweh); -} - -int sol_lua_push(sol::types, lua_State* L, const custom& c) { - ++custom::exact_push_calls; - // ensure there's enough space for 1 more thing on the stack - lua_checkstack(L, 1); - // tell Lua we've left something on - // the stack: return what comes from pushing an integer - return sol::stack::push(L, c.bweh); -} - -struct multi_custom { - int bweh; - bool bwuh; - std::string blah; - - static int get_calls; - static int check_calls; - static int check_get_calls; - static int push_calls; - static int exact_push_calls; -}; - -int multi_custom::get_calls = 0; -int multi_custom::check_calls = 0; -int multi_custom::check_get_calls = 0; -int multi_custom::push_calls = 0; -int multi_custom::exact_push_calls = 0; - -multi_custom sol_lua_get(sol::types, lua_State* L, int index, sol::stack::record& tracking) { - ++multi_custom::get_calls; - return { - sol::stack::get(L, index + 0, tracking), sol::stack::get(L, index + 1, tracking), sol::stack::get(L, index + 2, tracking) - }; -} - -template -bool sol_lua_check(sol::types, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking) { - ++multi_custom::check_calls; - bool success = sol::stack::check(L, index + 0, std::forward(handler), tracking) - && sol::stack::check(L, index + 1, std::forward(handler), tracking) - && sol::stack::check(L, index + 2, std::forward(handler), tracking); - return success; -} - -int sol_lua_push(lua_State* L, const multi_custom& c) { - ++multi_custom::push_calls; - // ensure there's enough space for 1 more thing on the stack - lua_checkstack(L, 3); - int p = sol::stack::push(L, c.bweh); - p += sol::stack::push(L, c.bwuh); - p += sol::stack::push(L, c.blah); - // tell Lua we've left something on - // the stack: return what comes from pushing an integer - return p; -} - -struct super_custom { - int bweh; - - static int get_calls; - static int check_calls; - static int check_get_calls; - static int push_calls; - static int exact_push_calls; -}; - -int super_custom::get_calls = 0; -int super_custom::check_calls = 0; -int super_custom::check_get_calls = 0; -int super_custom::push_calls = 0; -int super_custom::exact_push_calls = 0; - -super_custom* sol_lua_get(sol::types, lua_State* L, int index, sol::stack::record& tracking) { - ++super_custom::get_calls; - tracking.use(1); - void* vp = lua_touserdata(L, index); - super_custom** pscp = static_cast(vp); - return *pscp; -} - -super_custom& sol_lua_get(sol::types, lua_State* L, int index, sol::stack::record& tracking) { - return *sol_lua_get(sol::types(), L, index, tracking); -} - -template -bool sol_lua_check(sol::types, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking) { - ++super_custom::check_calls; - tracking.use(1); - if (luaL_testudata(L, index, "super_custom!") == nullptr) { - if (luaL_testudata(L, index, "super_custom!p") == nullptr) { - handler(L, index, sol::type::userdata, sol::type_of(L, index), "not a super_custom ?!"); - return false; - } - } - return true; -} - -int sol_lua_push(lua_State* L, const super_custom& c) { - ++super_custom::push_calls; - // ensure there's enough space for 1 more thing on the stack - lua_checkstack(L, 1); - // tell Lua we've left something on - // the stack: return what comes from pushing an integer - void* ud = lua_newuserdata(L, sizeof(super_custom*) + sizeof(super_custom)); - super_custom* tud = static_cast(static_cast(static_cast(ud) + sizeof(super_custom*))); - *static_cast(ud) = tud; - *tud = c; - luaL_newmetatable(L, "super_custom!"); - lua_setmetatable(L, -2); - return 1; -} - -int sol_lua_push(lua_State* L, super_custom* c) { - ++super_custom::push_calls; - // ensure there's enough space for 1 more thing on the stack - lua_checkstack(L, 1); - // tell Lua we've left something on - // the stack: return what comes from pushing an integer - void* ud = lua_newuserdata(L, sizeof(super_custom*)); - *static_cast(ud) = c; - luaL_newmetatable(L, "super_custom!p"); - lua_setmetatable(L, -2); - return 1; -} - -int sol_lua_push(lua_State* L, std::reference_wrapper c) { - return sol::stack::push(L, std::addressof(c.get())); -} - -TEST_CASE("customization/split struct", "using the newly documented customization points to handle different kinds of classes") { - sol::state lua; - - // Create a pass-through style of function - auto result1 = lua.safe_script("function f ( a, b, c ) return a + c, b end"); - REQUIRE(result1.valid()); - lua.set_function("g", [](int a, bool b, int c, double d) { return std::make_tuple(a + c, b, d + 2.5); }); - - // get the function out of Lua - sol::function f = lua["f"]; - sol::function g = lua["g"]; - - two_things thingsf = f(two_things{ 24, true }, 1); - two_things thingsg; - double d; - sol::tie(thingsg, d) = g(two_things{ 25, false }, 2, 34.0); - REQUIRE(thingsf.a == 25); - REQUIRE(thingsf.b); - - REQUIRE(thingsg.a == 27); - REQUIRE_FALSE(thingsg.b); - REQUIRE(d == 36.5); -} - -TEST_CASE("customization/usertype", "using the newly documented customization points to handle different kinds of classes") { - sol::state lua; - - // Create a pass-through style of function - auto result1 = lua.safe_script("function f ( a ) return a end"); - REQUIRE(result1.valid()); - lua.set_function("g", [](double a) { - number_shim ns; - ns.num = a; - return ns; - }); - - auto result2 = lua.safe_script("vf = f(25) vg = g(35)", sol::script_pass_on_error); - REQUIRE(result2.valid()); - - number_shim thingsf = lua["vf"]; - number_shim thingsg = lua["vg"]; - - REQUIRE(thingsf.num == 25); - REQUIRE(thingsg.num == 35); -} - -TEST_CASE("customization/overloading", "using multi-size customized types in an overload") { - bool TwoThingsWorks = false, OverloadWorks = false; - sol::state lua; - lua["test_two_things"] = [&](two_things) { TwoThingsWorks = true; }; - lua["test_overload"] = sol::overload([&](two_things) { OverloadWorks = true; }, [] {}); - - lua.script( - "test_two_things(0, true)\n" - "test_overload(0, true)"); - - REQUIRE(TwoThingsWorks); - REQUIRE(OverloadWorks); -} - -TEST_CASE("customization/adl", "using the ADL customization points in various situations") { - sol::state lua; - lua.open_libraries(sol::lib::base); - - SECTION("value-based") { - custom::get_calls = 0; - custom::check_calls = 0; - custom::check_get_calls = 0; - custom::push_calls = 0; - custom::exact_push_calls = 0; - - lua["meow"] = custom{ 25 }; - custom meow = lua["meow"]; - - REQUIRE(meow.bweh == 25); - REQUIRE(custom::get_calls > 0); - REQUIRE(custom::check_calls > 0); - REQUIRE(custom::check_get_calls > 0); - REQUIRE(custom::exact_push_calls > 0); - REQUIRE(custom::push_calls == 0); - } - SECTION("multi") { - multi_custom::get_calls = 0; - multi_custom::check_calls = 0; - multi_custom::check_get_calls = 0; - multi_custom::push_calls = 0; - multi_custom::exact_push_calls = 0; - - auto result = lua.safe_script("return function (a, b, c) return a, b, c end", sol::script_pass_on_error); - REQUIRE(result.valid()); - sol::protected_function f = result; - multi_custom pass_through = f(multi_custom{ 22, false, "miao" }); - REQUIRE(pass_through.bweh == 22); - REQUIRE_FALSE(pass_through.bwuh); - REQUIRE(pass_through.blah == "miao"); - - REQUIRE(multi_custom::get_calls > 0); - REQUIRE(multi_custom::check_calls > 0); - REQUIRE(multi_custom::push_calls > 0); - REQUIRE(multi_custom::check_get_calls == 0); - REQUIRE(multi_custom::exact_push_calls == 0); - } - SECTION("reference-based") { - super_custom::get_calls = 0; - super_custom::check_calls = 0; - super_custom::check_get_calls = 0; - super_custom::push_calls = 0; - super_custom::exact_push_calls = 0; - - super_custom meow_original{ 50 }; - lua["meow"] = std::ref(meow_original); - super_custom& meow = lua["meow"]; - super_custom meow_copy = lua["meow"]; - - REQUIRE(meow.bweh == 50); - REQUIRE(&meow == &meow_original); - REQUIRE(meow_copy.bweh == 50); - REQUIRE(super_custom::get_calls > 0); - REQUIRE(super_custom::check_calls > 0); - REQUIRE(super_custom::push_calls > 0); - REQUIRE(super_custom::check_get_calls == 0); - REQUIRE(super_custom::exact_push_calls == 0); - } -} +// sol3 + +// The MIT License (MIT) + +// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors + +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#include "sol_test.hpp" + +#include + +#include +#include + +struct custom { + int bweh; + + static int get_calls; + static int check_calls; + static int check_get_calls; + static int push_calls; + static int exact_push_calls; +}; + +int custom::get_calls = 0; +int custom::check_calls = 0; +int custom::check_get_calls = 0; +int custom::push_calls = 0; +int custom::exact_push_calls = 0; + +custom sol_lua_get(sol::types, lua_State* L, int index, sol::stack::record& tracking) { + ++custom::get_calls; + return { sol::stack::get(L, index, tracking) }; +} + +template +bool sol_lua_check(sol::types, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking) { + ++custom::check_calls; + return sol::stack::check(L, index, std::forward(handler), tracking); +} + +template +sol::optional sol_lua_check_get(sol::types type_tag, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking) { + ++custom::check_get_calls; + if (sol_lua_check(type_tag, L, index, std::forward(handler), tracking)) { + return sol_lua_get(type_tag, L, index, tracking); + } + return sol::nullopt; +} + +int sol_lua_push(lua_State* L, const custom& c) { + ++custom::push_calls; + // ensure there's enough space for 1 more thing on the stack + lua_checkstack(L, 1); + // tell Lua we've left something on + // the stack: return what comes from pushing an integer + return sol::stack::push(L, c.bweh); +} + +int sol_lua_push(sol::types, lua_State* L, const custom& c) { + ++custom::exact_push_calls; + // ensure there's enough space for 1 more thing on the stack + lua_checkstack(L, 1); + // tell Lua we've left something on + // the stack: return what comes from pushing an integer + return sol::stack::push(L, c.bweh); +} + +struct multi_custom { + int bweh; + bool bwuh; + std::string blah; + + static int get_calls; + static int check_calls; + static int check_get_calls; + static int push_calls; + static int exact_push_calls; +}; + +int multi_custom::get_calls = 0; +int multi_custom::check_calls = 0; +int multi_custom::check_get_calls = 0; +int multi_custom::push_calls = 0; +int multi_custom::exact_push_calls = 0; + +multi_custom sol_lua_get(sol::types, lua_State* L, int index, sol::stack::record& tracking) { + ++multi_custom::get_calls; + return { + sol::stack::get(L, index + 0, tracking), sol::stack::get(L, index + 1, tracking), sol::stack::get(L, index + 2, tracking) + }; +} + +template +bool sol_lua_check(sol::types, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking) { + ++multi_custom::check_calls; + bool success = sol::stack::check(L, index + 0, std::forward(handler), tracking) + && sol::stack::check(L, index + 1, std::forward(handler), tracking) + && sol::stack::check(L, index + 2, std::forward(handler), tracking); + return success; +} + +int sol_lua_push(lua_State* L, const multi_custom& c) { + ++multi_custom::push_calls; + // ensure there's enough space for 1 more thing on the stack + lua_checkstack(L, 3); + int p = sol::stack::push(L, c.bweh); + p += sol::stack::push(L, c.bwuh); + p += sol::stack::push(L, c.blah); + // tell Lua we've left something on + // the stack: return what comes from pushing an integer + return p; +} + +struct super_custom { + int bweh; + + static int get_calls; + static int check_calls; + static int check_get_calls; + static int push_calls; + static int exact_push_calls; +}; + +int super_custom::get_calls = 0; +int super_custom::check_calls = 0; +int super_custom::check_get_calls = 0; +int super_custom::push_calls = 0; +int super_custom::exact_push_calls = 0; + +super_custom* sol_lua_get(sol::types, lua_State* L, int index, sol::stack::record& tracking) { + ++super_custom::get_calls; + tracking.use(1); + void* vp = lua_touserdata(L, index); + super_custom** pscp = static_cast(vp); + return *pscp; +} + +super_custom& sol_lua_get(sol::types, lua_State* L, int index, sol::stack::record& tracking) { + return *sol_lua_get(sol::types(), L, index, tracking); +} + +template +bool sol_lua_check(sol::types, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking) { + ++super_custom::check_calls; + tracking.use(1); + if (luaL_testudata(L, index, "super_custom!") == nullptr) { + if (luaL_testudata(L, index, "super_custom!p") == nullptr) { + handler(L, index, sol::type::userdata, sol::type_of(L, index), "not a super_custom ?!"); + return false; + } + } + return true; +} + +int sol_lua_push(lua_State* L, const super_custom& c) { + ++super_custom::push_calls; + // ensure there's enough space for 1 more thing on the stack + lua_checkstack(L, 1); + // tell Lua we've left something on + // the stack: return what comes from pushing an integer + void* ud = lua_newuserdata(L, sizeof(super_custom*) + sizeof(super_custom)); + super_custom* tud = static_cast(static_cast(static_cast(ud) + sizeof(super_custom*))); + *static_cast(ud) = tud; + *tud = c; + luaL_newmetatable(L, "super_custom!"); + lua_setmetatable(L, -2); + return 1; +} + +int sol_lua_push(lua_State* L, super_custom* c) { + ++super_custom::push_calls; + // ensure there's enough space for 1 more thing on the stack + lua_checkstack(L, 1); + // tell Lua we've left something on + // the stack: return what comes from pushing an integer + void* ud = lua_newuserdata(L, sizeof(super_custom*)); + *static_cast(ud) = c; + luaL_newmetatable(L, "super_custom!p"); + lua_setmetatable(L, -2); + return 1; +} + +int sol_lua_push(lua_State* L, std::reference_wrapper c) { + return sol::stack::push(L, std::addressof(c.get())); +} + +TEST_CASE("customization/adl", "using the ADL customization points in various situations") { + sol::state lua; + lua.open_libraries(sol::lib::base); + + SECTION("value-based") { + custom::get_calls = 0; + custom::check_calls = 0; + custom::check_get_calls = 0; + custom::push_calls = 0; + custom::exact_push_calls = 0; + + lua["meow"] = custom{ 25 }; + custom meow = lua["meow"]; + + REQUIRE(meow.bweh == 25); + REQUIRE(custom::get_calls > 0); + REQUIRE(custom::check_calls > 0); + REQUIRE(custom::check_get_calls > 0); + REQUIRE(custom::exact_push_calls > 0); + REQUIRE(custom::push_calls == 0); + } + SECTION("multi") { + multi_custom::get_calls = 0; + multi_custom::check_calls = 0; + multi_custom::check_get_calls = 0; + multi_custom::push_calls = 0; + multi_custom::exact_push_calls = 0; + + auto result = lua.safe_script("return function (a, b, c) return a, b, c end", sol::script_pass_on_error); + REQUIRE(result.valid()); + sol::protected_function f = result; + multi_custom pass_through = f(multi_custom{ 22, false, "miao" }); + REQUIRE(pass_through.bweh == 22); + REQUIRE_FALSE(pass_through.bwuh); + REQUIRE(pass_through.blah == "miao"); + + REQUIRE(multi_custom::get_calls > 0); + REQUIRE(multi_custom::check_calls > 0); + REQUIRE(multi_custom::push_calls > 0); + REQUIRE(multi_custom::check_get_calls == 0); + REQUIRE(multi_custom::exact_push_calls == 0); + } + SECTION("reference-based") { + super_custom::get_calls = 0; + super_custom::check_calls = 0; + super_custom::check_get_calls = 0; + super_custom::push_calls = 0; + super_custom::exact_push_calls = 0; + + super_custom meow_original{ 50 }; + lua["meow"] = std::ref(meow_original); + super_custom& meow = lua["meow"]; + super_custom meow_copy = lua["meow"]; + + REQUIRE(meow.bweh == 50); + REQUIRE(&meow == &meow_original); + REQUIRE(meow_copy.bweh == 50); + REQUIRE(super_custom::get_calls > 0); + REQUIRE(super_custom::check_calls > 0); + REQUIRE(super_custom::push_calls > 0); + REQUIRE(super_custom::check_get_calls == 0); + REQUIRE(super_custom::exact_push_calls == 0); + } +} diff --git a/tests/runtime_tests/source/customizations_private.cpp b/tests/runtime_tests/source/customizations_private.cpp new file mode 100644 index 00000000..1826b7af --- /dev/null +++ b/tests/runtime_tests/source/customizations_private.cpp @@ -0,0 +1,169 @@ +// sol3 + +// The MIT License (MIT) + +// Copyright (c) 2013-2018 Rapptz, ThePhD and contributors + +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#include "sol_test.hpp" + +#include + +#include +#include + +struct two_things { + int a; + bool b; +}; + +struct number_shim { + double num = 0; +}; + +namespace sol { + + template <> + struct lua_size : std::integral_constant {}; + + template <> + struct lua_type_of : std::integral_constant {}; + + template <> + struct lua_type_of : std::integral_constant {}; + + namespace stack { + + template <> + struct unqualified_checker { + template + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + bool success = stack::check(L, index, handler) && stack::check(L, index + 1, handler); + tracking.use(2); + return success; + } + }; + + template <> + struct unqualified_getter { + static two_things get(lua_State* L, int index, record& tracking) { + int a = stack::get(L, index); + bool b = stack::get(L, index + 1); + tracking.use(2); + return two_things{ a, b }; + } + }; + + template <> + struct pusher { + static int push(lua_State* L, const two_things& things) { + int amount = stack::push(L, things.a); + amount += stack::push(L, things.b); + return amount; + } + }; + + template <> + struct unqualified_checker { + template + static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { + if (!check_usertype(L, index) && !stack::check(L, index)) { + handler(L, index, type_of(L, index), type::userdata, "expected a number_shim or a number"); + return false; + } + tracking.use(1); + return true; + } + }; + + template <> + struct unqualified_getter { + static number_shim get(lua_State* L, int index, record& tracking) { + if (check_usertype(L, index)) { + number_shim& ns = get_usertype(L, index, tracking); + return ns; + } + number_shim ns{}; + ns.num = stack::get(L, index, tracking); + return ns; + } + }; + + } // namespace stack +} // namespace sol + +TEST_CASE("customization/split struct", "using the newly documented customization points to handle different kinds of classes") { + sol::state lua; + + // Create a pass-through style of function + auto result1 = lua.safe_script("function f ( a, b, c ) return a + c, b end"); + REQUIRE(result1.valid()); + lua.set_function("g", [](int a, bool b, int c, double d) { return std::make_tuple(a + c, b, d + 2.5); }); + + // get the function out of Lua + sol::function f = lua["f"]; + sol::function g = lua["g"]; + + two_things thingsf = f(two_things{ 24, true }, 1); + two_things thingsg; + double d; + sol::tie(thingsg, d) = g(two_things{ 25, false }, 2, 34.0); + REQUIRE(thingsf.a == 25); + REQUIRE(thingsf.b); + + REQUIRE(thingsg.a == 27); + REQUIRE_FALSE(thingsg.b); + REQUIRE(d == 36.5); +} + +TEST_CASE("customization/usertype", "using the newly documented customization points to handle different kinds of classes") { + sol::state lua; + + // Create a pass-through style of function + auto result1 = lua.safe_script("function f ( a ) return a end"); + REQUIRE(result1.valid()); + lua.set_function("g", [](double a) { + number_shim ns; + ns.num = a; + return ns; + }); + + auto result2 = lua.safe_script("vf = f(25) vg = g(35)", sol::script_pass_on_error); + REQUIRE(result2.valid()); + + number_shim thingsf = lua["vf"]; + number_shim thingsg = lua["vg"]; + + REQUIRE(thingsf.num == 25); + REQUIRE(thingsg.num == 35); +} + +TEST_CASE("customization/overloading", "using multi-size customized types in an overload") { + bool TwoThingsWorks = false, OverloadWorks = false; + sol::state lua; + lua["test_two_things"] = [&](two_things) { TwoThingsWorks = true; }; + lua["test_overload"] = sol::overload([&](two_things) { OverloadWorks = true; }, [] {}); + + lua.script( + "test_two_things(0, true)\n" + "test_overload(0, true)"); + + REQUIRE(TwoThingsWorks); + REQUIRE(OverloadWorks); +} diff --git a/tests/runtime_tests/source/utility.cpp b/tests/runtime_tests/source/utility.cpp index 04df2b71..d358b58c 100644 --- a/tests/runtime_tests/source/utility.cpp +++ b/tests/runtime_tests/source/utility.cpp @@ -275,9 +275,7 @@ TEST_CASE("safety/check_stack", "check to make sure that if we overflow the stac lua["okay"] = []() { // clang-format off - return std::make_tuple( - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37); + return std::make_tuple(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37); // clang-format on }; lua["bad"] = [](lua_State* L) {