From 8d828ac47b7edea56ec9482450fec2da3f99f873 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Thu, 14 Sep 2017 00:35:40 -0400 Subject: [PATCH] implement main_reference as per @eliasdaler's suggestions --- .clang-format | 9 +- docs/source/threading.rst | 2 + single/sol/sol.hpp | 699 +++++++++++++++++---------- sol/container_traits.hpp | 4 +- sol/container_usertype_metatable.hpp | 4 +- sol/coroutine.hpp | 57 +-- sol/environment.hpp | 16 +- sol/forward.hpp | 40 +- sol/function.hpp | 8 +- sol/function_types.hpp | 8 +- sol/object.hpp | 8 +- sol/protected_function.hpp | 22 +- sol/proxy.hpp | 20 +- sol/reference.hpp | 213 +++++--- sol/simple_usertype_metatable.hpp | 6 +- sol/stack.hpp | 11 +- sol/stack_check.hpp | 9 + sol/stack_core.hpp | 4 +- sol/stack_get.hpp | 12 +- sol/stack_push.hpp | 11 +- sol/state.hpp | 4 +- sol/state_view.hpp | 6 +- sol/table_core.hpp | 16 +- sol/thread.hpp | 104 ++-- sol/types.hpp | 75 ++- sol/userdata.hpp | 2 +- sol/usertype_core.hpp | 27 +- sol/usertype_metatable.hpp | 8 +- tests/test_coroutines.cpp | 90 ++++ 29 files changed, 997 insertions(+), 498 deletions(-) diff --git a/.clang-format b/.clang-format index e1fc8fba..f99f7e1e 100644 --- a/.clang-format +++ b/.clang-format @@ -14,8 +14,8 @@ FixNamespaceComments: true ColumnLimit: 0 AlignAfterOpenBracket: DontAlign # uses ContinuationIndentWidth for this instead AccessModifierOffset: -5 # do not push public: or private: around -#AlignConsecutiveAssignments: true -#AlignConsecutiveDeclarations: true +#AlignConsecutiveAssignments: true # affects more than what's expected: do not use +#AlignConsecutiveDeclarations: true # affects more than what's expected: do not use # Type Alignment DerivePointerAlignment: false @@ -29,7 +29,6 @@ ReflowComments: true # Macros AlignEscapedNewlines: Left -SortIncludes: false IndentPPDirectives: None # Functions @@ -38,6 +37,8 @@ AlwaysBreakAfterReturnType: None BreakConstructorInitializers: BeforeComma ConstructorInitializerIndentWidth: 0 ConstructorInitializerAllOnOneLineOrOnePerLine: true +BinPackArguments: true +BinPackParameters: true # Classes BreakBeforeInheritanceComma: false @@ -66,7 +67,6 @@ AllowShortLoopsOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false IndentCaseLabels: false - # Spaces SpaceAfterCStyleCast: false SpacesInCStyleCastParentheses: false @@ -81,6 +81,7 @@ MaxEmptyLinesToKeep: 1 # OCD SortUsingDeclarations: true +SortIncludes: false --- Language: Cpp diff --git a/docs/source/threading.rst b/docs/source/threading.rst index 7510aa02..69950f99 100644 --- a/docs/source/threading.rst +++ b/docs/source/threading.rst @@ -18,6 +18,8 @@ working with multiple Lua threads You can mitigate some of the pressure of using coroutines and threading by using the ``lua_xmove`` constructors that sol implements. Simply keep a reference to your ``sol::state_view`` or ``sol::state`` or the target ``lua_State*`` pointer, and pass it into the constructor along with the object you want to copy. Note that there is also some implicit ``lua_xmove`` checks that are done for copy and move assignment operators as well, as noted :ref:`at the reference constructor explanations`. +Furthermore, for every single ``sol::reference`` derived type, there exists a version prefixed with the word ``main_``, such as ``sol::main_table``, ``sol::main_function``, ``sol::main_object`` and similar. These classes, on construction, assignment and other operations, forcibly obtain the ``lua_State*`` associated with the main thread, if possible. Using these classes will allow your code to be immune when a wrapped coroutine or a lua thread is set to ``nil`` and then garbage-collected. + .. code-block:: cpp :caption: transfer from state function :name: state-transfer diff --git a/single/sol/sol.hpp b/single/sol/sol.hpp index e25b3dee..f85cc9d1 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-09-13 15:45:14.036087 UTC -// This header was generated with sol v2.18.3 (revision a068c4e) +// Generated 2017-09-14 04:35:07.305798 UTC +// This header was generated with sol v2.18.3 (revision 72143a4) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -144,11 +144,18 @@ namespace sol { - class reference; + template + class basic_reference; + using reference = basic_reference; + using main_reference = basic_reference; class stack_reference; + struct proxy_base_tag; + template + struct proxy_base; template struct proxy; + template class usertype; template @@ -158,16 +165,21 @@ namespace sol { template using table_core = basic_table_core; template + using main_table_core = basic_table_core; + template 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; template struct basic_environment; using environment = basic_environment; + using main_environment = basic_environment; using stack_environment = basic_environment; template class basic_function; @@ -175,6 +187,8 @@ namespace sol { class basic_protected_function; using unsafe_function = basic_function; using safe_function = basic_protected_function; + using main_unsafe_function = basic_function; + using main_safe_function = basic_protected_function; using stack_unsafe_function = basic_function; using stack_safe_function = basic_protected_function; using stack_aligned_unsafe_function = basic_function; @@ -184,10 +198,12 @@ namespace sol { using stack_aligned_protected_function = stack_aligned_safe_function; #ifdef SOL_SAFE_FUNCTIONS using function = protected_function; + using main_function = main_protected_function; using stack_function = stack_protected_function; using stack_aligned_function = stack_aligned_safe_function; #else using function = unsafe_function; + using main_function = main_unsafe_function; using stack_function = stack_unsafe_function; using stack_aligned_function = stack_aligned_unsafe_function; #endif @@ -197,25 +213,39 @@ namespace sol { struct protected_function_result; using safe_function_result = protected_function_result; using unsafe_function_result = function_result; + template class basic_object; template class basic_userdata; template class basic_lightuserdata; + template + class basic_coroutine; + template + class basic_thread; + using object = basic_object; - using stack_object = basic_object; using userdata = basic_userdata; - using stack_userdata = basic_userdata; using lightuserdata = basic_lightuserdata; + using thread = basic_thread; + using coroutine = basic_coroutine; + using main_object = basic_object; + using main_userdata = basic_userdata; + using main_lightuserdata = basic_lightuserdata; + using stack_object = basic_object; + using stack_userdata = basic_userdata; using stack_lightuserdata = basic_lightuserdata; - class coroutine; - class thread; + using stack_thread = basic_thread; + using stack_coroutine = basic_coroutine; + struct variadic_args; struct variadic_results; struct stack_count; struct this_state; + struct this_main_state; struct this_environment; + template struct as_table_t; template @@ -4752,6 +4782,31 @@ namespace sol { struct this_state { lua_State* L; + + this_state(lua_State* Ls) + : L(Ls) { + } + + operator lua_State*() const noexcept { + return lua_state(); + } + + lua_State* operator->() const noexcept { + return lua_state(); + } + + lua_State* lua_state() const noexcept { + return L; + } + }; + + struct this_main_state { + lua_State* L; + + this_main_state(lua_State* Ls) + : L(Ls) { + } + operator lua_State*() const noexcept { return lua_state(); } @@ -4838,7 +4893,7 @@ namespace sol { }; inline const std::string& to_string(call_status c) { - static const std::array names{{ + static const std::array names{ { "ok", "yielded", "runtime", @@ -4847,7 +4902,7 @@ namespace sol { "gc", "syntax", "file", - }}; + } }; switch (c) { case call_status::ok: return names[0]; @@ -4870,13 +4925,13 @@ namespace sol { } inline const std::string& to_string(load_status c) { - static const std::array names{{ + static const std::array names{ { "ok", "memory", "gc", "syntax", "file", - }}; + } }; switch (c) { case load_status::ok: return names[0]; @@ -4893,11 +4948,11 @@ namespace sol { } inline const std::string& to_string(load_mode c) { - static const std::array names{{ + static const std::array names{ { "bt", "t", "b", - }}; + } }; return names[static_cast(c)]; } @@ -4941,7 +4996,7 @@ namespace sol { typedef meta_function meta_method; inline const std::array& meta_function_names() { - static const std::array names = {{"new", + static const std::array names = { { "new", "__index", "__newindex", "__mode", @@ -4974,7 +5029,7 @@ namespace sol { "__ipairs", "__next", "__type", - "__typeinfo"}}; + "__typeinfo" } }; return names; } @@ -5092,7 +5147,7 @@ namespace sol { struct lua_type_of : std::integral_constant {}; template <> - struct lua_type_of : std::integral_constant {}; + struct lua_type_of : std::integral_constant {}; template struct lua_type_of> : std::integral_constant {}; @@ -5112,8 +5167,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 {}; @@ -5184,6 +5239,9 @@ 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 {}; @@ -5270,6 +5328,7 @@ namespace sol { && detail::has_internal_marker>>::value && !detail::has_internal_marker>>::value) || std::is_base_of>::value + || std::is_base_of>::value || std::is_base_of>::value || meta::is_specialization_of>::value || meta::is_specialization_of>::value> {}; @@ -5277,8 +5336,19 @@ namespace sol { template struct is_lua_reference : std::integral_constant>::value - || std::is_base_of>::value - || meta::is_specialization_of>::value> {}; + || std::is_base_of>::value + || std::is_base_of>::value> {}; + + template + struct is_lua_reference_or_proxy : std::integral_constant>::value + || meta::is_specialization_of>::value> {}; + + template + struct is_main_threaded : std::is_base_of {}; + + template + struct is_stack_based : std::is_base_of {}; template struct is_lua_primitive : std::true_type {}; @@ -5313,6 +5383,8 @@ namespace sol { template <> struct is_transparent_argument : std::true_type {}; template <> + struct is_transparent_argument : std::true_type {}; + template <> struct is_transparent_argument : std::true_type {}; template <> struct is_transparent_argument : std::true_type {}; @@ -5330,13 +5402,6 @@ namespace sol { template <> struct is_lua_index : std::true_type {}; - template - struct is_stack_based : std::is_base_of {}; - template <> - struct is_stack_based : std::true_type {}; - template <> - struct is_stack_based : std::true_type {}; - template struct lua_bind_traits : meta::bind_traits { private: @@ -5927,10 +5992,23 @@ namespace sol { } const global_{}; struct no_safety_tag { } const no_safety{}; + + template + inline lua_State* pick_main_thread(lua_State* L, lua_State* backup_if_unsupported = nullptr) { + (void)L; + (void)backup_if_unsupported; + if (b) { + return main_thread(L, backup_if_unsupported); + } + return L; + } } // namespace detail - class reference { + template + class basic_reference { private: + template + friend class basic_reference; lua_State* luastate = nullptr; // non-owning int ref = LUA_NOREF; @@ -5941,9 +6019,58 @@ namespace sol { return luaL_ref(lua_state(), LUA_REGISTRYINDEX); } + template + void copy_assign(const basic_reference& r) { + if (valid()) { + deref(); + } + if (r.ref == LUA_REFNIL) { + luastate = detail::pick_main_thread < main_only && !r_main_only >(r.lua_state(), r.lua_state()); + ref = LUA_REFNIL; + return; + } + if (r.ref == LUA_NOREF) { + ref = LUA_NOREF; + return; + } + if (detail::xmovable(lua_state(), r.lua_state())) { + r.push(lua_state()); + ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); + return; + } + luastate = detail::pick_main_thread < main_only && !r_main_only >(r.lua_state(), r.lua_state()); + ref = r.copy(); + } + + template + void move_assign(basic_reference&& r) { + if (valid()) { + deref(); + } + if (r.ref == LUA_REFNIL) { + luastate = detail::pick_main_thread(r.lua_state(), r.lua_state()); + ref = LUA_REFNIL; + return; + } + if (r.ref == LUA_NOREF) { + ref = LUA_NOREF; + return; + } + if (detail::xmovable(lua_state(), r.lua_state())) { + r.push(lua_state()); + ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); + return; + } + + luastate = detail::pick_main_thread < main_only && !r_main_only >(r.lua_state(), r.lua_state()); + ref = r.ref; + r.ref = LUA_NOREF; + r.luastate = nullptr; + } + protected: - reference(lua_State* L, detail::global_tag) noexcept - : luastate(L) { + basic_reference(lua_State* L, detail::global_tag) noexcept + : luastate(detail::pick_main_thread(L, L)) { lua_pushglobaltable(lua_state()); ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); } @@ -5957,18 +6084,19 @@ namespace sol { } public: - reference() noexcept = default; - reference(lua_nil_t) noexcept - : reference() { + basic_reference() noexcept = default; + basic_reference(lua_nil_t) noexcept + : basic_reference() { } - reference(const stack_reference& r) noexcept - : reference(r.lua_state(), r.stack_index()) { + basic_reference(const stack_reference& r) noexcept + : basic_reference(r.lua_state(), r.stack_index()) { } - reference(stack_reference&& r) noexcept - : reference(r.lua_state(), r.stack_index()) { + basic_reference(stack_reference&& r) noexcept + : basic_reference(r.lua_state(), r.stack_index()) { } - reference(lua_State* L, const reference& r) noexcept - : luastate(L) { + template + basic_reference(lua_State* L, const basic_reference& r) noexcept + : luastate(detail::pick_main_thread(L, L)) { if (r.ref == LUA_REFNIL) { ref = LUA_REFNIL; return; @@ -5984,8 +6112,10 @@ namespace sol { } ref = r.copy(); } - reference(lua_State* L, reference&& r) noexcept - : luastate(L) { + + template + basic_reference(lua_State* L, basic_reference&& r) noexcept + : luastate(detail::pick_main_thread(L, L)) { if (r.ref == LUA_REFNIL) { ref = LUA_REFNIL; return; @@ -6003,8 +6133,9 @@ namespace sol { r.ref = LUA_NOREF; r.luastate = nullptr; } - reference(lua_State* L, const stack_reference& r) noexcept - : luastate(L) { + + basic_reference(lua_State* L, const stack_reference& r) noexcept + : luastate(detail::pick_main_thread(L, L)) { if (lua_state() == nullptr || r.lua_state() == nullptr || r.get_type() == type::none) { ref = LUA_NOREF; return; @@ -6019,83 +6150,72 @@ namespace sol { r.push(lua_state()); ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); } - reference(lua_State* L, int index = -1) noexcept - : luastate(L) { + basic_reference(lua_State* L, int index = -1) noexcept + : luastate(detail::pick_main_thread(L, L)) { lua_pushvalue(lua_state(), index); ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); } - reference(lua_State* L, ref_index index) noexcept - : luastate(L) { - lua_rawgeti(L, LUA_REGISTRYINDEX, index.index); + basic_reference(lua_State* L, ref_index index) noexcept + : luastate(detail::pick_main_thread(L, L)) { + lua_rawgeti(lua_state(), LUA_REGISTRYINDEX, index.index); ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); } - reference(lua_State* L, lua_nil_t) noexcept - : luastate(L) { + basic_reference(lua_State* L, lua_nil_t) noexcept + : luastate(detail::pick_main_thread(L, L)) { } - ~reference() noexcept { + ~basic_reference() noexcept { + if (lua_state() == nullptr || ref == LUA_NOREF) + return; deref(); } - reference(const reference& o) noexcept - : luastate(o.luastate), ref(o.copy()) { + basic_reference(const basic_reference& o) noexcept + : luastate(o.lua_state()), ref(o.copy()) { } - reference(reference&& o) noexcept - : luastate(o.luastate), ref(o.ref) { + basic_reference(basic_reference&& o) noexcept + : luastate(o.lua_state()), ref(o.ref) { o.luastate = nullptr; o.ref = LUA_NOREF; } - reference& operator=(reference&& r) noexcept { - if (valid()) { - deref(); - } - if (r.ref == LUA_REFNIL) { - luastate = r.lua_state(); - ref = LUA_REFNIL; - return *this; - } - if (r.ref == LUA_NOREF) { - ref = LUA_NOREF; - return *this; - } - if (detail::xmovable(lua_state(), r.lua_state())) { - r.push(lua_state()); - ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); - return *this; - } + basic_reference(const basic_reference& o) noexcept + : luastate(detail::pick_main_thread(o.lua_state(), o.lua_state())), ref(o.copy()) { + } - luastate = r.lua_state(); - ref = r.ref; - r.ref = LUA_NOREF; - r.luastate = nullptr; + basic_reference(basic_reference&& o) noexcept + : luastate(detail::pick_main_thread(o.lua_state(), o.lua_state())), ref(o.ref) { + o.luastate = nullptr; + o.ref = LUA_NOREF; + } + + basic_reference& operator=(basic_reference&& r) noexcept { + move_assign(std::move(r)); return *this; } - reference& operator=(const reference& r) noexcept { - if (valid()) { - deref(); - } - if (r.ref == LUA_REFNIL) { - luastate = r.lua_state(); - ref = LUA_REFNIL; - return *this; - } - if (r.ref == LUA_NOREF) { - ref = LUA_NOREF; - return *this; - } - if (detail::xmovable(lua_state(), r.lua_state())) { - r.push(lua_state()); - ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); - return *this; - } - luastate = r.lua_state(); - ref = r.copy(); + basic_reference& operator=(const basic_reference& r) noexcept { + copy_assign(r); return *this; } + basic_reference& operator=(basic_reference&& r) noexcept { + move_assign(std::move(r)); + return *this; + } + + basic_reference& operator=(const basic_reference& r) noexcept { + copy_assign(r); + return *this; + } + + template + basic_reference& operator=(proxy_base&& r); + + template + basic_reference& operator=(const proxy_base& r); + int push() const noexcept { return push(lua_state()); } @@ -6143,29 +6263,35 @@ namespace sol { } }; - inline bool operator==(const reference& l, const reference& r) { + template + inline bool operator==(const basic_reference& l, const basic_reference& r) { auto ppl = stack::push_pop(l); auto ppr = stack::push_pop(r); return lua_compare(l.lua_state(), -1, -2, LUA_OPEQ) == 1; } - inline bool operator!=(const reference& l, const reference& r) { + template + inline bool operator!=(const basic_reference& l, const basic_reference& r) { return !operator==(l, r); } - inline bool operator==(const reference& lhs, const lua_nil_t&) { + template + inline bool operator==(const basic_reference& lhs, const lua_nil_t&) { return !lhs.valid(); } - inline bool operator==(const lua_nil_t&, const reference& rhs) { + template + inline bool operator==(const lua_nil_t&, const basic_reference& rhs) { return !rhs.valid(); } - inline bool operator!=(const reference& lhs, const lua_nil_t&) { + template + inline bool operator!=(const basic_reference& lhs, const lua_nil_t&) { return lhs.valid(); } - inline bool operator!=(const lua_nil_t&, const reference& rhs) { + template + inline bool operator!=(const lua_nil_t&, const basic_reference& rhs) { return rhs.valid(); } } // namespace sol @@ -6500,7 +6626,7 @@ namespace sol { template inline int multi_push(lua_State* L, T&& t, Args&&... args) { int pushcount = push(L, std::forward(t)); - void(sol::detail::swallow{(pushcount += sol::stack::push(L, std::forward(args)), 0)...}); + void(detail::swallow{(pushcount += stack::push(L, std::forward(args)), 0)...}); return pushcount; } @@ -6512,7 +6638,7 @@ namespace sol { template inline int multi_push_reference(lua_State* L, T&& t, Args&&... args) { int pushcount = push_reference(L, std::forward(t)); - void(sol::detail::swallow{(pushcount += sol::stack::push_reference(L, std::forward(args)), 0)...}); + void(detail::swallow{(pushcount += stack::push_reference(L, std::forward(args)), 0)...}); return pushcount; } @@ -7002,6 +7128,15 @@ namespace stack { } }; + template + struct checker { + template + static bool check(lua_State*, int, Handler&&, record& tracking) { + tracking.use(0); + return true; + } + }; + template struct checker { template @@ -7704,7 +7839,7 @@ namespace stack { }; template - struct getter::value || std::is_base_of::value>> { + struct getter::value>> { static T get(lua_State* L, int index, record& tracking) { tracking.use(1); return T(L, index); @@ -7943,7 +8078,15 @@ namespace stack { struct getter { static this_state get(lua_State* L, int, record& tracking) { tracking.use(0); - return this_state{L}; + return this_state( L ); + } + }; + + template <> + struct getter { + static this_main_state get(lua_State* L, int, record& tracking) { + tracking.use(0); + return this_main_state( main_thread(L, L) ); } }; @@ -8398,7 +8541,7 @@ namespace stack { }; template - struct pusher>, std::is_function>, std::is_base_of>, std::is_base_of>>::value>> { + struct pusher>, std::is_function>, is_lua_reference>>::value>> { template static int push(lua_State* L, Args&&... args) { return pusher>{}.push(L, std::forward(args)...); @@ -8576,7 +8719,7 @@ namespace stack { }; template - struct pusher::value || std::is_base_of::value>> { + struct pusher::value>> { static int push(lua_State* L, const T& ref) { return ref.push(L); } @@ -9113,6 +9256,13 @@ namespace stack { } }; + template <> + struct pusher { + static int push(lua_State*, const this_main_state&) { + return 0; + } + }; + template <> struct pusher { static int push(lua_State* L, const new_table& nt) { @@ -9534,7 +9684,7 @@ namespace sol { const static std::size_t data_t_count = (sizeof(TValue) + voidsizem1) / voidsize; typedef std::array data_t; - data_t data{{}}; + data_t data{ {} }; std::memcpy(&data[0], std::addressof(item), itemsize); int pushcount = 0; for (auto&& v : data) { @@ -9547,7 +9697,7 @@ namespace sol { inline std::pair get_as_upvalues(lua_State* L, int index = 2) { const static std::size_t data_t_count = (sizeof(T) + (sizeof(void*) - 1)) / sizeof(void*); typedef std::array data_t; - data_t voiddata{{}}; + data_t voiddata{ {} }; for (std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof(void*)) { voiddata[i] = get(L, upvalue_index(index++)); } @@ -9641,7 +9791,12 @@ namespace sol { template >::value>> inline int call_into_lua(types, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { decltype(auto) r = call(types>(), ta, L, start, std::forward(fx), std::forward(fxargs)...); - typedef is_stack_based> is_stack; + typedef meta::unqualified_t R; + typedef meta::any, + std::is_same, + std::is_same, + std::is_same> + is_stack; if (clean_stack && !is_stack::value) { lua_settop(L, 0); } @@ -11757,12 +11912,12 @@ namespace sol { } #endif // noexcept function type - template >, std::is_base_of>>> = meta::enabler> + template >> = meta::enabler> static void select(lua_State* L, Fx&& fx, Args&&... args) { select_function(std::is_function>>(), L, std::forward(fx), std::forward(args)...); } - template >, std::is_base_of>>> = meta::enabler> + template >> = meta::enabler> static void select(lua_State* L, Fx&& fx) { stack::push(L, std::forward(fx)); } @@ -11870,10 +12025,10 @@ namespace sol { template struct pusher, std::enable_if_t::value && !std::is_void::value>> { static int push(lua_State* L, property_wrapper&& pw) { - return stack::push(L, sol::overload(std::move(pw.read), std::move(pw.write))); + return stack::push(L, overload(std::move(pw.read), std::move(pw.write))); } static int push(lua_State* L, const property_wrapper& pw) { - return stack::push(L, sol::overload(pw.read, pw.write)); + return stack::push(L, overload(pw.read, pw.write)); } }; @@ -12254,7 +12409,7 @@ namespace sol { template struct protected_handler { - typedef std::is_base_of is_stack; + typedef is_stack_based is_stack; const target_t& target; int stackindex; @@ -12297,11 +12452,12 @@ namespace sol { template class basic_protected_function : public base_t { public: - typedef std::is_base_of is_stack_handler; + typedef is_stack_based 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); + L = is_main_threaded::value ? main_thread(L, L) : L; lua_getglobal(L, detail::default_handler_name()); auto pp = stack::pop_n(L, 1); return handler_t(L, -1); @@ -12312,13 +12468,14 @@ namespace sol { if (ref.lua_state() == nullptr) { return; } + lua_State* L = ref.lua_state(); if (!ref.valid()) { - lua_pushnil(ref.lua_state()); - lua_setglobal(ref.lua_state(), detail::default_handler_name()); + lua_pushnil(L); + lua_setglobal(L, detail::default_handler_name()); } else { ref.push(); - lua_setglobal(ref.lua_state(), detail::default_handler_name()); + lua_setglobal(L, detail::default_handler_name()); } } @@ -12451,11 +12608,11 @@ namespace sol { : basic_protected_function(detail::force_cast(p), std::forward(eh)) { } - template >, std::is_base_of>> = meta::enabler> + template >> = meta::enabler> basic_protected_function(lua_State* L, T&& r) : basic_protected_function(L, std::forward(r), get_default_handler(L)) { } - template >, std::is_base_of>> = meta::enabler> + template >> = meta::enabler> basic_protected_function(lua_State* L, T&& r, handler_t eh) : base_t(L, std::forward(r)), error_handler(std::move(eh)) { } @@ -12467,7 +12624,7 @@ namespace sol { : base_t(L, index), error_handler(std::move(eh)) { #ifdef SOL_CHECK_ARGUMENTS constructor_handler handler{}; - stack::check(L, index, handler); + stack::check(lua_state(), index, handler); #endif // Safety } basic_protected_function(lua_State* L, absolute_index index) @@ -12477,7 +12634,7 @@ namespace sol { : base_t(L, index), error_handler(std::move(eh)) { #ifdef SOL_CHECK_ARGUMENTS constructor_handler handler{}; - stack::check(L, index, handler); + stack::check(lua_state(), index, handler); #endif // Safety } basic_protected_function(lua_State* L, raw_index index) @@ -12487,7 +12644,7 @@ namespace sol { : base_t(L, index), error_handler(std::move(eh)) { #ifdef SOL_CHECK_ARGUMENTS constructor_handler handler{}; - stack::check(L, index, handler); + stack::check(lua_state(), index, handler); #endif // Safety } basic_protected_function(lua_State* L, ref_index index) @@ -12609,8 +12766,8 @@ namespace sol { template static std::function get_std_func(types, types, lua_State* L, int index) { - sol::function f(L, index); - auto fx = [ f, L, index ](Args && ... args) -> meta::return_type_t { + unsafe_function f(L, index); + auto fx = [ f = std::move(f), L, index ](Args && ... args) -> meta::return_type_t { return f.call(std::forward(args)...); }; return std::move(fx); @@ -12618,8 +12775,8 @@ namespace sol { template static std::function get_std_func(types, types, lua_State* L, int index) { - sol::function f(L, index); - auto fx = [f, L, index](FxArgs&&... args) -> void { + unsafe_function f(L, index); + auto fx = [f = std::move(f), L, index](FxArgs&&... args) -> void { f(std::forward(args)...); }; return std::move(fx); @@ -12696,12 +12853,12 @@ namespace sol { return *this; } - template >>, meta::is_callable>> = meta::enabler> + template >>, meta::is_callable>> = meta::enabler> proxy& operator=(U&& other) { return set_function(std::forward(other)); } - template >>, meta::is_callable>> = meta::enabler> + template >>, meta::is_callable>> = meta::enabler> proxy& operator=(U&& other) { return set(std::forward(other)); } @@ -12813,11 +12970,25 @@ namespace sol { return right.valid(); } + template + template + basic_reference& basic_reference::operator=(proxy_base&& r) { + *this = r.template operator basic_reference(); + return *this; + } + + template + template + basic_reference& basic_reference::operator=(const proxy_base& r) { + *this = r.template operator basic_reference(); + return *this; + } + namespace stack { template struct pusher> { static int push(lua_State* L, const proxy& p) { - sol::reference r = p; + reference r = p; return r.push(L); } }; @@ -12945,7 +13116,7 @@ namespace sol { basic_userdata(stack_reference&& r) : basic_userdata(r.lua_state(), r.stack_index()) { } - template >, std::is_base_of>> = meta::enabler> + template >> = meta::enabler> basic_userdata(lua_State* L, T&& r) : base_t(L, std::forward(r)) { } @@ -13452,7 +13623,7 @@ namespace sol { namespace sol { - template ::value, typename T> + template ::value, typename T> R make_reference(lua_State* L, T&& value) { int backpedal = stack::push(L, std::forward(value)); R r = stack::get(L, -backpedal); @@ -13462,7 +13633,7 @@ namespace sol { return r; } - template ::value, typename... Args> + template ::value, typename... Args> R make_reference(lua_State* L, Args&&... args) { int backpedal = stack::push(L, std::forward(args)...); R r = stack::get(L, -backpedal); @@ -13491,7 +13662,7 @@ namespace sol { basic_object(T&& r) : base_t(std::forward(r)) { } - template >, std::is_base_of>> = meta::enabler> + template >> = meta::enabler> basic_object(lua_State* L, T&& r) : base_t(L, std::forward(r)) { } @@ -13531,7 +13702,7 @@ namespace sol { } template basic_object(lua_State* L, in_place_type_t, Args&&... args) noexcept - : basic_object(std::integral_constant::value>(), L, -stack::push(L, std::forward(args)...)) { + : basic_object(std::integral_constant::value>(), L, -stack::push(L, std::forward(args)...)) { } template basic_object(lua_State* L, in_place_t, T&& arg, Args&&... args) noexcept @@ -14312,7 +14483,7 @@ namespace sol { } static void add_insert_after(std::false_type, lua_State* L, T&, stack_object) { - luaL_error(L, "cannot call 'add' on type '%s': no suitable insert/push_back C++ functions", sol::detail::demangle().data()); + luaL_error(L, "cannot call 'add' on type '%s': no suitable insert/push_back C++ functions", detail::demangle().data()); } static void add_insert_after(std::true_type, lua_State*, T& self, stack_object value, iterator& at) { @@ -14572,7 +14743,7 @@ namespace sol { auto& src = get_src(L); stack::push(L, next); stack::push>(L, src, deferred_traits::begin(L, src)); - stack::push(L, sol::lua_nil); + stack::push(L, lua_nil); return 3; } @@ -15166,7 +15337,7 @@ namespace sol { }; template - struct pusher>, meta::neg>, std::is_base_of>>>>::value>> { + struct pusher>, meta::neg>>>::value>> { typedef meta::unqualified_t C; static int push(lua_State* L, const T& cont) { @@ -15181,7 +15352,7 @@ namespace sol { }; template - struct pusher>, meta::neg>, std::is_base_of>>>>::value>> { + struct pusher>, meta::neg>>>::value>> { typedef std::add_pointer_t>> C; static int push(lua_State* L, T* cont) { @@ -15298,7 +15469,7 @@ namespace sol { template = meta::enabler> inline void make_reg_op(Regs& l, int& index, const char* name) { lua_CFunction f = &comparsion_operator_wrap; - l[index] = luaL_Reg{name, f}; + l[index] = luaL_Reg{ name, f }; ++index; } @@ -15311,7 +15482,7 @@ namespace sol { inline void make_to_string_op(Regs& l, int& index) { const char* name = to_string(meta_function::to_string).c_str(); lua_CFunction f = &detail::static_trampoline<&default_to_string>; - l[index] = luaL_Reg{name, f}; + l[index] = luaL_Reg{ name, f }; ++index; } @@ -15324,7 +15495,7 @@ namespace sol { inline void make_call_op(Regs& l, int& index) { const char* name = to_string(meta_function::call).c_str(); lua_CFunction f = &c_call; - l[index] = luaL_Reg{name, f}; + l[index] = luaL_Reg{ name, f }; ++index; } @@ -15336,7 +15507,7 @@ namespace sol { template > = meta::enabler> inline void make_length_op(Regs& l, int& index) { const char* name = to_string(meta_function::length).c_str(); - l[index] = luaL_Reg{name, &c_call}; + l[index] = luaL_Reg{ name, &c_call }; ++index; } @@ -15348,7 +15519,7 @@ namespace sol { template >, std::is_destructible>> void make_destructor(Regs& l, int& index) { const char* name = to_string(meta_function::garbage_collect).c_str(); - l[index] = luaL_Reg{name, is_unique_usertype::value ? &detail::unique_destruct : &detail::usertype_alloc_destruct}; + l[index] = luaL_Reg{ name, is_unique_usertype::value ? &detail::unique_destruct : &detail::usertype_alloc_destruct }; ++index; } @@ -15360,7 +15531,7 @@ namespace sol { // this won't trigger if the user performs `new_usertype` / `new_simple_usertype` and // rigs the class up properly const char* name = to_string(meta_function::garbage_collect).c_str(); - l[index] = luaL_Reg{name, &detail::cannot_destruct}; + l[index] = luaL_Reg{ name, &detail::cannot_destruct }; ++index; } } @@ -15381,7 +15552,7 @@ namespace sol { } if (fx(meta_function::pairs)) { const char* name = to_string(meta_function::pairs).c_str(); - l[index] = luaL_Reg{name, container_usertype_metatable>::pairs_call}; + l[index] = luaL_Reg{ name, container_usertype_metatable>::pairs_call }; ++index; } if (fx(meta_function::length)) { @@ -15396,8 +15567,7 @@ namespace sol { } } // namespace usertype_detail - namespace stack { - namespace stack_detail { + namespace stack { namespace stack_detail { template struct undefined_metatable { typedef meta::all>, std::is_destructible> is_destructible; @@ -15417,6 +15587,16 @@ namespace sol { usertype_detail::insert_default_registrations

