Skip to content

Commit cb3acaa

Browse files
committed
add more documentation, add clear() to bytecode, include additional examples and better data
1 parent 09f5e86 commit cb3acaa

13 files changed

Lines changed: 354 additions & 152 deletions

File tree

docs/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@
2424
# # # Required minimum version statement
2525
cmake_minimum_required(VERSION 3.5.0)
2626

27-
find_package(PythonInterp 3)
27+
find_package(Python3 COMPONENTS Interpreter)
2828

29-
if (NOT PYTHONINTERP_FOUND)
29+
if (NOT Python3_Interpreter_FOUND)
3030
message(FATAL_ERROR "sol2 documentation cannot be generated as python 3 has not been found: install or set the python 3 interpreter for the docs to find it and be sure to pip install sphinx")
3131
endif()
3232

docs/source/api/coroutine.rst

Lines changed: 32 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3,61 +3,37 @@ coroutine
33
*resumable/yielding functions from Lua*
44

55

6-
A ``coroutine`` is a :doc:`reference<reference>` to a function in Lua that can be called multiple times to yield a specific result. It is run on the :doc:`lua_State<state>` that was used to create it (see :doc:`thread<thread>` for an example on how to get a coroutine that runs on a thread separate from your usual "main" :doc:`lua_State<state>`).
6+
A ``coroutine`` is a :doc:`reference<reference>` to a function in Lua that can be called multiple times to yield a specific result. It is a cooperative function. It is run on the :doc:`lua_State<state>` that was used to create it (see :doc:`thread<thread>` for an example on how to get a coroutine that runs on a stack space separate from your usual "main" stack space :doc:`lua_State<state>`).
77

