From ca685e01c97191d2f5f40d2eae8b7402c4697808 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Mon, 7 Aug 2017 02:07:21 -0400 Subject: [PATCH] gcc plagues me , and will continue to, for a while to come BUT IT WOOORKS! --- .gitignore | 1 + docs/source/api/stack_reference.rst | 2 +- examples/coroutine.cpp | 2 + examples/environment_snooping.cpp | 2 + examples/lua_inheritance.cpp | 2 +- examples/script_error_handling.cpp | 10 +- single/sol/sol.hpp | 458 +++++++++++++++++++--------- sol/container_traits.hpp | 43 +-- sol/protected_function.hpp | 27 +- sol/stack.hpp | 26 +- sol/stack_core.hpp | 6 +- sol/stack_get.hpp | 4 +- sol/state_view.hpp | 36 ++- sol/string_shim.hpp | 14 +- sol/types.hpp | 4 +- test_container_semantics.cpp | 108 ++++++- test_containers.cpp | 109 +------ test_functions.cpp | 14 +- 18 files changed, 544 insertions(+), 324 deletions(-) diff --git a/.gitignore b/.gitignore index 585f3fa5..9ffca222 100644 --- a/.gitignore +++ b/.gitignore @@ -79,3 +79,4 @@ lua-5.3.4/ temp.bad_runtime.lua temp.bad_syntax.lua temp.good.lua +catch_mock.hpp diff --git a/docs/source/api/stack_reference.rst b/docs/source/api/stack_reference.rst index 1527cace..3e95a0ab 100644 --- a/docs/source/api/stack_reference.rst +++ b/docs/source/api/stack_reference.rst @@ -57,4 +57,4 @@ Finally, there is a special abstraction that provides further stack optimization .. warning:: - Do not use ``sol::stack_top`` with a ``sol::stack_aligned_protected_function``. The default behavior checks if the ``error_handler`` member variable is valid, and attempts to push the handler onto the stack in preparation for calling the function. This inevitably changes the stack. Only use ``sol::stack_aligned_protected_function`` if you know that the handler is not valid (``nil``), or if you use ``sol::stack_aligned_stack_handler_protected_function``, which references an existing stack index that can be before the precise placement of the function and its arguments. + Do not use ``sol::stack_count`` with a ``sol::stack_aligned_protected_function``. The default behavior checks if the ``error_handler`` member variable is valid, and attempts to push the handler onto the stack in preparation for calling the function. This inevitably changes the stack. Only use ``sol::stack_aligned_protected_function`` with ``sol::stack_count`` if you know that the handler is not valid (it is ``nil`` or its ``error_handler.valid()`` function returns ``false``), or if you use ``sol::stack_aligned_stack_handler_protected_function``, which references an existing stack index that can be before the precise placement of the function and its arguments. diff --git a/examples/coroutine.cpp b/examples/coroutine.cpp index 533a2a01..927f7f1a 100644 --- a/examples/coroutine.cpp +++ b/examples/coroutine.cpp @@ -56,5 +56,7 @@ end )" ); + std::cout << std::endl; + return 0; } diff --git a/examples/environment_snooping.cpp b/examples/environment_snooping.cpp index 4002cebe..cd7da06c 100644 --- a/examples/environment_snooping.cpp +++ b/examples/environment_snooping.cpp @@ -81,5 +81,7 @@ int main() { lua.script("f()", freshenv); lua.script("g()", freshenv); + std::cout << std::endl; + return 0; } diff --git a/examples/lua_inheritance.cpp b/examples/lua_inheritance.cpp index bc87bc37..05646ac8 100644 --- a/examples/lua_inheritance.cpp +++ b/examples/lua_inheritance.cpp @@ -34,7 +34,7 @@ obj = object.new() obj:print() )"); - object& obj = lua["obj"]; + cpp_class& obj = lua["obj"]; assert(obj.value == 1); return 0; diff --git a/examples/script_error_handling.cpp b/examples/script_error_handling.cpp index 5ea7bc04..3c18ba38 100644 --- a/examples/script_error_handling.cpp +++ b/examples/script_error_handling.cpp @@ -21,9 +21,9 @@ return 24 // and then rely on the `lua_atpanic` function being called // and trapping errors there before exiting the application { - // default_on_error throws / panics when the code is bad: trap the error + // script_default_on_error throws / panics when the code is bad: trap the error try { - int value = lua.script(code, sol::default_on_error); + int value = lua.script(code, sol::script_default_on_error); // This will never be reached std::cout << value << std::endl; assert(value == 24); @@ -34,12 +34,12 @@ return 24 } /* OPTION 2 */ - // Use the simple_on_error handler + // Use the script_pass_on_error handler // this simply passes through the protected_function_result, // rather than throwing it or calling panic // This will check code validity and also whether or not it runs well { - sol::protected_function_result result = lua.script(code, sol::simple_on_error); + sol::protected_function_result result = lua.script(code, sol::script_pass_on_error); assert(!result.valid()); if (!result.valid()) { sol::error err = result; @@ -79,5 +79,7 @@ return 24 } } + std::cout << std::endl; + return 0; } diff --git a/single/sol/sol.hpp b/single/sol/sol.hpp index e2093b22..60536878 100644 --- a/single/sol/sol.hpp +++ b/single/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 2017-08-05 23:28:30.507703 UTC -// This header was generated with sol v2.18.0 (revision ee67f88) +// Generated 2017-08-07 06:06:53.826612 UTC +// This header was generated with sol v2.18.0 (revision 03c229b) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -172,14 +172,14 @@ namespace sol { using stack_environment = basic_environment; template class basic_function; - template + template class basic_protected_function; using unsafe_function = basic_function; - using safe_function = basic_protected_function; + using safe_function = basic_protected_function; using stack_unsafe_function = basic_function; - using stack_safe_function = basic_protected_function; + using stack_safe_function = basic_protected_function; using stack_aligned_unsafe_function = basic_function; - using stack_aligned_safe_function = basic_protected_function; + using stack_aligned_safe_function = basic_protected_function; using protected_function = safe_function; using stack_protected_function = stack_safe_function; using stack_aligned_protected_function = stack_aligned_safe_function; @@ -192,6 +192,8 @@ namespace sol { using stack_function = stack_unsafe_function; using stack_aligned_function = stack_aligned_unsafe_function; #endif + using stack_aligned_stack_handler_function = basic_protected_function; + struct function_result; struct protected_function_result; using safe_function_result = protected_function_result; @@ -3388,10 +3390,22 @@ namespace sol { return 0; } - const char* c_str() const { + const char* begin() const { return p; } + const char* end() const { + return p + s; + } + + const char* cbegin() const { + return p; + } + + const char* cend() const { + return p + s; + } + const char* data() const { return p; } @@ -3426,6 +3440,8 @@ namespace sol { }; #endif // C++17 } + + typedef string_detail::string_shim string_view; } // end of sol/string_shim.hpp @@ -4064,7 +4080,7 @@ namespace sol { inline int type_panic(lua_State* L, int index, type expected, type actual) noexcept(false) { return luaL_error(L, "stack index %d, expected %s, received %s", index, expected == type::poly ? "anything" : lua_typename(L, static_cast(expected)), - expected == type::poly ? "anything" : lua_typename(L, static_cast(actual)) + actual == type::poly ? "anything" : lua_typename(L, static_cast(actual)) ); } @@ -4266,8 +4282,8 @@ namespace sol { template struct lua_type_of> : std::integral_constant {}; - template - struct lua_type_of> : std::integral_constant {}; + template + struct lua_type_of> : std::integral_constant {}; template <> struct lua_type_of : std::integral_constant {}; @@ -4430,7 +4446,7 @@ namespace sol { struct is_variadic_arguments : std::is_same, variadic_args> {}; template - struct is_lua_index : std::false_type {}; + struct is_lua_index : std::is_integral {}; template <> struct is_lua_index : std::true_type {}; template <> @@ -4461,8 +4477,8 @@ namespace sol { struct is_function : std::false_type {}; template struct is_function> : std::true_type {}; - template - struct is_function> : std::true_type{}; + template + struct is_function> : std::true_type{}; template struct is_lightuserdata : std::false_type {}; @@ -4503,6 +4519,7 @@ namespace sol { public: stack_reference() noexcept = default; stack_reference(lua_nil_t) noexcept : stack_reference() {}; + stack_reference(lua_State* L, lua_nil_t) noexcept : L(L), index(0) {} stack_reference(lua_State* L, int i) noexcept : L(L), index(lua_absindex(L, i)) {} stack_reference(lua_State* L, absolute_index i) noexcept : L(L), index(i) {} stack_reference(lua_State* L, raw_index i) noexcept : L(L), index(i) {} @@ -4693,6 +4710,7 @@ namespace sol { lua_rawgeti(L, LUA_REGISTRYINDEX, index.index); ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); } + reference(lua_State* L, lua_nil_t) noexcept : luastate(L) {} ~reference() noexcept { deref(); @@ -5052,14 +5070,16 @@ namespace sol { } template - static int get_size_hint(const std::forward_list& c) { + static int get_size_hint(const std::forward_list&) { // forward_list makes me sad return static_cast(32); } template inline decltype(auto) unchecked_get(lua_State* L, int index, record& tracking) { - return getter>{}.get(L, index, tracking); + getter> g{}; + (void)g; + return g.get(L, index, tracking); } template @@ -6129,7 +6149,7 @@ namespace sol { template struct getter { static T& get(lua_State* L, int index, record& tracking) { - return getter>{}.get(L, index, tracking); + return getter>{}.get(L, index, tracking); } }; @@ -6303,7 +6323,7 @@ namespace sol { } template - static C get(types t, lua_State* L, int relindex, record& tracking) { + static C get(types, lua_State* L, int relindex, record& tracking) { tracking.use(1); int index = lua_absindex(L, relindex); @@ -8248,9 +8268,27 @@ namespace sol { namespace sol { namespace detail { inline const std::string& default_chunk_name() { - static const std::string name = "string"; + static const std::string name = "script"; return name; } + + template + const char* make_chunk_name(const string_view& code, const std::string& chunkname, char (&basechunkname)[N]) { + if (chunkname.empty()) { + auto it = code.cbegin(); + auto e = code.cend(); + std::size_t i = 0; + static const std::size_t n = N - 1; + for (i = 0; i < n && it != e; ++i, ++it) { + basechunkname[i] = *it; + } + basechunkname[i] = '\0'; + return &basechunkname[0]; + } + else { + return chunkname.c_str(); + } + } } // detail namespace stack { @@ -8389,8 +8427,10 @@ namespace sol { return call_syntax::colon; } - inline void script(lua_State* L, const string_detail::string_shim& code, string_detail::string_shim name = detail::default_chunk_name(), load_mode mode = load_mode::any) { - if (luaL_loadbufferx(L, code.data(), code.size(), name.data(), to_string(mode).c_str()) || lua_pcall(L, 0, LUA_MULTRET, 0)) { + inline void script(lua_State* L, const string_detail::string_shim& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + char basechunkname[17] = {}; + const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); + if (luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str()) || lua_pcall(L, 0, LUA_MULTRET, 0)) { lua_error(L); } } @@ -8481,9 +8521,7 @@ namespace sol { // 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.returncount = 0; + o.abandon(); } function_result& operator=(function_result&& o) { L = o.L; @@ -8492,9 +8530,7 @@ namespace sol { // 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.returncount = 0; + o.abandon(); return *this; } @@ -8514,7 +8550,11 @@ namespace sol { lua_State* lua_state() const { return L; }; int stack_index() const { return index; }; int return_count() const { return returncount; }; - + void abandon() noexcept { + L = nullptr; + index = 0; + returncount = 0; + } ~function_result() { lua_pop(L, returncount); } @@ -10762,11 +10802,7 @@ namespace sol { // Must be manual, otherwise destructor will screw us // return count being 0 is enough to keep things clean // but we will be thorough - o.L = nullptr; - o.index = 0; - o.returncount = 0; - o.popcount = 0; - o.err = call_status::runtime; + o.abandon(); } protected_function_result& operator=(protected_function_result&& o) noexcept { L = o.L; @@ -10777,11 +10813,7 @@ namespace sol { // Must be manual, otherwise destructor will screw us // return count being 0 is enough to keep things clean // but we will be thorough - o.L = nullptr; - o.index = 0; - o.returncount = 0; - o.popcount = 0; - o.err = call_status::runtime; + o.abandon(); return *this; } @@ -10802,7 +10834,13 @@ namespace sol { int stack_index() const noexcept { return index; }; int return_count() const noexcept { return returncount; }; int pop_count() const noexcept { return popcount; }; - + void abandon() noexcept { + L = nullptr; + index = 0; + returncount = 0; + popcount = 0; + err = call_status::runtime; + } ~protected_function_result() { stack::remove(L, index, popcount); } @@ -10834,63 +10872,90 @@ namespace sol { return name; } + template struct handler { - const reference& target; + typedef std::is_base_of is_stack; + const target_t& target; int stackindex; - handler(const reference& target) : target(target), stackindex(0) { - if (target.valid()) { + + handler(std::false_type, const target_t& target) : target(target), stackindex(0) { + if (b) { stackindex = lua_gettop(target.lua_state()) + 1; target.push(); } } - bool valid() const { return stackindex != 0; } + + handler(std::true_type, const target_t& target) : target(target), stackindex(0) { + if (b) { + stackindex = target.stack_index(); + } + } + + handler(const target_t& target) : handler(is_stack(), target) {} + + bool valid() const noexcept { return b; } + ~handler() { - if (valid()) { + if (!is_stack::value && stackindex != 0) { lua_remove(target.lua_state(), stackindex); } } }; - } + } // detail - template + template class basic_protected_function : public base_t { public: - static reference get_default_handler(lua_State* L) { - if (L == nullptr) - return reference(lua_nil); + typedef std::is_base_of is_stack_handler; + + static handler_t get_default_handler(lua_State* L) { + if (is_stack_handler::value || L == nullptr) + return handler_t(L, lua_nil); lua_getglobal(L, detail::default_handler_name()); auto pp = stack::pop_n(L, 1); - return reference(L, -1); + return handler_t(L, -1); } - static void set_default_handler(const reference& ref) { - ref.push(); - lua_setglobal(ref.lua_state(), detail::default_handler_name()); + template + static void set_default_handler(const T& ref) { + if (ref.lua_state() == nullptr) { + return; + } + if (!ref.valid()) { + lua_pushnil(ref.lua_state()); + lua_setglobal(ref.lua_state(), detail::default_handler_name()); + } + else { + ref.push(); + lua_setglobal(ref.lua_state(), detail::default_handler_name()); + } } private: - call_status luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount, detail::handler& h) const { + template + call_status luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount, detail::handler& h) const { return static_cast(lua_pcallk(lua_state(), static_cast(argcount), static_cast(resultcount), h.stackindex, 0, nullptr)); } - template - auto invoke(types, std::index_sequence, std::ptrdiff_t n, detail::handler& h) const { + template + auto invoke(types, std::index_sequence, std::ptrdiff_t n, detail::handler& h) const { luacall(n, sizeof...(Ret), h); return stack::pop>(lua_state()); } - template - Ret invoke(types, std::index_sequence, std::ptrdiff_t n, detail::handler& h) const { + template + Ret invoke(types, std::index_sequence, std::ptrdiff_t n, detail::handler& h) const { luacall(n, 1, h); return stack::pop(lua_state()); } - template - void invoke(types, std::index_sequence, std::ptrdiff_t n, detail::handler& h) const { + template + void invoke(types, std::index_sequence, std::ptrdiff_t n, detail::handler& h) const { luacall(n, 0, h); } - protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n, detail::handler& h) const { + template + protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n, detail::handler& h) const { int stacksize = lua_gettop(lua_state()); int poststacksize = stacksize; int firstreturn = 1; @@ -10899,7 +10964,7 @@ namespace sol { #ifndef SOL_NO_EXCEPTIONS auto onexcept = [&](const char* error) { h.stackindex = 0; - if (h.target.valid()) { + if (b) { h.target.push(); stack::push(lua_state(), error); lua_call(lua_state(), 1, 1); @@ -10939,10 +11004,15 @@ namespace sol { public: using base_t::lua_state; - reference error_handler; + handler_t error_handler; basic_protected_function() = default; - template , basic_protected_function>>, meta::neg>, std::is_base_of>> = meta::enabler> + template , basic_protected_function>>, + meta::neg>>, + meta::neg>, + std::is_base_of> + > = meta::enabler> basic_protected_function(T&& r) noexcept : base_t(std::forward(r)) { #ifdef SOL_CHECK_ARGUMENTS if (!is_function>::value) { @@ -10957,40 +11027,48 @@ namespace sol { basic_protected_function& operator=(basic_protected_function&&) = default; basic_protected_function(const basic_function& b) : basic_protected_function(b, get_default_handler(b.lua_state())) {} basic_protected_function(basic_function&& b) : basic_protected_function(std::move(b), get_default_handler(b.lua_state())) {} - basic_protected_function(const basic_function& b, reference eh) : base_t(b), error_handler(std::move(eh)) {} - basic_protected_function(basic_function&& b, reference eh) : base_t(std::move(b)), error_handler(std::move(eh)) {} + basic_protected_function(const basic_function& b, handler_t eh) : base_t(b), error_handler(std::move(eh)) {} + basic_protected_function(basic_function&& b, handler_t eh) : base_t(std::move(b)), error_handler(std::move(eh)) {} basic_protected_function(const stack_reference& r) : basic_protected_function(r.lua_state(), r.stack_index(), get_default_handler(r.lua_state())) {} basic_protected_function(stack_reference&& r) : basic_protected_function(r.lua_state(), r.stack_index(), get_default_handler(r.lua_state())) {} - basic_protected_function(const stack_reference& r, reference eh) : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) {} - basic_protected_function(stack_reference&& r, reference eh) : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) {} + basic_protected_function(const stack_reference& r, handler_t eh) : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) {} + basic_protected_function(stack_reference&& r, handler_t eh) : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) {} + template - basic_protected_function(const proxy_base& p) : basic_protected_function(p.operator basic_function(), get_default_handler(p.lua_state())) {} + basic_protected_function(const proxy_base& p) : basic_protected_function(p, get_default_handler(p.lua_state())) {} template - basic_protected_function(proxy_base&& p) : basic_protected_function(p.operator basic_function(), get_default_handler(p.lua_state())) {} - template >>, meta::neg>>> = meta::enabler> + basic_protected_function(proxy_base&& p) : basic_protected_function(std::move(p), get_default_handler(p.lua_state())) {} + template >, + meta::neg>> + > = meta::enabler> + basic_protected_function(Proxy&& p, Handler&& eh) : basic_protected_function(p.operator basic_function(), std::forward(eh)) {} + + template >>> = meta::enabler> basic_protected_function(lua_State* L, T&& r) : basic_protected_function(L, std::forward(r), get_default_handler(L)) {} - template >>, meta::neg>>> = meta::enabler> - basic_protected_function(lua_State* L, T&& r, reference eh) : basic_protected_function(L, sol::ref_index(r.registry_index()), std::move(eh)) {} + template >>> = meta::enabler> + basic_protected_function(lua_State* L, T&& r, handler_t eh) : basic_protected_function(L, sol::ref_index(r.registry_index()), std::move(eh)) {} + basic_protected_function(lua_State* L, int index = -1) : basic_protected_function(L, index, get_default_handler(L)) {} - basic_protected_function(lua_State* L, int index, reference eh) : base_t(L, index), error_handler(std::move(eh)) { + basic_protected_function(lua_State* L, int index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) { #ifdef SOL_CHECK_ARGUMENTS stack::check(L, index, type_panic); #endif // Safety } basic_protected_function(lua_State* L, absolute_index index) : basic_protected_function(L, index, get_default_handler(L)) {} - basic_protected_function(lua_State* L, absolute_index index, reference eh) : base_t(L, index), error_handler(std::move(eh)) { + basic_protected_function(lua_State* L, absolute_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) { #ifdef SOL_CHECK_ARGUMENTS stack::check(L, index, type_panic); #endif // Safety } basic_protected_function(lua_State* L, raw_index index) : basic_protected_function(L, index, get_default_handler(L)) {} - basic_protected_function(lua_State* L, raw_index index, reference eh) : base_t(L, index), error_handler(std::move(eh)) { + basic_protected_function(lua_State* L, raw_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) { #ifdef SOL_CHECK_ARGUMENTS stack::check(L, index, type_panic); #endif // Safety } basic_protected_function(lua_State* L, ref_index index) : basic_protected_function(L, index, get_default_handler(L)) {} - basic_protected_function(lua_State* L, ref_index index, reference eh) : base_t(L, index), error_handler(std::move(eh)) { + basic_protected_function(lua_State* L, ref_index index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) { #ifdef SOL_CHECK_ARGUMENTS auto pp = stack::push_pop(*this); stack::check(L, -1, type_panic); @@ -11009,12 +11087,45 @@ namespace sol { template decltype(auto) call(Args&&... args) const { - detail::handler h(error_handler); if (!aligned) { - base_t::push(); + // we do not expect the function to already be on the stack: push it + if (error_handler.valid()) { + detail::handler h(error_handler); + base_t::push(); + int pushcount = stack::multi_push_reference(lua_state(), std::forward(args)...); + return invoke(types(), std::make_index_sequence(), pushcount, h); + } + else { + detail::handler h(error_handler); + base_t::push(); + int pushcount = stack::multi_push_reference(lua_state(), std::forward(args)...); + return invoke(types(), std::make_index_sequence(), pushcount, h); + } + } + else { + // the function is already on the stack at the right location + if (error_handler.valid()) { + // the handler will be pushed onto the stack manually, + // since it's not already on the stack this means we need to push our own + // function on the stack too and swap things to be in-place + if (!is_stack_handler::value) { + // so, we need to remove the function at the top and then dump the handler out ourselves + base_t::push(); + } + detail::handler h(error_handler); + if (!is_stack_handler::value) { + lua_replace(lua_state(), -3); + h.stackindex = lua_absindex(lua_state(), -2); + } + int pushcount = stack::multi_push_reference(lua_state(), std::forward(args)...); + return invoke(types(), std::make_index_sequence(), pushcount, h); + } + else { + detail::handler h(error_handler); + int pushcount = stack::multi_push_reference(lua_state(), std::forward(args)...); + return invoke(types(), std::make_index_sequence(), pushcount, h); + } } - int pushcount = stack::multi_push_reference(lua_state(), std::forward(args)...); - return invoke(types(), std::make_index_sequence(), pushcount, h); } }; } // sol @@ -13594,7 +13705,7 @@ namespace sol { typedef typename T::value_type value_type; typedef std::conditional_t, std::pair> + std::conditional_t, std::pair> > KV; typedef typename KV::first_type K; typedef typename KV::second_type V; @@ -13602,7 +13713,7 @@ namespace sol { typedef typename meta::iterator_tag::type iterator_category; typedef std::is_same is_input_iterator; typedef std::conditional_t, + V, std::conditional_t, iterator_return> > push_type; typedef std::is_copy_assignable is_copyable; @@ -13635,11 +13746,11 @@ namespace sol { static int get_associative(std::true_type, lua_State* L, iterator& it) { auto& v = *it; - return stack::push_reference(L, v.second); + return stack::stack_detail::push_reference(L, v.second); } static int get_associative(std::false_type, lua_State* L, iterator& it) { - return stack::push_reference(L, *it); + return stack::stack_detail::push_reference(L, *it); } static int get_category(std::input_iterator_tag, lua_State* L, T& self, K& key) { @@ -13662,7 +13773,7 @@ namespace sol { } static int get_category(std::random_access_iterator_tag, lua_State* L, T& self, K& key) { - std::size_t len = size_start(L, self); + std::ptrdiff_t len = static_cast(size_start(L, self)); if (key < 1 || key > len) { return stack::push(L, lua_nil); } @@ -13726,7 +13837,7 @@ namespace sol { add_copyable(is_copyable(), L, self, std::move(value), meta::has_insert_after::value ? backit : it); return; } - // TODO: error here in safety mode + luaL_error(L, "out of bounds (too big) for set on '%s'", detail::demangle().c_str()); return; } set_writable(is_writable(), L, self, it, std::move(value)); @@ -13734,18 +13845,18 @@ namespace sol { static void set_category(std::random_access_iterator_tag, lua_State* L, T& self, stack_object okey, stack_object value) { decltype(auto) key = okey.as(); - std::size_t len = size_start(L, self); if (key < 1) { - // error here in safety mode + luaL_error(L, "sol: out of bounds (too small) for set on '%s'", detail::demangle().c_str()); return; } --key; + std::ptrdiff_t len = static_cast(size_start(L, self)); if (key == len) { add_copyable(is_copyable(), L, self, std::move(value)); return; } else if (key > len) { - // error here in safety mode + luaL_error(L, "sol: out of bounds (too big) for set on '%s'", detail::demangle().c_str()); return; } auto it = std::next(begin(L, self), key); @@ -13865,7 +13976,7 @@ namespace sol { luaL_error(L, "cannot call 'add' on type '%s': no suitable insert/push_back C++ functions", sol::detail::demangle().data()); } - static void add_insert_after(std::true_type, lua_State* L, T& self, stack_object value, iterator& at) { + static void add_insert_after(std::true_type, lua_State*, T& self, stack_object value, iterator& at) { self.insert_after(at, value.as()); } @@ -13965,7 +14076,7 @@ namespace sol { auto e = end(L, self); for (auto it = begin(L, self); key > 0; ++backit, ++it, --key) { if (backit == e) { - // TODO: error here in safety mode + luaL_error(L, "sol: out of bounds (too big) for set on '%s'", detail::demangle().c_str()); return; } } @@ -14027,7 +14138,7 @@ namespace sol { auto e = end(L, self); for (auto it = begin(L, self); key > 0; ++backit, ++it, --key) { if (backit == e) { - // TODO: error here in safety mode + luaL_error(L, "sol: out of bounds for erase on '%s'", detail::demangle().c_str()); return; } } @@ -14035,7 +14146,7 @@ namespace sol { self.erase_after(backit); } - static void erase_after_has(std::false_type, lua_State* L, T& self, const K& key) { + static void erase_after_has(std::false_type, lua_State* L, T&, const K&) { luaL_error(L, "sol: cannot call erase on '%s'", detail::demangle().c_str()); } @@ -14225,15 +14336,13 @@ namespace sol { }; static auto& get_src(lua_State* L) { -#ifdef SOL_SAFE_USERTYPE auto p = stack::check_get(L, 1); +#ifdef SOL_SAFE_USERTYPE if (!p || p.value() == nullptr) { luaL_error(L, "sol: 'self' argument is nil or not of type '%s' (pass 'self' as first argument with ':' or call on proper type)", detail::demangle().c_str()); } - return *p.value(); -#else - return stack::get(L, 1); #endif // Safe getting with error + return *p.value(); } static int find(std::true_type, lua_State* L) { @@ -14287,7 +14396,7 @@ namespace sol { static int get(lua_State* L) { T& self = get_src(L); - std::size_t idx = stack::get(L, 2); + std::ptrdiff_t idx = stack::get(L, 2); if (idx > std::extent::value || idx < 1) { return stack::push(L, lua_nil); } @@ -14301,9 +14410,12 @@ namespace sol { static int set(lua_State* L) { T& self = get_src(L); - std::size_t idx = stack::get(L, 2); - if (idx > std::extent::value || idx < 1) { - return luaL_error(L, "sol: index out of bounds on set"); + std::ptrdiff_t idx = stack::get(L, 2); + if (idx > std::extent::value) { + return luaL_error(L, "sol: index out of bounds (too big) for set on '%s'", detail::demangle().c_str()); + } + if (idx < 1) { + return luaL_error(L, "sol: index out of bounds (too small) for set on '%s'", detail::demangle().c_str()); } --idx; self[idx] = stack::get(L, 3); @@ -15574,7 +15686,7 @@ namespace sol { err += " error:"; if (t == type::string) { err += " "; - string_detail::string_shim serr = stack::get(L, pfr.stack_index()); + string_view serr = stack::get(L, pfr.stack_index()); err.append(serr.data(), serr.size()); } #ifdef SOL_NO_EXCEPTIONS @@ -15763,7 +15875,7 @@ namespace sol { return stack::pop(L); } - object require_script(const std::string& key, const string_detail::string_shim& code, bool create_global = true, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + object require_script(const std::string& key, const string_view& code, bool create_global = true, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { return require_core(key, [this, &code, &chunkname, &mode]() {stack::script(L, code, chunkname, mode); }, create_global); } @@ -15772,13 +15884,14 @@ namespace sol { } template - protected_function_result do_string(const string_detail::string_shim& code, const basic_environment& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { - load_status x = static_cast(luaL_loadbufferx(L, code.data(), code.size(), chunkname.c_str(), to_string(mode).c_str())); + protected_function_result do_string(const string_view& code, const basic_environment& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + char basechunkname[17] = {}; + const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); + load_status x = static_cast(luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str())); if (x != load_status::ok) { - return protected_function_result(L, -1, 0, 1, static_cast(x)); + return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast(x)); } - protected_function pf(L, -1); - pf.pop(); + stack_aligned_protected_function pf(L, -1); set_environment(env, pf); return pf(); } @@ -15787,36 +15900,35 @@ namespace sol { protected_function_result do_file(const std::string& filename, const basic_environment& env, load_mode mode = load_mode::any) { load_status x = static_cast(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str())); if (x != load_status::ok) { - return protected_function_result(L, -1, 0, 1, static_cast(x)); + return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast(x)); } - protected_function pf(L, -1); - pf.pop(); + stack_aligned_protected_function pf(L, -1); set_environment(env, pf); return pf(); } - protected_function_result do_string(const string_detail::string_shim& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { - load_status x = static_cast(luaL_loadbufferx(L, code.data(), code.size(), chunkname.c_str(), to_string(mode).c_str())); + protected_function_result do_string(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + char basechunkname[17] = {}; + const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); + load_status x = static_cast(luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str())); if (x != load_status::ok) { - return protected_function_result(L, -1, 0, 1, static_cast(x)); + return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast(x)); } - protected_function pf(L, -1); - pf.pop(); + stack_aligned_protected_function pf(L, -1); return pf(); } protected_function_result do_file(const std::string& filename, load_mode mode = load_mode::any) { load_status x = static_cast(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str())); if (x != load_status::ok) { - return protected_function_result(L, -1, 0, 1, static_cast(x)); + return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast(x)); } - protected_function pf(L, -1); - pf.pop(); + stack_aligned_protected_function pf(L, -1); return pf(); } template >> = meta::enabler> - protected_function_result safe_script(const string_detail::string_shim& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + protected_function_result safe_script(const string_view& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { protected_function_result pfr = do_string(code, chunkname, mode); if (!pfr.valid()) { return on_error(L, std::move(pfr)); @@ -15824,18 +15936,27 @@ namespace sol { return pfr; } - template >> = meta::enabler> - protected_function_result safe_script_file(const std::string& filename, Fx&& on_error, load_mode mode = load_mode::any) { - protected_function_result pfr = do_file(filename, mode); + template + protected_function_result safe_script(const string_view& code, const basic_environment& env, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + protected_function_result pfr = do_string(code, env, chunkname, mode); if (!pfr.valid()) { return on_error(L, std::move(pfr)); } return pfr; } - template - protected_function_result safe_script(const string_detail::string_shim& code, const basic_environment& env, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { - protected_function_result pfr = do_string(code, env, chunkname, mode); + template + protected_function_result safe_script(const string_view& code, const basic_environment& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + return safe_script(code, env, script_default_on_error, chunkname, mode); + } + + protected_function_result safe_script(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + return safe_script(code, script_default_on_error, chunkname, mode); + } + + template >> = meta::enabler> + protected_function_result safe_script_file(const std::string& filename, Fx&& on_error, load_mode mode = load_mode::any) { + protected_function_result pfr = do_file(filename, mode); if (!pfr.valid()) { return on_error(L, std::move(pfr)); } @@ -15851,25 +15972,50 @@ namespace sol { return pfr; } - protected_function_result safe_script(const string_detail::string_shim& code, const environment& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { - return safe_script(code, env, sol::script_default_on_error, chunkname, mode); - } - - protected_function_result safe_script_file(const std::string& filename, const environment& env, load_mode mode = load_mode::any) { - return safe_script_file(filename, env, sol::script_default_on_error, mode); - } - - protected_function_result safe_script(const string_detail::string_shim& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { - return safe_script(code, sol::script_default_on_error, chunkname, mode); + template + protected_function_result safe_script_file(const std::string& filename, const basic_environment& env, load_mode mode = load_mode::any) { + return safe_script_file(filename, env, script_default_on_error, mode); } protected_function_result safe_script_file(const std::string& filename, load_mode mode = load_mode::any) { - return safe_script_file(filename, sol::script_default_on_error, mode); + return safe_script_file(filename, script_default_on_error, mode); } - function_result unsafe_script(const string_detail::string_shim& code, const std::string& name = detail::default_chunk_name(), load_mode mode = load_mode::any) { + template + function_result unsafe_script(const string_view& code, const sol::basic_environment& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + char basechunkname[17] = {}; + const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); int index = lua_gettop(L); - stack::script(L, code, name, mode); + if (luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str())) { + lua_error(L); + } + set_environment(env, stack_reference(L, raw_index(index + 1))); + if (lua_call(L, 0, LUA_MULTRET)) { + lua_error(L); + } + int postindex = lua_gettop(L); + int returns = postindex - index; + return function_result(L, (std::max)(postindex - (returns - 1), 1), returns); + } + + function_result unsafe_script(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + int index = lua_gettop(L); + stack::script(L, code, chunkname, mode); + int postindex = lua_gettop(L); + int returns = postindex - index; + return function_result(L, (std::max)(postindex - (returns - 1), 1), returns); + } + + template + function_result unsafe_script_file(const std::string& filename, const sol::basic_environment& env, load_mode mode = load_mode::any) { + int index = lua_gettop(L); + if (luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str())) { + lua_error(L); + } + set_environment(env, stack_reference(L, raw_index(index + 1))); + if (lua_call(L, 0, LUA_MULTRET)) { + lua_error(L); + } int postindex = lua_gettop(L); int returns = postindex - index; return function_result(L, (std::max)(postindex - (returns - 1), 1), returns); @@ -15884,7 +16030,7 @@ namespace sol { } template >> = meta::enabler> - protected_function_result script(const string_detail::string_shim& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + protected_function_result script(const string_view& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { return safe_script(code, std::forward(on_error), chunkname, mode); } @@ -15894,7 +16040,7 @@ namespace sol { } template - protected_function_result script(const string_detail::string_shim& code, const basic_environment& env, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + protected_function_result script(const string_view& code, const basic_environment& env, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { return safe_script(code, env, std::forward(on_error), chunkname, mode); } @@ -15903,15 +16049,15 @@ namespace sol { return safe_script_file(filename, env, std::forward(on_error), mode); } - protected_function_result script(const string_detail::string_shim& code, const environment& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { - return safe_script(code, env, sol::script_default_on_error, chunkname, mode); + protected_function_result script(const string_view& code, const environment& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + return safe_script(code, env, script_default_on_error, chunkname, mode); } protected_function_result script_file(const std::string& filename, const environment& env, load_mode mode = load_mode::any) { - return safe_script_file(filename, env, sol::script_default_on_error, mode); + return safe_script_file(filename, env, script_default_on_error, mode); } - function_result script(const string_detail::string_shim& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + function_result script(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { return unsafe_script(code, chunkname, mode); } @@ -15919,19 +16065,23 @@ namespace sol { return unsafe_script_file(filename, mode); } - load_result load(const string_detail::string_shim& code, const std::string& name = detail::default_chunk_name(), load_mode mode = load_mode::any) { - load_status x = static_cast(luaL_loadbufferx(L, code.data(), code.size(), name.c_str(), to_string(mode).c_str())); - return load_result(L, lua_absindex(L, -1), 1, 1, x); + load_result load(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + char basechunkname[17] = {}; + const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); + load_status x = static_cast(luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str())); + return load_result(L, absolute_index(L, -1), 1, 1, x); } load_result load_file(const std::string& filename, load_mode mode = load_mode::any) { load_status x = static_cast(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str())); - return load_result(L, lua_absindex(L, -1), 1, 1, x); + return load_result(L, absolute_index(L, -1), 1, 1, x); } - load_result load(lua_Reader reader, void* data, const std::string& name = detail::default_chunk_name(), load_mode mode = load_mode::any) { - load_status x = static_cast(lua_load(L, reader, data, name.c_str(), to_string(mode).c_str())); - return load_result(L, lua_absindex(L, -1), 1, 1, x); + load_result load(lua_Reader reader, void* data, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + char basechunkname[17] = {}; + const char* chunknametarget = detail::make_chunk_name("lua_reader", chunkname, basechunkname); + load_status x = static_cast(lua_load(L, reader, data, chunknametarget, to_string(mode).c_str())); + return load_result(L, absolute_index(L, -1), 1, 1, x); } iterator begin() const { @@ -15962,6 +16112,10 @@ namespace sol { return total_memory_used(lua_state()); } + int stack_top() const { + return stack::top(L); + } + void collect_garbage() { lua_gc(lua_state(), LUA_GCCOLLECT, 0); } diff --git a/sol/container_traits.hpp b/sol/container_traits.hpp index 705ec691..7f17ddfe 100644 --- a/sol/container_traits.hpp +++ b/sol/container_traits.hpp @@ -381,7 +381,7 @@ namespace sol { typedef typename T::value_type value_type; typedef std::conditional_t, std::pair> + std::conditional_t, std::pair> > KV; typedef typename KV::first_type K; typedef typename KV::second_type V; @@ -389,7 +389,7 @@ namespace sol { typedef typename meta::iterator_tag::type iterator_category; typedef std::is_same is_input_iterator; typedef std::conditional_t, + V, std::conditional_t, iterator_return> > push_type; typedef std::is_copy_assignable is_copyable; @@ -422,11 +422,11 @@ namespace sol { static int get_associative(std::true_type, lua_State* L, iterator& it) { auto& v = *it; - return stack::push_reference(L, v.second); + return stack::stack_detail::push_reference(L, v.second); } static int get_associative(std::false_type, lua_State* L, iterator& it) { - return stack::push_reference(L, *it); + return stack::stack_detail::push_reference(L, *it); } static int get_category(std::input_iterator_tag, lua_State* L, T& self, K& key) { @@ -449,7 +449,7 @@ namespace sol { } static int get_category(std::random_access_iterator_tag, lua_State* L, T& self, K& key) { - std::size_t len = size_start(L, self); + std::ptrdiff_t len = static_cast(size_start(L, self)); if (key < 1 || key > len) { return stack::push(L, lua_nil); } @@ -513,7 +513,7 @@ namespace sol { add_copyable(is_copyable(), L, self, std::move(value), meta::has_insert_after::value ? backit : it); return; } - // TODO: error here in safety mode + luaL_error(L, "out of bounds (too big) for set on '%s'", detail::demangle().c_str()); return; } set_writable(is_writable(), L, self, it, std::move(value)); @@ -521,18 +521,18 @@ namespace sol { static void set_category(std::random_access_iterator_tag, lua_State* L, T& self, stack_object okey, stack_object value) { decltype(auto) key = okey.as(); - std::size_t len = size_start(L, self); if (key < 1) { - // error here in safety mode + luaL_error(L, "sol: out of bounds (too small) for set on '%s'", detail::demangle().c_str()); return; } --key; + std::ptrdiff_t len = static_cast(size_start(L, self)); if (key == len) { add_copyable(is_copyable(), L, self, std::move(value)); return; } else if (key > len) { - // error here in safety mode + luaL_error(L, "sol: out of bounds (too big) for set on '%s'", detail::demangle().c_str()); return; } auto it = std::next(begin(L, self), key); @@ -652,7 +652,7 @@ namespace sol { luaL_error(L, "cannot call 'add' on type '%s': no suitable insert/push_back C++ functions", sol::detail::demangle().data()); } - static void add_insert_after(std::true_type, lua_State* L, T& self, stack_object value, iterator& at) { + static void add_insert_after(std::true_type, lua_State*, T& self, stack_object value, iterator& at) { self.insert_after(at, value.as()); } @@ -752,7 +752,7 @@ namespace sol { auto e = end(L, self); for (auto it = begin(L, self); key > 0; ++backit, ++it, --key) { if (backit == e) { - // TODO: error here in safety mode + luaL_error(L, "sol: out of bounds (too big) for set on '%s'", detail::demangle().c_str()); return; } } @@ -814,7 +814,7 @@ namespace sol { auto e = end(L, self); for (auto it = begin(L, self); key > 0; ++backit, ++it, --key) { if (backit == e) { - // TODO: error here in safety mode + luaL_error(L, "sol: out of bounds for erase on '%s'", detail::demangle().c_str()); return; } } @@ -822,7 +822,7 @@ namespace sol { self.erase_after(backit); } - static void erase_after_has(std::false_type, lua_State* L, T& self, const K& key) { + static void erase_after_has(std::false_type, lua_State* L, T&, const K&) { luaL_error(L, "sol: cannot call erase on '%s'", detail::demangle().c_str()); } @@ -1012,15 +1012,13 @@ namespace sol { }; static auto& get_src(lua_State* L) { -#ifdef SOL_SAFE_USERTYPE auto p = stack::check_get(L, 1); +#ifdef SOL_SAFE_USERTYPE if (!p || p.value() == nullptr) { luaL_error(L, "sol: 'self' argument is nil or not of type '%s' (pass 'self' as first argument with ':' or call on proper type)", detail::demangle().c_str()); } - return *p.value(); -#else - return stack::get(L, 1); #endif // Safe getting with error + return *p.value(); } static int find(std::true_type, lua_State* L) { @@ -1074,7 +1072,7 @@ namespace sol { static int get(lua_State* L) { T& self = get_src(L); - std::size_t idx = stack::get(L, 2); + std::ptrdiff_t idx = stack::get(L, 2); if (idx > std::extent::value || idx < 1) { return stack::push(L, lua_nil); } @@ -1088,9 +1086,12 @@ namespace sol { static int set(lua_State* L) { T& self = get_src(L); - std::size_t idx = stack::get(L, 2); - if (idx > std::extent::value || idx < 1) { - return luaL_error(L, "sol: index out of bounds on set"); + std::ptrdiff_t idx = stack::get(L, 2); + if (idx > std::extent::value) { + return luaL_error(L, "sol: index out of bounds (too big) for set on '%s'", detail::demangle().c_str()); + } + if (idx < 1) { + return luaL_error(L, "sol: index out of bounds (too small) for set on '%s'", detail::demangle().c_str()); } --idx; self[idx] = stack::get(L, 3); diff --git a/sol/protected_function.hpp b/sol/protected_function.hpp index 3b885ebc..7bf7127e 100644 --- a/sol/protected_function.hpp +++ b/sol/protected_function.hpp @@ -60,7 +60,7 @@ namespace sol { bool valid() const noexcept { return b; } ~handler() { - if (b && !is_stack::value) { + if (!is_stack::value && stackindex != 0) { lua_remove(target.lua_state(), stackindex); } } @@ -128,7 +128,7 @@ namespace sol { #ifndef SOL_NO_EXCEPTIONS auto onexcept = [&](const char* error) { h.stackindex = 0; - if (h.target.valid()) { + if (b) { h.target.push(); stack::push(lua_state(), error); lua_call(lua_state(), 1, 1); @@ -171,7 +171,12 @@ namespace sol { handler_t error_handler; basic_protected_function() = default; - template , basic_protected_function>>, meta::neg>, std::is_base_of>> = meta::enabler> + template , basic_protected_function>>, + meta::neg>>, + meta::neg>, + std::is_base_of> + > = meta::enabler> basic_protected_function(T&& r) noexcept : base_t(std::forward(r)) { #ifdef SOL_CHECK_ARGUMENTS if (!is_function>::value) { @@ -192,14 +197,22 @@ namespace sol { basic_protected_function(stack_reference&& r) : basic_protected_function(r.lua_state(), r.stack_index(), get_default_handler(r.lua_state())) {} basic_protected_function(const stack_reference& r, handler_t eh) : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) {} basic_protected_function(stack_reference&& r, handler_t eh) : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) {} + template - basic_protected_function(const proxy_base& p) : basic_protected_function(p.operator basic_function(), get_default_handler(p.lua_state())) {} + basic_protected_function(const proxy_base& p) : basic_protected_function(p, get_default_handler(p.lua_state())) {} template - basic_protected_function(proxy_base&& p) : basic_protected_function(p.operator basic_function(), get_default_handler(p.lua_state())) {} - template >>, meta::neg>>> = meta::enabler> + basic_protected_function(proxy_base&& p) : basic_protected_function(std::move(p), get_default_handler(p.lua_state())) {} + template >, + meta::neg>> + > = meta::enabler> + basic_protected_function(Proxy&& p, Handler&& eh) : basic_protected_function(p.operator basic_function(), std::forward(eh)) {} + + template >>> = meta::enabler> basic_protected_function(lua_State* L, T&& r) : basic_protected_function(L, std::forward(r), get_default_handler(L)) {} - template >>, meta::neg>>> = meta::enabler> + template >>> = meta::enabler> basic_protected_function(lua_State* L, T&& r, handler_t eh) : basic_protected_function(L, sol::ref_index(r.registry_index()), std::move(eh)) {} + basic_protected_function(lua_State* L, int index = -1) : basic_protected_function(L, index, get_default_handler(L)) {} basic_protected_function(lua_State* L, int index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) { #ifdef SOL_CHECK_ARGUMENTS diff --git a/sol/stack.hpp b/sol/stack.hpp index 09e5bd61..5d2d1603 100644 --- a/sol/stack.hpp +++ b/sol/stack.hpp @@ -37,9 +37,27 @@ namespace sol { namespace detail { inline const std::string& default_chunk_name() { - static const std::string name = "string"; + static const std::string name = "script"; return name; } + + template + const char* make_chunk_name(const string_view& code, const std::string& chunkname, char (&basechunkname)[N]) { + if (chunkname.empty()) { + auto it = code.cbegin(); + auto e = code.cend(); + std::size_t i = 0; + static const std::size_t n = N - 1; + for (i = 0; i < n && it != e; ++i, ++it) { + basechunkname[i] = *it; + } + basechunkname[i] = '\0'; + return &basechunkname[0]; + } + else { + return chunkname.c_str(); + } + } } // detail namespace stack { @@ -178,8 +196,10 @@ namespace sol { return call_syntax::colon; } - inline void script(lua_State* L, const string_detail::string_shim& code, string_detail::string_shim name = detail::default_chunk_name(), load_mode mode = load_mode::any) { - if (luaL_loadbufferx(L, code.data(), code.size(), name.data(), to_string(mode).c_str()) || lua_pcall(L, 0, LUA_MULTRET, 0)) { + inline void script(lua_State* L, const string_detail::string_shim& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + char basechunkname[17] = {}; + const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); + if (luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str()) || lua_pcall(L, 0, LUA_MULTRET, 0)) { lua_error(L); } } diff --git a/sol/stack_core.hpp b/sol/stack_core.hpp index 08ce81fe..a9628f1c 100644 --- a/sol/stack_core.hpp +++ b/sol/stack_core.hpp @@ -166,14 +166,16 @@ namespace sol { } template - static int get_size_hint(const std::forward_list& c) { + static int get_size_hint(const std::forward_list&) { // forward_list makes me sad return static_cast(32); } template inline decltype(auto) unchecked_get(lua_State* L, int index, record& tracking) { - return getter>{}.get(L, index, tracking); + getter> g{}; + (void)g; + return g.get(L, index, tracking); } template diff --git a/sol/stack_get.hpp b/sol/stack_get.hpp index 81005f2d..633f829a 100644 --- a/sol/stack_get.hpp +++ b/sol/stack_get.hpp @@ -46,7 +46,7 @@ namespace sol { template struct getter { static T& get(lua_State* L, int index, record& tracking) { - return getter>{}.get(L, index, tracking); + return getter>{}.get(L, index, tracking); } }; @@ -220,7 +220,7 @@ namespace sol { } template - static C get(types t, lua_State* L, int relindex, record& tracking) { + static C get(types, lua_State* L, int relindex, record& tracking) { tracking.use(1); int index = lua_absindex(L, relindex); diff --git a/sol/state_view.hpp b/sol/state_view.hpp index e3d9bb95..a575d5d8 100644 --- a/sol/state_view.hpp +++ b/sol/state_view.hpp @@ -263,7 +263,9 @@ namespace sol { template protected_function_result do_string(const string_view& code, const basic_environment& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { - load_status x = static_cast(luaL_loadbufferx(L, code.data(), code.size(), chunkname.c_str(), to_string(mode).c_str())); + char basechunkname[17] = {}; + const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); + load_status x = static_cast(luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str())); if (x != load_status::ok) { return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast(x)); } @@ -284,7 +286,9 @@ namespace sol { } protected_function_result do_string(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { - load_status x = static_cast(luaL_loadbufferx(L, code.data(), code.size(), chunkname.c_str(), to_string(mode).c_str())); + char basechunkname[17] = {}; + const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); + load_status x = static_cast(luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str())); if (x != load_status::ok) { return protected_function_result(L, absolute_index(L, -1), 0, 1, static_cast(x)); } @@ -356,9 +360,11 @@ namespace sol { } template - function_result unsafe_script(const string_view& code, const sol::basic_environment& env, load_mode mode = load_mode::any) { + function_result unsafe_script(const string_view& code, const sol::basic_environment& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + char basechunkname[17] = {}; + const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); int index = lua_gettop(L); - if (luaL_loadbufferx(L, code.data(), code.size(), name.data(), to_string(mode).c_str())) { + if (luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str())) { lua_error(L); } set_environment(env, stack_reference(L, raw_index(index + 1))); @@ -370,9 +376,9 @@ namespace sol { return function_result(L, (std::max)(postindex - (returns - 1), 1), returns); } - function_result unsafe_script(const string_view& code, const std::string& name = detail::default_chunk_name(), load_mode mode = load_mode::any) { + function_result unsafe_script(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { int index = lua_gettop(L); - stack::script(L, code, name, mode); + stack::script(L, code, chunkname, mode); int postindex = lua_gettop(L); int returns = postindex - index; return function_result(L, (std::max)(postindex - (returns - 1), 1), returns); @@ -437,19 +443,23 @@ namespace sol { return unsafe_script_file(filename, mode); } - load_result load(const string_view& code, const std::string& name = detail::default_chunk_name(), load_mode mode = load_mode::any) { - load_status x = static_cast(luaL_loadbufferx(L, code.data(), code.size(), name.c_str(), to_string(mode).c_str())); - return load_result(L, lua_absindex(L, -1), 1, 1, x); + load_result load(const string_view& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + char basechunkname[17] = {}; + const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); + load_status x = static_cast(luaL_loadbufferx(L, code.data(), code.size(), chunknametarget, to_string(mode).c_str())); + return load_result(L, absolute_index(L, -1), 1, 1, x); } load_result load_file(const std::string& filename, load_mode mode = load_mode::any) { load_status x = static_cast(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str())); - return load_result(L, lua_absindex(L, -1), 1, 1, x); + return load_result(L, absolute_index(L, -1), 1, 1, x); } - load_result load(lua_Reader reader, void* data, const std::string& name = detail::default_chunk_name(), load_mode mode = load_mode::any) { - load_status x = static_cast(lua_load(L, reader, data, name.c_str(), to_string(mode).c_str())); - return load_result(L, lua_absindex(L, -1), 1, 1, x); + load_result load(lua_Reader reader, void* data, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { + char basechunkname[17] = {}; + const char* chunknametarget = detail::make_chunk_name("lua_reader", chunkname, basechunkname); + load_status x = static_cast(lua_load(L, reader, data, chunknametarget, to_string(mode).c_str())); + return load_result(L, absolute_index(L, -1), 1, 1, x); } iterator begin() const { diff --git a/sol/string_shim.hpp b/sol/string_shim.hpp index d9731573..bd3fbb43 100644 --- a/sol/string_shim.hpp +++ b/sol/string_shim.hpp @@ -53,10 +53,22 @@ namespace sol { return 0; } - const char* c_str() const { + const char* begin() const { return p; } + const char* end() const { + return p + s; + } + + const char* cbegin() const { + return p; + } + + const char* cend() const { + return p + s; + } + const char* data() const { return p; } diff --git a/sol/types.hpp b/sol/types.hpp index 69194ab2..57f6b98f 100644 --- a/sol/types.hpp +++ b/sol/types.hpp @@ -666,7 +666,7 @@ namespace sol { inline int type_panic(lua_State* L, int index, type expected, type actual) noexcept(false) { return luaL_error(L, "stack index %d, expected %s, received %s", index, expected == type::poly ? "anything" : lua_typename(L, static_cast(expected)), - expected == type::poly ? "anything" : lua_typename(L, static_cast(actual)) + actual == type::poly ? "anything" : lua_typename(L, static_cast(actual)) ); } @@ -1032,7 +1032,7 @@ namespace sol { struct is_variadic_arguments : std::is_same, variadic_args> {}; template - struct is_lua_index : std::false_type {}; + struct is_lua_index : std::is_integral {}; template <> struct is_lua_index : std::true_type {}; template <> diff --git a/test_container_semantics.cpp b/test_container_semantics.cpp index 7c251341..46b6ee48 100644 --- a/test_container_semantics.cpp +++ b/test_container_semantics.cpp @@ -128,7 +128,7 @@ void ordered_container_check(sol::state& lua, T& items) { { auto r1 = lua.script(R"( for i=1,#c do - v = c[i] + v = c[(i + 10)] assert(v == (i + 10)) end )", sol::script_pass_on_error); @@ -323,8 +323,8 @@ void associative_ordered_container_check(sol::state& lua, T& items) { { auto r1 = lua.script(R"( for i=1,#c do - v = c[i] - assert(v == (i + 10)) + v = c[(i + 10)] + assert(v == (i + 20)) end )", sol::script_pass_on_error); REQUIRE(r1.valid()); @@ -810,3 +810,105 @@ TEST_CASE("containers/associative unordered containers", "check associative (map associative_unordered_container_check(lua, items); } } + +TEST_CASE("containers/auxiliary functions test", "make sure the manipulation functions are present and usable and working across various container types") { + sol::state lua; + lua.open_libraries(); + + lua.script(R"( +function g (x) + x:add(20) +end + +function h (x) + x:add(20, 40) +end + +function i (x) + x:clear() +end + +function sf (x,v) + return x:find(v) +end + +)"); + + // Have the function we + // just defined in Lua + sol::function g = lua["g"]; + sol::function h = lua["h"]; + sol::function i = lua["i"]; + sol::function sf = lua["sf"]; + + // Set a global variable called + // "arr" to be a vector of 5 lements + lua["c_arr"] = std::array{ { 2, 4, 6, 8, 10 } }; + lua["arr"] = std::vector{ 2, 4, 6, 8, 10 }; + lua["map"] = std::map{ { 1 , 2 },{ 2, 4 },{ 3, 6 },{ 4, 8 },{ 5, 10 } }; + lua["set"] = std::set{ 2, 4, 6, 8, 10 }; + std::array& c_arr = lua["c_arr"]; + std::vector& arr = lua["arr"]; + std::map& map = lua["map"]; + std::set& set = lua["set"]; + REQUIRE(c_arr.size() == 5); + REQUIRE(arr.size() == 5); + REQUIRE(map.size() == 5); + REQUIRE(set.size() == 5); + + g(lua["set"]); + g(lua["arr"]); + h(lua["map"]); + REQUIRE(arr.size() == 6); + REQUIRE(map.size() == 6); + REQUIRE(set.size() == 6); + + { + int r = sf(set, 8); + REQUIRE(r == 8); + sol::object rn = sf(set, 9); + REQUIRE(rn == sol::nil); + } + + { + int r = sf(map, 3); + REQUIRE(r == 6); + sol::object rn = sf(map, 9); + REQUIRE(rn == sol::nil); + } + + i(lua["arr"]); + i(lua["map"]); + i(lua["set"]); + REQUIRE(arr.empty()); + REQUIRE(map.empty()); + REQUIRE(set.empty()); + + REQUIRE_NOTHROW([&]() { + lua.script(R"( +c_arr[1] = 7 +c_arr[2] = 7 +c_arr[3] = 7 +)"); + }()); +} + +TEST_CASE("containers/indices test", "test indices on fixed array types") { + SECTION("zero index test") { + sol::state lua; + lua["c_arr"] = std::array{ { 2, 4, 6, 8, 10 } }; + auto result = lua.safe_script(R"( +c_arr[0] = 7 +)", sol::script_pass_on_error); + REQUIRE_FALSE(result.valid()); + } + + SECTION("negative index test") { + sol::state lua; + lua["c_arr"] = std::array{ { 2, 4, 6, 8, 10 } }; + auto result = lua.safe_script(R"( +c_arr[-1] = 7 +)", sol::script_pass_on_error); + REQUIRE_FALSE(result.valid()); + } +} diff --git a/test_containers.cpp b/test_containers.cpp index 1f50c90f..938832c3 100644 --- a/test_containers.cpp +++ b/test_containers.cpp @@ -65,8 +65,8 @@ TEST_CASE("containers/table conversion", "test table conversions with as_table a lua.script("v1 = bark()"); lua.script("v2 = woof()"); - sol::as_table_t> as_table_strings = lua["v"]; - sol::nested> nested_strings = lua["v"]; + sol::as_table_t> as_table_strings = lua["v1"]; + sol::nested> nested_strings = lua["v2"]; std::vector expected_values{"bark", "woof"}; REQUIRE(as_table_strings.source == expected_values); @@ -456,106 +456,6 @@ TEST_CASE("containers/arbitrary creation", "userdata and tables should be usable REQUIRE(d.get("four") == 4); } -TEST_CASE("containers/extra functions", "make sure the manipulation functions are present and usable and working across various container types") { - sol::state lua; - lua.open_libraries(); - - lua.script(R"( -function g (x) - x:add(20) -end - -function h (x) - x:add(20, 40) -end - -function i (x) - x:clear() -end - -function sf (x,v) - return x:find(v) -end - -)"); - - // Have the function we - // just defined in Lua - sol::function g = lua["g"]; - sol::function h = lua["h"]; - sol::function i = lua["i"]; - sol::function sf = lua["sf"]; - - // Set a global variable called - // "arr" to be a vector of 5 lements - lua["c_arr"] = std::array{ { 2, 4, 6, 8, 10 } }; - lua["arr"] = std::vector{ 2, 4, 6, 8, 10 }; - lua["map"] = std::map{ { 1 , 2 },{ 2, 4 },{ 3, 6 },{ 4, 8 },{ 5, 10 } }; - lua["set"] = std::set{ 2, 4, 6, 8, 10 }; - std::array& c_arr = lua["c_arr"]; - std::vector& arr = lua["arr"]; - std::map& map = lua["map"]; - std::set& set = lua["set"]; - REQUIRE(c_arr.size() == 5); - REQUIRE(arr.size() == 5); - REQUIRE(map.size() == 5); - REQUIRE(set.size() == 5); - - g(lua["set"]); - g(lua["arr"]); - h(lua["map"]); - REQUIRE(arr.size() == 6); - REQUIRE(map.size() == 6); - REQUIRE(set.size() == 6); - - { - int r = sf(set, 8); - REQUIRE(r == 8); - sol::object rn = sf(set, 9); - REQUIRE(rn == sol::nil); - } - - { - int r = sf(map, 3); - REQUIRE(r == 6); - sol::object rn = sf(map, 9); - REQUIRE(rn == sol::nil); - } - - i(lua["arr"]); - i(lua["map"]); - i(lua["set"]); - REQUIRE(arr.empty()); - REQUIRE(map.empty()); - REQUIRE(set.empty()); - - REQUIRE_NOTHROW([&]() { - lua.script(R"( -c_arr[1] = 7 -c_arr[2] = 7 -c_arr[3] = 7 -)"); - }()); - SECTION("throw test") { - sol::state tlua; - tlua["c_arr"] = std::array{ { 2, 4, 6, 8, 10 } }; - REQUIRE_THROWS([&]() { - tlua.script(R"( -c_arr[0] = 7 -)"); - }()); - } - SECTION("throw test 2") { - sol::state tlua; - tlua["c_arr"] = std::array{ { 2, 4, 6, 8, 10 } }; - REQUIRE_THROWS([&]() { - tlua.script(R"( -c_arr[-1] = 7 -)"); - }()); - } -} - TEST_CASE("containers/usertype transparency", "Make sure containers pass their arguments through transparently and push the results as references, not new values") { class A { public: @@ -919,20 +819,19 @@ TEST_CASE("containers/input iterators", "test shitty input iterators that are al not_really_a_container c; lua["c"] = &c; -#if SOL_LUA_VERSION > 503 +#if SOL_LUA_VERSION > 502 lua.script(R"lua( for k, v in pairs(c) do assert((k - 1) == v:val()) end )lua"); -#else +#endif lua.script(R"lua( for k=1,#c do v = c[k] assert((k - 1) == v:val()) end )lua"); -#endif } TEST_CASE("containers/pairs", "test how well pairs work with the underlying system") { diff --git a/test_functions.cpp b/test_functions.cpp index 4bdfc354..dff764ec 100644 --- a/test_functions.cpp +++ b/test_functions.cpp @@ -5,13 +5,6 @@ #include #include "test_stack_guard.hpp" -std::function makefn() { - auto fx = []() -> int { - return 0x1456789; - }; - return fx; -} - template T va_func(sol::variadic_args va, T first) { T s = 0; @@ -25,6 +18,13 @@ T va_func(sol::variadic_args va, T first) { return s; } +std::function makefn() { + auto fx = []() -> int { + return 0x1456789; + }; + return fx; +} + void takefn(std::function purr) { if (purr() != 0x1456789) throw 0;