add xmove constructors for function, (light )userdata, table, reference and object

add additional coroutine example
improve traits
add tests for thread transfers
update single
This commit is contained in:
ThePhD 2017-09-11 16:12:23 -04:00
parent 85c81f618c
commit 074b9ae655
15 changed files with 382 additions and 56 deletions

View File

@ -16,14 +16,19 @@ Note that you can obtain safety with regards to functions you bind by using the
``SOL_SAFE_FUNCTION`` triggers the following change:
* All uses of ``sol::function`` and ``sol::stack_function`` will default to ``sol::protected_function`` and ``sol::stack_protected_function``, respectively, rather than ``sol::unsafe_function`` and ``sol::stack_unsafe_function``.
* **Not** turned on by default under any detectible compiler settings: *you MUST turn this one on manually*
* Will make any ``sol::state_view::script`` calls default to their safe variants if there is no supplied environment or error handler function
* **Not** turned on by default under any detectible compiler settings: *this MUST be turned on manually*
``SOL_STRINGS_ARE_NUMBERS`` triggers the following changes:
* ``sol::stack::get`` and ``sol::stack::check_get`` will allow anything that Lua thinks is number-worthy to be number-worthy
* This includes: integers, numbers, and strings
* Does **not** include: booleans, types with ``__tostring`` enabled, and everything else
* Overrides ``SOL_CHECK_ARGUMENTS`` and always applies if it is turned on
* **Not** turned on by default under any settings: *you MUST be turned on manually*
* **Not** turned on by default under any settings: *this MUST be turned on manually*
``SOL_NO_CHECK_NUMBER_PRECISION`` triggers the following changes:
* If ``SOL_CHECK_ARGUMENTS`` is defined, turns off number precision and integer precision fitting when pushing numbers into sol2
* **Not** turned on by default under any settings: *thus MUSt be turned on manually*
``SOL_CHECK_ARGUMENTS`` triggers the following changes:
* ``sol::stack::get`` (used everywhere) defaults to using ``sol::stack::check_get`` and dereferencing the argument. It uses ``sol::type_panic`` as the handler if something goes wrong
@ -31,10 +36,8 @@ Note that you can obtain safety with regards to functions you bind by using the
* ``sol::stack::call`` and its variants will, if no templated boolean is specified, check all of the arguments for a function call
* If ``SOL_SAFE_USERTYPE`` is not defined, it gets defined to turn being on and the effects described above kick in
* Numbers will also be checked to see if they fit within a ``lua_Number`` if there is no ``lua_Integer`` type available that can fit your signed or unsigned number. You can opt-out of this behavior with ``SOL_NO_CHECK_NUMBER_PRECISION``
* **Not** turned on by default under any settings: *this MUST be turned on manually*
``SOL_NO_CHECK_NUMBER_PRECISION`` triggers the following changes:
* If ``SOL_CHECK_ARGUMENTS`` is defined, turns off number precision and integer precision fitting when pushing numbers into sol2
Tests are compiled with this on to ensure everything is going as expected. Remember that if you want these features, you must explicitly turn them on all of them to be sure you are getting them.
memory

View File