(l, index, fx); usertype_detail::make_destructor(l, index); luaL_setfuncs(L, l, 0); + + // __type table + lua_createtable(L, 0, 2); + const std::string& name = detail::demangle(); + lua_pushlstring(L, name.c_str(), name.size()); + lua_setfield(L, -2, "name"); + lua_CFunction is_func = &usertype_detail::is_check; + lua_pushcclosure(L, is_func, 0); + lua_setfield(L, -2, "is"); + lua_setfield(L, -2, to_string(meta_function::type).c_str()); } lua_setmetatable(L, -2); } @@ -15642,10 +15822,10 @@ namespace sol { std::string& accessor = maybeaccessor.value(); auto preexistingit = functions.find(accessor); if (preexistingit == functions.cend()) { - functions.emplace_hint(preexistingit, std::move(accessor), sol::object(L, 3)); + functions.emplace_hint(preexistingit, std::move(accessor), object(L, 3)); } else { - preexistingit->second = sol::object(L, 3); + preexistingit->second = object(L, 3); } return; } @@ -15668,7 +15848,7 @@ namespace sol { } else { target = preexistingit->second.runtime_target; - runtime[target] = sol::object(L, 3); + runtime[target] = object(L, 3); preexistingit->second = call_information(&runtime_object_call, &runtime_new_index, target); } }; @@ -15858,7 +16038,7 @@ namespace sol { case meta_function::garbage_collect: if (destructfunc != nullptr) { #ifdef SOL_NO_EXCEPTIONS - throw sol::error("sol: 2 separate garbage_collect functions were set on this type. Please specify only 1 sol::meta_function::gc type AND wrap the function in a sol::destruct call, as shown by the documentation and examples"); + throw error("sol: 2 separate garbage_collect functions were set on this type. Please specify only 1 sol::meta_function::gc type AND wrap the function in a sol::destruct call, as shown by the documentation and examples"); #else assert(false && "sol: 2 separate garbage_collect functions were set on this type. Please specify only 1 sol::meta_function::gc type AND wrap the function in a sol::destruct call, as shown by the documentation and examples"); #endif @@ -16221,7 +16401,7 @@ namespace sol { } auto fit = functions.find(accessorkey); if (fit != functions.cend()) { - sol::object& func = fit->second; + object& func = fit->second; if (is_index) { return stack::push(L, func); } @@ -16669,7 +16849,7 @@ namespace sol { stack_reference metabehind(L, -1); stack::set_field(L, meta_function::type, type_table, metabehind.stack_index()); if (umx.callconstructfunc.valid()) { - stack::set_field(L, sol::meta_function::call_function, umx.callconstructfunc, metabehind.stack_index()); + stack::set_field(L, meta_function::call_function, umx.callconstructfunc, metabehind.stack_index()); } if (umx.secondarymeta) { stack::set_field(L, meta_function::index, @@ -16704,7 +16884,7 @@ namespace sol { stack_reference metabehind(L, -1); stack::set_field(L, meta_function::type, type_table, metabehind.stack_index()); if (umx.callconstructfunc.valid()) { - stack::set_field(L, sol::meta_function::call_function, umx.callconstructfunc, metabehind.stack_index()); + stack::set_field(L, meta_function::call_function, umx.callconstructfunc, metabehind.stack_index()); } // use indexing function stack::set_field(L, meta_function::index, @@ -16965,9 +17145,9 @@ namespace sol { auto pp = stack::push_pop(*this); stack::push(base_t::lua_state(), lua_nil); while (lua_next(base_t::lua_state(), -2)) { - sol::object key(base_t::lua_state(), -2); - sol::object value(base_t::lua_state(), -1); - std::pair keyvalue(key, value); + object key(base_t::lua_state(), -2); + object value(base_t::lua_state(), -1); + std::pair keyvalue(key, value); auto pn = stack::pop_n(base_t::lua_state(), 1); fx(keyvalue); } @@ -16978,8 +17158,8 @@ namespace sol { auto pp = stack::push_pop(*this); stack::push(base_t::lua_state(), lua_nil); while (lua_next(base_t::lua_state(), -2)) { - sol::object key(base_t::lua_state(), -2); - sol::object value(base_t::lua_state(), -1); + object key(base_t::lua_state(), -2); + object value(base_t::lua_state(), -1); auto pn = stack::pop_n(base_t::lua_state(), 1); fx(key, value); } @@ -17096,13 +17276,13 @@ namespace sol { basic_table_core(stack_reference&& r) : basic_table_core(r.lua_state(), r.stack_index()) { } - template >, std::is_base_of>> = meta::enabler> + template >> = meta::enabler> basic_table_core(lua_State* L, T&& r) : basic_table_core(L, std::forward(r)) { } basic_table_core(lua_State* L, new_table nt) : base_t(L, (lua_createtable(L, nt.sequence_hint, nt.map_hint), -1)) { - if (!std::is_base_of::value) { + if (!is_stack_based>::value) { lua_pop(L, 1); } } @@ -17346,7 +17526,7 @@ namespace sol { template void for_each(Fx&& fx) const { - typedef meta::is_invokable)> is_paired; + typedef meta::is_invokable)> is_paired; for_each(is_paired(), std::forward(fx)); } @@ -17523,10 +17703,11 @@ namespace sol { basic_environment(lua_State* L, new_table nt) : base_t(L, std::move(nt)) { } - basic_environment(lua_State* L, new_table t, const reference& fallback) + template + basic_environment(lua_State* L, new_table t, const basic_reference& fallback) : basic_environment(L, std::move(t)) { - sol::stack_table mt(L, sol::new_table(0, 1)); - mt.set(sol::meta_function::index, fallback); + stack_table mt(L, new_table(0, 1)); + mt.set(meta_function::index, fallback); this->set(metatable_key, mt); mt.pop(); } @@ -17539,7 +17720,8 @@ namespace sol { #endif // Safety lua_pop(this->lua_state(), 2); } - basic_environment(env_t, const reference& extraction_target) + template + basic_environment(env_t, const basic_reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { #ifdef SOL_CHECK_ARGUMENTS constructor_handler handler{}; @@ -17611,7 +17793,7 @@ namespace sol { this_environment() : env(nullopt) { } - this_environment(sol::environment e) + this_environment(environment e) : env(std::move(e)) { } this_environment(const this_environment&) = default; @@ -17668,8 +17850,8 @@ namespace sol { return this_environment(); } - sol::stack_reference f(L, -1); - sol::environment env(sol::env_key, f); + stack_reference f(L, -1); + environment env(env_key, f); if (!env.valid()) { lua_settop(L, pre_stack_size); return this_environment(); @@ -17839,7 +18021,7 @@ namespace sol { return kb; } - inline protected_function_result script_pass_on_error(lua_State*, sol::protected_function_result result) { + inline protected_function_result script_pass_on_error(lua_State*, protected_function_result result) { return result; } @@ -18149,7 +18331,7 @@ namespace sol { } 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) { + function_result unsafe_script(const string_view& code, const basic_environment& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { detail::typical_chunk_name_t basechunkname = {}; const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); int index = lua_gettop(L); @@ -18174,7 +18356,7 @@ namespace sol { } template - function_result unsafe_script_file(const std::string& filename, const sol::basic_environment& env, load_mode mode = load_mode::any) { + function_result unsafe_script_file(const std::string& filename, const 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); @@ -18501,6 +18683,10 @@ namespace sol { struct lua_thread_state { lua_State* L; + lua_thread_state(lua_State* Ls) + : L(Ls) { + } + lua_State* lua_state() const noexcept { return L; } @@ -18525,7 +18711,7 @@ namespace sol { struct getter { lua_thread_state get(lua_State* L, int index, record& tracking) { tracking.use(1); - lua_thread_state lts{lua_tothread(L, index)}; + lua_thread_state lts( lua_tothread(L, index) ); return lts; } }; @@ -18534,8 +18720,8 @@ namespace sol { struct check_getter { template optional get(lua_State* L, int index, Handler&& handler, record& tracking) { - lua_thread_state lts{lua_tothread(L, index)}; - if (lts.L == nullptr) { + lua_thread_state lts( lua_tothread(L, index) ); + if (lts.lua_state() == nullptr) { handler(L, index, type::thread, type_of(L, index), "value is not a valid thread type"); return nullopt; } @@ -18559,50 +18745,59 @@ namespace sol { } } // namespace stack - class thread : public reference { + template + class basic_thread : public base_t { public: - thread() noexcept = default; - thread(const thread&) = default; - thread(thread&&) = default; - template , thread>>, std::is_base_of>> = meta::enabler> - thread(T&& r) - : reference(std::forward(r)) { + using base_t::lua_state; + + basic_thread() noexcept = default; + basic_thread(const basic_thread&) = default; + basic_thread(basic_thread&&) = default; + template , basic_thread>>, std::is_base_of>> = meta::enabler> + basic_thread(T&& r) + : base_t(std::forward(r)) { } - thread(const stack_reference& r) - : thread(r.lua_state(), r.stack_index()){}; - thread(stack_reference&& r) - : thread(r.lua_state(), r.stack_index()){}; - thread& operator=(const thread&) = default; - thread& operator=(thread&&) = default; - template >>, meta::neg>> = meta::enabler> - thread(lua_State* L, T&& r) - : thread(L, sol::ref_index(r.registry_index())) { + basic_thread(const stack_reference& r) + : basic_thread(r.lua_state(), r.stack_index()){}; + basic_thread(stack_reference&& r) + : basic_thread(r.lua_state(), r.stack_index()){}; + basic_thread& operator=(const basic_thread&) = default; + basic_thread& operator=(basic_thread&&) = default; + template >>> = meta::enabler> + basic_thread(lua_State* L, T&& r) + : basic_thread(L, std::forward(r)) { } - thread(lua_State* L, int index = -1) - : reference(L, index) { -#ifdef SOL_CHECK_ARGUMENTS - type_assert(L, index, type::thread); -#endif // Safety - } - thread(lua_State* L, ref_index index) - : reference(L, index) { + basic_thread(lua_State* L, int index = -1) + : base_t(L, index) { #ifdef SOL_CHECK_ARGUMENTS auto pp = stack::push_pop(*this); - type_assert(L, -1, type::thread); + constructor_handler handler{}; + stack::check(lua_state(), -1, handler); #endif // Safety } - thread(lua_State* L, lua_State* actualthread) - : thread(L, lua_thread_state{actualthread}) { - } - thread(lua_State* L, sol::this_state actualthread) - : thread(L, lua_thread_state{actualthread.L}) { - } - thread(lua_State* L, lua_thread_state actualthread) - : reference(L, -stack::push(L, actualthread)) { + basic_thread(lua_State* L, ref_index index) + : base_t(L, index) { #ifdef SOL_CHECK_ARGUMENTS - type_assert(L, -1, type::thread); + auto pp = stack::push_pop(*this); + constructor_handler handler{}; + stack::check(lua_state(), -1, handler); #endif // Safety - lua_pop(L, 1); + } + basic_thread(lua_State* L, lua_State* actualthread) + : basic_thread(L, lua_thread_state{ actualthread }) { + } + basic_thread(lua_State* L, this_state actualthread) + : basic_thread(L, lua_thread_state{ actualthread.L }) { + } + basic_thread(lua_State* L, lua_thread_state actualthread) + : base_t(L, -stack::push(L, actualthread)) { +#ifdef SOL_CHECK_ARGUMENTS + constructor_handler handler{}; + stack::check(lua_state(), -1, handler); +#endif // Safety + if (!is_stack_based::value) { + lua_pop(lua_state(), 1); + } } state_view state() const { @@ -18625,23 +18820,28 @@ namespace sol { lua_State* lthread = thread_state(); thread_status lstat = static_cast(lua_status(lthread)); if (lstat != thread_status::ok && lua_gettop(lthread) == 0) { - // No thing on the thread's stack means its dead + // No thing on the basic_thread's stack means its dead return thread_status::dead; } return lstat; } - thread create() { + basic_thread create() { return create(lua_state()); } - static thread create(lua_State* L) { + static basic_thread create(lua_State* L) { lua_newthread(L); - thread result(L); - lua_pop(L, 1); + basic_thread result(L); + if (!is_stack_based::value) { + lua_pop(L, 1); + } return result; } }; + + typedef basic_thread thread; + typedef basic_thread stack_thread; } // namespace sol // end of sol/thread.hpp @@ -18693,7 +18893,7 @@ namespace sol { : unique_base(luaL_newstate(), lua_close), state_view(unique_base::get()) { set_panic(panic); lua_CFunction f = c_call; - protected_function::set_default_handler(sol::object(lua_state(), in_place, f)); + protected_function::set_default_handler(object(lua_state(), in_place, f)); stack::register_main_thread(unique_base::get()); stack::luajit_exception_handler(unique_base::get()); } @@ -18702,7 +18902,7 @@ namespace sol { : unique_base(lua_newstate(alfunc, alpointer), lua_close), state_view(unique_base::get()) { set_panic(panic); lua_CFunction f = c_call; - protected_function::set_default_handler(sol::object(lua_state(), in_place, f)); + protected_function::set_default_handler(object(lua_state(), in_place, f)); stack::register_main_thread(unique_base::get()); stack::luajit_exception_handler(unique_base::get()); } @@ -18728,7 +18928,8 @@ namespace sol { // beginning of sol/coroutine.hpp namespace sol { - class coroutine : public reference { + template + class basic_coroutine : public base_t { private: call_status stats = call_status::yielded; @@ -18766,41 +18967,43 @@ namespace sol { } public: - coroutine() noexcept = default; - coroutine(const coroutine&) noexcept = default; - coroutine(coroutine&&) noexcept = default; - coroutine& operator=(const coroutine&) noexcept = default; - coroutine& operator=(coroutine&&) noexcept = default; - template , coroutine>>, std::is_base_of>> = meta::enabler> - coroutine(T&& r) - : reference(std::forward(r)) { + using base_t::lua_state; + + basic_coroutine() noexcept = default; + basic_coroutine(const basic_coroutine&) noexcept = default; + basic_coroutine(basic_coroutine&&) noexcept = default; + basic_coroutine& operator=(const basic_coroutine&) noexcept = default; + basic_coroutine& operator=(basic_coroutine&&) noexcept = default; + template , basic_coroutine>>, is_lua_reference>> = meta::enabler> + basic_coroutine(T&& r) + : base_t(std::forward(r)) { } - coroutine(lua_nil_t r) - : reference(r) { + basic_coroutine(lua_nil_t r) + : base_t(r) { } - coroutine(const stack_reference& r) noexcept - : coroutine(r.lua_state(), r.stack_index()) { + basic_coroutine(const stack_reference& r) noexcept + : basic_coroutine(r.lua_state(), r.stack_index()) { } - coroutine(stack_reference&& r) noexcept - : coroutine(r.lua_state(), r.stack_index()) { + basic_coroutine(stack_reference&& r) noexcept + : basic_coroutine(r.lua_state(), r.stack_index()) { } - template >>, meta::neg>> = meta::enabler> - coroutine(lua_State* L, T&& r) - : coroutine(L, sol::ref_index(r.registry_index())) { + template >>> = meta::enabler> + basic_coroutine(lua_State* L, T&& r) + : base_t(L, std::forward(r)) { } - coroutine(lua_State* L, int index = -1) - : reference(L, index) { + basic_coroutine(lua_State* L, int index = -1) + : base_t(L, index) { #ifdef SOL_CHECK_ARGUMENTS constructor_handler handler{}; - stack::check(L, index, handler); + stack::check(lua_state(), index, handler); #endif // Safety } - coroutine(lua_State* L, ref_index index) - : reference(L, index) { + basic_coroutine(lua_State* L, ref_index index) + : base_t(L, index) { #ifdef SOL_CHECK_ARGUMENTS auto pp = stack::push_pop(*this); constructor_handler handler{}; - stack::check(L, -1, handler); + stack::check(lua_state(), -1, handler); #endif // Safety } @@ -18814,7 +19017,7 @@ namespace sol { } bool runnable() const noexcept { - return valid() + return base_t::valid() && (status() == call_status::yielded); } @@ -18834,8 +19037,8 @@ namespace sol { template decltype(auto) call(Args&&... args) { - push(); - int pushcount = stack::multi_push(lua_state(), std::forward(args)...); + base_t::push(); + int pushcount = stack::multi_push_reference(lua_state(), std::forward(args)...); return invoke(types(), std::make_index_sequence(), pushcount); } }; diff --git a/sol/container_traits.hpp b/sol/container_traits.hpp index 5a0e5c0a..398f046b 100644 --- a/sol/container_traits.hpp +++ b/sol/container_traits.hpp @@ -760,7 +760,7 @@ namespace sol { } static void add_insert_after(std::false_type, lua_State* L, T&, stack_object) { - luaL_error(L, "cannot call 'add' on type '%s': no suitable insert/push_back C++ functions", sol::detail::demangle().data()); + luaL_error(L, "cannot call 'add' on type '%s': no suitable insert/push_back C++ functions", detail::demangle().data()); } static void add_insert_after(std::true_type, lua_State*, T& self, stack_object value, iterator& at) { @@ -1020,7 +1020,7 @@ namespace sol { auto& src = get_src(L); stack::push(L, next); stack::push>(L, src, deferred_traits::begin(L, src)); - stack::push(L, sol::lua_nil); + stack::push(L, lua_nil); return 3; } diff --git a/sol/container_usertype_metatable.hpp b/sol/container_usertype_metatable.hpp index 97fe3d88..2c8288ca 100644 --- a/sol/container_usertype_metatable.hpp +++ b/sol/container_usertype_metatable.hpp @@ -346,7 +346,7 @@ namespace sol { }; template - struct pusher>, meta::neg>, std::is_base_of>>>>::value>> { + struct pusher>, meta::neg>>>::value>> { typedef meta::unqualified_t C; static int push(lua_State* L, const T& cont) { @@ -361,7 +361,7 @@ namespace sol { }; template - struct pusher>, meta::neg>, std::is_base_of>>>>::value>> { + struct pusher>, meta::neg>>>::value>> { typedef std::add_pointer_t>> C; static int push(lua_State* L, T* cont) { diff --git a/sol/coroutine.hpp b/sol/coroutine.hpp index 818257a0..79df5fd1 100644 --- a/sol/coroutine.hpp +++ b/sol/coroutine.hpp @@ -28,7 +28,8 @@ #include "thread.hpp" namespace sol { - class coroutine : public reference { + template + class basic_coroutine : public base_t { private: call_status stats = call_status::yielded; @@ -66,41 +67,43 @@ namespace sol { } public: - coroutine() noexcept = default; - coroutine(const coroutine&) noexcept = default; - coroutine(coroutine&&) noexcept = default; - coroutine& operator=(const coroutine&) noexcept = default; - coroutine& operator=(coroutine&&) noexcept = default; - template , coroutine>>, std::is_base_of>> = meta::enabler> - coroutine(T&& r) - : reference(std::forward(r)) { + using base_t::lua_state; + + basic_coroutine() noexcept = default; + basic_coroutine(const basic_coroutine&) noexcept = default; + basic_coroutine(basic_coroutine&&) noexcept = default; + basic_coroutine& operator=(const basic_coroutine&) noexcept = default; + basic_coroutine& operator=(basic_coroutine&&) noexcept = default; + template , basic_coroutine>>, is_lua_reference>> = meta::enabler> + basic_coroutine(T&& r) + : base_t(std::forward(r)) { } - coroutine(lua_nil_t r) - : reference(r) { + basic_coroutine(lua_nil_t r) + : base_t(r) { } - coroutine(const stack_reference& r) noexcept - : coroutine(r.lua_state(), r.stack_index()) { + basic_coroutine(const stack_reference& r) noexcept + : basic_coroutine(r.lua_state(), r.stack_index()) { } - coroutine(stack_reference&& r) noexcept - : coroutine(r.lua_state(), r.stack_index()) { + basic_coroutine(stack_reference&& r) noexcept + : basic_coroutine(r.lua_state(), r.stack_index()) { } - template >>, meta::neg>> = meta::enabler> - coroutine(lua_State* L, T&& r) - : coroutine(L, sol::ref_index(r.registry_index())) { + template >>> = meta::enabler> + basic_coroutine(lua_State* L, T&& r) + : base_t(L, std::forward(r)) { } - coroutine(lua_State* L, int index = -1) - : reference(L, index) { + basic_coroutine(lua_State* L, int index = -1) + : base_t(L, index) { #ifdef SOL_CHECK_ARGUMENTS constructor_handler handler{}; - stack::check(L, index, handler); + stack::check(lua_state(), index, handler); #endif // Safety } - coroutine(lua_State* L, ref_index index) - : reference(L, index) { + basic_coroutine(lua_State* L, ref_index index) + : base_t(L, index) { #ifdef SOL_CHECK_ARGUMENTS auto pp = stack::push_pop(*this); constructor_handler handler{}; - stack::check(L, -1, handler); + stack::check(lua_state(), -1, handler); #endif // Safety } @@ -114,7 +117,7 @@ namespace sol { } bool runnable() const noexcept { - return valid() + return base_t::valid() && (status() == call_status::yielded); } @@ -134,8 +137,8 @@ namespace sol { template decltype(auto) call(Args&&... args) { - push(); - int pushcount = stack::multi_push(lua_state(), std::forward(args)...); + base_t::push(); + int pushcount = stack::multi_push_reference(lua_state(), std::forward(args)...); return invoke(types(), std::make_index_sequence(), pushcount); } }; diff --git a/sol/environment.hpp b/sol/environment.hpp index a55c7942..6f24e5e4 100644 --- a/sol/environment.hpp +++ b/sol/environment.hpp @@ -49,10 +49,11 @@ namespace sol { basic_environment(lua_State* L, new_table nt) : base_t(L, std::move(nt)) { } - basic_environment(lua_State* L, new_table t, const reference& fallback) + template + basic_environment(lua_State* L, new_table t, const basic_reference& fallback) : basic_environment(L, std::move(t)) { - sol::stack_table mt(L, sol::new_table(0, 1)); - mt.set(sol::meta_function::index, fallback); + stack_table mt(L, new_table(0, 1)); + mt.set(meta_function::index, fallback); this->set(metatable_key, mt); mt.pop(); } @@ -65,7 +66,8 @@ namespace sol { #endif // Safety lua_pop(this->lua_state(), 2); } - basic_environment(env_t, const reference& extraction_target) + template + basic_environment(env_t, const basic_reference& extraction_target) : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { #ifdef SOL_CHECK_ARGUMENTS constructor_handler handler{}; @@ -137,7 +139,7 @@ namespace sol { this_environment() : env(nullopt) { } - this_environment(sol::environment e) + this_environment(environment e) : env(std::move(e)) { } this_environment(const this_environment&) = default; @@ -194,8 +196,8 @@ namespace sol { return this_environment(); } - sol::stack_reference f(L, -1); - sol::environment env(sol::env_key, f); + stack_reference f(L, -1); + environment env(env_key, f); if (!env.valid()) { lua_settop(L, pre_stack_size); return this_environment(); diff --git a/sol/forward.hpp b/sol/forward.hpp index 741edf9d..95d63a4e 100644 --- a/sol/forward.hpp +++ b/sol/forward.hpp @@ -26,11 +26,18 @@ namespace sol { - class reference; + template + class basic_reference; + using reference = basic_reference; + using main_reference = basic_reference; class stack_reference; + struct proxy_base_tag; + template + struct proxy_base; template struct proxy; + template class usertype; template @@ -40,16 +47,21 @@ namespace sol { template using table_core = basic_table_core; template + using main_table_core = basic_table_core; + template 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; template struct basic_environment; using environment = basic_environment; + using main_environment = basic_environment; using stack_environment = basic_environment; template class basic_function; @@ -57,6 +69,8 @@ namespace sol { class basic_protected_function; using unsafe_function = basic_function; using safe_function = basic_protected_function; + using main_unsafe_function = basic_function; + using main_safe_function = basic_protected_function; using stack_unsafe_function = basic_function; using stack_safe_function = basic_protected_function; using stack_aligned_unsafe_function = basic_function; @@ -66,10 +80,12 @@ namespace sol { using stack_aligned_protected_function = stack_aligned_safe_function; #ifdef SOL_SAFE_FUNCTIONS using function = protected_function; + using main_function = main_protected_function; using stack_function = stack_protected_function; using stack_aligned_function = stack_aligned_safe_function; #else using function = unsafe_function; + using main_function = main_unsafe_function; using stack_function = stack_unsafe_function; using stack_aligned_function = stack_aligned_unsafe_function; #endif @@ -79,25 +95,39 @@ namespace sol { struct protected_function_result; using safe_function_result = protected_function_result; using unsafe_function_result = function_result; + template class basic_object; template class basic_userdata; template class basic_lightuserdata; + template + class basic_coroutine; + template + class basic_thread; + using object = basic_object; - using stack_object = basic_object; using userdata = basic_userdata; - using stack_userdata = basic_userdata; using lightuserdata = basic_lightuserdata; + using thread = basic_thread; + using coroutine = basic_coroutine; + using main_object = basic_object; + using main_userdata = basic_userdata; + using main_lightuserdata = basic_lightuserdata; + using stack_object = basic_object; + using stack_userdata = basic_userdata; using stack_lightuserdata = basic_lightuserdata; - class coroutine; - class thread; + using stack_thread = basic_thread; + using stack_coroutine = basic_coroutine; + struct variadic_args; struct variadic_results; struct stack_count; struct this_state; + struct this_main_state; struct this_environment; + template struct as_table_t; template diff --git a/sol/function.hpp b/sol/function.hpp index 71f8e6b0..d5143467 100644 --- a/sol/function.hpp +++ b/sol/function.hpp @@ -77,8 +77,8 @@ namespace sol { template static std::function get_std_func(types, types, lua_State* L, int index) { - sol::function f(L, index); - auto fx = [ f, L, index ](Args && ... args) -> meta::return_type_t { + unsafe_function f(L, index); + auto fx = [ f = std::move(f), L, index ](Args && ... args) -> meta::return_type_t { return f.call(std::forward(args)...); }; return std::move(fx); @@ -86,8 +86,8 @@ namespace sol { template static std::function get_std_func(types, types, lua_State* L, int index) { - sol::function f(L, index); - auto fx = [f, L, index](FxArgs&&... args) -> void { + unsafe_function f(L, index); + auto fx = [f = std::move(f), L, index](FxArgs&&... args) -> void { f(std::forward(args)...); }; return std::move(fx); diff --git a/sol/function_types.hpp b/sol/function_types.hpp index 515097bb..b1767e5d 100644 --- a/sol/function_types.hpp +++ b/sol/function_types.hpp @@ -196,12 +196,12 @@ namespace sol { } #endif // noexcept function type - template >, std::is_base_of>>> = meta::enabler> + template >> = meta::enabler> static void select(lua_State* L, Fx&& fx, Args&&... args) { select_function(std::is_function>>(), L, std::forward(fx), std::forward(args)...); } - template >, std::is_base_of>>> = meta::enabler> + template >> = meta::enabler> static void select(lua_State* L, Fx&& fx) { stack::push(L, std::forward(fx)); } @@ -309,10 +309,10 @@ namespace sol { template struct pusher, std::enable_if_t::value && !std::is_void::value>> { static int push(lua_State* L, property_wrapper&& pw) { - return stack::push(L, sol::overload(std::move(pw.read), std::move(pw.write))); + return stack::push(L, overload(std::move(pw.read), std::move(pw.write))); } static int push(lua_State* L, const property_wrapper& pw) { - return stack::push(L, sol::overload(pw.read, pw.write)); + return stack::push(L, overload(pw.read, pw.write)); } }; diff --git a/sol/object.hpp b/sol/object.hpp index ee68775c..39dc0fde 100644 --- a/sol/object.hpp +++ b/sol/object.hpp @@ -32,7 +32,7 @@ namespace sol { - template ::value, typename T> + template ::value, typename T> R make_reference(lua_State* L, T&& value) { int backpedal = stack::push(L, std::forward(value)); R r = stack::get(L, -backpedal); @@ -42,7 +42,7 @@ namespace sol { return r; } - template ::value, typename... Args> + template ::value, typename... Args> R make_reference(lua_State* L, Args&&... args) { int backpedal = stack::push(L, std::forward(args)...); R r = stack::get(L, -backpedal); @@ -71,7 +71,7 @@ namespace sol { basic_object(T&& r) : base_t(std::forward(r)) { } - template >, std::is_base_of>> = meta::enabler> + template >> = meta::enabler> basic_object(lua_State* L, T&& r) : base_t(L, std::forward(r)) { } @@ -111,7 +111,7 @@ namespace sol { } template basic_object(lua_State* L, in_place_type_t, Args&&... args) noexcept - : basic_object(std::integral_constant::value>(), L, -stack::push(L, std::forward(args)...)) { + : basic_object(std::integral_constant::value>(), L, -stack::push(L, std::forward(args)...)) { } template basic_object(lua_State* L, in_place_t, T&& arg, Args&&... args) noexcept diff --git a/sol/protected_function.hpp b/sol/protected_function.hpp index a79aa737..9006bbd7 100644 --- a/sol/protected_function.hpp +++ b/sol/protected_function.hpp @@ -38,7 +38,7 @@ namespace sol { template struct protected_handler { - typedef std::is_base_of is_stack; + typedef is_stack_based is_stack; const target_t& target; int stackindex; @@ -81,11 +81,12 @@ namespace sol { template class basic_protected_function : public base_t { public: - typedef std::is_base_of is_stack_handler; + typedef is_stack_based 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); + L = is_main_threaded::value ? main_thread(L, L) : L; lua_getglobal(L, detail::default_handler_name()); auto pp = stack::pop_n(L, 1); return handler_t(L, -1); @@ -96,13 +97,14 @@ namespace sol { if (ref.lua_state() == nullptr) { return; } + lua_State* L = ref.lua_state(); if (!ref.valid()) { - lua_pushnil(ref.lua_state()); - lua_setglobal(ref.lua_state(), detail::default_handler_name()); + lua_pushnil(L); + lua_setglobal(L, detail::default_handler_name()); } else { ref.push(); - lua_setglobal(ref.lua_state(), detail::default_handler_name()); + lua_setglobal(L, detail::default_handler_name()); } } @@ -235,11 +237,11 @@ namespace sol { : basic_protected_function(detail::force_cast(p), std::forward(eh)) { } - template >, std::is_base_of>> = meta::enabler> + template >> = meta::enabler> basic_protected_function(lua_State* L, T&& r) : basic_protected_function(L, std::forward(r), get_default_handler(L)) { } - template >, std::is_base_of>> = meta::enabler> + template >> = meta::enabler> basic_protected_function(lua_State* L, T&& r, handler_t eh) : base_t(L, std::forward(r)), error_handler(std::move(eh)) { } @@ -251,7 +253,7 @@ namespace sol { : base_t(L, index), error_handler(std::move(eh)) { #ifdef SOL_CHECK_ARGUMENTS constructor_handler handler{}; - stack::check(L, index, handler); + stack::check(lua_state(), index, handler); #endif // Safety } basic_protected_function(lua_State* L, absolute_index index) @@ -261,7 +263,7 @@ namespace sol { : base_t(L, index), error_handler(std::move(eh)) { #ifdef SOL_CHECK_ARGUMENTS constructor_handler handler{}; - stack::check(L, index, handler); + stack::check(lua_state(), index, handler); #endif // Safety } basic_protected_function(lua_State* L, raw_index index) @@ -271,7 +273,7 @@ namespace sol { : base_t(L, index), error_handler(std::move(eh)) { #ifdef SOL_CHECK_ARGUMENTS constructor_handler handler{}; - stack::check(L, index, handler); + stack::check(lua_state(), index, handler); #endif // Safety } basic_protected_function(lua_State* L, ref_index index) diff --git a/sol/proxy.hpp b/sol/proxy.hpp index 3e29d68a..91905c2a 100644 --- a/sol/proxy.hpp +++ b/sol/proxy.hpp @@ -77,12 +77,12 @@ namespace sol { return *this; } - template >>, meta::is_callable>> = meta::enabler> + template >>, meta::is_callable>> = meta::enabler> proxy& operator=(U&& other) { return set_function(std::forward(other)); } - template >>, meta::is_callable>> = meta::enabler> + template >>, meta::is_callable>> = meta::enabler> proxy& operator=(U&& other) { return set(std::forward(other)); } @@ -194,11 +194,25 @@ namespace sol { return right.valid(); } + template + template + basic_reference& basic_reference::operator=(proxy_base&& r) { + *this = r.template operator basic_reference(); + return *this; + } + + template + template + basic_reference& basic_reference::operator=(const proxy_base& r) { + *this = r.template operator basic_reference(); + return *this; + } + namespace stack { template struct pusher> { static int push(lua_State* L, const proxy& p) { - sol::reference r = p; + reference r = p; return r.push(L); } }; diff --git a/sol/reference.hpp b/sol/reference.hpp index 7b85d24a..bccf0e9a 100644 --- a/sol/reference.hpp +++ b/sol/reference.hpp @@ -152,10 +152,23 @@ namespace sol { } const global_{}; struct no_safety_tag { } const no_safety{}; + + template + inline lua_State* pick_main_thread(lua_State* L, lua_State* backup_if_unsupported = nullptr) { + (void)L; + (void)backup_if_unsupported; + if (b) { + return main_thread(L, backup_if_unsupported); + } + return L; + } } // namespace detail - class reference { + template + class basic_reference { private: + template + friend class basic_reference; lua_State* luastate = nullptr; // non-owning int ref = LUA_NOREF; @@ -166,9 +179,58 @@ namespace sol { return luaL_ref(lua_state(), LUA_REGISTRYINDEX); } + template + void copy_assign(const basic_reference& r) { + if (valid()) { + deref(); + } + if (r.ref == LUA_REFNIL) { + luastate = detail::pick_main_thread < main_only && !r_main_only >(r.lua_state(), r.lua_state()); + ref = LUA_REFNIL; + return; + } + if (r.ref == LUA_NOREF) { + ref = LUA_NOREF; + return; + } + if (detail::xmovable(lua_state(), r.lua_state())) { + r.push(lua_state()); + ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); + return; + } + luastate = detail::pick_main_thread < main_only && !r_main_only >(r.lua_state(), r.lua_state()); + ref = r.copy(); + } + + template + void move_assign(basic_reference&& r) { + if (valid()) { + deref(); + } + if (r.ref == LUA_REFNIL) { + luastate = detail::pick_main_thread(r.lua_state(), r.lua_state()); + ref = LUA_REFNIL; + return; + } + if (r.ref == LUA_NOREF) { + ref = LUA_NOREF; + return; + } + if (detail::xmovable(lua_state(), r.lua_state())) { + r.push(lua_state()); + ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); + return; + } + + luastate = detail::pick_main_thread < main_only && !r_main_only >(r.lua_state(), r.lua_state()); + ref = r.ref; + r.ref = LUA_NOREF; + r.luastate = nullptr; + } + protected: - reference(lua_State* L, detail::global_tag) noexcept - : luastate(L) { + basic_reference(lua_State* L, detail::global_tag) noexcept + : luastate(detail::pick_main_thread(L, L)) { lua_pushglobaltable(lua_state()); ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); } @@ -182,18 +244,19 @@ namespace sol { } public: - reference() noexcept = default; - reference(lua_nil_t) noexcept - : reference() { + basic_reference() noexcept = default; + basic_reference(lua_nil_t) noexcept + : basic_reference() { } - reference(const stack_reference& r) noexcept - : reference(r.lua_state(), r.stack_index()) { + basic_reference(const stack_reference& r) noexcept + : basic_reference(r.lua_state(), r.stack_index()) { } - reference(stack_reference&& r) noexcept - : reference(r.lua_state(), r.stack_index()) { + basic_reference(stack_reference&& r) noexcept + : basic_reference(r.lua_state(), r.stack_index()) { } - reference(lua_State* L, const reference& r) noexcept - : luastate(L) { + template + basic_reference(lua_State* L, const basic_reference& r) noexcept + : luastate(detail::pick_main_thread(L, L)) { if (r.ref == LUA_REFNIL) { ref = LUA_REFNIL; return; @@ -209,8 +272,10 @@ namespace sol { } ref = r.copy(); } - reference(lua_State* L, reference&& r) noexcept - : luastate(L) { + + template + basic_reference(lua_State* L, basic_reference&& r) noexcept + : luastate(detail::pick_main_thread(L, L)) { if (r.ref == LUA_REFNIL) { ref = LUA_REFNIL; return; @@ -228,8 +293,9 @@ namespace sol { r.ref = LUA_NOREF; r.luastate = nullptr; } - reference(lua_State* L, const stack_reference& r) noexcept - : luastate(L) { + + basic_reference(lua_State* L, const stack_reference& r) noexcept + : luastate(detail::pick_main_thread(L, L)) { if (lua_state() == nullptr || r.lua_state() == nullptr || r.get_type() == type::none) { ref = LUA_NOREF; return; @@ -244,83 +310,72 @@ namespace sol { r.push(lua_state()); ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); } - reference(lua_State* L, int index = -1) noexcept - : luastate(L) { + basic_reference(lua_State* L, int index = -1) noexcept + : luastate(detail::pick_main_thread(L, L)) { lua_pushvalue(lua_state(), index); ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); } - reference(lua_State* L, ref_index index) noexcept - : luastate(L) { - lua_rawgeti(L, LUA_REGISTRYINDEX, index.index); + basic_reference(lua_State* L, ref_index index) noexcept + : luastate(detail::pick_main_thread(L, L)) { + lua_rawgeti(lua_state(), LUA_REGISTRYINDEX, index.index); ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); } - reference(lua_State* L, lua_nil_t) noexcept - : luastate(L) { + basic_reference(lua_State* L, lua_nil_t) noexcept + : luastate(detail::pick_main_thread(L, L)) { } - ~reference() noexcept { + ~basic_reference() noexcept { + if (lua_state() == nullptr || ref == LUA_NOREF) + return; deref(); } - reference(const reference& o) noexcept - : luastate(o.luastate), ref(o.copy()) { + basic_reference(const basic_reference& o) noexcept + : luastate(o.lua_state()), ref(o.copy()) { } - reference(reference&& o) noexcept - : luastate(o.luastate), ref(o.ref) { + basic_reference(basic_reference&& o) noexcept + : luastate(o.lua_state()), ref(o.ref) { o.luastate = nullptr; o.ref = LUA_NOREF; } - reference& operator=(reference&& r) noexcept { - if (valid()) { - deref(); - } - if (r.ref == LUA_REFNIL) { - luastate = r.lua_state(); - ref = LUA_REFNIL; - return *this; - } - if (r.ref == LUA_NOREF) { - ref = LUA_NOREF; - return *this; - } - if (detail::xmovable(lua_state(), r.lua_state())) { - r.push(lua_state()); - ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); - return *this; - } + basic_reference(const basic_reference& o) noexcept + : luastate(detail::pick_main_thread(o.lua_state(), o.lua_state())), ref(o.copy()) { + } - luastate = r.lua_state(); - ref = r.ref; - r.ref = LUA_NOREF; - r.luastate = nullptr; + basic_reference(basic_reference&& o) noexcept + : luastate(detail::pick_main_thread(o.lua_state(), o.lua_state())), ref(o.ref) { + o.luastate = nullptr; + o.ref = LUA_NOREF; + } + + basic_reference& operator=(basic_reference&& r) noexcept { + move_assign(std::move(r)); return *this; } - reference& operator=(const reference& r) noexcept { - if (valid()) { - deref(); - } - if (r.ref == LUA_REFNIL) { - luastate = r.lua_state(); - ref = LUA_REFNIL; - return *this; - } - if (r.ref == LUA_NOREF) { - ref = LUA_NOREF; - return *this; - } - if (detail::xmovable(lua_state(), r.lua_state())) { - r.push(lua_state()); - ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); - return *this; - } - luastate = r.lua_state(); - ref = r.copy(); + basic_reference& operator=(const basic_reference& r) noexcept { + copy_assign(r); return *this; } + basic_reference& operator=(basic_reference&& r) noexcept { + move_assign(std::move(r)); + return *this; + } + + basic_reference& operator=(const basic_reference& r) noexcept { + copy_assign(r); + return *this; + } + + template + basic_reference& operator=(proxy_base&& r); + + template + basic_reference& operator=(const proxy_base& r); + int push() const noexcept { return push(lua_state()); } @@ -368,29 +423,35 @@ namespace sol { } }; - inline bool operator==(const reference& l, const reference& r) { + template + inline bool operator==(const basic_reference& l, const basic_reference& r) { auto ppl = stack::push_pop(l); auto ppr = stack::push_pop(r); return lua_compare(l.lua_state(), -1, -2, LUA_OPEQ) == 1; } - inline bool operator!=(const reference& l, const reference& r) { + template + inline bool operator!=(const basic_reference& l, const basic_reference& r) { return !operator==(l, r); } - inline bool operator==(const reference& lhs, const lua_nil_t&) { + template + inline bool operator==(const basic_reference& lhs, const lua_nil_t&) { return !lhs.valid(); } - inline bool operator==(const lua_nil_t&, const reference& rhs) { + template + inline bool operator==(const lua_nil_t&, const basic_reference& rhs) { return !rhs.valid(); } - inline bool operator!=(const reference& lhs, const lua_nil_t&) { + template + inline bool operator!=(const basic_reference& lhs, const lua_nil_t&) { return lhs.valid(); } - inline bool operator!=(const lua_nil_t&, const reference& rhs) { + template + inline bool operator!=(const lua_nil_t&, const basic_reference& rhs) { return rhs.valid(); } } // namespace sol diff --git a/sol/simple_usertype_metatable.hpp b/sol/simple_usertype_metatable.hpp index 1ab62446..3ed1cabc 100644 --- a/sol/simple_usertype_metatable.hpp +++ b/sol/simple_usertype_metatable.hpp @@ -77,7 +77,7 @@ namespace sol { } auto fit = functions.find(accessorkey); if (fit != functions.cend()) { - sol::object& func = fit->second; + object& func = fit->second; if (is_index) { return stack::push(L, func); } @@ -525,7 +525,7 @@ namespace sol { stack_reference metabehind(L, -1); stack::set_field(L, meta_function::type, type_table, metabehind.stack_index()); if (umx.callconstructfunc.valid()) { - stack::set_field(L, sol::meta_function::call_function, umx.callconstructfunc, metabehind.stack_index()); + stack::set_field(L, meta_function::call_function, umx.callconstructfunc, metabehind.stack_index()); } if (umx.secondarymeta) { stack::set_field(L, meta_function::index, @@ -560,7 +560,7 @@ namespace sol { stack_reference metabehind(L, -1); stack::set_field(L, meta_function::type, type_table, metabehind.stack_index()); if (umx.callconstructfunc.valid()) { - stack::set_field(L, sol::meta_function::call_function, umx.callconstructfunc, metabehind.stack_index()); + stack::set_field(L, meta_function::call_function, umx.callconstructfunc, metabehind.stack_index()); } // use indexing function stack::set_field(L, meta_function::index, diff --git a/sol/stack.hpp b/sol/stack.hpp index 73004548..5ec25601 100644 --- a/sol/stack.hpp +++ b/sol/stack.hpp @@ -78,7 +78,7 @@ namespace sol { const static std::size_t data_t_count = (sizeof(TValue) + voidsizem1) / voidsize; typedef std::array data_t; - data_t data{{}}; + data_t data{ {} }; std::memcpy(&data[0], std::addressof(item), itemsize); int pushcount = 0; for (auto&& v : data) { @@ -91,7 +91,7 @@ namespace sol { inline std::pair get_as_upvalues(lua_State* L, int index = 2) { const static std::size_t data_t_count = (sizeof(T) + (sizeof(void*) - 1)) / sizeof(void*); typedef std::array data_t; - data_t voiddata{{}}; + data_t voiddata{ {} }; for (std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof(void*)) { voiddata[i] = get(L, upvalue_index(index++)); } @@ -185,7 +185,12 @@ namespace sol { template >::value>> inline int call_into_lua(types, types ta, lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) { decltype(auto) r = call(types>(), ta, L, start, std::forward(fx), std::forward(fxargs)...); - typedef is_stack_based> is_stack; + typedef meta::unqualified_t R; + typedef meta::any, + std::is_same, + std::is_same, + std::is_same> + is_stack; if (clean_stack && !is_stack::value) { lua_settop(L, 0); } diff --git a/sol/stack_check.hpp b/sol/stack_check.hpp index 330879da..261ef979 100644 --- a/sol/stack_check.hpp +++ b/sol/stack_check.hpp @@ -184,6 +184,15 @@ namespace stack { } }; + template + struct checker { + template + static bool check(lua_State*, int, Handler&&, record& tracking) { + tracking.use(0); + return true; + } + }; + template struct checker { template diff --git a/sol/stack_core.hpp b/sol/stack_core.hpp index f291cca8..b4b2fa83 100644 --- a/sol/stack_core.hpp +++ b/sol/stack_core.hpp @@ -245,7 +245,7 @@ namespace sol { template inline int multi_push(lua_State* L, T&& t, Args&&... args) { int pushcount = push(L, std::forward(t)); - void(sol::detail::swallow{(pushcount += sol::stack::push(L, std::forward(args)), 0)...}); + void(detail::swallow{(pushcount += stack::push(L, std::forward(args)), 0)...}); return pushcount; } @@ -257,7 +257,7 @@ namespace sol { template inline int multi_push_reference(lua_State* L, T&& t, Args&&... args) { int pushcount = push_reference(L, std::forward(t)); - void(sol::detail::swallow{(pushcount += sol::stack::push_reference(L, std::forward(args)), 0)...}); + void(detail::swallow{(pushcount += stack::push_reference(L, std::forward(args)), 0)...}); return pushcount; } diff --git a/sol/stack_get.hpp b/sol/stack_get.hpp index 64711a27..fbed1cc7 100644 --- a/sol/stack_get.hpp +++ b/sol/stack_get.hpp @@ -330,7 +330,7 @@ namespace stack { }; template - struct getter::value || std::is_base_of::value>> { + struct getter::value>> { static T get(lua_State* L, int index, record& tracking) { tracking.use(1); return T(L, index); @@ -569,7 +569,15 @@ namespace stack { struct getter { static this_state get(lua_State* L, int, record& tracking) { tracking.use(0); - return this_state{L}; + return this_state( L ); + } + }; + + template <> + struct getter { + static this_main_state get(lua_State* L, int, record& tracking) { + tracking.use(0); + return this_main_state( main_thread(L, L) ); } }; diff --git a/sol/stack_push.hpp b/sol/stack_push.hpp index c24cbf7d..d08e295f 100644 --- a/sol/stack_push.hpp +++ b/sol/stack_push.hpp @@ -137,7 +137,7 @@ namespace stack { }; template - struct pusher>, std::is_function>, std::is_base_of>, std::is_base_of>>::value>> { + struct pusher>, std::is_function>, is_lua_reference>>::value>> { template static int push(lua_State* L, Args&&... args) { return pusher>{}.push(L, std::forward(args)...); @@ -315,7 +315,7 @@ namespace stack { }; template - struct pusher::value || std::is_base_of::value>> { + struct pusher::value>> { static int push(lua_State* L, const T& ref) { return ref.push(L); } @@ -852,6 +852,13 @@ namespace stack { } }; + template <> + struct pusher { + static int push(lua_State*, const this_main_state&) { + return 0; + } + }; + template <> struct pusher { static int push(lua_State* L, const new_table& nt) { diff --git a/sol/state.hpp b/sol/state.hpp index 877350e3..9bbbcba9 100644 --- a/sol/state.hpp +++ b/sol/state.hpp @@ -72,7 +72,7 @@ namespace sol { : unique_base(luaL_newstate(), lua_close), state_view(unique_base::get()) { set_panic(panic); lua_CFunction f = c_call; - protected_function::set_default_handler(sol::object(lua_state(), in_place, f)); + protected_function::set_default_handler(object(lua_state(), in_place, f)); stack::register_main_thread(unique_base::get()); stack::luajit_exception_handler(unique_base::get()); } @@ -81,7 +81,7 @@ namespace sol { : unique_base(lua_newstate(alfunc, alpointer), lua_close), state_view(unique_base::get()) { set_panic(panic); lua_CFunction f = c_call; - protected_function::set_default_handler(sol::object(lua_state(), in_place, f)); + protected_function::set_default_handler(object(lua_state(), in_place, f)); stack::register_main_thread(unique_base::get()); stack::luajit_exception_handler(unique_base::get()); } diff --git a/sol/state_view.hpp b/sol/state_view.hpp index 0bab62a8..35cd6567 100644 --- a/sol/state_view.hpp +++ b/sol/state_view.hpp @@ -67,7 +67,7 @@ namespace sol { return kb; } - inline protected_function_result script_pass_on_error(lua_State*, sol::protected_function_result result) { + inline protected_function_result script_pass_on_error(lua_State*, protected_function_result result) { return result; } @@ -377,7 +377,7 @@ namespace sol { } 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) { + function_result unsafe_script(const string_view& code, const basic_environment& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) { detail::typical_chunk_name_t basechunkname = {}; const char* chunknametarget = detail::make_chunk_name(code, chunkname, basechunkname); int index = lua_gettop(L); @@ -402,7 +402,7 @@ namespace sol { } template - function_result unsafe_script_file(const std::string& filename, const sol::basic_environment& env, load_mode mode = load_mode::any) { + function_result unsafe_script_file(const std::string& filename, const 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); diff --git a/sol/table_core.hpp b/sol/table_core.hpp index ceb54b8f..5795357d 100644 --- a/sol/table_core.hpp +++ b/sol/table_core.hpp @@ -73,9 +73,9 @@ namespace sol { auto pp = stack::push_pop(*this); stack::push(base_t::lua_state(), lua_nil); while (lua_next(base_t::lua_state(), -2)) { - sol::object key(base_t::lua_state(), -2); - sol::object value(base_t::lua_state(), -1); - std::pair keyvalue(key, value); + object key(base_t::lua_state(), -2); + object value(base_t::lua_state(), -1); + std::pair keyvalue(key, value); auto pn = stack::pop_n(base_t::lua_state(), 1); fx(keyvalue); } @@ -86,8 +86,8 @@ namespace sol { auto pp = stack::push_pop(*this); stack::push(base_t::lua_state(), lua_nil); while (lua_next(base_t::lua_state(), -2)) { - sol::object key(base_t::lua_state(), -2); - sol::object value(base_t::lua_state(), -1); + object key(base_t::lua_state(), -2); + object value(base_t::lua_state(), -1); auto pn = stack::pop_n(base_t::lua_state(), 1); fx(key, value); } @@ -204,13 +204,13 @@ namespace sol { basic_table_core(stack_reference&& r) : basic_table_core(r.lua_state(), r.stack_index()) { } - template >, std::is_base_of>> = meta::enabler> + template >> = meta::enabler> basic_table_core(lua_State* L, T&& r) : basic_table_core(L, std::forward(r)) { } basic_table_core(lua_State* L, new_table nt) : base_t(L, (lua_createtable(L, nt.sequence_hint, nt.map_hint), -1)) { - if (!std::is_base_of::value) { + if (!is_stack_based>::value) { lua_pop(L, 1); } } @@ -454,7 +454,7 @@ namespace sol { template void for_each(Fx&& fx) const { - typedef meta::is_invokable)> is_paired; + typedef meta::is_invokable)> is_paired; for_each(is_paired(), std::forward(fx)); } diff --git a/sol/thread.hpp b/sol/thread.hpp index 9f418d5d..218d0e97 100644 --- a/sol/thread.hpp +++ b/sol/thread.hpp @@ -29,6 +29,10 @@ namespace sol { struct lua_thread_state { lua_State* L; + lua_thread_state(lua_State* Ls) + : L(Ls) { + } + lua_State* lua_state() const noexcept { return L; } @@ -53,7 +57,7 @@ namespace sol { struct getter { lua_thread_state get(lua_State* L, int index, record& tracking) { tracking.use(1); - lua_thread_state lts{lua_tothread(L, index)}; + lua_thread_state lts( lua_tothread(L, index) ); return lts; } }; @@ -62,8 +66,8 @@ namespace sol { struct check_getter { template optional get(lua_State* L, int index, Handler&& handler, record& tracking) { - lua_thread_state lts{lua_tothread(L, index)}; - if (lts.L == nullptr) { + lua_thread_state lts( lua_tothread(L, index) ); + if (lts.lua_state() == nullptr) { handler(L, index, type::thread, type_of(L, index), "value is not a valid thread type"); return nullopt; } @@ -87,50 +91,59 @@ namespace sol { } } // namespace stack - class thread : public reference { + template + class basic_thread : public base_t { public: - thread() noexcept = default; - thread(const thread&) = default; - thread(thread&&) = default; - template , thread>>, std::is_base_of>> = meta::enabler> - thread(T&& r) - : reference(std::forward(r)) { + using base_t::lua_state; + + basic_thread() noexcept = default; + basic_thread(const basic_thread&) = default; + basic_thread(basic_thread&&) = default; + template , basic_thread>>, std::is_base_of>> = meta::enabler> + basic_thread(T&& r) + : base_t(std::forward(r)) { } - thread(const stack_reference& r) - : thread(r.lua_state(), r.stack_index()){}; - thread(stack_reference&& r) - : thread(r.lua_state(), r.stack_index()){}; - thread& operator=(const thread&) = default; - thread& operator=(thread&&) = default; - template >>, meta::neg>> = meta::enabler> - thread(lua_State* L, T&& r) - : thread(L, sol::ref_index(r.registry_index())) { + basic_thread(const stack_reference& r) + : basic_thread(r.lua_state(), r.stack_index()){}; + basic_thread(stack_reference&& r) + : basic_thread(r.lua_state(), r.stack_index()){}; + basic_thread& operator=(const basic_thread&) = default; + basic_thread& operator=(basic_thread&&) = default; + template >>> = meta::enabler> + basic_thread(lua_State* L, T&& r) + : basic_thread(L, std::forward(r)) { } - thread(lua_State* L, int index = -1) - : reference(L, index) { -#ifdef SOL_CHECK_ARGUMENTS - type_assert(L, index, type::thread); -#endif // Safety - } - thread(lua_State* L, ref_index index) - : reference(L, index) { + basic_thread(lua_State* L, int index = -1) + : base_t(L, index) { #ifdef SOL_CHECK_ARGUMENTS auto pp = stack::push_pop(*this); - type_assert(L, -1, type::thread); + constructor_handler handler{}; + stack::check(lua_state(), -1, handler); #endif // Safety } - thread(lua_State* L, lua_State* actualthread) - : thread(L, lua_thread_state{actualthread}) { - } - thread(lua_State* L, sol::this_state actualthread) - : thread(L, lua_thread_state{actualthread.L}) { - } - thread(lua_State* L, lua_thread_state actualthread) - : reference(L, -stack::push(L, actualthread)) { + basic_thread(lua_State* L, ref_index index) + : base_t(L, index) { #ifdef SOL_CHECK_ARGUMENTS - type_assert(L, -1, type::thread); + auto pp = stack::push_pop(*this); + constructor_handler handler{}; + stack::check(lua_state(), -1, handler); #endif // Safety - lua_pop(L, 1); + } + basic_thread(lua_State* L, lua_State* actualthread) + : basic_thread(L, lua_thread_state{ actualthread }) { + } + basic_thread(lua_State* L, this_state actualthread) + : basic_thread(L, lua_thread_state{ actualthread.L }) { + } + basic_thread(lua_State* L, lua_thread_state actualthread) + : base_t(L, -stack::push(L, actualthread)) { +#ifdef SOL_CHECK_ARGUMENTS + constructor_handler handler{}; + stack::check(lua_state(), -1, handler); +#endif // Safety + if (!is_stack_based::value) { + lua_pop(lua_state(), 1); + } } state_view state() const { @@ -153,23 +166,28 @@ namespace sol { lua_State* lthread = thread_state(); thread_status lstat = static_cast(lua_status(lthread)); if (lstat != thread_status::ok && lua_gettop(lthread) == 0) { - // No thing on the thread's stack means its dead + // No thing on the basic_thread's stack means its dead return thread_status::dead; } return lstat; } - thread create() { + basic_thread create() { return create(lua_state()); } - static thread create(lua_State* L) { + static basic_thread create(lua_State* L) { lua_newthread(L); - thread result(L); - lua_pop(L, 1); + basic_thread result(L); + if (!is_stack_based::value) { + lua_pop(L, 1); + } return result; } }; + + typedef basic_thread thread; + typedef basic_thread stack_thread; } // namespace sol #endif // SOL_THREAD_HPP diff --git a/sol/types.hpp b/sol/types.hpp index 4d44bf13..3a8d68cc 100644 --- a/sol/types.hpp +++ b/sol/types.hpp @@ -491,6 +491,31 @@ namespace sol { struct this_state { lua_State* L; + + this_state(lua_State* Ls) + : L(Ls) { + } + + operator lua_State*() const noexcept { + return lua_state(); + } + + lua_State* operator->() const noexcept { + return lua_state(); + } + + lua_State* lua_state() const noexcept { + return L; + } + }; + + struct this_main_state { + lua_State* L; + + this_main_state(lua_State* Ls) + : L(Ls) { + } + operator lua_State*() const noexcept { return lua_state(); } @@ -577,7 +602,7 @@ namespace sol { }; inline const std::string& to_string(call_status c) { - static const std::array names{{ + static const std::array names{ { "ok", "yielded", "runtime", @@ -586,7 +611,7 @@ namespace sol { "gc", "syntax", "file", - }}; + } }; switch (c) { case call_status::ok: return names[0]; @@ -609,13 +634,13 @@ namespace sol { } inline const std::string& to_string(load_status c) { - static const std::array names{{ + static const std::array names{ { "ok", "memory", "gc", "syntax", "file", - }}; + } }; switch (c) { case load_status::ok: return names[0]; @@ -632,11 +657,11 @@ namespace sol { } inline const std::string& to_string(load_mode c) { - static const std::array names{{ + static const std::array names{ { "bt", "t", "b", - }}; + } }; return names[static_cast(c)]; } @@ -680,7 +705,7 @@ namespace sol { typedef meta_function meta_method; inline const std::array& meta_function_names() { - static const std::array names = {{"new", + static const std::array names = { { "new", "__index", "__newindex", "__mode", @@ -713,7 +738,7 @@ namespace sol { "__ipairs", "__next", "__type", - "__typeinfo"}}; + "__typeinfo" } }; return names; } @@ -831,7 +856,7 @@ namespace sol { struct lua_type_of : std::integral_constant {}; template <> - struct lua_type_of : std::integral_constant {}; + struct lua_type_of : std::integral_constant {}; template struct lua_type_of> : std::integral_constant {}; @@ -851,8 +876,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 {}; @@ -923,6 +948,9 @@ 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 {}; @@ -1009,6 +1037,7 @@ namespace sol { && detail::has_internal_marker>>::value && !detail::has_internal_marker>>::value) || std::is_base_of>::value + || std::is_base_of>::value || std::is_base_of>::value || meta::is_specialization_of>::value || meta::is_specialization_of>::value> {}; @@ -1016,8 +1045,19 @@ namespace sol { template struct is_lua_reference : std::integral_constant>::value - || std::is_base_of>::value - || meta::is_specialization_of>::value> {}; + || std::is_base_of>::value + || std::is_base_of>::value> {}; + + template + struct is_lua_reference_or_proxy : std::integral_constant>::value + || meta::is_specialization_of>::value> {}; + + template + struct is_main_threaded : std::is_base_of {}; + + template + struct is_stack_based : std::is_base_of {}; template struct is_lua_primitive : std::true_type {}; @@ -1052,6 +1092,8 @@ namespace sol { template <> struct is_transparent_argument : std::true_type {}; template <> + struct is_transparent_argument : std::true_type {}; + template <> struct is_transparent_argument : std::true_type {}; template <> struct is_transparent_argument : std::true_type {}; @@ -1069,13 +1111,6 @@ namespace sol { template <> struct is_lua_index : std::true_type {}; - template - struct is_stack_based : std::is_base_of {}; - template <> - struct is_stack_based : std::true_type {}; - template <> - struct is_stack_based : std::true_type {}; - template struct lua_bind_traits : meta::bind_traits { private: diff --git a/sol/userdata.hpp b/sol/userdata.hpp index ed0c85e8..f9b4466a 100644 --- a/sol/userdata.hpp +++ b/sol/userdata.hpp @@ -54,7 +54,7 @@ namespace sol { basic_userdata(stack_reference&& r) : basic_userdata(r.lua_state(), r.stack_index()) { } - template >, std::is_base_of>> = meta::enabler> + template >> = meta::enabler> basic_userdata(lua_State* L, T&& r) : base_t(L, std::forward(r)) { } diff --git a/sol/usertype_core.hpp b/sol/usertype_core.hpp index b1764032..d99dda20 100644 --- a/sol/usertype_core.hpp +++ b/sol/usertype_core.hpp @@ -112,7 +112,7 @@ namespace sol { template = meta::enabler> inline void make_reg_op(Regs& l, int& index, const char* name) { lua_CFunction f = &comparsion_operator_wrap; - l[index] = luaL_Reg{name, f}; + l[index] = luaL_Reg{ name, f }; ++index; } @@ -125,7 +125,7 @@ namespace sol { inline void make_to_string_op(Regs& l, int& index) { const char* name = to_string(meta_function::to_string).c_str(); lua_CFunction f = &detail::static_trampoline<&default_to_string>; - l[index] = luaL_Reg{name, f}; + l[index] = luaL_Reg{ name, f }; ++index; } @@ -138,7 +138,7 @@ namespace sol { inline void make_call_op(Regs& l, int& index) { const char* name = to_string(meta_function::call).c_str(); lua_CFunction f = &c_call; - l[index] = luaL_Reg{name, f}; + l[index] = luaL_Reg{ name, f }; ++index; } @@ -150,7 +150,7 @@ namespace sol { template > = meta::enabler> inline void make_length_op(Regs& l, int& index) { const char* name = to_string(meta_function::length).c_str(); - l[index] = luaL_Reg{name, &c_call}; + l[index] = luaL_Reg{ name, &c_call }; ++index; } @@ -162,7 +162,7 @@ namespace sol { template >, std::is_destructible>> void make_destructor(Regs& l, int& index) { const char* name = to_string(meta_function::garbage_collect).c_str(); - l[index] = luaL_Reg{name, is_unique_usertype::value ? &detail::unique_destruct : &detail::usertype_alloc_destruct}; + l[index] = luaL_Reg{ name, is_unique_usertype::value ? &detail::unique_destruct : &detail::usertype_alloc_destruct }; ++index; } @@ -174,7 +174,7 @@ namespace sol { // this won't trigger if the user performs `new_usertype` / `new_simple_usertype` and // rigs the class up properly const char* name = to_string(meta_function::garbage_collect).c_str(); - l[index] = luaL_Reg{name, &detail::cannot_destruct}; + l[index] = luaL_Reg{ name, &detail::cannot_destruct }; ++index; } } @@ -195,7 +195,7 @@ namespace sol { } if (fx(meta_function::pairs)) { const char* name = to_string(meta_function::pairs).c_str(); - l[index] = luaL_Reg{name, container_usertype_metatable>::pairs_call}; + l[index] = luaL_Reg{ name, container_usertype_metatable>::pairs_call }; ++index; } if (fx(meta_function::length)) { @@ -210,8 +210,7 @@ namespace sol { } } // namespace usertype_detail - namespace stack { - namespace stack_detail { + namespace stack { namespace stack_detail { template struct undefined_metatable { typedef meta::all>, std::is_destructible> is_destructible; @@ -231,6 +230,16 @@ namespace sol { usertype_detail::insert_default_registrations