8-
The ``coroutine`` object is entirely similar to the :doc:`protected_function<protected_function>` object, with additional member functions to check if a coroutine has yielded (:doc:`call_status::yielded<types>`) and is thus runnable again, whether it has completed (:ref:`call_status::ok<call-status>`) and thus cannot yield anymore values, or whether it has suffered an error (see :ref:`status()<status>` and :ref:`call_status<call-status>`'s error codes).
8+
The ``coroutine`` object is entirely similar to the :doc:`protected_function<protected_function>` object, with additional member functions to check if a coroutine has yielded (:doc:`call_status::yielded<types>`) and is thus runnable again, whether it has completed (:ref:`call_status::ok<call-status>`) and thus cannot yield anymore values, or whether it has suffered an error (see :ref:`status()<thread-status>`'s and :ref:`call_status<call-status>`'s error codes).
99

1010
For example, you can work with a coroutine like this:
1111

12-
.. code-block:: lua
12+
.. literalinclude:: ../../../examples/source/docs/coroutine_main.cpp
1313
:caption: co.lua
1414
:name: co-lua
15+
:lines: 8-15
16+
:linenos:
1517

16-
function loop()
17-
while counter ~= 30
18-
do
19-
coroutine.yield(counter);
20-
counter = counter + 1;
21-
end
22-
return counter
23-
end
18+
This is a function that yields. We set the ``counter`` value in C++, and then use the coroutine to get a few values:
2419

25-
This is a function that yields:
20+
.. literalinclude:: ../../../examples/source/docs/coroutine_main.cpp
21+
:caption: coroutine_main.cpp
22+
:name: coroutine_main
23+
:lines: 1-6,18-19,21,25-
24+
:linenos:
2625

27-
.. code-block:: cpp
28-
:caption: main.cpp
29-
:name: yield-main
30-
31-
sol::state lua;
32-
lua.open_libraries(sol::lib::base, sol::lib::coroutine);
33-
lua.script_file("co.lua");
34-
sol::coroutine cr = lua["loop"];
26+
Note that this code doesn't check for errors: to do so, you can call the function and assign it as ``auto result = loop_coroutine();``, then check ``result.valid()`` as is the case with :doc:`protected_function<protected_function>`.
3527

36-
for (int counter = 0; // start from 0
37-
counter < 10 && cr; // we want 10 values, and we only want to run if the coroutine "cr" is valid
38-
// Alternative: counter < 10 && cr.valid()
39-
++counter) {
40-
// Call the coroutine, does the computation and then suspends
41-
int value = cr();
42-
}
28+
Finally, you can run this coroutine on another stack space (NOT a different computer thread: Lua uses the term 'thread' a bit strangely, as we follow its usage of the term, but it is NOT a separate thread) by doing the following:
4329

44-
Note that this code doesn't check for errors: to do so, you can call the function and assign it as ``auto result = cr();``, then check ``result.valid()`` as is the case with :doc:`protected_function<protected_function>`. Finally, you can run this coroutine on another thread by doing the following:
45-
46-
.. code-block:: cpp
47-
:caption: main_with_thread.cpp
30+
.. literalinclude:: ../../../examples/source/docs/coroutine_thread.cpp
31+
:caption: coroutine_thread.cpp
4832
:name: yield-main-thread
33+
:lines: 1-6,18-19,21,25-
34+
:linenos:
4935

50-
sol::state lua;
51-
lua.open_libraries(sol::lib::base, sol::lib::coroutine);
52-
lua.script_file("co.lua");
53-
sol::thread runner = sol::thread::create(lua.lua_state());
54-
sol::state_view runnerstate = runner.state();
55-
sol::coroutine cr = runnerstate["loop"];
5636

57-
for (int counter = 0; counter < 10 && cr; ++counter) {
58-
// Call the coroutine, does the computation and then suspends
59-
int value = cr();
60-
}
6137

6238
The following are the members of ``sol::coroutine``:
6339

@@ -73,44 +49,44 @@ members
7349
Grabs the coroutine at the specified index given a ``lua_State*``.
7450

7551
.. code-block:: cpp
76-
:caption: returning the coroutine's status
52+
:caption: returning the coroutine's status
7753
:name: sol-coroutine-status
7854
79-
call_status status() const noexcept;
55+
call_status status() const noexcept;
8056
8157
Returns the status of a coroutine.
8258

8359

8460
.. code-block:: cpp
85-
:caption: checks for an error
61+
:caption: checks for an error
8662
:name: sol-coroutine-error
8763
88-
bool error() const noexcept;
64+
bool error() const noexcept;
8965
9066
Checks if an error occured when the coroutine was run.
9167

9268
.. _runnable:
9369

9470
.. code-block:: cpp
95-
:caption: runnable and explicit operator bool
71+
:caption: runnable and explicit operator bool
9672
:name: sol-coroutine-runnable
9773
98-
bool runnable () const noexcept;
99-
explicit operator bool() const noexcept;
74+
bool runnable () const noexcept;
75+
explicit operator bool() const noexcept;
10076
10177
These functions allow you to check if a coroutine can still be called (has more values to yield and has not errored). If you have a coroutine object ``coroutine my_co = /*...*/``, you can either check ``runnable()`` or do ``if ( my_co ) { /* use coroutine */ }``.
10278

10379
.. code-block:: cpp
104-
:caption: calling a coroutine
80+
:caption: calling a coroutine
10581
:name: sol-coroutine-operator-call
10682
107-
template<typename... Args>
108-
protected_function_result operator()( Args&&... args );
83+
template<typename... Args>
84+
protected_function_result operator()( Args&&... args );
10985
110-
template<typename... Ret, typename... Args>
111-
decltype(auto) call( Args&&... args );
86+
template<typename... Ret, typename... Args>
87+
decltype(auto) call( Args&&... args );
11288
113-
template<typename... Ret, typename... Args>
114-
decltype(auto) operator()( types<Ret...>, Args&&... args );
89+
template<typename... Ret, typename... Args>
90+
decltype(auto) operator()( types<Ret...>, Args&&... args );
11591
116-
Calls the coroutine. The second ``operator()`` lets you specify the templated return types using the ``my_co(sol::types<int, std::string>, ...)`` syntax. Check ``status()`` afterwards for more information about the success of the run or just check the coroutine object in an ifs tatement, as shown :ref:`above<runnable>`.
92+
Calls the coroutine. The second ``operator()`` lets you specify the templated return types using the ``my_co(sol::types<int, std::string>, ...)`` syntax. Check ``status()`` afterwards for more information about the success of the run or just check the coroutine object in an ifs tatement, as shown :ref:`above<runnable>`.

docs/source/api/environment.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@ free functions
3838
template <typename T>
3939
void set_environment( const environment& env, const T& target );
4040
41-
See :ref:`environment::set_on<environment-set-on>`.
41+
See :ref:`environment::set_on<sol-environment-set_on>`.
4242

4343

4444
.. code-block:: cpp
4545
:caption: function: get_environment
46-
:name: sol-environment-set_environment
46+
:name: sol-environment-get_environment
4747
4848
template <typename E = reference, typename T>
4949
basic_environment<E> get_environment( const T& target );

docs/source/threading.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ Lua has no thread safety. sol does not force thread safety bottlenecks anywhere.
55

66
Assume any access or any call on Lua affects the whole ``sol::state``/``lua_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're working with multiple C++ threads). When you start hitting the same state from multiple threads, race conditions (data or instruction) can happen.
77

8-
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 execution stack (Lua confusingly calls it a ``thread`` in the C API, but it really just means a separate execution stack) as well as some other associated bits and pieces that won't quite interfere with the global state.
8+
To handle multithreaded environments, it is encouraged to either spawn a Lua state (``sol::state``) for each thread you are working with and keep inter-state communication to synchronized serialization points. This means that 3 C++ threads should have 3 Lua states, and access between them should be controlled using some kind of synchronized C++ mechanism (actual transfer between states must be done by serializing the value into C++ and then re-pushing it into the other state).
99

10-
To handle multithreaded environments, it is encouraged to either spawn a Lua state (``sol::state``) for each thread you are working with and keep inter-state communication to synchronized serialization points. This means that 3 C++ threads should each have their own Lua state, and access between them should be controlled using some kind of synchronized C++ mechanism (actual transfer between states must be done by serializing the value into C++ and then re-pushing it into the other state).
10+
`Here is an example of a processor that explicitly serializes`_ Lua returns into C++ values, and Lua functions into state-transferrable byte code to do work.
1111

1212
Using coroutines and Lua's threads might also buy you some concurrency and parallelism (**unconfirmed and likely untrue, do not gamble on this**), 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>`).
1313

@@ -37,3 +37,5 @@ Here's an example of explicit state transferring below:
3737
.. literalinclude:: ../../examples/source/docs/state_transfer.cpp
3838
:name: state-transfer
3939
:linenos:
40+
41+
.. _Here is an example of a processor that explicitly serializes: https://github.com/ThePhD/sol2/blob/develop/examples/source/docs/std_thread.cpp
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#define SOL_ALL_SAFTIES_ON 1
2+
#include <sol/sol.hpp>
3+
4+
#include <iostream>
5+
6+
int main() {
7+
const auto& co_lua_script = R"(
8+
function loop()
9+
while counter ~= 30
10+
do
11+
coroutine.yield(counter);
12+
counter = counter + 1;
13+
end
14+
return counter
15+
end
16+
)";
17+
18+
sol::state lua;
19+
lua.open_libraries(sol::lib::base, sol::lib::coroutine);
20+
/*
21+
lua.script_file("co.lua");
22+
we load string directly rather than use a file
23+
*/
24+
lua.script(co_lua_script);
25+
sol::coroutine loop_coroutine = lua["loop"];
26+
// set counter variable in C++
27+
// (can set it to something else to
28+
// have loop_coroutine() yield different values)
29+
lua["counter"] = 20;
30+
31+
// example of using and re-using coroutine
32+
// you do not have to use coroutines in a loop,
33+
// this is just the example
34+
35+
// we start from 0;
36+
// we want 10 values, and we only want to
37+
// run if the coroutine "loop_coroutine" is valid
38+
for (int counter = 0; counter < 10 && loop_coroutine; ++counter) {
39+
// Alternative: counter < 10 && cr.valid()
40+
41+
// Call the coroutine, does the computation and then suspends
42+
// once it returns, we get the value back from the return
43+
// and then can use it
44+
// we can either leave the coroutine like that can come to it later,
45+
// or loop back around
46+
int value = loop_coroutine();
47+
std::cout << "In C++: " << value << std::endl;
48+
}
49+
50+
return 0;
51+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#define SOL_ALL_SAFTIES_ON 1
2+
#include <sol/sol.hpp>
3+
4+
#include <iostream>
5+
6+
int main() {
7+
const auto& co_lua_script = R"(
8+
function loop()
9+
while counter ~= 30
10+
do
11+
coroutine.yield(counter);
12+
counter = counter + 1;
13+
end
14+
return counter
15+
end
16+
)";
17+
18+
sol::state lua;
19+
lua.open_libraries(sol::lib::base, sol::lib::coroutine);
20+
/*
21+
lua.script_file("co.lua");
22+
we load string directly rather than use a file
23+
*/
24+
lua.script(co_lua_script);
25+
sol::thread runner = sol::thread::create(lua.lua_state());
26+
sol::state_view runnerstate = runner.state();
27+
sol::coroutine loop_coroutine = lua["loop"];
28+
lua["counter"] = 20;
29+
30+
for (int counter = 0; counter < 10 && loop_coroutine; ++counter) {
31+
// Call the coroutine, does the computation and then suspends
32+
int value = loop_coroutine();
33+
}
34+
35+
return 0;
36+
}

0 commit comments

Comments
 (0)