@ -6,3 +6,60 @@ Lua has no thread safety. sol2 does not force thread safety bottlenecks anywhere
Assume any access or any call on Lua affects the whole global state (because it does, in a fair bit of cases). Therefore, every call to a state should be blocked off in C++ with some kind of access control. When you start hitting the same state from multiple threads, race conditions (data or instruction) can happen. Individual Lua coroutines might be able to run on separate C++-created threads without tanking the state utterly, since each Lua coroutine has the capability to run on an independent Lua thread which has its own stack, as well as some other associated bits and pieces that won't quite interfere with the global state.
To handle multithreaded environments, it is encouraged to either spawn mutliple Lua states for each thread you are working with and keep inter-state communication to synchronized serialization points. Using coroutines and Lua's threads might also buy you some concurrency and parallelism, but remember that Lua's threading technique is ultimately cooperative and requires explicit yielding and resuming (simplified as function calls for :doc:`sol::coroutine<api/coroutine>`).
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. For example:
.. codeblock:: cpp
:caption: transfer from state function
:name: state-transfer
#define SOL_CHECK_ARGUMENTS
#include <sol.hpp>
#include <iostream>
int main (int, char*[]) {
sol::state lua;
lua.open_libraries();
sol::function transferred_into;
lua["f"] = [&lua, &transferred_into](sol::object t, sol::this_state this_L) {
std::cout << "state of main : " << (void*)lua.lua_state() << std::endl;
std::cout << "state of function : " << (void*)this_L.lua_state() << std::endl;
// pass original lua_State* (or sol::state/sol::state_view)
// transfers ownership from the state of "t",
// to the "lua" sol::state
transferred_into = sol::function(lua, t);
};
lua.script(R"(
i = 0
function test()
co = coroutine.create(
function()
local g = function() i = i + 1 end
f(g)
g = nil
collectgarbage()
end
)
coroutine.resume(co)
co = nil
collectgarbage()
end
)");
// give it a try
lua.safe_script("test()");
// should call 'g' from main thread, increment i by 1
transferred_into();
// check
int i = lua["i"];
assert(i == 1);
return 0;
}

View File

@ -0,0 +1,46 @@
#define SOL_CHECK_ARGUMENTS
#include <sol.hpp>
#include <iostream>
int main(int, char*[]) {
sol::state lua;
lua.open_libraries();
sol::function transferred_into;
lua["f"] = [&lua, &transferred_into](sol::object t, sol::this_state this_L) {
std::cout << "state of main : " << (void*)lua.lua_state() << std::endl;
std::cout << "state of function : " << (void*)this_L.lua_state() << std::endl;
// pass original lua_State* (or sol::state/sol::state_view)
// transfers ownership from the state of "t",
// to the "lua" sol::state
transferred_into = sol::function(lua, t);
};
lua.script(R"(
i = 0
function test()
co = coroutine.create(
function()
local g = function() i = i + 1 end
f(g)
g = nil
collectgarbage()
end
)
coroutine.resume(co)
co = nil
collectgarbage()
end
)");
// give it a try
lua.safe_script("test()");
// should call 'g' from main thread, increment i by 1
transferred_into();
// check
int i = lua["i"];
assert(i == 1);
return 0;
}

View File

