From a2f86d88dcd75135538fed2dd5e45eea60a5cdfd Mon Sep 17 00:00:00 2001 From: ThePhD Date: Thu, 17 Jan 2019 08:28:34 -0500 Subject: [PATCH] optimize get/traverse_get and set/traverse_set items consider potential optimizations for new_enum to reduce compiler churn consider potential optimizations for proxy --- include/sol/coroutine.hpp | 8 +- include/sol/forward.hpp | 16 +- include/sol/object.hpp | 19 ++ include/sol/object_base.hpp | 6 +- include/sol/optional.hpp | 13 +- include/sol/protected_function.hpp | 8 +- include/sol/reference.hpp | 31 +- include/sol/stack_get_unqualified.hpp | 9 +- include/sol/state_view.hpp | 4 +- include/sol/table_core.hpp | 201 +++++++----- include/sol/thread.hpp | 8 +- include/sol/traits.hpp | 44 +-- include/sol/types.hpp | 12 + include/sol/unsafe_function.hpp | 7 +- include/sol/userdata.hpp | 3 +- single/include/sol/forward.hpp | 20 +- single/include/sol/sol.hpp | 401 +++++++++++++++--------- tests/runtime_tests/source/basic.cpp | 62 ++++ tests/runtime_tests/source/sol_test.hpp | 3 + 19 files changed, 586 insertions(+), 289 deletions(-) diff --git a/include/sol/coroutine.hpp b/include/sol/coroutine.hpp index ff05ab66..036d78cd 100644 --- a/include/sol/coroutine.hpp +++ b/include/sol/coroutine.hpp @@ -25,14 +25,18 @@ #define SOL_COROUTINE_HPP #include "reference.hpp" +#include "object.hpp" #include "stack.hpp" #include "function_result.hpp" #include "thread.hpp" #include "protected_handler.hpp" namespace sol { - template - class basic_coroutine : public base_t { + template + class basic_coroutine : public basic_object { + private: + using base_t = basic_object; + public: typedef reference handler_t; handler_t error_handler; diff --git a/include/sol/forward.hpp b/include/sol/forward.hpp index a5c7e05e..e795b39e 100644 --- a/include/sol/forward.hpp +++ b/include/sol/forward.hpp @@ -53,12 +53,12 @@ namespace sol { using stack_table_core = basic_table_core; template using basic_table = basic_table_core; - typedef table_core table; - typedef table_core global_table; - typedef main_table_core main_table; - typedef main_table_core main_global_table; - typedef stack_table_core stack_table; - typedef stack_table_core stack_global_table; + using table = table_core; + using global_table = table_core; + using main_table = main_table_core; + using main_global_table = main_table_core; + using stack_table = stack_table_core; + using stack_global_table = stack_table_core; template class basic_usertype; @@ -115,6 +115,8 @@ namespace sol { using function_result = unsafe_function_result; #endif + template + class basic_object_base; template class basic_object; template @@ -158,6 +160,8 @@ namespace sol { template struct as_container_t; template + struct force_t; + template struct nested; template struct light; diff --git a/include/sol/object.hpp b/include/sol/object.hpp index 1fe1000e..bebcd304 100644 --- a/include/sol/object.hpp +++ b/include/sol/object.hpp @@ -44,6 +44,25 @@ namespace sol { } } + protected: + basic_object(detail::no_safety_tag, lua_nil_t n) : base_t(n) { + } + basic_object(detail::no_safety_tag, lua_State* L, int index) : base_t(L, index) { + } + basic_object(lua_State* L, detail::global_tag t) : base_t(L, t) { + } + basic_object(detail::no_safety_tag, lua_State* L, ref_index index) : base_t(L, index) { + } + template , basic_object>>, meta::neg>, + meta::neg>>, is_lua_reference>> = meta::enabler> + basic_object(detail::no_safety_tag, T&& r) noexcept : base_t(std::forward(r)) { + } + + template >> = meta::enabler> + basic_object(detail::no_safety_tag, lua_State* L, T&& r) noexcept : base_t(L, std::forward(r)) { + } + public: basic_object() noexcept = default; template , basic_object>>, meta::neg>, is_lua_reference>> = meta::enabler> diff --git a/include/sol/object_base.hpp b/include/sol/object_base.hpp index 25cbb257..5154d654 100644 --- a/include/sol/object_base.hpp +++ b/include/sol/object_base.hpp @@ -29,9 +29,11 @@ namespace sol { - template - class basic_object_base : public base_t { + template + class basic_object_base : public ref_t { private: + using base_t = ref_t; + template decltype(auto) as_stack(std::true_type) const { return stack::get(base_t::lua_state(), base_t::stack_index()); diff --git a/include/sol/optional.hpp b/include/sol/optional.hpp index 1325a62e..d502b646 100644 --- a/include/sol/optional.hpp +++ b/include/sol/optional.hpp @@ -26,6 +26,7 @@ #include "forward.hpp" #include "in_place.hpp" +#include "traits.hpp" #if defined(SOL_USE_BOOST) && SOL_USE_BOOST #include #else @@ -47,13 +48,15 @@ namespace sol { namespace meta { template - struct is_optional : std::false_type {}; - template - struct is_optional> : std::true_type {}; + using is_optional = any< + is_specialization_of #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES - template - struct is_optional> : std::true_type {}; + , is_specialization_of #endif + >; + + template + constexpr inline bool is_optional_v = is_optional::value; } // namespace meta } // namespace sol diff --git a/include/sol/protected_function.hpp b/include/sol/protected_function.hpp index 8c705a87..cec9c86e 100644 --- a/include/sol/protected_function.hpp +++ b/include/sol/protected_function.hpp @@ -25,6 +25,7 @@ #define SOL_PROTECTED_FUNCTION_HPP #include "reference.hpp" +#include "object.hpp" #include "stack.hpp" #include "protected_function_result.hpp" #include "unsafe_function.hpp" @@ -49,8 +50,11 @@ namespace sol { } } - template - class basic_protected_function : public base_t { + template + class basic_protected_function : public basic_object { + private: + using base_t = basic_object; + public: typedef is_stack_based is_stack_handler; diff --git a/include/sol/reference.hpp b/include/sol/reference.hpp index e1638737..705e92a1 100644 --- a/include/sol/reference.hpp +++ b/include/sol/reference.hpp @@ -91,33 +91,58 @@ namespace sol { lua_pop(L, t); } }; + template <> struct push_popper_n { push_popper_n(lua_State*, int) { } }; + template struct push_popper { + using Tu = meta::unqualified_t; T t; + int idx; + push_popper(T x) - : t(x) { - t.push(); + : t(x), idx(lua_absindex(t.lua_state(), -t.push())) { + } + + int index_of(const Tu&) { + return idx; + } + ~push_popper() { t.pop(); } }; + template struct push_popper { + using Tu = meta::unqualified_t; + push_popper(T) { } + + int index_of(const Tu&) { + return -1; + } + ~push_popper() { } }; template struct push_popper>::value>> { + using Tu = meta::unqualified_t; + push_popper(T) { } + + int index_of(const Tu& r) { + return r.stack_index(); + } + ~push_popper() { } }; @@ -126,12 +151,14 @@ namespace sol { push_popper push_pop(T&& x) { return push_popper(std::forward(x)); } + template push_popper_at push_pop_at(T&& x) { int c = x.push(); lua_State* L = x.lua_state(); return push_popper_at(L, lua_absindex(L, -c), c); } + template push_popper_n pop_n(lua_State* L, int x) { return push_popper_n(L, x); diff --git a/include/sol/stack_get_unqualified.hpp b/include/sol/stack_get_unqualified.hpp index 044de34c..71ef025a 100644 --- a/include/sol/stack_get_unqualified.hpp +++ b/include/sol/stack_get_unqualified.hpp @@ -215,11 +215,12 @@ namespace sol { namespace stack { tracking.use(1); // the W4 flag is really great, - // so great that it can tell my for loops (2-nested) - // below never actually terminate without hitting a "return arr;" - // where the goto's are now so it would tell + // so great that it can tell my for loops (twice nested) + // below never actually terminate + // without hitting where the gotos have infested + + // so now I would get the error W4XXX unreachable // me that the return arr at the end of this function - // is W4XXX unreachable, // which is fair until other compilers complain // that there isn't a return and that based on // SOME MAGICAL FORCE diff --git a/include/sol/state_view.hpp b/include/sol/state_view.hpp index 50f604dd..04f5c0ea 100644 --- a/include/sol/state_view.hpp +++ b/include/sol/state_view.hpp @@ -93,8 +93,8 @@ namespace sol { } public: - typedef global_table::iterator iterator; - typedef global_table::const_iterator const_iterator; + using iterator = typename global_table::iterator; + using const_iterator = typename global_table::const_iterator; state_view(lua_State* Ls) : L(Ls), reg(Ls, LUA_REGISTRYINDEX), global(Ls, detail::global_) { diff --git a/include/sol/table_core.hpp b/include/sol/table_core.hpp index 83d8ca36..5a173606 100644 --- a/include/sol/table_core.hpp +++ b/include/sol/table_core.hpp @@ -29,8 +29,9 @@ #include "function_types.hpp" #include "table_iterator.hpp" #include "types.hpp" -#include "object_base.hpp" +#include "object.hpp" #include "usertype.hpp" +#include "optional.hpp" namespace sol { namespace detail { @@ -55,95 +56,110 @@ namespace sol { inline int fail_on_newindex(lua_State* L) { return luaL_error(L, "sol: cannot modify the elements of an enumeration table"); } + + template + using is_global = meta::all, meta::is_c_str...>; + + template + constexpr inline bool is_global_v = is_global::value; } // namespace detail - template - class basic_table_core : public basic_object_base { - typedef basic_object_base base_t; + template + class basic_table_core : public basic_object { + private: + using base_t = basic_object; + friend class state; friend class state_view; - template - using is_global = meta::all, meta::is_c_str...>; - - template - auto tuple_get(types, std::index_sequence<0, 1, I...>, Keys&& keys) const - -> decltype(stack::pop>(nullptr)) { - typedef decltype(stack::pop>(nullptr)) Tup; - return Tup(traverse_get_optional(meta::is_optional>(), std::get<0>(std::forward(keys))), - traverse_get_optional(meta::is_optional>(), std::get<1>(std::forward(keys))), - traverse_get_optional(meta::is_optional>(), std::get(std::forward(keys)))...); + template + decltype(auto) tuple_get(int table_index, Keys&&... keys) const { + if constexpr (sizeof...(Ret) < 2) { + return traverse_get_single_maybe_tuple(table_index, std::forward(keys)...); + } + else { + using multi_ret = decltype(stack::pop>(nullptr)); + return multi_ret(traverse_get_single_maybe_tuple(table_index, std::forward(keys))...); + } } - template - decltype(auto) tuple_get(types, std::index_sequence, Keys&& keys) const { - return traverse_get_optional(meta::is_optional>(), std::get(std::forward(keys))); + template + decltype(auto) traverse_get_single_tuple(int table_index, std::index_sequence, Key&& key) const { + return traverse_get_single(table_index, std::get(std::forward(key))...); + } + + template + decltype(auto) traverse_get_single_maybe_tuple(int table_index, Key&& key) const { + if constexpr (meta::is_tuple_v>) { + return traverse_get_single_tuple( + table_index, std::make_index_sequence>>(), std::forward(key)); + } + else { + return traverse_get_single(table_index, std::forward(key)); + } + } + + template + decltype(auto) traverse_get_single(int table_index, Keys&&... keys) const { + constexpr static bool global = detail::is_global_v; + 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)...); + } + else { + 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) { - auto pp = stack::push_pop < top_level && (is_global(std::forward(pairs)))...>::value) > (*this); + constexpr bool global = detail::is_global(std::forward(pairs)))...>::value; + auto pp = stack::push_pop(*this); + int table_index = pp.index_of(*this); void(detail::swallow{ (stack::set_field(base_t::lua_state(), std::get(std::forward(pairs)), std::get(std::forward(pairs)), - lua_gettop(base_t::lua_state())), + table_index), 0)... }); } - template - decltype(auto) traverse_get_deep(Key&& key) const { - stack::get_field(base_t::lua_state(), std::forward(key)); + template + decltype(auto) traverse_get_deep(int table_index, Key&& key, Keys&&... keys) const { + stack::get_field(base_t::lua_state(), std::forward(key), table_index); + (void)detail::swallow{ 0, (stack::get_field(base_t::lua_state(), std::forward(keys), lua_gettop(base_t::lua_state())), 0)... }; return stack::get(base_t::lua_state()); } template - decltype(auto) traverse_get_deep(Key&& key, Keys&&... keys) const { - stack::get_field(base_t::lua_state(), std::forward(key)); - return traverse_get_deep(std::forward(keys)...); - } - - template - decltype(auto) traverse_get_deep_optional(int& popcount, Key&& key) const { - typedef decltype(stack::get(base_t::lua_state())) R; - auto p = stack::probe_get_field(base_t::lua_state(), std::forward(key), lua_gettop(base_t::lua_state())); - popcount += p.levels; - if (!p.success) - return R(nullopt); - return stack::get(base_t::lua_state()); - } - - template - decltype(auto) traverse_get_deep_optional(int& popcount, Key&& key, Keys&&... keys) const { - auto p = I > 0 ? stack::probe_get_field(base_t::lua_state(), std::forward(key), -1) - : stack::probe_get_field(base_t::lua_state(), std::forward(key), lua_gettop(base_t::lua_state())); - popcount += p.levels; - if (!p.success) - return T(nullopt); - return traverse_get_deep_optional(popcount, std::forward(keys)...); - } - - template - decltype(auto) traverse_get_optional(std::false_type, Keys&&... keys) const { - detail::clean c(base_t::lua_state()); - return traverse_get_deep(std::forward(keys)...); - } - - template - decltype(auto) traverse_get_optional(std::true_type, Keys&&... keys) const { - int popcount = 0; - detail::ref_clean c(base_t::lua_state(), popcount); - return traverse_get_deep_optional(popcount, std::forward(keys)...); - } - - template - void traverse_set_deep(Key&& key, Value&& value) const { - stack::set_field(base_t::lua_state(), std::forward(key), std::forward(value)); + decltype(auto) traverse_get_deep_optional(int& popcount, int table_index, Key&& key, Keys&&... keys) const { + if constexpr (sizeof...(Keys) > 0) { + auto p = stack::probe_get_field(base_t::lua_state(), std::forward(key), table_index); + popcount += p.levels; + if (!p.success) + return T(nullopt); + return traverse_get_deep_optional(popcount, lua_gettop(base_t::lua_state()), std::forward(keys)...); + } + else { + using R = decltype(stack::get(base_t::lua_state())); + auto p = stack::probe_get_field(base_t::lua_state(), std::forward(key), table_index); + popcount += p.levels; + if (!p.success) + return R(nullopt); + return stack::get(base_t::lua_state()); + } } template - void traverse_set_deep(Key&& key, Keys&&... keys) const { - stack::get_field(base_t::lua_state(), std::forward(key)); - traverse_set_deep(std::forward(keys)...); + void traverse_set_deep(int table_index, Key&& key, Keys&&... keys) const { + if constexpr (sizeof...(Keys) == 1) { + stack::set_field(base_t::lua_state(), std::forward(key), std::forward(keys)..., table_index); + } + else { + stack::get_field(base_t::lua_state(), std::forward(key), table_index); + traverse_set_deep(lua_gettop(base_t::lua_state()), std::forward(keys)...); + } } basic_table_core(lua_State* L, detail::global_tag t) noexcept : base_t(L, t) { @@ -157,7 +173,7 @@ namespace sol { basic_table_core(detail::no_safety_tag, lua_State* L, ref_index index) : base_t(L, index) { } template , basic_table_core>>, meta::neg>, + meta::enable, basic_table_core>>, meta::neg>, meta::neg>>, is_lua_reference>> = meta::enabler> basic_table_core(detail::no_safety_tag, T&& r) noexcept : base_t(std::forward(r)) { } @@ -166,8 +182,8 @@ namespace sol { } public: - typedef basic_table_iterator iterator; - typedef iterator const_iterator; + using iterator = basic_table_iterator; + using const_iterator = iterator; using base_t::lua_state; @@ -189,7 +205,7 @@ namespace sol { #endif // Safety } basic_table_core(lua_State* L, const new_table& nt) : base_t(L, -stack::push(L, nt)) { - if (!is_stack_based>::value) { + if (!is_stack_based>::value) { lua_pop(L, 1); } } @@ -207,7 +223,7 @@ namespace sol { #endif // Safety } template , basic_table_core>>, meta::neg>, + meta::enable, basic_table_core>>, meta::neg>, meta::neg>>, is_lua_reference>> = meta::enabler> basic_table_core(T&& r) noexcept : basic_table_core(detail::no_safety, std::forward(r)) { #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES @@ -240,8 +256,10 @@ namespace sol { template decltype(auto) get(Keys&&... keys) const { static_assert(sizeof...(Keys) == sizeof...(Ret), "number of keys and number of return types do not match"); - auto pp = stack::push_pop::value>(*this); - return tuple_get(types(), std::make_index_sequence(), std::forward_as_tuple(std::forward(keys)...)); + constexpr static bool global = detail::is_global_v; + auto pp = stack::push_pop(*this); + int table_index = pp.index_of(*this); + return tuple_get(table_index, std::forward(keys)...); } template @@ -265,29 +283,40 @@ namespace sol { template decltype(auto) traverse_get(Keys&&... keys) const { - auto pp = stack::push_pop::value>(*this); - return traverse_get_optional(meta::is_optional>(), std::forward(keys)...); + constexpr static bool global = detail::is_global_v; + auto pp = stack::push_pop(*this); + int table_index = pp.index_of(*this); + return traverse_get_single(table_index, std::forward(keys)...); } template basic_table_core& traverse_set(Keys&&... keys) { - auto pp = stack::push_pop::value>(*this); + constexpr static bool global = detail::is_global_v; + auto pp = stack::push_pop(*this); + int table_index = pp.index_of(*this); auto pn = stack::pop_n(base_t::lua_state(), static_cast(sizeof...(Keys) - 2)); - traverse_set_deep(std::forward(keys)...); + traverse_set_deep(table_index, std::forward(keys)...); return *this; } template basic_table_core& set(Args&&... args) { - tuple_set(std::make_index_sequence(), std::forward_as_tuple(std::forward(args)...)); + if constexpr(sizeof...(Args) == 2) { + traverse_set(std::forward(args)...); + } + else { + tuple_set(std::make_index_sequence(), std::forward_as_tuple(std::forward(args)...)); + } return *this; } 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"); - auto pp = stack::push_pop::value>(*this); - return tuple_get(types(), std::make_index_sequence(), std::forward_as_tuple(std::forward(keys)...)); + constexpr static bool global = detail::is_global_v; + auto pp = stack::push_pop(*this); + int table_index = pp.index_of(*this); + return tuple_get(table_index, std::forward(keys)...); } template @@ -311,13 +340,16 @@ namespace sol { template decltype(auto) traverse_raw_get(Keys&&... keys) const { - auto pp = stack::push_pop::value>(*this); - return traverse_get_optional(meta::is_optional>(), std::forward(keys)...); + constexpr static bool global = detail::is_global_v; + auto pp = stack::push_pop(*this); + int table_index = pp.index_of(*this); + return traverse_get_single(table_index, std::forward(keys)...); } template basic_table_core& traverse_raw_set(Keys&&... keys) { - auto pp = stack::push_pop::value>(*this); + constexpr static bool global = detail::is_global_v; + auto pp = stack::push_pop(*this); auto pn = stack::pop_n(base_t::lua_state(), static_cast(sizeof...(Keys) - 2)); traverse_set_deep(std::forward(keys)...); return *this; @@ -435,7 +467,8 @@ namespace sol { template basic_table_core& add(Args&&... args) { auto pp = stack::push_pop(*this); - (void)detail::swallow{ 0, (stack::set_ref(base_t::lua_state(), std::forward(args)), 0)... }; + int table_index = pp.index_of(*this); + (void)detail::swallow{ 0, (stack::set_ref(base_t::lua_state(), std::forward(args), table_index), 0)... }; return *this; } diff --git a/include/sol/thread.hpp b/include/sol/thread.hpp index e1704b03..1752d949 100644 --- a/include/sol/thread.hpp +++ b/include/sol/thread.hpp @@ -25,6 +25,7 @@ #define SOL_THREAD_HPP #include "reference.hpp" +#include "object.hpp" #include "stack.hpp" #include "state_view.hpp" @@ -80,8 +81,11 @@ namespace sol { }; } // namespace stack - template - class basic_thread : public base_t { + template + class basic_thread : public basic_object { + private: + using base_t = basic_object; + public: using base_t::lua_state; diff --git a/include/sol/traits.hpp b/include/sol/traits.hpp index 4439fda7..b0233350 100644 --- a/include/sol/traits.hpp +++ b/include/sol/traits.hpp @@ -39,6 +39,9 @@ namespace sol { namespace meta { + using sfinae_yes_t = std::true_type; + using sfinae_no_t = std::false_type; + template using index_value = std::integral_constant; @@ -57,8 +60,18 @@ namespace sol { template using conditional_t = typename conditional::template type; - using sfinae_yes_t = std::true_type; - using sfinae_no_t = std::false_type; + namespace meta_detail { + template class Templ> + struct is_specialization_of : std::false_type {}; + template class Templ> + struct is_specialization_of, Templ> : std::true_type {}; + } // namespace meta_detail + + template class Templ> + using is_specialization_of = meta_detail::is_specialization_of, Templ>; + + template class Templ> + inline constexpr bool is_specialization_of_v = is_specialization_of, Templ>::value; template struct identity { @@ -68,14 +81,14 @@ namespace sol { template using identity_t = typename identity::type; - template - struct is_tuple : std::false_type {}; - - template - struct is_tuple> : std::true_type {}; + template + using is_tuple = is_specialization_of; template - struct is_builtin_type : std::integral_constant::value || std::is_pointer::value || std::is_array::value> {}; + constexpr inline bool is_tuple_v = is_tuple::value; + + template + using is_builtin_type = std::integral_constant::value || std::is_pointer::value || std::is_array::value>; template struct unwrapped { @@ -112,19 +125,6 @@ namespace sol { template using remove_member_pointer_t = remove_member_pointer; - namespace meta_detail { - template class Templ> - struct is_specialization_of : std::false_type {}; - template class Templ> - struct is_specialization_of, Templ> : std::true_type {}; - } // namespace meta_detail - - template class Templ> - using is_specialization_of = meta_detail::is_specialization_of, Templ>; - - template class Templ> - inline constexpr bool is_specialization_of_v = is_specialization_of, Templ>::value; - template struct all_same : std::true_type {}; @@ -144,7 +144,7 @@ namespace sol { using invoke_t = typename T::type; template - using invoke_b = boolean; + using invoke_v = boolean; template using neg = boolean; diff --git a/include/sol/types.hpp b/include/sol/types.hpp index ed479c51..397ac86e 100644 --- a/include/sol/types.hpp +++ b/include/sol/types.hpp @@ -498,6 +498,18 @@ namespace sol { return as_container_t(std::forward(value)); } + template + struct force_t { + T arg; + + force_t(T value) : arg(value) {} + }; + + template + auto force(T&& value) { + return force_t(std::forward(value)); + } + struct this_state { lua_State* L; diff --git a/include/sol/unsafe_function.hpp b/include/sol/unsafe_function.hpp index 2746ddfa..4c79eaa7 100644 --- a/include/sol/unsafe_function.hpp +++ b/include/sol/unsafe_function.hpp @@ -25,15 +25,18 @@ #define SOL_UNSAFE_FUNCTION_HPP #include "reference.hpp" +#include "object.hpp" #include "stack.hpp" #include "function_result.hpp" #include "function_types.hpp" #include namespace sol { - template - class basic_function : public base_t { + template + class basic_function : public basic_object { private: + using base_t = basic_object; + void luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount) const { lua_call(lua_state(), static_cast(argcount), static_cast(resultcount)); } diff --git a/include/sol/userdata.hpp b/include/sol/userdata.hpp index 678f22a7..a5fe9faa 100644 --- a/include/sol/userdata.hpp +++ b/include/sol/userdata.hpp @@ -30,7 +30,8 @@ namespace sol { template class basic_userdata : public basic_table { - typedef basic_table base_t; + private: + using base_t = basic_table; public: using base_t::lua_state; diff --git a/single/include/sol/forward.hpp b/single/include/sol/forward.hpp index 1ea564c8..5925ffc1 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 2019-01-14 02:43:17.627340 UTC -// This header was generated with sol v2.20.6 (revision 91faa7a) +// Generated 2019-01-17 06:28:58.332972 UTC +// This header was generated with sol v2.20.6 (revision 88a089c) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP @@ -269,12 +269,12 @@ namespace sol { using stack_table_core = basic_table_core; template using basic_table = basic_table_core; - typedef table_core table; - typedef table_core global_table; - typedef main_table_core main_table; - typedef main_table_core main_global_table; - typedef stack_table_core stack_table; - typedef stack_table_core stack_global_table; + using table = table_core; + using global_table = table_core; + using main_table = main_table_core; + using main_global_table = main_table_core; + using stack_table = stack_table_core; + using stack_global_table = stack_table_core; template class basic_usertype; @@ -331,6 +331,8 @@ namespace sol { using function_result = unsafe_function_result; #endif + template + class basic_object_base; template class basic_object; template @@ -374,6 +376,8 @@ namespace sol { template struct as_container_t; template + struct force_t; + template struct nested; template struct light; diff --git a/single/include/sol/sol.hpp b/single/include/sol/sol.hpp index cb9fd195..b1e0f08d 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 2019-01-14 02:43:17.362011 UTC -// This header was generated with sol v2.20.6 (revision 91faa7a) +// Generated 2019-01-17 06:28:58.073560 UTC +// This header was generated with sol v2.20.6 (revision 88a089c) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -297,12 +297,12 @@ namespace sol { using stack_table_core = basic_table_core; template using basic_table = basic_table_core; - typedef table_core table; - typedef table_core global_table; - typedef main_table_core main_table; - typedef main_table_core main_global_table; - typedef stack_table_core stack_table; - typedef stack_table_core stack_global_table; + using table = table_core; + using global_table = table_core; + using main_table = main_table_core; + using main_global_table = main_table_core; + using stack_table = stack_table_core; + using stack_global_table = stack_table_core; template class basic_usertype; @@ -359,6 +359,8 @@ namespace sol { using function_result = unsafe_function_result; #endif + template + class basic_object_base; template class basic_object; template @@ -402,6 +404,8 @@ namespace sol { template struct as_container_t; template + struct force_t; + template struct nested; template struct light; @@ -1227,6 +1231,9 @@ namespace sol { namespace sol { namespace meta { + using sfinae_yes_t = std::true_type; + using sfinae_no_t = std::false_type; + template using index_value = std::integral_constant; @@ -1245,8 +1252,18 @@ namespace sol { template using conditional_t = typename conditional::template type; - using sfinae_yes_t = std::true_type; - using sfinae_no_t = std::false_type; + namespace meta_detail { + template class Templ> + struct is_specialization_of : std::false_type {}; + template class Templ> + struct is_specialization_of, Templ> : std::true_type {}; + } // namespace meta_detail + + template class Templ> + using is_specialization_of = meta_detail::is_specialization_of, Templ>; + + template class Templ> + inline constexpr bool is_specialization_of_v = is_specialization_of, Templ>::value; template struct identity { @@ -1256,14 +1273,14 @@ namespace sol { template using identity_t = typename identity::type; - template - struct is_tuple : std::false_type {}; - - template - struct is_tuple> : std::true_type {}; + template + using is_tuple = is_specialization_of; template - struct is_builtin_type : std::integral_constant::value || std::is_pointer::value || std::is_array::value> {}; + constexpr inline bool is_tuple_v = is_tuple::value; + + template + using is_builtin_type = std::integral_constant::value || std::is_pointer::value || std::is_array::value>; template struct unwrapped { @@ -1300,19 +1317,6 @@ namespace sol { template using remove_member_pointer_t = remove_member_pointer; - namespace meta_detail { - template class Templ> - struct is_specialization_of : std::false_type {}; - template class Templ> - struct is_specialization_of, Templ> : std::true_type {}; - } // namespace meta_detail - - template class Templ> - using is_specialization_of = meta_detail::is_specialization_of, Templ>; - - template class Templ> - inline constexpr bool is_specialization_of_v = is_specialization_of, Templ>::value; - template struct all_same : std::true_type {}; @@ -1332,7 +1336,7 @@ namespace sol { using invoke_t = typename T::type; template - using invoke_b = boolean; + using invoke_v = boolean; template using neg = boolean; @@ -3450,7 +3454,7 @@ namespace sol { namespace detail { }} // namespace sol::detail #endif -#define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) tl::detail::is_trivially_copy_constructible::value +#define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) sol::detail::is_trivially_copy_constructible::value #define SOL_TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::is_trivially_copy_assignable::value #define SOL_TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible::value #else @@ -3573,7 +3577,7 @@ namespace sol { template using void_t = typename voider::type; - // Trait for checking if a type is a tl::optional + // Trait for checking if a type is a sol::optional template struct is_optional_impl : std::false_type {}; template @@ -3581,7 +3585,7 @@ namespace sol { template using is_optional = is_optional_impl>; - // Change void to tl::monostate + // Change void to sol::monostate template using fixup_void = conditional_t::value, monostate, U>; @@ -3987,9 +3991,9 @@ namespace sol { /// /// *Examples*: /// ``` - /// tl::optional a = tl::nullopt; - /// void foo (tl::optional); - /// foo(tl::nullopt); //pass an empty optional + /// sol::optional a = sol::nullopt; + /// void foo (sol::optional); + /// foo(sol::nullopt); //pass an empty optional /// ``` static constexpr nullopt_t nullopt{ nullopt_t::do_not_use{}, nullopt_t::do_not_use{} }; @@ -4991,7 +4995,7 @@ namespace sol { /// /// ``` /// int i = 42; - /// tl::optional o = i; + /// sol::optional o = i; /// *o == 42; //true /// i = 12; /// *o = 12; //true @@ -5624,13 +5628,15 @@ namespace sol { namespace meta { template - struct is_optional : std::false_type {}; - template - struct is_optional> : std::true_type {}; + using is_optional = any< + is_specialization_of #if defined(SOL_CXX17_FEATURES) && SOL_CXX17_FEATURES - template - struct is_optional> : std::true_type {}; + , is_specialization_of #endif + >; + + template + constexpr inline bool is_optional_v = is_optional::value; } // namespace meta } // namespace sol @@ -6284,6 +6290,18 @@ namespace sol { return as_container_t(std::forward(value)); } + template + struct force_t { + T arg; + + force_t(T value) : arg(value) {} + }; + + template + auto force(T&& value) { + return force_t(std::forward(value)); + } + struct this_state { lua_State* L; @@ -8000,33 +8018,58 @@ namespace sol { lua_pop(L, t); } }; + template <> struct push_popper_n { push_popper_n(lua_State*, int) { } }; + template struct push_popper { + using Tu = meta::unqualified_t; T t; + int idx; + push_popper(T x) - : t(x) { - t.push(); + : t(x), idx(lua_absindex(t.lua_state(), -t.push())) { + } + + int index_of(const Tu&) { + return idx; + } + ~push_popper() { t.pop(); } }; + template struct push_popper { + using Tu = meta::unqualified_t; + push_popper(T) { } + + int index_of(const Tu&) { + return -1; + } + ~push_popper() { } }; template struct push_popper>::value>> { + using Tu = meta::unqualified_t; + push_popper(T) { } + + int index_of(const Tu& r) { + return r.stack_index(); + } + ~push_popper() { } }; @@ -8035,12 +8078,14 @@ namespace sol { push_popper push_pop(T&& x) { return push_popper(std::forward(x)); } + template push_popper_at push_pop_at(T&& x) { int c = x.push(); lua_State* L = x.lua_state(); return push_popper_at(L, lua_absindex(L, -c), c); } + template push_popper_n pop_n(lua_State* L, int x) { return push_popper_n(L, x); @@ -11176,11 +11221,12 @@ namespace sol { namespace stack { tracking.use(1); // the W4 flag is really great, - // so great that it can tell my for loops (2-nested) - // below never actually terminate without hitting a "return arr;" - // where the goto's are now so it would tell + // so great that it can tell my for loops (twice nested) + // below never actually terminate + // without hitting where the gotos have infested + + // so now I would get the error W4XXX unreachable // me that the return arr at the end of this function - // is W4XXX unreachable, // which is fair until other compilers complain // that there isn't a return and that based on // SOME MAGICAL FORCE @@ -14034,9 +14080,11 @@ namespace sol { namespace sol { - template - class basic_object_base : public base_t { + template + class basic_object_base : public ref_t { private: + using base_t = ref_t; + template decltype(auto) as_stack(std::true_type) const { return stack::get(base_t::lua_state(), base_t::stack_index()); @@ -14104,6 +14152,25 @@ namespace sol { } } + protected: + basic_object(detail::no_safety_tag, lua_nil_t n) : base_t(n) { + } + basic_object(detail::no_safety_tag, lua_State* L, int index) : base_t(L, index) { + } + basic_object(lua_State* L, detail::global_tag t) : base_t(L, t) { + } + basic_object(detail::no_safety_tag, lua_State* L, ref_index index) : base_t(L, index) { + } + template , basic_object>>, meta::neg>, + meta::neg>>, is_lua_reference>> = meta::enabler> + basic_object(detail::no_safety_tag, T&& r) noexcept : base_t(std::forward(r)) { + } + + template >> = meta::enabler> + basic_object(detail::no_safety_tag, lua_State* L, T&& r) noexcept : base_t(L, std::forward(r)) { + } + public: basic_object() noexcept = default; template , basic_object>>, meta::neg>, is_lua_reference>> = meta::enabler> @@ -17230,9 +17297,11 @@ namespace sol { // end of sol/function_types.hpp namespace sol { - template - class basic_function : public base_t { + template + class basic_function : public basic_object { private: + using base_t = basic_object; + void luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount) const { lua_call(lua_state(), static_cast(argcount), static_cast(resultcount)); } @@ -17440,8 +17509,11 @@ namespace sol { } } - template - class basic_protected_function : public base_t { + template + class basic_protected_function : public basic_object { + private: + using base_t = basic_object; + public: typedef is_stack_based is_stack_handler; @@ -21036,7 +21108,7 @@ namespace sol { } proxy& force() { - if (this->valid()) { + if (!this->valid()) { this->set(new_table()); } return *this; @@ -21233,95 +21305,110 @@ namespace sol { inline int fail_on_newindex(lua_State* L) { return luaL_error(L, "sol: cannot modify the elements of an enumeration table"); } + + template + using is_global = meta::all, meta::is_c_str...>; + + template + constexpr inline bool is_global_v = is_global::value; } // namespace detail - template - class basic_table_core : public basic_object_base { - typedef basic_object_base base_t; + template + class basic_table_core : public basic_object { + private: + using base_t = basic_object; + friend class state; friend class state_view; - template - using is_global = meta::all, meta::is_c_str...>; - - template - auto tuple_get(types, std::index_sequence<0, 1, I...>, Keys&& keys) const - -> decltype(stack::pop>(nullptr)) { - typedef decltype(stack::pop>(nullptr)) Tup; - return Tup(traverse_get_optional(meta::is_optional>(), std::get<0>(std::forward(keys))), - traverse_get_optional(meta::is_optional>(), std::get<1>(std::forward(keys))), - traverse_get_optional(meta::is_optional>(), std::get(std::forward(keys)))...); + template + decltype(auto) tuple_get(int table_index, Keys&&... keys) const { + if constexpr (sizeof...(Ret) < 2) { + return traverse_get_single_maybe_tuple(table_index, std::forward(keys)...); + } + else { + using multi_ret = decltype(stack::pop>(nullptr)); + return multi_ret(traverse_get_single_maybe_tuple(table_index, std::forward(keys))...); + } } - template - decltype(auto) tuple_get(types, std::index_sequence, Keys&& keys) const { - return traverse_get_optional(meta::is_optional>(), std::get(std::forward(keys))); + template + decltype(auto) traverse_get_single_tuple(int table_index, std::index_sequence, Key&& key) const { + return traverse_get_single(table_index, std::get(std::forward(key))...); + } + + template + decltype(auto) traverse_get_single_maybe_tuple(int table_index, Key&& key) const { + if constexpr (meta::is_tuple_v>) { + return traverse_get_single_tuple( + table_index, std::make_index_sequence>>(), std::forward(key)); + } + else { + return traverse_get_single(table_index, std::forward(key)); + } + } + + template + decltype(auto) traverse_get_single(int table_index, Keys&&... keys) const { + constexpr static bool global = detail::is_global_v; + 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)...); + } + else { + 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) { - auto pp = stack::push_pop < top_level && (is_global(std::forward(pairs)))...>::value) > (*this); + constexpr bool global = detail::is_global(std::forward(pairs)))...>::value; + auto pp = stack::push_pop(*this); + int table_index = pp.index_of(*this); void(detail::swallow{ (stack::set_field(base_t::lua_state(), std::get(std::forward(pairs)), std::get(std::forward(pairs)), - lua_gettop(base_t::lua_state())), + table_index), 0)... }); } - template - decltype(auto) traverse_get_deep(Key&& key) const { - stack::get_field(base_t::lua_state(), std::forward(key)); + template + decltype(auto) traverse_get_deep(int table_index, Key&& key, Keys&&... keys) const { + stack::get_field(base_t::lua_state(), std::forward(key), table_index); + (void)detail::swallow{ 0, (stack::get_field(base_t::lua_state(), std::forward(keys), lua_gettop(base_t::lua_state())), 0)... }; return stack::get(base_t::lua_state()); } template - decltype(auto) traverse_get_deep(Key&& key, Keys&&... keys) const { - stack::get_field(base_t::lua_state(), std::forward(key)); - return traverse_get_deep(std::forward(keys)...); - } - - template - decltype(auto) traverse_get_deep_optional(int& popcount, Key&& key) const { - typedef decltype(stack::get(base_t::lua_state())) R; - auto p = stack::probe_get_field(base_t::lua_state(), std::forward(key), lua_gettop(base_t::lua_state())); - popcount += p.levels; - if (!p.success) - return R(nullopt); - return stack::get(base_t::lua_state()); - } - - template - decltype(auto) traverse_get_deep_optional(int& popcount, Key&& key, Keys&&... keys) const { - auto p = I > 0 ? stack::probe_get_field(base_t::lua_state(), std::forward(key), -1) - : stack::probe_get_field(base_t::lua_state(), std::forward(key), lua_gettop(base_t::lua_state())); - popcount += p.levels; - if (!p.success) - return T(nullopt); - return traverse_get_deep_optional(popcount, std::forward(keys)...); - } - - template - decltype(auto) traverse_get_optional(std::false_type, Keys&&... keys) const { - detail::clean c(base_t::lua_state()); - return traverse_get_deep(std::forward(keys)...); - } - - template - decltype(auto) traverse_get_optional(std::true_type, Keys&&... keys) const { - int popcount = 0; - detail::ref_clean c(base_t::lua_state(), popcount); - return traverse_get_deep_optional(popcount, std::forward(keys)...); - } - - template - void traverse_set_deep(Key&& key, Value&& value) const { - stack::set_field(base_t::lua_state(), std::forward(key), std::forward(value)); + decltype(auto) traverse_get_deep_optional(int& popcount, int table_index, Key&& key, Keys&&... keys) const { + if constexpr (sizeof...(Keys) > 0) { + auto p = stack::probe_get_field(base_t::lua_state(), std::forward(key), table_index); + popcount += p.levels; + if (!p.success) + return T(nullopt); + return traverse_get_deep_optional(popcount, lua_gettop(base_t::lua_state()), std::forward(keys)...); + } + else { + using R = decltype(stack::get(base_t::lua_state())); + auto p = stack::probe_get_field(base_t::lua_state(), std::forward(key), table_index); + popcount += p.levels; + if (!p.success) + return R(nullopt); + return stack::get(base_t::lua_state()); + } } template - void traverse_set_deep(Key&& key, Keys&&... keys) const { - stack::get_field(base_t::lua_state(), std::forward(key)); - traverse_set_deep(std::forward(keys)...); + void traverse_set_deep(int table_index, Key&& key, Keys&&... keys) const { + if constexpr (sizeof...(Keys) == 1) { + stack::set_field(base_t::lua_state(), std::forward(key), std::forward(keys)..., table_index); + } + else { + stack::get_field(base_t::lua_state(), std::forward(key), table_index); + traverse_set_deep(lua_gettop(base_t::lua_state()), std::forward(keys)...); + } } basic_table_core(lua_State* L, detail::global_tag t) noexcept : base_t(L, t) { @@ -21335,7 +21422,7 @@ namespace sol { basic_table_core(detail::no_safety_tag, lua_State* L, ref_index index) : base_t(L, index) { } template , basic_table_core>>, meta::neg>, + meta::enable, basic_table_core>>, meta::neg>, meta::neg>>, is_lua_reference>> = meta::enabler> basic_table_core(detail::no_safety_tag, T&& r) noexcept : base_t(std::forward(r)) { } @@ -21344,8 +21431,8 @@ namespace sol { } public: - typedef basic_table_iterator iterator; - typedef iterator const_iterator; + using iterator = basic_table_iterator; + using const_iterator = iterator; using base_t::lua_state; @@ -21367,7 +21454,7 @@ namespace sol { #endif // Safety } basic_table_core(lua_State* L, const new_table& nt) : base_t(L, -stack::push(L, nt)) { - if (!is_stack_based>::value) { + if (!is_stack_based>::value) { lua_pop(L, 1); } } @@ -21385,7 +21472,7 @@ namespace sol { #endif // Safety } template , basic_table_core>>, meta::neg>, + meta::enable, basic_table_core>>, meta::neg>, meta::neg>>, is_lua_reference>> = meta::enabler> basic_table_core(T&& r) noexcept : basic_table_core(detail::no_safety, std::forward(r)) { #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES @@ -21418,8 +21505,10 @@ namespace sol { template decltype(auto) get(Keys&&... keys) const { static_assert(sizeof...(Keys) == sizeof...(Ret), "number of keys and number of return types do not match"); - auto pp = stack::push_pop::value>(*this); - return tuple_get(types(), std::make_index_sequence(), std::forward_as_tuple(std::forward(keys)...)); + constexpr static bool global = detail::is_global_v; + auto pp = stack::push_pop(*this); + int table_index = pp.index_of(*this); + return tuple_get(table_index, std::forward(keys)...); } template @@ -21443,29 +21532,40 @@ namespace sol { template decltype(auto) traverse_get(Keys&&... keys) const { - auto pp = stack::push_pop::value>(*this); - return traverse_get_optional(meta::is_optional>(), std::forward(keys)...); + constexpr static bool global = detail::is_global_v; + auto pp = stack::push_pop(*this); + int table_index = pp.index_of(*this); + return traverse_get_single(table_index, std::forward(keys)...); } template basic_table_core& traverse_set(Keys&&... keys) { - auto pp = stack::push_pop::value>(*this); + constexpr static bool global = detail::is_global_v; + auto pp = stack::push_pop(*this); + int table_index = pp.index_of(*this); auto pn = stack::pop_n(base_t::lua_state(), static_cast(sizeof...(Keys) - 2)); - traverse_set_deep(std::forward(keys)...); + traverse_set_deep(table_index, std::forward(keys)...); return *this; } template basic_table_core& set(Args&&... args) { - tuple_set(std::make_index_sequence(), std::forward_as_tuple(std::forward(args)...)); + if constexpr(sizeof...(Args) == 2) { + traverse_set(std::forward(args)...); + } + else { + tuple_set(std::make_index_sequence(), std::forward_as_tuple(std::forward(args)...)); + } return *this; } 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"); - auto pp = stack::push_pop::value>(*this); - return tuple_get(types(), std::make_index_sequence(), std::forward_as_tuple(std::forward(keys)...)); + constexpr static bool global = detail::is_global_v; + auto pp = stack::push_pop(*this); + int table_index = pp.index_of(*this); + return tuple_get(table_index, std::forward(keys)...); } template @@ -21489,13 +21589,16 @@ namespace sol { template decltype(auto) traverse_raw_get(Keys&&... keys) const { - auto pp = stack::push_pop::value>(*this); - return traverse_get_optional(meta::is_optional>(), std::forward(keys)...); + constexpr static bool global = detail::is_global_v; + auto pp = stack::push_pop(*this); + int table_index = pp.index_of(*this); + return traverse_get_single(table_index, std::forward(keys)...); } template basic_table_core& traverse_raw_set(Keys&&... keys) { - auto pp = stack::push_pop::value>(*this); + constexpr static bool global = detail::is_global_v; + auto pp = stack::push_pop(*this); auto pn = stack::pop_n(base_t::lua_state(), static_cast(sizeof...(Keys) - 2)); traverse_set_deep(std::forward(keys)...); return *this; @@ -21613,7 +21716,8 @@ namespace sol { template basic_table_core& add(Args&&... args) { auto pp = stack::push_pop(*this); - (void)detail::swallow{ 0, (stack::set_ref(base_t::lua_state(), std::forward(args)), 0)... }; + int table_index = pp.index_of(*this); + (void)detail::swallow{ 0, (stack::set_ref(base_t::lua_state(), std::forward(args), table_index), 0)... }; return *this; } @@ -22499,8 +22603,8 @@ namespace sol { } public: - typedef global_table::iterator iterator; - typedef global_table::const_iterator const_iterator; + using iterator = typename global_table::iterator; + using const_iterator = typename global_table::const_iterator; state_view(lua_State* Ls) : L(Ls), reg(Ls, LUA_REGISTRYINDEX), global(Ls, detail::global_) { @@ -23205,8 +23309,11 @@ namespace sol { }; } // namespace stack - template - class basic_thread : public base_t { + template + class basic_thread : public basic_object { + private: + using base_t = basic_object; + public: using base_t::lua_state; @@ -23356,8 +23463,11 @@ namespace sol { // beginning of sol/coroutine.hpp namespace sol { - template - class basic_coroutine : public base_t { + template + class basic_coroutine : public basic_object { + private: + using base_t = basic_object; + public: typedef reference handler_t; handler_t error_handler; @@ -23573,7 +23683,8 @@ namespace sol { namespace sol { template class basic_userdata : public basic_table { - typedef basic_table base_t; + private: + using base_t = basic_table; public: using base_t::lua_state; diff --git a/tests/runtime_tests/source/basic.cpp b/tests/runtime_tests/source/basic.cpp index 5e64195e..41255a5b 100644 --- a/tests/runtime_tests/source/basic.cpp +++ b/tests/runtime_tests/source/basic.cpp @@ -84,6 +84,10 @@ TEST_CASE("table/traversal", "ensure that we can chain requests and tunnel down { test_stack_guard g(lua.lua_state(), begintop, endtop); lua["t1"]["t2"]["t3"] = 64; + } + REQUIRE(begintop == endtop); + + { int traversex64 = lua.traverse_get("t1", "t2", "t3"); REQUIRE(traversex64 == 64); } @@ -99,6 +103,11 @@ TEST_CASE("table/traversal", "ensure that we can chain requests and tunnel down { test_stack_guard g(lua.lua_state(), begintop, endtop); lua.traverse_set("t1", "t2", "t3", 13); + } + REQUIRE(begintop == endtop); + + { + test_stack_guard g(lua.lua_state(), begintop, endtop); int traversex13 = lua.traverse_get("t1", "t2", "t3"); REQUIRE(traversex13 == 13); } @@ -661,3 +670,56 @@ TEST_CASE("object/is", "test whether or not the is abstraction works properly fo } } } + +TEST_CASE("object/base_of_things", "make sure that object is the base of things and can be sliced / returned safely") { + SECTION("reference") { + sol::state lua; + lua.open_libraries(sol::lib::coroutine); + + lua["ud"] = base1{}; + + lua["f1"] = [](sol::object o) -> sol::object { return o; }; + lua["f2"] = [](sol::table o) -> sol::object { return o; }; + lua["f3"] = [](sol::thread o) -> sol::object { return o; }; + lua["f4"] = [](sol::unsafe_function o) -> sol::object { return o; }; + lua["f5"] = [](sol::protected_function o) -> sol::object { return o; }; + lua["f6"] = [](sol::userdata o) -> sol::object { return o; }; + auto result1 = lua.safe_script("f1(2)", sol::script_pass_on_error); + REQUIRE(result1.valid()); + auto result2 = lua.safe_script("f2({})", sol::script_pass_on_error); + REQUIRE(result2.valid()); + auto result3 = lua.safe_script("f3(coroutine.create( function () end ) )", sol::script_pass_on_error); + REQUIRE(result3.valid()); + auto result4 = lua.safe_script("f4( function () end )", sol::script_pass_on_error); + REQUIRE(result4.valid()); + auto result5 = lua.safe_script("f5( function () end )", sol::script_pass_on_error); + REQUIRE(result5.valid()); + auto result6 = lua.safe_script("f6(ud)", sol::script_pass_on_error); + REQUIRE(result6.valid()); + } + SECTION("stack_reference") { + sol::state lua; + lua.open_libraries(sol::lib::coroutine); + + lua["ud"] = base1{}; + + lua["f1"] = [](sol::stack_object o) -> sol::stack_object { return o; }; + lua["f2"] = [](sol::stack_table o) -> sol::stack_object { return o; }; + lua["f3"] = [](sol::stack_thread o) -> sol::stack_object { return o; }; + lua["f4"] = [](sol::stack_unsafe_function o) -> sol::stack_object { return o; }; + lua["f5"] = [](sol::stack_protected_function o) -> sol::stack_object { return o; }; + lua["f6"] = [](sol::stack_userdata o) -> sol::stack_object { return o; }; + auto result1 = lua.safe_script("f1(2)", sol::script_pass_on_error); + REQUIRE(result1.valid()); + auto result2 = lua.safe_script("f2({})", sol::script_pass_on_error); + REQUIRE(result2.valid()); + auto result3 = lua.safe_script("f3(coroutine.create( function () end ) )", sol::script_pass_on_error); + REQUIRE(result3.valid()); + auto result4 = lua.safe_script("f4( function () end )", sol::script_pass_on_error); + REQUIRE(result4.valid()); + auto result5 = lua.safe_script("f5( function () end )", sol::script_pass_on_error); + REQUIRE(result5.valid()); + auto result6 = lua.safe_script("f6(ud)", sol::script_pass_on_error); + REQUIRE(result6.valid()); + } +} diff --git a/tests/runtime_tests/source/sol_test.hpp b/tests/runtime_tests/source/sol_test.hpp index a3a33c8a..9a53440c 100644 --- a/tests/runtime_tests/source/sol_test.hpp +++ b/tests/runtime_tests/source/sol_test.hpp @@ -27,6 +27,9 @@ #if !defined(SOL_CHECK_ARGUMENTS) #define SOL_CHECK_ARGUMENTS 1 #endif // SOL_CHECK_ARGUMENTS +#if !defined(SOL_PRINT_ERRORS) + #define SOL_PRINT_ERRORS 1 +#endif // SOL_CHECK_ARGUMENTS #if !defined(SOL_ENABLE_INTEROP) #define SOL_ENABLE_INTEROP 1 #endif // SOL_ENABLE_INTEROP