(l, index, fx); usertype_detail::make_destructor(l, index); luaL_setfuncs(L, l, 0); + + // __type table + lua_createtable(L, 0, 2); + const std::string& name = detail::demangle(); + lua_pushlstring(L, name.c_str(), name.size()); + lua_setfield(L, -2, "name"); + lua_CFunction is_func = &usertype_detail::is_check; + lua_pushcclosure(L, is_func, 0); + lua_setfield(L, -2, "is"); + lua_setfield(L, -2, to_string(meta_function::type).c_str()); } lua_setmetatable(L, -2); } diff --git a/sol/usertype_metatable.hpp b/sol/usertype_metatable.hpp index 82117b9b..e1b44569 100644 --- a/sol/usertype_metatable.hpp +++ b/sol/usertype_metatable.hpp @@ -252,10 +252,10 @@ namespace sol { std::string& accessor = maybeaccessor.value(); auto preexistingit = functions.find(accessor); if (preexistingit == functions.cend()) { - functions.emplace_hint(preexistingit, std::move(accessor), sol::object(L, 3)); + functions.emplace_hint(preexistingit, std::move(accessor), object(L, 3)); } else { - preexistingit->second = sol::object(L, 3); + preexistingit->second = object(L, 3); } return; } @@ -278,7 +278,7 @@ namespace sol { } else { target = preexistingit->second.runtime_target; - runtime[target] = sol::object(L, 3); + runtime[target] = object(L, 3); preexistingit->second = call_information(&runtime_object_call, &runtime_new_index, target); } }; @@ -468,7 +468,7 @@ namespace sol { case meta_function::garbage_collect: if (destructfunc != nullptr) { #ifdef SOL_NO_EXCEPTIONS - throw sol::error("sol: 2 separate garbage_collect functions were set on this type. Please specify only 1 sol::meta_function::gc type AND wrap the function in a sol::destruct call, as shown by the documentation and examples"); + throw error("sol: 2 separate garbage_collect functions were set on this type. Please specify only 1 sol::meta_function::gc type AND wrap the function in a sol::destruct call, as shown by the documentation and examples"); #else assert(false && "sol: 2 separate garbage_collect functions were set on this type. Please specify only 1 sol::meta_function::gc type AND wrap the function in a sol::destruct call, as shown by the documentation and examples"); #endif diff --git a/tests/test_coroutines.cpp b/tests/test_coroutines.cpp index 782a77f1..b59c72ad 100644 --- a/tests/test_coroutines.cpp +++ b/tests/test_coroutines.cpp @@ -281,3 +281,93 @@ co = nil std::string s = t[1]; REQUIRE(s == "SOME_TABLE"); } + +TEST_CASE("coroutines/main transfer", "check that copy and move assignment constructors using main-forced types work") { + const std::string code = R"( +-- main thread - L1 +-- co - L2 +-- co2 - L3 + +x = co_test.new("x") +local co = coroutine.wrap( + function() + local t = co_test.new("t") + local co2 = coroutine.wrap( + function() + local t2 = { "SOME_TABLE" } + t:copy_store(t2) -- t2 = [L3], t.obj = [L2] + end + ) + + co2() + co2 = nil + + collectgarbage() -- t2 ref in t remains valid! + + x:store(t:get()) -- t.obj = [L2], x.obj = [L1] + end +) + +co() +co = nil +collectgarbage() +)"; + + struct co_test_implicit { + std::string identifier; + sol::main_reference obj; + + co_test_implicit(sol::this_state L, std::string id) : identifier(id), obj(L, sol::lua_nil) { + + } + + void store(sol::table ref) { + // main_reference does the state shift implicitly + obj = std::move(ref); + lua_State* Lmain = sol::main_thread(ref.lua_state()); + REQUIRE(obj.lua_state() == Lmain); + } + + void copy_store(sol::table ref) { + // main_reference does the state shift implicitly + obj = ref; + lua_State* Lmain = sol::main_thread(ref.lua_state()); + REQUIRE(obj.lua_state() == Lmain); + } + + sol::reference get() { + return obj; + } + + ~co_test_implicit() { + + } + }; + + sol::state lua; + lua.open_libraries(sol::lib::coroutine, sol::lib::base); + + lua.new_usertype("co_test", + sol::constructors(), + "store", &co_test_implicit::store, + "copy_store", &co_test_implicit::copy_store, + "get", &co_test_implicit::get + ); + + + auto r = lua.safe_script(code); + REQUIRE(r.valid()); + + co_test_implicit& ct = lua["x"]; + + lua_State* Lmain1 = lua.lua_state(); + lua_State* Lmain2 = sol::main_thread(lua); + lua_State* Lmain3 = ct.get().lua_state(); + REQUIRE(Lmain1 == Lmain2); + REQUIRE(Lmain1 == Lmain3); + + sol::table t = ct.get(); + REQUIRE(t.size() == 1); + std::string s = t[1]; + REQUIRE(s == "SOME_TABLE"); +}