@ -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-11 17:24:33.633292 UTC
// This header was generated with sol v2.18.2 (revision ac849a5)
// Generated 2017-09-11 20:10:45.557320 UTC
// This header was generated with sol v2.18.2 (revision 85c81f6)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_HPP
@ -980,6 +980,9 @@ namespace sol {
template<typename... Args>
using enable = std::enable_if_t<all<Args...>::value, enable_t>;
template<typename... Args>
using enable_any = std::enable_if_t<any<Args...>::value, enable_t>;
template<typename... Args>
using disable = std::enable_if_t<neg<all<Args...>>::value, enable_t>;
@ -4603,10 +4606,15 @@ namespace sol {
struct this_state {
lua_State* L;
operator lua_State* () const {
return L;
operator lua_State* () const noexcept {
return lua_state();
}
lua_State* operator-> () const {
lua_State* operator-> () const noexcept {
return lua_state();
}
lua_State* lua_state() const noexcept {
return L;
}
};
@ -5522,7 +5530,7 @@ namespace sol {
namespace sol {
class stack_reference {
private:
lua_State* L = nullptr;
lua_State* luastate = nullptr;
int index = 0;
protected:
@ -5533,11 +5541,25 @@ namespace sol {
public:
stack_reference() noexcept = default;
stack_reference(lua_nil_t) noexcept : stack_reference() {};
stack_reference(lua_State* L, lua_nil_t) noexcept : L(L), index(0) {}
stack_reference(lua_State* L, int i) noexcept : L(L), index(lua_absindex(L, i)) {}
stack_reference(lua_State* L, absolute_index i) noexcept : L(L), index(i) {}
stack_reference(lua_State* L, raw_index i) noexcept : L(L), index(i) {}
stack_reference(lua_State* L, lua_nil_t) noexcept : luastate(L), index(0) {}
stack_reference(lua_State* L, int i) noexcept : stack_reference(L, absolute_index(L, i)) {}
stack_reference(lua_State* L, absolute_index i) noexcept : luastate(L), index(i) {}
stack_reference(lua_State* L, raw_index i) noexcept : luastate(L), index(i) {}
stack_reference(lua_State* L, ref_index i) noexcept = delete;
stack_reference(lua_State* L, const reference& r) noexcept = delete;
stack_reference(lua_State* L, const stack_reference& r) noexcept : luastate(L) {
if (!r.valid()) {
index = 0;
return;
}
int i = r.stack_index();
if (r.lua_state() != luastate) {
lua_pushvalue(r.lua_state(), r.index);
lua_xmove(r.lua_state(), luastate, 1);
i = absolute_index(luastate, -1);
}
index = i;
}
stack_reference(stack_reference&& o) noexcept = default;
stack_reference& operator=(stack_reference&&) noexcept = default;
stack_reference(const stack_reference&) noexcept = default;
@ -5568,12 +5590,12 @@ namespace sol {
}
type get_type() const noexcept {
int result = lua_type(L, index);
int result = lua_type(lua_state(), index);
return static_cast<type>(result);
}
lua_State* lua_state() const noexcept {
return L;
return luastate;
}
bool valid() const noexcept {
@ -5722,6 +5744,41 @@ namespace sol {
reference(lua_nil_t) noexcept : reference() {}
reference(const stack_reference& r) noexcept : reference(r.lua_state(), r.stack_index()) {}
reference(stack_reference&& r) noexcept : reference(r.lua_state(), r.stack_index()) {}
reference(lua_State* L, const reference& r) noexcept : luastate(L) {
if (r.ref == LUA_NOREF) {
ref = LUA_NOREF;
return;
}
int p = r.push();
if (r.lua_state() != luastate) {
lua_xmove(r.lua_state(), L, p);
}
ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);
}
reference(lua_State* L, reference&& r) noexcept : luastate(L) {
if (r.ref == LUA_NOREF) {
ref = LUA_NOREF;
return;
}
if (r.lua_state() != luastate) {
int p = r.push();
lua_xmove(r.lua_state(), L, p);
ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);
}
else {
ref = r.ref;
r.luastate = nullptr;
r.ref = LUA_NOREF;
}
}
reference(lua_State* L, const stack_reference& r) noexcept : luastate(L) {
if (!r.valid()) {
ref = LUA_NOREF;
return;
}
r.push(luastate);
ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);
}
reference(lua_State* L, int index = -1) noexcept : luastate(L) {
lua_pushvalue(lua_state(), index);
ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);
@ -5774,7 +5831,10 @@ namespace sol {
}
int push(lua_State* Ls) const noexcept {
lua_rawgeti(Ls, LUA_REGISTRYINDEX, ref);
lua_rawgeti(lua_state(), LUA_REGISTRYINDEX, ref);
if (Ls != lua_state()) {
lua_xmove(lua_state(), Ls, 1);
}
return 1;
}
@ -11737,8 +11797,11 @@ namespace sol {
basic_function& operator=(basic_function&&) = default;
basic_function(const stack_reference& r) : basic_function(r.lua_state(), r.stack_index()) {}
basic_function(stack_reference&& r) : basic_function(r.lua_state(), r.stack_index()) {}
template <typename T, meta::enable<meta::neg<is_lua_index<meta::unqualified_t<T>>>> = meta::enabler>
basic_function(lua_State* L, T&& r) : basic_function(L, sol::ref_index(r.registry_index())) {}
template <typename T, meta::enable_any<
std::is_base_of<reference, meta::unqualified_t<T>>,
std::is_base_of<stack_reference, meta::unqualified_t<T>>
> = meta::enabler>
basic_function(lua_State* L, T&& r) : base_t(L, std::forward<T>(r)) {}
basic_function(lua_State* L, int index = -1) : base_t(L, index) {
#ifdef SOL_CHECK_ARGUMENTS
constructor_handler handler{};
@ -12085,10 +12148,16 @@ namespace sol {
> = meta::enabler>
basic_protected_function(Proxy&& p, Handler&& eh) : basic_protected_function(detail::force_cast<base_t>(p), std::forward<Handler>(eh)) {}
template <typename T, meta::enable<meta::neg<is_lua_index<meta::unqualified_t<T>>>> = meta::enabler>
template <typename T, meta::enable<
std::is_base_of<reference, meta::unqualified_t<T>>,
std::is_base_of<stack_reference, meta::unqualified_t<T>>
> = meta::enabler>
basic_protected_function(lua_State* L, T&& r) : basic_protected_function(L, std::forward<T>(r), get_default_handler(L)) {}
template <typename T, meta::enable<meta::neg<is_lua_index<meta::unqualified_t<T>>>> = meta::enabler>
basic_protected_function(lua_State* L, T&& r, handler_t eh) : basic_protected_function(L, sol::ref_index(r.registry_index()), std::move(eh)) {}
template <typename T, meta::enable_any<
std::is_base_of<reference, meta::unqualified_t<T>>,
std::is_base_of<stack_reference, meta::unqualified_t<T>>
> = meta::enabler>
basic_protected_function(lua_State* L, T&& r, handler_t eh) : base_t(L, std::forward<T>(r)), error_handler(std::move(eh)) {}
basic_protected_function(lua_State* L, int index = -1) : basic_protected_function(L, index, get_default_handler(L)) {}
basic_protected_function(lua_State* L, int index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) {
@ -12551,8 +12620,11 @@ namespace sol {
basic_userdata& operator=(basic_userdata&&) = default;
basic_userdata(const stack_reference& r) : basic_userdata(r.lua_state(), r.stack_index()) {}
basic_userdata(stack_reference&& r) : basic_userdata(r.lua_state(), r.stack_index()) {}
template <typename T, meta::enable<meta::neg<is_lua_index<meta::unqualified_t<T>>>> = meta::enabler>
basic_userdata(lua_State* L, T&& r) : basic_userdata(L, sol::ref_index(r.registry_index())) {}
template <typename T, meta::enable_any<
std::is_base_of<reference, meta::unqualified_t<T>>,
std::is_base_of<stack_reference, meta::unqualified_t<T>>
> = meta::enabler>
basic_userdata(lua_State* L, T&& r) : base_t(L, std::forward<T>(r)) {}
basic_userdata(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS
constructor_handler handler{};
@ -12590,8 +12662,11 @@ namespace sol {
basic_lightuserdata& operator=(basic_lightuserdata&&) = default;
basic_lightuserdata(const stack_reference& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) {}
basic_lightuserdata(stack_reference&& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) {}
template <typename T, meta::enable<meta::neg<is_lua_index<T>>> = meta::enabler>
basic_lightuserdata(lua_State* L, T&& r) : basic_lightuserdata(L, sol::ref_index(r.registry_index())) {}
template <typename T, meta::enable_any<
std::is_base_of<reference, meta::unqualified_t<T>>,
std::is_base_of<stack_reference, meta::unqualified_t<T>>
> = meta::enabler>
basic_lightuserdata(lua_State* L, T&& r) : basic_lightuserdata(L, std::forward<T>(r)) {}
basic_lightuserdata(lua_State* L, int index = -1) : base_t(L, index) {
#ifdef SOL_CHECK_ARGUMENTS
constructor_handler handler{};
@ -13025,8 +13100,17 @@ namespace sol {
public:
basic_object() noexcept = default;
template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_object>>, meta::neg<std::is_same<base_type, stack_reference>>, std::is_base_of<base_type, meta::unqualified_t<T>>> = meta::enabler>
template <typename T, meta::enable<
meta::neg<std::is_same<meta::unqualified_t<T>, basic_object>>,
meta::neg<std::is_same<base_type, stack_reference>>,
std::is_base_of<base_type, meta::unqualified_t<T>>
> = meta::enabler>
basic_object(T&& r) : base_t(std::forward<T>(r)) {}
template <typename T, meta::enable_any<
std::is_base_of<reference, meta::unqualified_t<T>>,
std::is_base_of<stack_reference, meta::unqualified_t<T>>
> = meta::enabler>
basic_object(lua_State* L, T&& r) : base_t(L, std::forward<T>(r)) {}
basic_object(lua_nil_t r) : base_t(r) {}
basic_object(const basic_object&) = default;
basic_object(basic_object&&) = default;
@ -13036,6 +13120,7 @@ namespace sol {
basic_object(const proxy_base<Super>& r) noexcept : basic_object(r.operator basic_object()) {}
template <typename Super>
basic_object(proxy_base<Super>&& r) noexcept : basic_object(r.operator basic_object()) {}
basic_object(lua_State* L, lua_nil_t r) noexcept : base_t(L, r) {}
basic_object(lua_State* L, int index = -1) noexcept : base_t(L, index) {}
basic_object(lua_State* L, absolute_index index) noexcept : base_t(L, index) {}
basic_object(lua_State* L, raw_index index) noexcept : base_t(L, index) {}
@ -16518,8 +16603,11 @@ namespace sol {
basic_table_core& operator=(basic_table_core&&) = default;
basic_table_core(const stack_reference& r) : basic_table_core(r.lua_state(), r.stack_index()) {}
basic_table_core(stack_reference&& r) : basic_table_core(r.lua_state(), r.stack_index()) {}
template <typename T, meta::enable<meta::neg<is_lua_index<meta::unqualified_t<T>>>> = meta::enabler>
basic_table_core(lua_State* L, T&& r) : basic_table_core(L, sol::ref_index(r.registry_index())) {}
template <typename T, meta::enable_any<
std::is_base_of<reference, meta::unqualified_t<T>>,
std::is_base_of<stack_reference, meta::unqualified_t<T>>
> = meta::enabler>
basic_table_core(lua_State* L, T&& r) : basic_table_core(L, std::forward<T>(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<stack_reference, base_type>::value) {
lua_pop(L, 1);

View File

@ -23,7 +23,7 @@
#define SOL_COMPATIBILITY_HPP
// The various pieces of the compatibility layer
// comes from https://github.com/keplerproject/lua-compat-5.2
// comes from https://github.com/keplerproject/lua-compat-5.3
// but has been modified in many places for use with Sol and luajit,
// though the core abstractions remain the same
@ -40,7 +40,6 @@
#include "compatibility//compat-5.3.h"
#endif // SOL_NO_COMPAT
#endif // SOL_COMPATIBILITY_HPP

View File

@ -66,8 +66,17 @@ namespace sol {
public:
basic_object() noexcept = default;
template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_object>>, meta::neg<std::is_same<base_type, stack_reference>>, std::is_base_of<base_type, meta::unqualified_t<T>>> = meta::enabler>
template <typename T, meta::enable<
meta::neg<std::is_same<meta::unqualified_t<T>, basic_object>>,
meta::neg<std::is_same<base_type, stack_reference>>,
std::is_base_of<base_type, meta::unqualified_t<T>>
> = meta::enabler>
basic_object(T&& r) : base_t(std::forward<T>(r)) {}
template <typename T, meta::enable_any<
std::is_base_of<reference, meta::unqualified_t<T>>,
std::is_base_of<stack_reference, meta::unqualified_t<T>>
> = meta::enabler>
basic_object(lua_State* L, T&& r) : base_t(L, std::forward<T>(r)) {}
basic_object(lua_nil_t r) : base_t(r) {}
basic_object(const basic_object&) = default;
basic_object(basic_object&&) = default;
@ -77,6 +86,7 @@ namespace sol {
basic_object(const proxy_base<Super>& r) noexcept : basic_object(r.operator basic_object()) {}
template <typename Super>
basic_object(proxy_base<Super>&& r) noexcept : basic_object(r.operator basic_object()) {}
basic_object(lua_State* L, lua_nil_t r) noexcept : base_t(L, r) {}
basic_object(lua_State* L, int index = -1) noexcept : base_t(L, index) {}
basic_object(lua_State* L, absolute_index index) noexcept : base_t(L, index) {}
basic_object(lua_State* L, raw_index index) noexcept : base_t(L, index) {}

View File

@ -214,10 +214,16 @@ namespace sol {
> = meta::enabler>
basic_protected_function(Proxy&& p, Handler&& eh) : basic_protected_function(detail::force_cast<base_t>(p), std::forward<Handler>(eh)) {}
template <typename T, meta::enable<meta::neg<is_lua_index<meta::unqualified_t<T>>>> = meta::enabler>
template <typename T, meta::enable<
std::is_base_of<reference, meta::unqualified_t<T>>,
std::is_base_of<stack_reference, meta::unqualified_t<T>>
> = meta::enabler>
basic_protected_function(lua_State* L, T&& r) : basic_protected_function(L, std::forward<T>(r), get_default_handler(L)) {}
template <typename T, meta::enable<meta::neg<is_lua_index<meta::unqualified_t<T>>>> = meta::enabler>
basic_protected_function(lua_State* L, T&& r, handler_t eh) : basic_protected_function(L, sol::ref_index(r.registry_index()), std::move(eh)) {}
template <typename T, meta::enable_any<
std::is_base_of<reference, meta::unqualified_t<T>>,
std::is_base_of<stack_reference, meta::unqualified_t<T>>
> = meta::enabler>
basic_protected_function(lua_State* L, T&& r, handler_t eh) : base_t(L, std::forward<T>(r)), error_handler(std::move(eh)) {}
basic_protected_function(lua_State* L, int index = -1) : basic_protected_function(L, index, get_default_handler(L)) {}
basic_protected_function(lua_State* L, int index, handler_t eh) : base_t(L, index), error_handler(std::move(eh)) {

View File

@ -138,6 +138,41 @@ namespace sol {
reference(lua_nil_t) noexcept : reference() {}
reference(const stack_reference& r) noexcept : reference(r.lua_state(), r.stack_index()) {}
reference(stack_reference&& r) noexcept : reference(r.lua_state(), r.stack_index()) {}
reference(lua_State* L, const reference& r) noexcept : luastate(L) {
if (r.ref == LUA_NOREF) {
ref = LUA_NOREF;
return;
}
int p = r.push();
if (r.lua_state() != luastate) {
lua_xmove(r.lua_state(), L, p);
}
ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);
}
reference(lua_State* L, reference&& r) noexcept : luastate(L) {
if (r.ref == LUA_NOREF) {
ref = LUA_NOREF;
return;
}
if (r.lua_state() != luastate) {
int p = r.push();
lua_xmove(r.lua_state(), L, p);
ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);
}
else {
ref = r.ref;
r.luastate = nullptr;
r.ref = LUA_NOREF;
}
}
reference(lua_State* L, const stack_reference& r) noexcept : luastate(L) {
if (!r.valid()) {
ref = LUA_NOREF;
return;
}
r.push(luastate);
ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);
}
reference(lua_State* L, int index = -1) noexcept : luastate(L) {
lua_pushvalue(lua_state(), index);
ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);
@ -190,7 +225,10 @@ namespace sol {
}
int push(lua_State* Ls) const noexcept {
lua_rawgeti(Ls, LUA_REGISTRYINDEX, ref);
lua_rawgeti(lua_state(), LUA_REGISTRYINDEX, ref);
if (Ls != lua_state()) {
lua_xmove(lua_state(), Ls, 1);
}
return 1;
}

View File

@ -27,7 +27,7 @@
namespace sol {
class stack_reference {
private:
lua_State* L = nullptr;
lua_State* luastate = nullptr;
int index = 0;
protected:
@ -38,11 +38,25 @@ namespace sol {
public:
stack_reference() noexcept = default;
stack_reference(lua_nil_t) noexcept : stack_reference() {};
stack_reference(lua_State* L, lua_nil_t) noexcept : L(L), index(0) {}
stack_reference(lua_State* L, int i) noexcept : L(L), index(lua_absindex(L, i)) {}
stack_reference(lua_State* L, absolute_index i) noexcept : L(L), index(i) {}
stack_reference(lua_State* L, raw_index i) noexcept : L(L), index(i) {}
stack_reference(lua_State* L, lua_nil_t) noexcept : luastate(L), index(0) {}
stack_reference(lua_State* L, int i) noexcept : stack_reference(L, absolute_index(L, i)) {}
stack_reference(lua_State* L, absolute_index i) noexcept : luastate(L), index(i) {}
stack_reference(lua_State* L, raw_index i) noexcept : luastate(L), index(i) {}
stack_reference(lua_State* L, ref_index i) noexcept = delete;
stack_reference(lua_State* L, const reference& r) noexcept = delete;
stack_reference(lua_State* L, const stack_reference& r) noexcept : luastate(L) {
if (!r.valid()) {
index = 0;
return;
}
int i = r.stack_index();
if (r.lua_state() != luastate) {
lua_pushvalue(r.lua_state(), r.index);
lua_xmove(r.lua_state(), luastate, 1);
i = absolute_index(luastate, -1);
}
index = i;
}
stack_reference(stack_reference&& o) noexcept = default;
stack_reference& operator=(stack_reference&&) noexcept = default;
stack_reference(const stack_reference&) noexcept = default;
@ -73,12 +87,12 @@ namespace sol {
}
type get_type() const noexcept {
int result = lua_type(L, index);
int result = lua_type(lua_state(), index);
return static_cast<type>(result);
}
lua_State* lua_state() const noexcept {
return L;
return luastate;
}
bool valid() const noexcept {

View File

@ -176,8 +176,11 @@ namespace sol {
basic_table_core& operator=(basic_table_core&&) = default;
basic_table_core(const stack_reference& r) : basic_table_core(r.lua_state(), r.stack_index()) {}
basic_table_core(stack_reference&& r) : basic_table_core(r.lua_state(), r.stack_index()) {}
template <typename T, meta::enable<meta::neg<is_lua_index<meta::unqualified_t<T>>>> = meta::enabler>
basic_table_core(lua_State* L, T&& r) : basic_table_core(L, sol::ref_index(r.registry_index())) {}
template <typename T, meta::enable_any<
std::is_base_of<reference, meta::unqualified_t<T>>,
std::is_base_of<stack_reference, meta::unqualified_t<T>>
> = meta::enabler>
basic_table_core(lua_State* L, T&& r) : basic_table_core(L, std::forward<T>(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<stack_reference, base_type>::value) {
lua_pop(L, 1);

View File

@ -144,6 +144,9 @@ namespace sol {
template<typename... Args>
using enable = std::enable_if_t<all<Args...>::value, enable_t>;
template<typename... Args>
using enable_any = std::enable_if_t<any<Args...>::value, enable_t>;
template<typename... Args>
using disable = std::enable_if_t<neg<all<Args...>>::value, enable_t>;

View File

@ -443,10 +443,15 @@ namespace sol {
struct this_state {
lua_State* L;
operator lua_State* () const {
return L;
operator lua_State* () const noexcept {
return lua_state();
}
lua_State* operator-> () const {
lua_State* operator-> () const noexcept {
return lua_state();
}
lua_State* lua_state() const noexcept {
return L;
}
};

View File

@ -82,8 +82,11 @@ namespace sol {
basic_function& operator=(basic_function&&) = default;
basic_function(const stack_reference& r) : basic_function(r.lua_state(), r.stack_index()) {}
basic_function(stack_reference&& r) : basic_function(r.lua_state(), r.stack_index()) {}
template <typename T, meta::enable<meta::neg<is_lua_index<meta::unqualified_t<T>>>> = meta::enabler>
basic_function(lua_State* L, T&& r) : basic_function(L, sol::ref_index(r.registry_index())) {}
template <typename T, meta::enable_any<
std::is_base_of<reference, meta::unqualified_t<T>>,
std::is_base_of<stack_reference, meta::unqualified_t<T>>
> = meta::enabler>
basic_function(lua_State* L, T&& r) : base_t(L, std::forward<T>(r)) {}
basic_function(lua_State* L, int index = -1) : base_t(L, index) {
#ifdef SOL_CHECK_ARGUMENTS
constructor_handler handler{};

View File

@ -48,8 +48,11 @@ namespace sol {
basic_userdata& operator=(basic_userdata&&) = default;
basic_userdata(const stack_reference& r) : basic_userdata(r.lua_state(), r.stack_index()) {}
basic_userdata(stack_reference&& r) : basic_userdata(r.lua_state(), r.stack_index()) {}
template <typename T, meta::enable<meta::neg<is_lua_index<meta::unqualified_t<T>>>> = meta::enabler>
basic_userdata(lua_State* L, T&& r) : basic_userdata(L, sol::ref_index(r.registry_index())) {}
template <typename T, meta::enable_any<
std::is_base_of<reference, meta::unqualified_t<T>>,
std::is_base_of<stack_reference, meta::unqualified_t<T>>
> = meta::enabler>
basic_userdata(lua_State* L, T&& r) : base_t(L, std::forward<T>(r)) {}
basic_userdata(lua_State* L, int index = -1) : base_t(detail::no_safety, L, index) {
#ifdef SOL_CHECK_ARGUMENTS
constructor_handler handler{};
@ -87,8 +90,11 @@ namespace sol {
basic_lightuserdata& operator=(basic_lightuserdata&&) = default;
basic_lightuserdata(const stack_reference& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) {}
basic_lightuserdata(stack_reference&& r) : basic_lightuserdata(r.lua_state(), r.stack_index()) {}
template <typename T, meta::enable<meta::neg<is_lua_index<T>>> = meta::enabler>
basic_lightuserdata(lua_State* L, T&& r) : basic_lightuserdata(L, sol::ref_index(r.registry_index())) {}
template <typename T, meta::enable_any<
std::is_base_of<reference, meta::unqualified_t<T>>,
std::is_base_of<stack_reference, meta::unqualified_t<T>>
> = meta::enabler>
basic_lightuserdata(lua_State* L, T&& r) : basic_lightuserdata(L, std::forward<T>(r)) {}
basic_lightuserdata(lua_State* L, int index = -1) : base_t(L, index) {
#ifdef SOL_CHECK_ARGUMENTS
constructor_handler handler{};

View File

@ -61,4 +61,49 @@ end
}
counter -= 1;
REQUIRE(counter == 30);
}
}
TEST_CASE("coroutines/transfer", "test that things created inside of a coroutine can have their state transferred using lua_xmove constructors") {
for (std::size_t tries = 0; tries < 200; ++tries) {
sol::state lua;
lua.open_libraries();
{
sol::function f2;
lua["f"] = [&lua, &f2](sol::object t) {
f2 = sol::function(lua, t);
};
lua.script(R"(
i = 0
function INIT()
co = coroutine.create(
function()
local g = function() i = i + 1 end
f(g)
g = nil
collectgarbage()
end
)
coroutine.resume(co)
co = nil
collectgarbage()
end
)");
sol::function f3;
sol::function f1;
lua.safe_script("INIT()");
f2();
sol::function update = lua.safe_script("return function() collectgarbage() end");
update();
f3 = f2;
f3();
update();
f1 = f2;
f1();
update();
int i = lua["i"];
REQUIRE(i == 3);
}
}
}