From 5dee45cd9eabc30b1c7270fd50cac6f7287857c3 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Tue, 21 May 2019 02:13:56 -0400 Subject: [PATCH] Rework table internals for more performance in more cases and handle additional cases of update_if_empty and create_if_nil --- cmake/Modules/FindCatch.cmake | 4 +- include/sol/demangle.hpp | 10 +- include/sol/function.hpp | 2 +- include/sol/function_types.hpp | 20 +- include/sol/function_types_core.hpp | 2 +- include/sol/stack_core.hpp | 119 ++--- include/sol/stack_field.hpp | 2 +- include/sol/table_core.hpp | 185 ++++--- include/sol/traits.hpp | 57 ++- include/sol/types.hpp | 46 +- single/include/sol/forward.hpp | 4 +- single/include/sol/sol.hpp | 463 ++++++++++++------ .../runtime_tests/source/tables.insertion.cpp | 56 +++ .../source/usertypes.inheritance.cpp | 284 ----------- .../source/usertypes.inheritance.multi.cpp | 333 +++++++++++++ .../source/usertypes.properties.cpp | 14 + 16 files changed, 991 insertions(+), 610 deletions(-) create mode 100644 tests/runtime_tests/source/usertypes.inheritance.multi.cpp diff --git a/cmake/Modules/FindCatch.cmake b/cmake/Modules/FindCatch.cmake index d4c2c225..527fb6c1 100644 --- a/cmake/Modules/FindCatch.cmake +++ b/cmake/Modules/FindCatch.cmake @@ -70,8 +70,8 @@ add_library(${catch_lib} INTERFACE) target_include_directories(${catch_lib} INTERFACE ${catch_include_dirs}) if (MSVC) - target_compile_options(${catch_lib} INTERFACE - /D_SILENCE_CXX17_UNCAUGHT_EXCEPTION_DEPRECATION_WARNING) + target_compile_definitions(${catch_lib} INTERFACE + _SILENCE_CXX17_UNCAUGHT_EXCEPTION_DEPRECATION_WARNING) endif() set(CATCH_FOUND TRUE) diff --git a/include/sol/demangle.hpp b/include/sol/demangle.hpp index d11443c5..2161585a 100644 --- a/include/sol/demangle.hpp +++ b/include/sol/demangle.hpp @@ -85,7 +85,7 @@ namespace detail { } #elif defined(_MSC_VER) template - inline std::string ctti_get_type_name() { + std::string ctti_get_type_name() { std::string name = __FUNCSIG__; std::size_t start = name.find("get_type_name"); if (start == std::string::npos) @@ -122,13 +122,13 @@ namespace detail { #endif // compilers template - inline std::string demangle_once() { + std::string demangle_once() { std::string realname = ctti_get_type_name(); return realname; } template - inline std::string short_demangle_once() { + std::string short_demangle_once() { std::string realname = ctti_get_type_name(); // This isn't the most complete but it'll do for now...? static const std::array ops = {{"operator<", "operator<<", "operator<<=", "operator<=", "operator>", "operator>>", "operator>>=", "operator>=", "operator->", "operator->*"}}; @@ -166,13 +166,13 @@ namespace detail { } template - inline const std::string& demangle() { + const std::string& demangle() { static const std::string d = demangle_once(); return d; } template - inline const std::string& short_demangle() { + const std::string& short_demangle() { static const std::string d = short_demangle_once(); return d; } diff --git a/include/sol/function.hpp b/include/sol/function.hpp index c9642da8..84dcaf67 100644 --- a/include/sol/function.hpp +++ b/include/sol/function.hpp @@ -32,7 +32,7 @@ namespace sol { template - inline decltype(auto) stack_proxy::call(Args&&... args) { + decltype(auto) stack_proxy::call(Args&&... args) { stack_function sf(this->lua_state(), this->stack_index()); return sf.template call(std::forward(args)...); } diff --git a/include/sol/function_types.hpp b/include/sol/function_types.hpp index 5caf0072..333dc0af 100644 --- a/include/sol/function_types.hpp +++ b/include/sol/function_types.hpp @@ -42,7 +42,7 @@ namespace sol { struct call_indicator {}; template - inline int lua_c_wrapper(lua_State* L) { + int lua_c_wrapper(lua_State* L) { lua_CFunction cf = lua_tocfunction(L, lua_upvalueindex(2)); int nr = cf(L); if constexpr (yielding) { @@ -54,7 +54,7 @@ namespace sol { } template - inline int lua_c_noexcept_wrapper(lua_State* L) noexcept { + int lua_c_noexcept_wrapper(lua_State* L) noexcept { detail::lua_CFunction_noexcept cf = reinterpret_cast(lua_tocfunction(L, lua_upvalueindex(2))); int nr = cf(L); if constexpr (yielding) { @@ -68,10 +68,10 @@ namespace sol { struct c_function_invocation {}; template - inline void select(lua_State* L, Fx&& fx, Args&&... args); + void select(lua_State* L, Fx&& fx, Args&&... args); template - inline void select_set_fx(lua_State* L, Args&&... args) { + void select_set_fx(lua_State* L, Args&&... args) { lua_CFunction freefunc = detail::static_trampoline, 2, is_yielding>>; int upvalues = 0; @@ -81,7 +81,7 @@ namespace sol { } template - inline void select_convertible(types, lua_State* L, Fx&& fx, Args&&... args) { + void select_convertible(types, lua_State* L, Fx&& fx, Args&&... args) { using dFx = std::decay_t>; using fx_ptr_t = R (*)(A...); constexpr bool is_convertible = std::is_convertible_v; @@ -96,13 +96,13 @@ namespace sol { } template - inline void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) { + void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) { typedef meta::function_signature_t> Sig; select_convertible(types(), L, std::forward(fx), std::forward(args)...); } template - inline void select_member_variable(lua_State* L, Fx&& fx, Args&&... args) { + void select_member_variable(lua_State* L, Fx&& fx, Args&&... args) { using uFx = meta::unqualified_t; if constexpr (sizeof...(Args) < 1) { using C = typename meta::bind_traits::object_type; @@ -152,7 +152,7 @@ namespace sol { } template - inline void select_member_function_with(lua_State* L, Fx&& fx, T&& obj, Args&&... args) { + void select_member_function_with(lua_State* L, Fx&& fx, T&& obj, Args&&... args) { using dFx = std::decay_t; using Tu = meta::unqualified_t; if constexpr (meta::is_specialization_of_v) { @@ -185,7 +185,7 @@ namespace sol { } template - inline void select_member_function(lua_State* L, Fx&& fx, Args&&... args) { + void select_member_function(lua_State* L, Fx&& fx, Args&&... args) { using dFx = std::decay_t; if constexpr (sizeof...(Args) < 1) { using C = typename meta::bind_traits>::object_type; @@ -202,7 +202,7 @@ namespace sol { } template - inline void select(lua_State* L, Fx&& fx, Args&&... args) { + void select(lua_State* L, Fx&& fx, Args&&... args) { using uFx = meta::unqualified_t; if constexpr (is_lua_reference_v) { // TODO: hoist into lambda in this case for yielding??? diff --git a/include/sol/function_types_core.hpp b/include/sol/function_types_core.hpp index 411e0c3c..cc080cd8 100644 --- a/include/sol/function_types_core.hpp +++ b/include/sol/function_types_core.hpp @@ -32,7 +32,7 @@ namespace sol { namespace function_detail { template - inline int call(lua_State* L) { + int call(lua_State* L) { Fx& fx = stack::get>(L, upvalue_index(start)); int nr = fx(L); if (is_yielding) { diff --git a/include/sol/stack_core.hpp b/include/sol/stack_core.hpp index e562d9f6..463f0cd8 100644 --- a/include/sol/stack_core.hpp +++ b/include/sol/stack_core.hpp @@ -91,7 +91,7 @@ namespace sol { } template - inline std::size_t aligned_space_for(void* alignment = nullptr) { + std::size_t aligned_space_for(void* alignment = nullptr) { char* start = static_cast(alignment); (void)detail::swallow{ int{}, (align_one(std::alignment_of_v, sizeof(Args), alignment), int{})... }; return static_cast(alignment) - start; @@ -113,7 +113,7 @@ namespace sol { } template - inline void* align_usertype_unique_destructor(void* ptr) { + void* align_usertype_unique_destructor(void* ptr) { using use_align = std::integral_constant - inline void* align_usertype_unique_tag(void* ptr) { + void* align_usertype_unique_tag(void* ptr) { using use_align = std::integral_constant - inline void* align_usertype_unique(void* ptr) { + void* align_usertype_unique(void* ptr) { typedef std::integral_constant - inline void* align_user(void* ptr) { + void* align_user(void* ptr) { typedef std::integral_constant - inline T** usertype_allocate_pointer(lua_State* L) { + T** usertype_allocate_pointer(lua_State* L) { typedef std::integral_constant - inline T* usertype_allocate(lua_State* L) { + T* usertype_allocate(lua_State* L) { typedef std::integral_constant - inline Real* usertype_unique_allocate(lua_State* L, T**& pref, unique_destructor*& dx, unique_tag*& id) { + Real* usertype_unique_allocate(lua_State* L, T**& pref, unique_destructor*& dx, unique_tag*& id) { typedef std::integral_constant - inline T* user_allocate(lua_State* L) { + T* user_allocate(lua_State* L) { typedef std::integral_constant - inline int usertype_alloc_destruct(lua_State* L) { + int usertype_alloc_destruct(lua_State* L) { void* memory = lua_touserdata(L, 1); memory = align_usertype_pointer(memory); T** pdata = static_cast(memory); @@ -475,7 +475,7 @@ namespace sol { } template - inline int unique_destruct(lua_State* L) { + int unique_destruct(lua_State* L) { void* memory = lua_touserdata(L, 1); memory = align_usertype_unique_destructor(memory); unique_destructor& dx = *static_cast(memory); @@ -485,7 +485,7 @@ namespace sol { } template - inline int user_alloc_destruct(lua_State* L) { + int user_alloc_destruct(lua_State* L) { void* memory = lua_touserdata(L, 1); memory = align_user(memory); T* data = static_cast(memory); @@ -495,7 +495,7 @@ namespace sol { } template - inline void usertype_unique_alloc_destroy(void* memory) { + void usertype_unique_alloc_destroy(void* memory) { memory = align_usertype_unique(memory); Real* target = static_cast(memory); std::allocator alloc; @@ -503,7 +503,7 @@ namespace sol { } template - inline int cannot_destruct(lua_State* L) { + int cannot_destruct(lua_State* L) { return luaL_error(L, "cannot call the destructor for '%s': it is either hidden (protected/private) or removed with '= " "delete' and thusly this type is being destroyed without properly destructing, invoking undefined " @@ -650,7 +650,8 @@ namespace sol { = decltype(sol_lua_interop_check(types(), static_cast(nullptr), -1, type::none, no_panic, std::declval())); template - using adl_sol_lua_check_get_test_t = decltype(sol_lua_check_get(types(), static_cast(nullptr), -1, no_panic, std::declval())); + using adl_sol_lua_check_get_test_t + = decltype(sol_lua_check_get(types(), static_cast(nullptr), -1, no_panic, std::declval())); template using adl_sol_lua_push_test_t = decltype(sol_lua_push(static_cast(nullptr), std::declval()...)); @@ -723,7 +724,7 @@ namespace sol { } template - inline decltype(auto) unchecked_unqualified_get(lua_State* L, int index, record& tracking) { + decltype(auto) unchecked_unqualified_get(lua_State* L, int index, record& tracking) { using Tu = meta::unqualified_t; if constexpr (meta::meta_detail::is_adl_sol_lua_get_v) { return sol_lua_get(types(), L, index, tracking); @@ -736,7 +737,7 @@ namespace sol { } template - inline decltype(auto) unchecked_get(lua_State* L, int index, record& tracking) { + decltype(auto) unchecked_get(lua_State* L, int index, record& tracking) { if constexpr (meta::meta_detail::is_adl_sol_lua_get_v) { return sol_lua_get(types(), L, index, tracking); } @@ -748,7 +749,7 @@ namespace sol { } template - inline decltype(auto) unqualified_interop_get(lua_State* L, int index, void* unadjusted_pointer, record& tracking) { + decltype(auto) unqualified_interop_get(lua_State* L, int index, void* unadjusted_pointer, record& tracking) { using Tu = meta::unqualified_t; if constexpr (meta::meta_detail::is_adl_sol_lua_interop_get_v) { return sol_lua_interop_get(types(), L, index, unadjusted_pointer, tracking); @@ -764,7 +765,7 @@ namespace sol { } template - inline decltype(auto) interop_get(lua_State* L, int index, void* unadjusted_pointer, record& tracking) { + decltype(auto) interop_get(lua_State* L, int index, void* unadjusted_pointer, record& tracking) { if constexpr (meta::meta_detail::is_adl_sol_lua_interop_get_v) { return sol_lua_interop_get(types(), L, index, unadjusted_pointer, tracking); } @@ -798,7 +799,7 @@ namespace sol { return unqualified_interop_check(L, index, index_type, std::forward(handler), tracking); } } - + using undefined_method_func = void (*)(stack_reference); struct undefined_metatable { @@ -874,7 +875,7 @@ namespace sol { } template - inline int push(lua_State* L, T&& t, Args&&... args) { + int push(lua_State* L, T&& t, Args&&... args) { using Tu = meta::unqualified_t; if constexpr (meta::meta_detail::is_adl_sol_lua_push_exact_v) { return sol_lua_push(types(), L, std::forward(t), std::forward(args)...); @@ -894,7 +895,7 @@ namespace sol { // overload allows to use a pusher of a specific type, but pass in any kind of args template ::value>> - inline int push(lua_State* L, Arg&& arg, Args&&... args) { + int push(lua_State* L, Arg&& arg, Args&&... args) { using Tu = meta::unqualified_t; if constexpr (meta::meta_detail::is_adl_sol_lua_push_exact_v) { return sol_lua_push(types(), L, std::forward(arg), std::forward(args)...); @@ -915,7 +916,7 @@ namespace sol { namespace stack_detail { template - inline int push_reference(lua_State* L, Arg&& arg, Args&&... args) { + int push_reference(lua_State* L, Arg&& arg, Args&&... args) { using use_reference_tag = meta::all, meta::neg>, meta::neg>>, @@ -927,12 +928,12 @@ namespace sol { } // namespace stack_detail template - inline int push_reference(lua_State* L, T&& t, Args&&... args) { + int push_reference(lua_State* L, T&& t, Args&&... args) { return stack_detail::push_reference(L, std::forward(t), std::forward(args)...); } template - inline int push_reference(lua_State* L, Arg&& arg, Args&&... args) { + int push_reference(lua_State* L, Arg&& arg, Args&&... args) { return stack_detail::push_reference(L, std::forward(arg), std::forward(args)...); } @@ -942,7 +943,7 @@ namespace sol { } template - inline int multi_push(lua_State* L, T&& t, Args&&... args) { + int multi_push(lua_State* L, T&& t, Args&&... args) { int pushcount = push(L, std::forward(t)); void(detail::swallow{ (pushcount += stack::push(L, std::forward(args)), 0)... }); return pushcount; @@ -954,7 +955,7 @@ namespace sol { } template - inline int multi_push_reference(lua_State* L, T&& t, Args&&... args) { + int multi_push_reference(lua_State* L, T&& t, Args&&... args) { int pushcount = push_reference(L, std::forward(t)); void(detail::swallow{ (pushcount += stack::push_reference(L, std::forward(args)), 0)... }); return pushcount; @@ -1039,7 +1040,7 @@ namespace sol { } template - inline decltype(auto) unqualified_check_get(lua_State* L, int index, Handler&& handler, record& tracking) { + decltype(auto) unqualified_check_get(lua_State* L, int index, Handler&& handler, record& tracking) { using Tu = meta::unqualified_t; if constexpr (meta::meta_detail::is_adl_sol_lua_check_get_v) { return sol_lua_check_get(types(), L, index, std::forward(handler), tracking); @@ -1055,19 +1056,19 @@ namespace sol { } template - inline decltype(auto) unqualified_check_get(lua_State* L, int index, Handler&& handler) { + decltype(auto) unqualified_check_get(lua_State* L, int index, Handler&& handler) { record tracking{}; return unqualified_check_get(L, index, handler, tracking); } template - inline decltype(auto) unqualified_check_get(lua_State* L, int index = -lua_size>::value) { + decltype(auto) unqualified_check_get(lua_State* L, int index = -lua_size>::value) { auto handler = no_panic; return unqualified_check_get(L, index, handler); } template - inline decltype(auto) check_get(lua_State* L, int index, Handler&& handler, record& tracking) { + decltype(auto) check_get(lua_State* L, int index, Handler&& handler, record& tracking) { if constexpr (meta::meta_detail::is_adl_sol_lua_check_get_v) { return sol_lua_check_get(types(), L, index, std::forward(handler), tracking); } @@ -1079,13 +1080,13 @@ namespace sol { } template - inline decltype(auto) check_get(lua_State* L, int index, Handler&& handler) { + decltype(auto) check_get(lua_State* L, int index, Handler&& handler) { record tracking{}; return check_get(L, index, handler, tracking); } template - inline decltype(auto) check_get(lua_State* L, int index = -lua_size>::value) { + decltype(auto) check_get(lua_State* L, int index = -lua_size>::value) { auto handler = no_panic; return check_get(L, index, handler); } @@ -1093,19 +1094,19 @@ namespace sol { namespace stack_detail { template - inline bool check_types(lua_State*, int, Handler&&, record&) { + bool check_types(lua_State*, int, Handler&&, record&) { return true; } template - inline bool check_types(lua_State* L, int firstargument, Handler&& handler, record& tracking) { + bool check_types(lua_State* L, int firstargument, Handler&& handler, record& tracking) { if (!stack::check(L, firstargument + tracking.used, handler, tracking)) return false; return check_types(L, firstargument, std::forward(handler), tracking); } template - inline bool check_types(types, lua_State* L, int index, Handler&& handler, record& tracking) { + bool check_types(types, lua_State* L, int index, Handler&& handler, record& tracking) { return check_types(L, index, std::forward(handler), tracking); } @@ -1128,7 +1129,7 @@ namespace sol { } template - inline auto unqualified_get(lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_unqualified_get(L, index, tracking)) { + auto unqualified_get(lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_unqualified_get(L, index, tracking)) { #if defined(SOL_SAFE_GETTER) && SOL_SAFE_GETTER static constexpr bool is_op = meta::is_specialization_of_v #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES @@ -1151,13 +1152,13 @@ namespace sol { } template - inline decltype(auto) unqualified_get(lua_State* L, int index = -lua_size>::value) { + decltype(auto) unqualified_get(lua_State* L, int index = -lua_size>::value) { record tracking{}; return unqualified_get(L, index, tracking); } template - inline auto get(lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_get(L, index, tracking)) { + auto get(lua_State* L, int index, record& tracking) -> decltype(stack_detail::unchecked_get(L, index, tracking)) { #if defined(SOL_SAFE_GETTER) && SOL_SAFE_GETTER static constexpr bool is_op = meta::is_specialization_of_v #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES @@ -1180,25 +1181,25 @@ namespace sol { } template - inline decltype(auto) get(lua_State* L, int index = -lua_size>::value) { + decltype(auto) get(lua_State* L, int index = -lua_size>::value) { record tracking{}; return get(L, index, tracking); } template - inline decltype(auto) get_usertype(lua_State* L, int index, record& tracking) { + decltype(auto) get_usertype(lua_State* L, int index, record& tracking) { using UT = meta::conditional_t::value, detail::as_pointer_tag>, detail::as_value_tag>; return get(L, index, tracking); } template - inline decltype(auto) get_usertype(lua_State* L, int index = -lua_size>::value) { + decltype(auto) get_usertype(lua_State* L, int index = -lua_size>::value) { record tracking{}; return get_usertype(L, index, tracking); } template - inline decltype(auto) pop(lua_State* L) { + decltype(auto) pop(lua_State* L) { return popper>{}.pop(L); } @@ -1263,7 +1264,7 @@ namespace sol { } template - inline void modify_unique_usertype_as(const stack_reference& obj, F&& f) { + void modify_unique_usertype_as(const stack_reference& obj, F&& f) { using u_traits = unique_usertype_traits; void* raw = lua_touserdata(obj.lua_state(), obj.stack_index()); void* ptr_memory = detail::align_usertype_pointer(raw); @@ -1274,7 +1275,7 @@ namespace sol { } template - inline void modify_unique_usertype(const stack_reference& obj, F&& f) { + void modify_unique_usertype(const stack_reference& obj, F&& f) { using bt = meta::bind_traits>; using T = typename bt::template arg_at<0>; using Tu = meta::unqualified_t; @@ -1286,7 +1287,7 @@ namespace sol { namespace detail { template - inline lua_CFunction make_destructor(std::true_type) { + lua_CFunction make_destructor(std::true_type) { if constexpr (is_unique_usertype_v) { return &unique_destruct; } @@ -1299,12 +1300,12 @@ namespace sol { } template - inline lua_CFunction make_destructor(std::false_type) { + lua_CFunction make_destructor(std::false_type) { return &cannot_destruct; } template - inline lua_CFunction make_destructor() { + lua_CFunction make_destructor() { return make_destructor(std::is_destructible()); } @@ -1316,18 +1317,18 @@ namespace sol { }; template - inline int is_check(lua_State* L) { + int is_check(lua_State* L) { return stack::push(L, stack::check(L, 1, &no_panic)); } template - inline int member_default_to_string(std::true_type, lua_State* L) { + int member_default_to_string(std::true_type, lua_State* L) { decltype(auto) ts = stack::get(L, 1).to_string(); return stack::push(L, std::forward(ts)); } template - inline int member_default_to_string(std::false_type, lua_State* L) { + int member_default_to_string(std::false_type, lua_State* L) { return luaL_error(L, "cannot perform to_string on '%s': no 'to_string' overload in namespace, 'to_string' member " "function, or operator<<(ostream&, ...) present", @@ -1335,36 +1336,36 @@ namespace sol { } template - inline int adl_default_to_string(std::true_type, lua_State* L) { + int adl_default_to_string(std::true_type, lua_State* L) { using namespace std; decltype(auto) ts = to_string(stack::get(L, 1)); return stack::push(L, std::forward(ts)); } template - inline int adl_default_to_string(std::false_type, lua_State* L) { + int adl_default_to_string(std::false_type, lua_State* L) { return member_default_to_string(meta::supports_to_string_member(), L); } template - inline int oss_default_to_string(std::true_type, lua_State* L) { + int oss_default_to_string(std::true_type, lua_State* L) { std::ostringstream oss; oss << stack::unqualified_get(L, 1); return stack::push(L, oss.str()); } template - inline int oss_default_to_string(std::false_type, lua_State* L) { + int oss_default_to_string(std::false_type, lua_State* L) { return adl_default_to_string(meta::supports_adl_to_string(), L); } template - inline int default_to_string(lua_State* L) { + int default_to_string(lua_State* L) { return oss_default_to_string(meta::supports_ostream_op(), L); } template - inline int default_size(lua_State* L) { + int default_size(lua_State* L) { decltype(auto) self = stack::unqualified_get(L, 1); return stack::push(L, self.size()); } @@ -1391,8 +1392,8 @@ namespace sol { } else { if constexpr (std::is_same_v, Op> // clang-format hack - || std::is_same_v, Op> // - || std::is_same_v, Op>) { // + || std::is_same_v, Op> // + || std::is_same_v, Op>) { // if (detail::ptr(l) == detail::ptr(r)) { return stack::push(L, true); } diff --git a/include/sol/stack_field.hpp b/include/sol/stack_field.hpp index 0ecce6a8..90615874 100644 --- a/include/sol/stack_field.hpp +++ b/include/sol/stack_field.hpp @@ -39,7 +39,7 @@ namespace stack { template void get(lua_State* L, Key&& key, int tableindex = default_table_index) { - if constexpr (std::is_same_v || std::is_same_v) { + if constexpr (std::is_same_v || std::is_same_v || std::is_same_v) { (void)L; (void)key; (void)tableindex; diff --git a/include/sol/table_core.hpp b/include/sol/table_core.hpp index 916beed5..eef76de8 100644 --- a/include/sol/table_core.hpp +++ b/include/sol/table_core.hpp @@ -102,58 +102,120 @@ namespace sol { template decltype(auto) traverse_get_single(int table_index, Keys&&... keys) const { - constexpr static bool global = meta::all, meta::is_c_str>...>::value; + constexpr static bool global = top_level && (meta::count_for_to_pack_v<1, meta::is_c_str, meta::unqualified_t...> > 0); if constexpr (meta::is_optional_v>) { int popcount = 0; detail::ref_clean c(base_t::lua_state(), popcount); - return traverse_get_deep_optional(popcount, table_index, std::forward(keys)...); + return traverse_get_deep_optional(popcount, table_index, std::forward(keys)...); } else { - detail::clean c(base_t::lua_state()); - return traverse_get_deep(table_index, std::forward(keys)...); + detail::clean...>> c(base_t::lua_state()); + return traverse_get_deep(table_index, std::forward(keys)...); } } template void tuple_set(std::index_sequence, Pairs&& pairs) { - constexpr bool global = meta::all, meta::is_c_str(std::forward(pairs)))>...>::value; + constexpr static bool global = top_level && (meta::count_even_for_pack_v(std::forward(pairs)))>...> > 0); auto pp = stack::push_pop(*this); int table_index = pp.index_of(*this); lua_State* L = base_t::lua_state(); (void)table_index; (void)L; - void(detail::swallow{ (stack::set_field(L, + void(detail::swallow{ (stack::set_field<(top_level), raw>(L, std::get(std::forward(pairs)), std::get(std::forward(pairs)), table_index), 0)... }); } - template + template decltype(auto) traverse_get_deep(int table_index, Key&& key, Keys&&... keys) const { - lua_State* L = base_t::lua_state(); - stack::get_field(L, std::forward(key), table_index); - (void)detail::swallow{ 0, (stack::get_field(L, std::forward(keys), lua_gettop(L)), 0)... }; - return stack::get(L); - } - - template - decltype(auto) traverse_get_deep_optional(int& popcount, int table_index, Key&& key, Keys&&... keys) const { - lua_State* L = base_t::lua_state(); - if constexpr (sizeof...(Keys) > 0) { - auto p = stack::probe_get_field(L, std::forward(key), table_index); - popcount += p.levels; - if (!p.success) - return T(nullopt); - return traverse_get_deep_optional(popcount, lua_gettop(L), std::forward(keys)...); + if constexpr (std::is_same_v, create_if_nil_t>) { + (void)key; + return traverse_get_deep(mode | detail::insert_mode::create_if_nil), T>( + table_index, std::forward(keys)...); } else { - using R = decltype(stack::get(L)); - auto p = stack::probe_get_field(L, std::forward(key), table_index); - popcount += p.levels; - if (!p.success) - return R(nullopt); - return stack::get(L); + lua_State* L = base_t::lua_state(); + stack::get_field(L, std::forward(key), table_index); + if constexpr (sizeof...(Keys) > 0) { + if constexpr ((mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) { + type t = type_of(L, -1); + if (t == type::nil || t == type::none) { + lua_pop(L, 1); + stack::push(L, new_table(0, 0)); + } + } + return traverse_get_deep(lua_gettop(L), std::forward(keys)...); + } + else { + if constexpr ((mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) { + type t = type_of(L, -1); + if ((t == type::nil || t == type::none) && (is_table_like_v)) { + lua_pop(L, 1); + stack::push(L, new_table(0, 0)); + } + } + return stack::get(L); + } + } + } + + template + decltype(auto) traverse_get_deep_optional(int& popcount, int table_index, Key&& key, Keys&&... keys) const { + if constexpr (std::is_same_v, create_if_nil_t>) { + constexpr detail::insert_mode new_mode = static_cast(mode | detail::insert_mode::create_if_nil); + (void)key; + return traverse_get_deep_optional(popcount, table_index, std::forward(keys)...); + } + else if constexpr (std::is_same_v, update_if_empty_t>) { + constexpr detail::insert_mode new_mode = static_cast(mode | detail::insert_mode::update_if_empty); + (void)key; + return traverse_get_deep_optional(popcount, table_index, std::forward(keys)...); + } + else if constexpr (std::is_same_v, override_value_t>) { + constexpr detail::insert_mode new_mode = static_cast(mode | detail::insert_mode::override_value); + (void)key; + return traverse_get_deep_optional(popcount, table_index, std::forward(keys)...); + } + else { + if constexpr (sizeof...(Keys) > 0) { + lua_State* L = base_t::lua_state(); + auto p = stack::probe_get_field(L, std::forward(key), table_index); + popcount += p.levels; + if (!p.success) { + if constexpr ((mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) { + lua_pop(L, 1); + constexpr bool is_seq = meta::count_for_to_pack_v<1, std::is_integral, Keys...> > 0; + stack::push(L, new_table(static_cast(is_seq), static_cast(!is_seq))); + stack::set_field(L, std::forward(key), stack_reference(L, -1), table_index); + } + else { + return T(nullopt); + } + } + return traverse_get_deep_optional(popcount, lua_gettop(L), std::forward(keys)...); + } + else { + using R = decltype(stack::get(nullptr)); + using value_type = typename meta::unqualified_t::value_type; + lua_State* L = base_t::lua_state(); + auto p = stack::probe_get_field(L, key, table_index); + popcount += p.levels; + if (!p.success) { + if constexpr ((mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) { + lua_pop(L, 1); + stack::push(L, new_table(0, 0)); + stack::set_field(L, std::forward(key), stack_reference(L, -1), table_index); + if (stack::check(L, lua_gettop(L), no_panic)) { + return stack::get(L); + } + } + return R(nullopt); + } + return stack::get(L); + } } } @@ -162,19 +224,25 @@ namespace sol { using KeyU = meta::unqualified_t; if constexpr (std::is_same_v) { (void)key; - traverse_set_deep(table_index, std::forward(keys)...); + traverse_set_deep(mode | detail::insert_mode::update_if_empty)>(table_index, std::forward(keys)...); + } + else if constexpr (std::is_same_v) { + (void)key; + traverse_set_deep(mode | detail::insert_mode::create_if_nil)>( + table_index, std::forward(keys)...); } else if constexpr (std::is_same_v) { (void)key; - traverse_set_deep(table_index, std::forward(keys)...); + traverse_set_deep(mode | detail::insert_mode::override_value)>( + table_index, std::forward(keys)...); } else { lua_State* L = base_t::lua_state(); if constexpr (sizeof...(Keys) == 1) { if constexpr ((mode & detail::insert_mode::update_if_empty) == detail::insert_mode::update_if_empty) { - stack::get_field(L, key, table_index); - type vt = type_of(L, -1); - if (vt == type::lua_nil || vt == type::none) { + auto p = stack::probe_get_field(L, key, table_index); + lua_pop(L, p.levels); + if (!p.success) { stack::set_field(L, std::forward(key), std::forward(keys)..., table_index); } } @@ -183,22 +251,25 @@ namespace sol { } } else { - if constexpr ((mode & detail::insert_mode::override_value) == detail::insert_mode::override_value) { - stack::probe p = stack::probe_get_field(L, key, table_index); - if (!p.success) { - constexpr bool is_seq = std::is_integral_v; - stack::set_field(L, key, new_table(static_cast(is_seq), !static_cast(is_seq)), table_index); - stack::get_field(L, std::forward(key), table_index); - } - } - else if constexpr((mode & detail::insert_mode::update_if_empty) == detail::insert_mode::update_if_empty) { + if constexpr (mode != detail::insert_mode::none) { stack::get_field(L, key, table_index); type vt = type_of(L, -1); - if (vt == type::lua_nil || vt == type::none) { - constexpr bool is_seq = std::is_integral_v; - lua_pop(L, 1); - stack::set_field(L, key, new_table(static_cast(is_seq), !static_cast(is_seq)), table_index); - stack::get_field(L, std::forward(key), table_index); + if constexpr ((mode & detail::insert_mode::update_if_empty) == detail::insert_mode::update_if_empty + || (mode & detail::insert_mode::create_if_nil) == detail::insert_mode::create_if_nil) { + if (vt == type::lua_nil || vt == type::none) { + constexpr bool is_seq = meta::count_for_to_pack_v<1, std::is_integral, Keys...> > 0; + lua_pop(L, 1); + stack::push(L, new_table(static_cast(is_seq), static_cast(!is_seq))); + stack::set_field(L, std::forward(key), stack_reference(L, -1), table_index); + } + } + else { + if (vt != type::table) { + constexpr bool is_seq = meta::count_for_to_pack_v<1, std::is_integral, Keys...> > 0; + lua_pop(L, 1); + stack::push(L, new_table(static_cast(is_seq), static_cast(!is_seq))); + stack::set_field(L, std::forward(key), stack_reference(L, -1), table_index); + } } } else { @@ -336,7 +407,8 @@ namespace sol { template decltype(auto) traverse_get(Keys&&... keys) const { - constexpr static bool global = meta::all, meta::is_c_str>...>::value; + static_assert(sizeof...(Keys) > 0, "must pass at least 1 key to get"); + constexpr static bool global = top_level && (meta::count_for_to_pack_v<1, meta::is_c_str, meta::unqualified_t...> > 0); auto pp = stack::push_pop(*this); int table_index = pp.index_of(*this); return traverse_get_single(table_index, std::forward(keys)...); @@ -344,11 +416,12 @@ namespace sol { template basic_table_core& traverse_set(Keys&&... keys) { - constexpr static bool global = meta::all, meta::is_c_str>...>::value; + static_assert(sizeof...(Keys) > 1, "must pass at least 1 key and 1 value to set"); + constexpr static bool global = top_level && (meta::count_when_for_to_pack_v...> > 0); auto pp = stack::push_pop(*this); int table_index = pp.index_of(*this); lua_State* L = base_t::lua_state(); - auto pn = stack::pop_n(L, static_cast(sizeof...(Keys) - 2)); + auto pn = stack::pop_n(L, static_cast(sizeof...(Keys) - 2 - meta::count_for_pack_v...>)); traverse_set_deep(table_index, std::forward(keys)...); return *this; } @@ -367,7 +440,7 @@ namespace sol { template decltype(auto) raw_get(Keys&&... keys) const { static_assert(sizeof...(Keys) == sizeof...(Ret), "number of keys and number of return types do not match"); - constexpr static bool global = meta::all, meta::is_c_str>...>::value; + constexpr static bool global = top_level && (meta::count_for_to_pack_v<1, meta::is_c_str, meta::unqualified_t...> > 0); auto pp = stack::push_pop(*this); int table_index = pp.index_of(*this); return tuple_get(table_index, std::forward(keys)...); @@ -394,7 +467,7 @@ namespace sol { template decltype(auto) traverse_raw_get(Keys&&... keys) const { - constexpr static bool global = meta::all, meta::is_c_str>...>::value; + constexpr static bool global = top_level && (meta::count_for_to_pack_v<1, meta::is_c_str, meta::unqualified_t...> > 0); auto pp = stack::push_pop(*this); int table_index = pp.index_of(*this); return traverse_get_single(table_index, std::forward(keys)...); @@ -402,10 +475,10 @@ namespace sol { template basic_table_core& traverse_raw_set(Keys&&... keys) { - constexpr static bool global = meta::all, meta::is_c_str>...>::value; + constexpr static bool global = top_level && (meta::count_for_to_pack_v<1, meta::is_c_str, meta::unqualified_t...> > 0); auto pp = stack::push_pop(*this); lua_State* L = base_t::lua_state(); - auto pn = stack::pop_n(L, static_cast(sizeof...(Keys) - 2)); + auto pn = stack::pop_n(L, static_cast(sizeof...(Keys) - 2 - meta::count_for_pack...>)); traverse_set_deep(std::forward(keys)...); return *this; } @@ -572,7 +645,7 @@ namespace sol { template static inline table create_with(lua_State* L, Args&&... args) { static_assert(sizeof...(Args) % 2 == 0, "You must have an even number of arguments for a key, value ... list."); - static const int narr = static_cast(meta::count_2_for_pack::value); + constexpr int narr = static_cast(meta::count_odd_for_pack_v); return create(L, narr, static_cast((sizeof...(Args) / 2) - narr), std::forward(args)...); } @@ -606,7 +679,7 @@ namespace sol { template table create_named(Name&& name, Args&&... args) { - static const int narr = static_cast(meta::count_2_for_pack::value); + static const int narr = static_cast(meta::count_even_for_pack_v); return create(std::forward(name), narr, (sizeof...(Args) / 2) - narr, std::forward(args)...); } }; diff --git a/include/sol/traits.hpp b/include/sol/traits.hpp index ed537912..ca6a841b 100644 --- a/include/sol/traits.hpp +++ b/include/sol/traits.hpp @@ -179,23 +179,30 @@ namespace sol { }; namespace meta_detail { - template class Pred, typename... Ts> - struct count_for_pack : std::integral_constant {}; - template class Pred, typename T, typename... Ts> - struct count_for_pack : conditional_t < sizeof...(Ts) - == 0 - || Limit<2, std::integral_constant(Limit != 0 && Pred::value)>, - count_for_pack(Pred::value), Pred, Ts...>> {}; - template class Pred, typename... Ts> - struct count_2_for_pack : std::integral_constant {}; - template class Pred, typename T, typename U, typename... Ts> - struct count_2_for_pack - : conditional_t(Pred::value)>, - count_2_for_pack(Pred::value), Pred, Ts...>> {}; + template + using on_even = meta::boolean<(TI::value % 2) == 0>; + + template + using on_odd = meta::boolean<(TI::value % 2) == 1>; + + template + using on_always = std::true_type; + + template