diff --git a/include/sol/forward.hpp b/include/sol/forward.hpp index b555504c..d8389890 100644 --- a/include/sol/forward.hpp +++ b/include/sol/forward.hpp @@ -39,10 +39,12 @@ extern "C" { namespace sol { + class stateless_reference; template class basic_reference; using reference = basic_reference; using main_reference = basic_reference; + class stateless_stack_reference; class stack_reference; template diff --git a/include/sol/reference.hpp b/include/sol/reference.hpp index 8e6f00b7..3859beab 100644 --- a/include/sol/reference.hpp +++ b/include/sol/reference.hpp @@ -134,7 +134,7 @@ namespace sol { }; template - struct push_popper>::value>> { + struct push_popper>>> { using Tu = meta::unqualified_t; push_popper(T) { @@ -203,20 +203,183 @@ namespace sol { } } // namespace detail + class stateless_reference { + private: + template + friend class basic_reference; + + int ref = LUA_NOREF; + + int copy(lua_State* L) const noexcept { + if (ref == LUA_NOREF) + return LUA_NOREF; + push(L); + return luaL_ref(L, LUA_REGISTRYINDEX); + } + + lua_State* copy_assign(lua_State* L, lua_State* rL, const stateless_reference& r) { + if (valid(L)) { + deref(L); + } + ref = r.copy(L); + return rL; + } + + lua_State* move_assign(lua_State* L, lua_State* rL, stateless_reference&& r) { + if (valid(L)) { + deref(L); + } + ref = r.ref; + r.ref = LUA_NOREF; + return rL; + } + + protected: + int stack_index () const noexcept { + return -1; + } + + stateless_reference(lua_State* L, detail::global_tag) noexcept { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, "not enough Lua stack space to push this reference value"); +#endif // make sure stack doesn't overflow + lua_pushglobaltable(L); + ref = luaL_ref(L, LUA_REGISTRYINDEX); + } + + stateless_reference(int raw_ref_index) noexcept : ref(raw_ref_index) { + } + + public: + stateless_reference() noexcept = default; + stateless_reference(lua_nil_t) noexcept : stateless_reference() { + } + stateless_reference(const stack_reference& r) noexcept : stateless_reference(r.lua_state(), r.stack_index()) { + } + stateless_reference(stack_reference&& r) noexcept : stateless_reference(r.lua_state(), r.stack_index()) { + } + stateless_reference(lua_State* L, const stateless_reference& r) noexcept { + if (r.ref == LUA_REFNIL) { + ref = LUA_REFNIL; + return; + } + if (r.ref == LUA_NOREF || L == nullptr) { + ref = LUA_NOREF; + return; + } + ref = r.copy(L); + } + + stateless_reference(lua_State* L, stateless_reference&& r) noexcept { + if (r.ref == LUA_REFNIL) { + ref = LUA_REFNIL; + return; + } + if (r.ref == LUA_NOREF || L == nullptr) { + ref = LUA_NOREF; + return; + } + ref = r.ref; + r.ref = LUA_NOREF; + } + + stateless_reference(lua_State* L, const stack_reference& r) noexcept { + if (L == nullptr || r.lua_state() == nullptr || r.get_type() == type::none) { + ref = LUA_NOREF; + return; + } + if (r.get_type() == type::lua_nil) { + ref = LUA_REFNIL; + return; + } + if (L != r.lua_state() && !detail::xmovable(L, r.lua_state())) { + return; + } + r.push(L); + ref = luaL_ref(L, LUA_REGISTRYINDEX); + } + + stateless_reference(lua_State* L, int index = -1) noexcept { + // use L to stick with that state's execution stack +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, "not enough Lua stack space to push this reference value"); +#endif // make sure stack doesn't overflow + lua_pushvalue(L, index); + ref = luaL_ref(L, LUA_REGISTRYINDEX); + } + stateless_reference(lua_State* L, ref_index index) noexcept { + lua_rawgeti(L, LUA_REGISTRYINDEX, index.index); + ref = luaL_ref(L, LUA_REGISTRYINDEX); + } + stateless_reference(lua_State*, lua_nil_t) noexcept { + } + + ~stateless_reference() noexcept = default; + + stateless_reference(const stateless_reference& o) noexcept = delete; + stateless_reference& operator=(const stateless_reference& r) noexcept = delete; + + stateless_reference(stateless_reference&& o) noexcept + : ref(o.ref) { + o.ref = LUA_NOREF; + } + + stateless_reference& operator=(stateless_reference&& o) noexcept { + ref = o.ref; + o.ref = LUA_NOREF; + return *this; + } + + + int push(lua_State* L) const noexcept { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, "not enough Lua stack space to push this reference value"); +#endif // make sure stack doesn't overflow + lua_rawgeti(L, LUA_REGISTRYINDEX, ref); + return 1; + } + + void pop(lua_State* L, int n = 1) const noexcept { + lua_pop(L, n); + } + + int registry_index() const noexcept { + return ref; + } + + bool valid(lua_State*) const noexcept { + return !(ref == LUA_NOREF || ref == LUA_REFNIL); + } + + const void* pointer(lua_State* L) const noexcept { + int si = push(L); + const void* vp = lua_topointer(L, -si); + lua_pop(L, si); + return vp; + } + + type get_type(lua_State* L) const noexcept { + int p = push(L); + int result = lua_type(L, -1); + pop(L, p); + return static_cast(result); + } + + void abandon(lua_State* = nullptr) { + ref = LUA_NOREF; + } + + void deref(lua_State* L) const noexcept { + luaL_unref(L, LUA_REGISTRYINDEX, ref); + } + }; + template - class basic_reference { + class basic_reference : public stateless_reference { private: template friend class basic_reference; lua_State* luastate = nullptr; // non-owning - int ref = LUA_NOREF; - - int copy() const noexcept { - if (ref == LUA_NOREF) - return LUA_NOREF; - push(); - return luaL_ref(lua_state(), LUA_REGISTRYINDEX); - } template void copy_assign(const basic_reference& r) { @@ -271,20 +434,26 @@ namespace sol { protected: basic_reference(lua_State* L, detail::global_tag) noexcept - : luastate(detail::pick_main_thread(L, L)) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, "not enough Lua stack space to push this reference value"); -#endif // make sure stack doesn't overflow - lua_pushglobaltable(lua_state()); - ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); + : basic_reference(detail::pick_main_thread(L, L), detail::global_, detail::global_) { } - int stack_index() const noexcept { - return -1; + basic_reference(lua_State* L, detail::global_tag, detail::global_tag) noexcept + : stateless_reference(L, detail::global_), luastate(L) { + } + + basic_reference(lua_State* oL, const basic_reference& o) noexcept : stateless_reference(oL, o), luastate(oL) { } void deref() const noexcept { - luaL_unref(lua_state(), LUA_REGISTRYINDEX, ref); + return stateless_reference::deref(lua_state()); + } + + int copy() const noexcept { + return copy(lua_state()); + } + + int copy(lua_State* L) const noexcept { + return stateless_reference::copy(L); } public: @@ -379,21 +548,20 @@ namespace sol { } basic_reference(const basic_reference& o) noexcept - : luastate(o.lua_state()), ref(o.copy()) { + : stateless_reference(o.copy()), luastate(o.lua_state()) { } basic_reference(basic_reference&& o) noexcept - : luastate(o.lua_state()), ref(o.ref) { + : stateless_reference(std::move(o)), luastate(o.lua_state()) { o.luastate = nullptr; - o.ref = LUA_NOREF; } basic_reference(const basic_reference& o) noexcept - : luastate(detail::pick_main_thread < main_only && !main_only > (o.lua_state(), o.lua_state())), ref(o.copy()) { + : basic_reference(detail::pick_main_thread < main_only && !main_only > (o.lua_state(), o.lua_state()), o) { } basic_reference(basic_reference&& o) noexcept - : luastate(detail::pick_main_thread < main_only && !main_only > (o.lua_state(), o.lua_state())), ref(o.ref) { + : stateless_reference(std::move(o)), luastate(detail::pick_main_thread(o.lua_state(), o.lua_state())) { o.luastate = nullptr; o.ref = LUA_NOREF; } @@ -437,17 +605,17 @@ namespace sol { return push(lua_state()); } - int push(lua_State* Ls) const noexcept { + int push(lua_State* L) const noexcept { #if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(Ls, 1, "not enough Lua stack space to push this reference value"); + luaL_checkstack(L, 1, "not enough Lua stack space to push this reference value"); #endif // make sure stack doesn't overflow if (lua_state() == nullptr) { - lua_pushnil(Ls); + lua_pushnil(L); return 1; } lua_rawgeti(lua_state(), LUA_REGISTRYINDEX, ref); - if (Ls != lua_state()) { - lua_xmove(lua_state(), Ls, 1); + if (L != lua_state()) { + lua_xmove(lua_state(), L, 1); } return 1; } @@ -456,23 +624,20 @@ namespace sol { pop(lua_state()); } - void pop(lua_State* Ls, int n = 1) const noexcept { - lua_pop(Ls, n); + void pop(lua_State* L, int n = 1) const noexcept { + stateless_reference::pop(L, n); } int registry_index() const noexcept { - return ref; + return stateless_reference::registry_index(); } bool valid() const noexcept { - return !(ref == LUA_NOREF || ref == LUA_REFNIL); + return stateless_reference::valid(lua_state()); } const void* pointer() const noexcept { - int si = push(); - const void* vp = lua_topointer(lua_state(), -si); - lua_pop(this->lua_state(), si); - return vp; + return stateless_reference::pointer(lua_state()); } explicit operator bool() const noexcept { @@ -480,9 +645,7 @@ namespace sol { } type get_type() const noexcept { - auto pp = stack::push_pop(*this); - int result = lua_type(lua_state(), -1); - return static_cast(result); + return stateless_reference::get_type(lua_state()); } lua_State* lua_state() const noexcept { diff --git a/include/sol/stack_check_get_unqualified.hpp b/include/sol/stack_check_get_unqualified.hpp index 65f0ebf7..d552c084 100644 --- a/include/sol/stack_check_get_unqualified.hpp +++ b/include/sol/stack_check_get_unqualified.hpp @@ -61,7 +61,7 @@ namespace stack { } return stack_detail::unchecked_get(L, index, tracking); } - else if constexpr (std::is_integral_v && !std::is_same_v) { + else if constexpr ((std::is_integral_v || std::is_same_v) && !std::is_same_v) { #if SOL_LUA_VERSION >= 503 if (lua_isinteger(L, index) != 0) { tracking.use(1); @@ -87,7 +87,7 @@ namespace stack { handler(L, index, type::number, t, "not an integer"); return nullopt; } - else if constexpr(std::is_floating_point_v) { + else if constexpr (std::is_floating_point_v || std::is_same_v) { int isnum = 0; lua_Number value = lua_tonumberx(L, index, &isnum); if (isnum == 0) { diff --git a/include/sol/stack_check_unqualified.hpp b/include/sol/stack_check_unqualified.hpp index ab7beab9..64ea7c5e 100644 --- a/include/sol/stack_check_unqualified.hpp +++ b/include/sol/stack_check_unqualified.hpp @@ -102,7 +102,7 @@ namespace sol { namespace stack { else if constexpr (meta::any_same_v) { return stack::check>(L, index, std::forward(handler), tracking); } - else if constexpr (std::is_integral_v) { + else if constexpr (std::is_integral_v || std::is_same_v) { tracking.use(1); #if SOL_LUA_VERSION >= 503 #if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS @@ -160,7 +160,7 @@ namespace sol { namespace stack { return success; #endif // Lua Version 5.3 versus others } - else if constexpr (std::is_floating_point_v) { + else if constexpr (std::is_floating_point_v || std::is_same_v) { tracking.use(1); #if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS bool success = lua_isnumber(L, index) == 1; diff --git a/include/sol/stack_get_unqualified.hpp b/include/sol/stack_get_unqualified.hpp index 05f1e014..4c475661 100644 --- a/include/sol/stack_get_unqualified.hpp +++ b/include/sol/stack_get_unqualified.hpp @@ -127,7 +127,7 @@ namespace sol { namespace stack { tracking.use(1); return static_cast(lua_tointegerx(L, index, nullptr)); } - else if constexpr (std::is_integral_v) { + else if constexpr (std::is_integral_v || std::is_same_v) { tracking.use(1); #if SOL_LUA_VERSION >= 503 if (lua_isinteger(L, index) != 0) { @@ -136,7 +136,7 @@ namespace sol { namespace stack { #endif return static_cast(llround(lua_tonumber(L, index))); } - else if constexpr (std::is_floating_point_v) { + else if constexpr (std::is_floating_point_v || std::is_same_v) { tracking.use(1); return static_cast(lua_tonumber(L, index)); } diff --git a/include/sol/stack_push.hpp b/include/sol/stack_push.hpp index 089642dd..ead3d8fe 100644 --- a/include/sol/stack_push.hpp +++ b/include/sol/stack_push.hpp @@ -254,7 +254,7 @@ namespace sol { lua_pushboolean(L, std::forward(args)...); return 1; } - else if constexpr (std::is_integral_v) { + else if constexpr (std::is_integral_v || std::is_same_v) { const Tu& value(std::forward(args)...); #if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK luaL_checkstack(L, 1, detail::not_enough_stack_space_integral); @@ -280,7 +280,7 @@ namespace sol { lua_pushnumber(L, static_cast(value)); return 1; } - else if constexpr (std::is_floating_point_v) { + else if constexpr (std::is_floating_point_v || std::is_same_v) { #if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK luaL_checkstack(L, 1, detail::not_enough_stack_space_floating); #endif // make sure stack doesn't overflow diff --git a/include/sol/stack_reference.hpp b/include/sol/stack_reference.hpp index 739b634c..b53eebd6 100644 --- a/include/sol/stack_reference.hpp +++ b/include/sol/stack_reference.hpp @@ -39,7 +39,9 @@ namespace sol { } // namespace detail class stateless_stack_reference { - protected: + private: + friend class stack_reference; + int index = 0; int registry_index() const noexcept { @@ -97,33 +99,27 @@ namespace sol { type t = get_type(L); return t != type::lua_nil && t != type::none; } + + void abandon(lua_State* = nullptr) { + index = 0; + } }; - class stack_reference { + class stack_reference : public stateless_stack_reference { private: lua_State* luastate = nullptr; - int index = 0; - - protected: - int registry_index() const noexcept { - return LUA_NOREF; - } public: stack_reference() noexcept = default; stack_reference(lua_nil_t) noexcept : stack_reference() {}; - stack_reference(lua_State* L, lua_nil_t) noexcept - : luastate(L), index(0) { + stack_reference(lua_State* L, lua_nil_t) noexcept : stateless_stack_reference(L, 0), luastate(L) { } - stack_reference(lua_State* L, int i) noexcept - : stack_reference(L, absolute_index(L, i)) { + stack_reference(lua_State* L, int i) noexcept : stateless_stack_reference(L, i), luastate(L) { } - stack_reference(lua_State* L, absolute_index i) noexcept - : luastate(L), index(i) { + stack_reference(lua_State* L, absolute_index i) noexcept : stateless_stack_reference(L, i), luastate(L) { } - stack_reference(lua_State* L, raw_index i) noexcept - : luastate(L), index(i) { + stack_reference(lua_State* L, raw_index i) noexcept : stateless_stack_reference(L, i), luastate(L) { } stack_reference(lua_State* L, ref_index i) noexcept = delete; stack_reference(lua_State* L, const reference& r) noexcept = delete; @@ -154,18 +150,7 @@ namespace sol { } int push(lua_State* Ls) const noexcept { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(Ls, 1, "not enough Lua stack space to push a single reference value"); -#endif // make sure stack doesn't overflow - if (lua_state() == nullptr) { - lua_pushnil(Ls); - return 1; - } - lua_pushvalue(lua_state(), index); - if (Ls != lua_state()) { - lua_xmove(lua_state(), Ls, 1); - } - return 1; + return stateless_stack_reference::push(Ls); } void pop() const noexcept { @@ -173,21 +158,15 @@ namespace sol { } void pop(lua_State* Ls, int n = 1) const noexcept { - lua_pop(Ls, n); - } - - int stack_index() const noexcept { - return index; + stateless_stack_reference::pop(Ls, n); } const void* pointer() const noexcept { - const void* vp = lua_topointer(lua_state(), stack_index()); - return vp; + return stateless_stack_reference::pointer(lua_state()); } type get_type() const noexcept { - int result = lua_type(lua_state(), index); - return static_cast(result); + return stateless_stack_reference::get_type(lua_state()); } lua_State* lua_state() const noexcept { @@ -195,8 +174,11 @@ namespace sol { } bool valid() const noexcept { - type t = get_type(); - return t != type::lua_nil && t != type::none; + return stateless_stack_reference::valid(lua_state()); + } + + void abandon () { + stateless_stack_reference::abandon(lua_state()); } }; diff --git a/include/sol/types.hpp b/include/sol/types.hpp index 25830604..7441df30 100644 --- a/include/sol/types.hpp +++ b/include/sol/types.hpp @@ -1098,10 +1098,10 @@ namespace sol { struct lua_type_of : std::integral_constant {}; template - struct lua_type_of::value>> : std::integral_constant {}; + struct lua_type_of || std::is_same_v || std::is_same_v>> : std::integral_constant {}; template - struct lua_type_of::value>> : std::integral_constant {}; + struct lua_type_of>> : std::integral_constant {}; template <> struct lua_type_of : std::integral_constant {}; @@ -1115,7 +1115,7 @@ namespace sol { template struct lua_type_of> - : meta::conditional_t<::sol::is_container::value, std::integral_constant, lua_type_of> {}; + : meta::conditional_t<::sol::is_container_v, std::integral_constant, lua_type_of> {}; template class V, typename... Args> struct accumulate : std::integral_constant {}; diff --git a/single/include/sol/forward.hpp b/single/include/sol/forward.hpp index bf8dcfa4..2f01caf5 100644 --- a/single/include/sol/forward.hpp +++ b/single/include/sol/forward.hpp @@ -20,8 +20,8 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // This file was generated with a script. -// Generated 2019-06-09 01:46:16.048592 UTC -// This header was generated with sol v3.0.2 (revision d63ba49) +// Generated 2019-06-10 08:21:46.886787 UTC +// This header was generated with sol v3.0.2 (revision ef1c0e7) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP @@ -261,10 +261,12 @@ extern "C" { namespace sol { + class stateless_reference; template class basic_reference; using reference = basic_reference; using main_reference = basic_reference; + class stateless_stack_reference; class stack_reference; template diff --git a/single/include/sol/sol.hpp b/single/include/sol/sol.hpp index cdd6a4cf..9fc199ce 100644 --- a/single/include/sol/sol.hpp +++ b/single/include/sol/sol.hpp @@ -20,8 +20,8 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // This file was generated with a script. -// Generated 2019-06-09 01:46:15.617622 UTC -// This header was generated with sol v3.0.2 (revision d63ba49) +// Generated 2019-06-10 08:21:46.618479 UTC +// This header was generated with sol v3.0.2 (revision ef1c0e7) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -287,10 +287,12 @@ extern "C" { namespace sol { + class stateless_reference; template class basic_reference; using reference = basic_reference; using main_reference = basic_reference; + class stateless_stack_reference; class stack_reference; template @@ -7289,10 +7291,10 @@ namespace sol { struct lua_type_of : std::integral_constant {}; template - struct lua_type_of::value>> : std::integral_constant {}; + struct lua_type_of || std::is_same_v || std::is_same_v>> : std::integral_constant {}; template - struct lua_type_of::value>> : std::integral_constant {}; + struct lua_type_of>> : std::integral_constant {}; template <> struct lua_type_of : std::integral_constant {}; @@ -7306,7 +7308,7 @@ namespace sol { template struct lua_type_of> - : meta::conditional_t<::sol::is_container::value, std::integral_constant, lua_type_of> {}; + : meta::conditional_t<::sol::is_container_v, std::integral_constant, lua_type_of> {}; template class V, typename... Args> struct accumulate : std::integral_constant {}; @@ -8367,7 +8369,9 @@ namespace sol { } // namespace detail class stateless_stack_reference { - protected: + private: + friend class stack_reference; + int index = 0; int registry_index() const noexcept { @@ -8425,33 +8429,27 @@ namespace sol { type t = get_type(L); return t != type::lua_nil && t != type::none; } + + void abandon(lua_State* = nullptr) { + index = 0; + } }; - class stack_reference { + class stack_reference : public stateless_stack_reference { private: lua_State* luastate = nullptr; - int index = 0; - - protected: - int registry_index() const noexcept { - return LUA_NOREF; - } public: stack_reference() noexcept = default; stack_reference(lua_nil_t) noexcept : stack_reference() {}; - stack_reference(lua_State* L, lua_nil_t) noexcept - : luastate(L), index(0) { + stack_reference(lua_State* L, lua_nil_t) noexcept : stateless_stack_reference(L, 0), luastate(L) { } - stack_reference(lua_State* L, int i) noexcept - : stack_reference(L, absolute_index(L, i)) { + stack_reference(lua_State* L, int i) noexcept : stateless_stack_reference(L, i), luastate(L) { } - stack_reference(lua_State* L, absolute_index i) noexcept - : luastate(L), index(i) { + stack_reference(lua_State* L, absolute_index i) noexcept : stateless_stack_reference(L, i), luastate(L) { } - stack_reference(lua_State* L, raw_index i) noexcept - : luastate(L), index(i) { + stack_reference(lua_State* L, raw_index i) noexcept : stateless_stack_reference(L, i), luastate(L) { } stack_reference(lua_State* L, ref_index i) noexcept = delete; stack_reference(lua_State* L, const reference& r) noexcept = delete; @@ -8482,18 +8480,7 @@ namespace sol { } int push(lua_State* Ls) const noexcept { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(Ls, 1, "not enough Lua stack space to push a single reference value"); -#endif // make sure stack doesn't overflow - if (lua_state() == nullptr) { - lua_pushnil(Ls); - return 1; - } - lua_pushvalue(lua_state(), index); - if (Ls != lua_state()) { - lua_xmove(lua_state(), Ls, 1); - } - return 1; + return stateless_stack_reference::push(Ls); } void pop() const noexcept { @@ -8501,21 +8488,15 @@ namespace sol { } void pop(lua_State* Ls, int n = 1) const noexcept { - lua_pop(Ls, n); - } - - int stack_index() const noexcept { - return index; + stateless_stack_reference::pop(Ls, n); } const void* pointer() const noexcept { - const void* vp = lua_topointer(lua_state(), stack_index()); - return vp; + return stateless_stack_reference::pointer(lua_state()); } type get_type() const noexcept { - int result = lua_type(lua_state(), index); - return static_cast(result); + return stateless_stack_reference::get_type(lua_state()); } lua_State* lua_state() const noexcept { @@ -8523,8 +8504,11 @@ namespace sol { } bool valid() const noexcept { - type t = get_type(); - return t != type::lua_nil && t != type::none; + return stateless_stack_reference::valid(lua_state()); + } + + void abandon () { + stateless_stack_reference::abandon(lua_state()); } }; @@ -8684,7 +8668,7 @@ namespace sol { }; template - struct push_popper>::value>> { + struct push_popper>>> { using Tu = meta::unqualified_t; push_popper(T) { @@ -8753,20 +8737,182 @@ namespace sol { } } // namespace detail + class stateless_reference { + private: + template + friend class basic_reference; + + int ref = LUA_NOREF; + + int copy(lua_State* L) const noexcept { + if (ref == LUA_NOREF) + return LUA_NOREF; + push(L); + return luaL_ref(L, LUA_REGISTRYINDEX); + } + + lua_State* copy_assign(lua_State* L, lua_State* rL, const stateless_reference& r) { + if (valid(L)) { + deref(L); + } + ref = r.copy(L); + return rL; + } + + lua_State* move_assign(lua_State* L, lua_State* rL, stateless_reference&& r) { + if (valid(L)) { + deref(L); + } + ref = r.ref; + r.ref = LUA_NOREF; + return rL; + } + + protected: + int stack_index () const noexcept { + return -1; + } + + stateless_reference(lua_State* L, detail::global_tag) noexcept { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, "not enough Lua stack space to push this reference value"); +#endif // make sure stack doesn't overflow + lua_pushglobaltable(L); + ref = luaL_ref(L, LUA_REGISTRYINDEX); + } + + stateless_reference(int raw_ref_index) noexcept : ref(raw_ref_index) { + } + + public: + stateless_reference() noexcept = default; + stateless_reference(lua_nil_t) noexcept : stateless_reference() { + } + stateless_reference(const stack_reference& r) noexcept : stateless_reference(r.lua_state(), r.stack_index()) { + } + stateless_reference(stack_reference&& r) noexcept : stateless_reference(r.lua_state(), r.stack_index()) { + } + stateless_reference(lua_State* L, const stateless_reference& r) noexcept { + if (r.ref == LUA_REFNIL) { + ref = LUA_REFNIL; + return; + } + if (r.ref == LUA_NOREF || L == nullptr) { + ref = LUA_NOREF; + return; + } + ref = r.copy(L); + } + + stateless_reference(lua_State* L, stateless_reference&& r) noexcept { + if (r.ref == LUA_REFNIL) { + ref = LUA_REFNIL; + return; + } + if (r.ref == LUA_NOREF || L == nullptr) { + ref = LUA_NOREF; + return; + } + ref = r.ref; + r.ref = LUA_NOREF; + } + + stateless_reference(lua_State* L, const stack_reference& r) noexcept { + if (L == nullptr || r.lua_state() == nullptr || r.get_type() == type::none) { + ref = LUA_NOREF; + return; + } + if (r.get_type() == type::lua_nil) { + ref = LUA_REFNIL; + return; + } + if (L != r.lua_state() && !detail::xmovable(L, r.lua_state())) { + return; + } + r.push(L); + ref = luaL_ref(L, LUA_REGISTRYINDEX); + } + + stateless_reference(lua_State* L, int index = -1) noexcept { + // use L to stick with that state's execution stack +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, "not enough Lua stack space to push this reference value"); +#endif // make sure stack doesn't overflow + lua_pushvalue(L, index); + ref = luaL_ref(L, LUA_REGISTRYINDEX); + } + stateless_reference(lua_State* L, ref_index index) noexcept { + lua_rawgeti(L, LUA_REGISTRYINDEX, index.index); + ref = luaL_ref(L, LUA_REGISTRYINDEX); + } + stateless_reference(lua_State*, lua_nil_t) noexcept { + } + + ~stateless_reference() noexcept = default; + + stateless_reference(const stateless_reference& o) noexcept = delete; + stateless_reference& operator=(const stateless_reference& r) noexcept = delete; + + stateless_reference(stateless_reference&& o) noexcept + : ref(o.ref) { + o.ref = LUA_NOREF; + } + + stateless_reference& operator=(stateless_reference&& o) noexcept { + ref = o.ref; + o.ref = LUA_NOREF; + return *this; + } + + int push(lua_State* L) const noexcept { +#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK + luaL_checkstack(L, 1, "not enough Lua stack space to push this reference value"); +#endif // make sure stack doesn't overflow + lua_rawgeti(L, LUA_REGISTRYINDEX, ref); + return 1; + } + + void pop(lua_State* L, int n = 1) const noexcept { + lua_pop(L, n); + } + + int registry_index() const noexcept { + return ref; + } + + bool valid(lua_State*) const noexcept { + return !(ref == LUA_NOREF || ref == LUA_REFNIL); + } + + const void* pointer(lua_State* L) const noexcept { + int si = push(L); + const void* vp = lua_topointer(L, -si); + lua_pop(L, si); + return vp; + } + + type get_type(lua_State* L) const noexcept { + int p = push(L); + int result = lua_type(L, -1); + pop(L, p); + return static_cast(result); + } + + void abandon(lua_State* = nullptr) { + ref = LUA_NOREF; + } + + void deref(lua_State* L) const noexcept { + luaL_unref(L, LUA_REGISTRYINDEX, ref); + } + }; + template - class basic_reference { + class basic_reference : public stateless_reference { private: template friend class basic_reference; lua_State* luastate = nullptr; // non-owning - int ref = LUA_NOREF; - - int copy() const noexcept { - if (ref == LUA_NOREF) - return LUA_NOREF; - push(); - return luaL_ref(lua_state(), LUA_REGISTRYINDEX); - } template void copy_assign(const basic_reference& r) { @@ -8821,20 +8967,26 @@ namespace sol { protected: basic_reference(lua_State* L, detail::global_tag) noexcept - : luastate(detail::pick_main_thread(L, L)) { -#if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(L, 1, "not enough Lua stack space to push this reference value"); -#endif // make sure stack doesn't overflow - lua_pushglobaltable(lua_state()); - ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX); + : basic_reference(detail::pick_main_thread(L, L), detail::global_, detail::global_) { } - int stack_index() const noexcept { - return -1; + basic_reference(lua_State* L, detail::global_tag, detail::global_tag) noexcept + : stateless_reference(L, detail::global_), luastate(L) { + } + + basic_reference(lua_State* oL, const basic_reference& o) noexcept : stateless_reference(oL, o), luastate(oL) { } void deref() const noexcept { - luaL_unref(lua_state(), LUA_REGISTRYINDEX, ref); + return stateless_reference::deref(lua_state()); + } + + int copy() const noexcept { + return copy(lua_state()); + } + + int copy(lua_State* L) const noexcept { + return stateless_reference::copy(L); } public: @@ -8929,21 +9081,20 @@ namespace sol { } basic_reference(const basic_reference& o) noexcept - : luastate(o.lua_state()), ref(o.copy()) { + : stateless_reference(o.copy()), luastate(o.lua_state()) { } basic_reference(basic_reference&& o) noexcept - : luastate(o.lua_state()), ref(o.ref) { + : stateless_reference(std::move(o)), luastate(o.lua_state()) { o.luastate = nullptr; - o.ref = LUA_NOREF; } basic_reference(const basic_reference& o) noexcept - : luastate(detail::pick_main_thread < main_only && !main_only > (o.lua_state(), o.lua_state())), ref(o.copy()) { + : basic_reference(detail::pick_main_thread < main_only && !main_only > (o.lua_state(), o.lua_state()), o) { } basic_reference(basic_reference&& o) noexcept - : luastate(detail::pick_main_thread < main_only && !main_only > (o.lua_state(), o.lua_state())), ref(o.ref) { + : stateless_reference(std::move(o)), luastate(detail::pick_main_thread(o.lua_state(), o.lua_state())) { o.luastate = nullptr; o.ref = LUA_NOREF; } @@ -8987,17 +9138,17 @@ namespace sol { return push(lua_state()); } - int push(lua_State* Ls) const noexcept { + int push(lua_State* L) const noexcept { #if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK - luaL_checkstack(Ls, 1, "not enough Lua stack space to push this reference value"); + luaL_checkstack(L, 1, "not enough Lua stack space to push this reference value"); #endif // make sure stack doesn't overflow if (lua_state() == nullptr) { - lua_pushnil(Ls); + lua_pushnil(L); return 1; } lua_rawgeti(lua_state(), LUA_REGISTRYINDEX, ref); - if (Ls != lua_state()) { - lua_xmove(lua_state(), Ls, 1); + if (L != lua_state()) { + lua_xmove(lua_state(), L, 1); } return 1; } @@ -9006,23 +9157,20 @@ namespace sol { pop(lua_state()); } - void pop(lua_State* Ls, int n = 1) const noexcept { - lua_pop(Ls, n); + void pop(lua_State* L, int n = 1) const noexcept { + stateless_reference::pop(L, n); } int registry_index() const noexcept { - return ref; + return stateless_reference::registry_index(); } bool valid() const noexcept { - return !(ref == LUA_NOREF || ref == LUA_REFNIL); + return stateless_reference::valid(lua_state()); } const void* pointer() const noexcept { - int si = push(); - const void* vp = lua_topointer(lua_state(), -si); - lua_pop(this->lua_state(), si); - return vp; + return stateless_reference::pointer(lua_state()); } explicit operator bool() const noexcept { @@ -9030,9 +9178,7 @@ namespace sol { } type get_type() const noexcept { - auto pp = stack::push_pop(*this); - int result = lua_type(lua_state(), -1); - return static_cast(result); + return stateless_reference::get_type(lua_state()); } lua_State* lua_state() const noexcept { @@ -10721,7 +10867,7 @@ namespace sol { namespace stack { else if constexpr (meta::any_same_v) { return stack::check>(L, index, std::forward(handler), tracking); } - else if constexpr (std::is_integral_v) { + else if constexpr (std::is_integral_v || std::is_same_v) { tracking.use(1); #if SOL_LUA_VERSION >= 503 #if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS @@ -10779,7 +10925,7 @@ namespace sol { namespace stack { return success; #endif // Lua Version 5.3 versus others } - else if constexpr (std::is_floating_point_v) { + else if constexpr (std::is_floating_point_v || std::is_same_v) { tracking.use(1); #if defined(SOL_STRINGS_ARE_NUMBERS) && SOL_STRINGS_ARE_NUMBERS bool success = lua_isnumber(L, index) == 1; @@ -11714,7 +11860,7 @@ namespace sol { namespace stack { tracking.use(1); return static_cast(lua_tointegerx(L, index, nullptr)); } - else if constexpr (std::is_integral_v) { + else if constexpr (std::is_integral_v || std::is_same_v) { tracking.use(1); #if SOL_LUA_VERSION >= 503 if (lua_isinteger(L, index) != 0) { @@ -11723,7 +11869,7 @@ namespace sol { namespace stack { #endif return static_cast(llround(lua_tonumber(L, index))); } - else if constexpr (std::is_floating_point_v) { + else if constexpr (std::is_floating_point_v || std::is_same_v) { tracking.use(1); return static_cast(lua_tonumber(L, index)); } @@ -12653,7 +12799,7 @@ namespace stack { } return stack_detail::unchecked_get(L, index, tracking); } - else if constexpr (std::is_integral_v && !std::is_same_v) { + else if constexpr ((std::is_integral_v || std::is_same_v) && !std::is_same_v) { #if SOL_LUA_VERSION >= 503 if (lua_isinteger(L, index) != 0) { tracking.use(1); @@ -12679,7 +12825,7 @@ namespace stack { handler(L, index, type::number, t, "not an integer"); return nullopt; } - else if constexpr(std::is_floating_point_v) { + else if constexpr (std::is_floating_point_v || std::is_same_v) { int isnum = 0; lua_Number value = lua_tonumberx(L, index, &isnum); if (isnum == 0) { @@ -13063,7 +13209,7 @@ namespace sol { lua_pushboolean(L, std::forward(args)...); return 1; } - else if constexpr (std::is_integral_v) { + else if constexpr (std::is_integral_v || std::is_same_v) { const Tu& value(std::forward(args)...); #if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK luaL_checkstack(L, 1, detail::not_enough_stack_space_integral); @@ -13089,7 +13235,7 @@ namespace sol { lua_pushnumber(L, static_cast(value)); return 1; } - else if constexpr (std::is_floating_point_v) { + else if constexpr (std::is_floating_point_v || std::is_same_v) { #if defined(SOL_SAFE_STACK_CHECK) && SOL_SAFE_STACK_CHECK luaL_checkstack(L, 1, detail::not_enough_stack_space_floating); #endif // make sure stack doesn't overflow diff --git a/tests/runtime_tests/source/containers.table.cpp b/tests/runtime_tests/source/containers.table.cpp index 55218b35..0389b855 100644 --- a/tests/runtime_tests/source/containers.table.cpp +++ b/tests/runtime_tests/source/containers.table.cpp @@ -226,14 +226,11 @@ TEST_CASE("containers/as_table with pointers", "test to make sure pointers are r struct Entity { public: - Entity(EHandle handle) : handle_(handle) {} + Entity(EHandle) {} Entity(const Entity&) = default; Entity(Entity&&) = default; Entity& operator=(const Entity&) = default; Entity& operator=(Entity&&) = default; - - private: - EHandle handle_; }; auto test_func_vec = []() -> std::vector { diff --git a/tests/runtime_tests/source/usertypes.properties.cpp b/tests/runtime_tests/source/usertypes.properties.cpp index a5a60139..1e094031 100644 --- a/tests/runtime_tests/source/usertypes.properties.cpp +++ b/tests/runtime_tests/source/usertypes.properties.cpp @@ -21,6 +21,10 @@ // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// we have a test for weirdly aligned wrappers +// do not make lots of noise about it +#pragma warning(disable : 4324) + #include "sol_test.hpp" #include "common_classes.hpp"