From 26b85c813657bfb80bec1bb44c15007302f4f78a Mon Sep 17 00:00:00 2001 From: ThePhD Date: Mon, 26 Dec 2016 13:50:08 -0500 Subject: [PATCH] Make sure resolve works and provide some protection against deleting the handler that originates from a specific `sol::state`. `sol::state_view` users will be left out in the dark, though. --- docs/source/compilation.rst | 8 +- single/sol/sol.hpp | 27 ++- sol/resolve.hpp | 339 ++++++++++++++++++------------------ sol/state.hpp | 176 ++++++++++--------- 4 files changed, 297 insertions(+), 253 deletions(-) diff --git a/docs/source/compilation.rst b/docs/source/compilation.rst index 7041c465..22b894e7 100644 --- a/docs/source/compilation.rst +++ b/docs/source/compilation.rst @@ -5,15 +5,21 @@ getting good final product out of sol2 For individiauls who use :doc:`usertypes` a lot, they can find their compilation times increase. This is due to C++11 and C++14 not having very good facilities for handling template parameters and variadic template parameters. There are a few things in cutting-edge C++17 and C++Next that sol can use, but the problem is many people cannot work with the latest and greatest: therefore, we have to use older techniques that result in a fair amount of redundant function specializations that can be subject to the pickiness of the compiler's inlining and other such techniques. +what to do +---------- + Here are some notes on achieving better compile-times without sacrificing too much performance: * When you bind lots of usertypes, put them all in a *single* translation unit (one C++ file) so that it is not recompiled multiple times over, only to be discarded later by the linker. - Remember that the usertype binding ends up being serialized into the Lua state, so you never need them to appear in a header and cause that same compilation overhead for every compiled unit in your project. * For extremely large usertypes, consider using :doc:`simple_usertype`. - It performs much more work at runtime rather than compile-time, and should still give comparative performance (but it loses out in some cases for variable bindings or when you bind all functions to a usertype). -* If you are developing a shared library, restrict your overall surface area by specifically and explicitly marking functions as visible and exported and letting everything else as hidden or invisible by default +* If you are developing a shared library, restrict your overall surface area by specifically and explicitly marking functions as visible and exported and leaving everything else as hidden or invisible by default +next steps +---------- + The next step for Sol from a developer standpoint is to formally make the library a C++17 one. This would mean using Fold Expressions and several other things which will reduce compilation time drastically. Unfortunately, that means also boosting compiler requirements. While most wouldn't care, others are very slow to upgrade: finding the balance is difficult, and often we have to opt for backwards compatibility and fixes for bad / older compilers (of which there are many in the codebase already). Hopefully, as things progress, we move things forward. diff --git a/single/sol/sol.hpp b/single/sol/sol.hpp index f0dbb54c..604922a3 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 2016-12-16 10:31:09.106965 UTC -// This header was generated with sol v2.15.5 (revision 87f8456) +// Generated 2016-12-26 18:50:00.916890 UTC +// This header was generated with sol v2.15.5 (revision 3aa42c5) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -8531,9 +8531,10 @@ namespace sol { // beginning of sol/resolve.hpp namespace sol { - // Clang has distinct problems with constexpr arguments, - // so don't use the constexpr versions inside of clang. + #ifndef __clang__ + // constexpr is fine for not-clang + namespace detail { template(Args...)>> inline constexpr auto resolve_i(types, F&&)->R(meta::unqualified_t::*)(Args...) { @@ -8600,6 +8601,10 @@ namespace sol { return detail::resolve_i(types(), std::forward(f)); } #else + + // Clang has distinct problems with constexpr arguments, + // so don't use the constexpr versions inside of clang. + namespace detail { template(Args...)>> inline auto resolve_i(types, F&&)->R(meta::unqualified_t::*)(Args...) { @@ -8665,7 +8670,9 @@ namespace sol { inline auto resolve(F&& f) -> decltype(detail::resolve_i(types(), std::forward(f))) { return detail::resolve_i(types(), std::forward(f)); } + #endif + } // sol // end of sol/resolve.hpp @@ -12829,7 +12836,19 @@ namespace sol { stack::luajit_exception_handler(unique_base::get()); } + state(const state&) = delete; + state(state&&) = default; + state& operator=(const state&) = delete; + state& operator=(state&&) = default; + using state_view::get; + + ~state() { + auto& handler = protected_function::get_default_handler(); + if (handler.lua_state() == this->lua_state()) { + protected_function::set_default_handler(reference()); + } + } }; } // sol diff --git a/sol/resolve.hpp b/sol/resolve.hpp index 57964559..acd372dd 100644 --- a/sol/resolve.hpp +++ b/sol/resolve.hpp @@ -1,166 +1,173 @@ -// The MIT License (MIT) - -// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors - -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -#ifndef SOL_RESOLVE_HPP -#define SOL_RESOLVE_HPP - -#include "traits.hpp" -#include "tuple.hpp" - -namespace sol { - // Clang has distinct problems with constexpr arguments, - // so don't use the constexpr versions inside of clang. -#ifndef __clang__ - namespace detail { - template(Args...)>> - inline constexpr auto resolve_i(types, F&&)->R(meta::unqualified_t::*)(Args...) { - using Sig = R(Args...); - typedef meta::unqualified_t Fu; - return static_cast(&Fu::operator()); - } - - template> - inline constexpr auto resolve_f(std::true_type, F&& f) - -> decltype(resolve_i(types>(), std::forward(f))) { - return resolve_i(types>(), std::forward(f)); - } - - template - inline constexpr void resolve_f(std::false_type, F&&) { - static_assert(meta::has_deducible_signature::value, - "Cannot use no-template-parameter call with an overloaded functor: specify the signature"); - } - - template> - inline constexpr auto resolve_i(types<>, F&& f) -> decltype(resolve_f(meta::has_deducible_signature(), std::forward(f))) { - return resolve_f(meta::has_deducible_signature {}, std::forward(f)); - } - - template> - inline constexpr auto resolve_i(types, F&& f) -> decltype(resolve_i(types(), std::forward(f))) { - return resolve_i(types(), std::forward(f)); - } - - template - inline constexpr Sig C::* resolve_v(std::false_type, Sig C::* mem_func_ptr) { - return mem_func_ptr; - } - - template - inline constexpr Sig C::* resolve_v(std::true_type, Sig C::* mem_variable_ptr) { - return mem_variable_ptr; - } - } // detail - - template - inline constexpr auto resolve(R fun_ptr(Args...))->R(*)(Args...) { - return fun_ptr; - } - - template - inline constexpr Sig* resolve(Sig* fun_ptr) { - return fun_ptr; - } - - template - inline constexpr auto resolve(R(C::*mem_ptr)(Args...))->R(C::*)(Args...) { - return mem_ptr; - } - - template - inline constexpr Sig C::* resolve(Sig C::* mem_ptr) { - return detail::resolve_v(std::is_member_object_pointer(), mem_ptr); - } - - template>> = meta::enabler> - inline constexpr auto resolve(F&& f) -> decltype(detail::resolve_i(types(), std::forward(f))) { - return detail::resolve_i(types(), std::forward(f)); - } -#else - namespace detail { - template(Args...)>> - inline auto resolve_i(types, F&&)->R(meta::unqualified_t::*)(Args...) { - using Sig = R(Args...); - typedef meta::unqualified_t Fu; - return static_cast(&Fu::operator()); - } - - template> - inline auto resolve_f(std::true_type, F&& f) - -> decltype(resolve_i(types>(), std::forward(f))) { - return resolve_i(types>(), std::forward(f)); - } - - template - inline void resolve_f(std::false_type, F&&) { - static_assert(meta::has_deducible_signature::value, - "Cannot use no-template-parameter call with an overloaded functor: specify the signature"); - } - - template> - inline auto resolve_i(types<>, F&& f) -> decltype(resolve_f(meta::has_deducible_signature(), std::forward(f))) { - return resolve_f(meta::has_deducible_signature {}, std::forward(f)); - } - - template> - inline auto resolve_i(types, F&& f) -> decltype(resolve_i(types(), std::forward(f))) { - return resolve_i(types(), std::forward(f)); - } - - template - inline Sig C::* resolve_v(std::false_type, Sig C::* mem_func_ptr) { - return mem_func_ptr; - } - - template - inline Sig C::* resolve_v(std::true_type, Sig C::* mem_variable_ptr) { - return mem_variable_ptr; - } - } // detail - - template - inline auto resolve(R fun_ptr(Args...))->R(*)(Args...) { - return fun_ptr; - } - - template - inline Sig* resolve(Sig* fun_ptr) { - return fun_ptr; - } - - template - inline auto resolve(R(C::*mem_ptr)(Args...))->R(C::*)(Args...) { - return mem_ptr; - } - - template - inline Sig C::* resolve(Sig C::* mem_ptr) { - return detail::resolve_v(std::is_member_object_pointer(), mem_ptr); - } - - template - inline auto resolve(F&& f) -> decltype(detail::resolve_i(types(), std::forward(f))) { - return detail::resolve_i(types(), std::forward(f)); - } -#endif -} // sol - -#endif // SOL_RESOLVE_HPP +// The MIT License (MIT) + +// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors + +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#ifndef SOL_RESOLVE_HPP +#define SOL_RESOLVE_HPP + +#include "traits.hpp" +#include "tuple.hpp" + +namespace sol { + +#ifndef __clang__ + // constexpr is fine for not-clang + + namespace detail { + template(Args...)>> + inline constexpr auto resolve_i(types, F&&)->R(meta::unqualified_t::*)(Args...) { + using Sig = R(Args...); + typedef meta::unqualified_t Fu; + return static_cast(&Fu::operator()); + } + + template> + inline constexpr auto resolve_f(std::true_type, F&& f) + -> decltype(resolve_i(types>(), std::forward(f))) { + return resolve_i(types>(), std::forward(f)); + } + + template + inline constexpr void resolve_f(std::false_type, F&&) { + static_assert(meta::has_deducible_signature::value, + "Cannot use no-template-parameter call with an overloaded functor: specify the signature"); + } + + template> + inline constexpr auto resolve_i(types<>, F&& f) -> decltype(resolve_f(meta::has_deducible_signature(), std::forward(f))) { + return resolve_f(meta::has_deducible_signature {}, std::forward(f)); + } + + template> + inline constexpr auto resolve_i(types, F&& f) -> decltype(resolve_i(types(), std::forward(f))) { + return resolve_i(types(), std::forward(f)); + } + + template + inline constexpr Sig C::* resolve_v(std::false_type, Sig C::* mem_func_ptr) { + return mem_func_ptr; + } + + template + inline constexpr Sig C::* resolve_v(std::true_type, Sig C::* mem_variable_ptr) { + return mem_variable_ptr; + } + } // detail + + template + inline constexpr auto resolve(R fun_ptr(Args...))->R(*)(Args...) { + return fun_ptr; + } + + template + inline constexpr Sig* resolve(Sig* fun_ptr) { + return fun_ptr; + } + + template + inline constexpr auto resolve(R(C::*mem_ptr)(Args...))->R(C::*)(Args...) { + return mem_ptr; + } + + template + inline constexpr Sig C::* resolve(Sig C::* mem_ptr) { + return detail::resolve_v(std::is_member_object_pointer(), mem_ptr); + } + + template>> = meta::enabler> + inline constexpr auto resolve(F&& f) -> decltype(detail::resolve_i(types(), std::forward(f))) { + return detail::resolve_i(types(), std::forward(f)); + } +#else + + // Clang has distinct problems with constexpr arguments, + // so don't use the constexpr versions inside of clang. + + namespace detail { + template(Args...)>> + inline auto resolve_i(types, F&&)->R(meta::unqualified_t::*)(Args...) { + using Sig = R(Args...); + typedef meta::unqualified_t Fu; + return static_cast(&Fu::operator()); + } + + template> + inline auto resolve_f(std::true_type, F&& f) + -> decltype(resolve_i(types>(), std::forward(f))) { + return resolve_i(types>(), std::forward(f)); + } + + template + inline void resolve_f(std::false_type, F&&) { + static_assert(meta::has_deducible_signature::value, + "Cannot use no-template-parameter call with an overloaded functor: specify the signature"); + } + + template> + inline auto resolve_i(types<>, F&& f) -> decltype(resolve_f(meta::has_deducible_signature(), std::forward(f))) { + return resolve_f(meta::has_deducible_signature {}, std::forward(f)); + } + + template> + inline auto resolve_i(types, F&& f) -> decltype(resolve_i(types(), std::forward(f))) { + return resolve_i(types(), std::forward(f)); + } + + template + inline Sig C::* resolve_v(std::false_type, Sig C::* mem_func_ptr) { + return mem_func_ptr; + } + + template + inline Sig C::* resolve_v(std::true_type, Sig C::* mem_variable_ptr) { + return mem_variable_ptr; + } + } // detail + + template + inline auto resolve(R fun_ptr(Args...))->R(*)(Args...) { + return fun_ptr; + } + + template + inline Sig* resolve(Sig* fun_ptr) { + return fun_ptr; + } + + template + inline auto resolve(R(C::*mem_ptr)(Args...))->R(C::*)(Args...) { + return mem_ptr; + } + + template + inline Sig C::* resolve(Sig C::* mem_ptr) { + return detail::resolve_v(std::is_member_object_pointer(), mem_ptr); + } + + template + inline auto resolve(F&& f) -> decltype(detail::resolve_i(types(), std::forward(f))) { + return detail::resolve_i(types(), std::forward(f)); + } + +#endif + +} // sol + +#endif // SOL_RESOLVE_HPP diff --git a/sol/state.hpp b/sol/state.hpp index 1cdb65d1..97bbc260 100644 --- a/sol/state.hpp +++ b/sol/state.hpp @@ -1,82 +1,94 @@ -// The MIT License (MIT) - -// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors - -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -#ifndef SOL_STATE_HPP -#define SOL_STATE_HPP - -#include "state_view.hpp" - -namespace sol { - inline int default_at_panic(lua_State* L) { -#ifdef SOL_NO_EXCEPTIONS - (void)L; - return -1; -#else - const char* message = lua_tostring(L, -1); - if (message) { - std::string err = message; - lua_pop(L, 1); - throw error(err); - } - throw error(std::string("An unexpected error occurred and forced the lua state to call atpanic")); -#endif - } - - inline int default_error_handler(lua_State*L) { - using namespace sol; - std::string msg = "An unknown error has triggered the default error handler"; - optional maybetopmsg = stack::check_get(L, 1); - if (maybetopmsg) { - const string_detail::string_shim& topmsg = maybetopmsg.value(); - msg.assign(topmsg.c_str(), topmsg.size()); - } - luaL_traceback(L, L, msg.c_str(), 1); - optional maybetraceback = stack::check_get(L, -1); - if (maybetraceback) { - const string_detail::string_shim& traceback = maybetraceback.value(); - msg.assign(traceback.c_str(), traceback.size()); - } - return stack::push(L, msg); - } - - - class state : private std::unique_ptr, public state_view { - private: - typedef std::unique_ptr unique_base; - public: - state(lua_CFunction panic = default_at_panic) : unique_base(luaL_newstate(), lua_close), - state_view(unique_base::get()) { - set_panic(panic); - stack::luajit_exception_handler(unique_base::get()); - } - - state(lua_CFunction panic, lua_Alloc alfunc, void* alpointer = nullptr) : unique_base(lua_newstate(alfunc, alpointer), lua_close), - state_view(unique_base::get()) { - set_panic(panic); - sol::protected_function::set_default_handler(sol::object(lua_state(), in_place, default_error_handler)); - stack::luajit_exception_handler(unique_base::get()); - } - - using state_view::get; - }; -} // sol - -#endif // SOL_STATE_HPP +// The MIT License (MIT) + +// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors + +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#ifndef SOL_STATE_HPP +#define SOL_STATE_HPP + +#include "state_view.hpp" + +namespace sol { + inline int default_at_panic(lua_State* L) { +#ifdef SOL_NO_EXCEPTIONS + (void)L; + return -1; +#else + const char* message = lua_tostring(L, -1); + if (message) { + std::string err = message; + lua_pop(L, 1); + throw error(err); + } + throw error(std::string("An unexpected error occurred and forced the lua state to call atpanic")); +#endif + } + + inline int default_error_handler(lua_State*L) { + using namespace sol; + std::string msg = "An unknown error has triggered the default error handler"; + optional maybetopmsg = stack::check_get(L, 1); + if (maybetopmsg) { + const string_detail::string_shim& topmsg = maybetopmsg.value(); + msg.assign(topmsg.c_str(), topmsg.size()); + } + luaL_traceback(L, L, msg.c_str(), 1); + optional maybetraceback = stack::check_get(L, -1); + if (maybetraceback) { + const string_detail::string_shim& traceback = maybetraceback.value(); + msg.assign(traceback.c_str(), traceback.size()); + } + return stack::push(L, msg); + } + + + class state : private std::unique_ptr, public state_view { + private: + typedef std::unique_ptr unique_base; + public: + state(lua_CFunction panic = default_at_panic) : unique_base(luaL_newstate(), lua_close), + state_view(unique_base::get()) { + set_panic(panic); + stack::luajit_exception_handler(unique_base::get()); + } + + state(lua_CFunction panic, lua_Alloc alfunc, void* alpointer = nullptr) : unique_base(lua_newstate(alfunc, alpointer), lua_close), + state_view(unique_base::get()) { + set_panic(panic); + sol::protected_function::set_default_handler(sol::object(lua_state(), in_place, default_error_handler)); + stack::luajit_exception_handler(unique_base::get()); + } + + state(const state&) = delete; + state(state&&) = default; + state& operator=(const state&) = delete; + state& operator=(state&&) = default; + + using state_view::get; + + ~state() { + auto& handler = protected_function::get_default_handler(); + if (handler.lua_state() == this->lua_state()) { + protected_function::set_default_handler(reference()); + } + } + }; +} // sol + +#endif // SOL_STATE_HPP