Overhaul examples

Overhaul docs for examples
Overhaul function_result and protected_function_result proxies
This commit is contained in:
ThePhD 2017-11-09 17:41:46 -05:00
parent 90bbeadd8c
commit 2203c1f64f
51 changed files with 1809 additions and 612 deletions

View File

@ -158,13 +158,24 @@ for f in glob.glob('tests/test*.cpp'):
examples = []
examples_input = []
def add_example (f):
if 'win32' in sys.platform:
example = os.path.join(builddir, replace_extension(f, '.exe'))
example = example.replace('/', '\\');
else:
example = os.path.join(builddir, replace_extension(f, ''))
example = example.replace('\\', '/');
#if ' ' in example:
# example = '"' + example + '"'
examples_input.append(f)
examples.append(example)
for f in glob.glob('examples/*.cpp'):
if 'win32' in sys.platform:
example = os.path.join(builddir, replace_extension(f, '.exe'))
else:
example = os.path.join(builddir, replace_extension(f, ''))
examples_input.append(f)
examples.append(example)
add_example(f)
for f in glob.glob('examples/tutorials/quick_n_dirty/**.cpp'):
add_example(f)
# ninja file

View File

@ -29,4 +29,4 @@ This marker does NOT apply to :doc:`usertypes<usertype>`.
You can also use this to nest types and retrieve tables within tables as shown by `this example`_.
.. _this example: https://github.com/ThePhD/sol2/blob/develop/examples/usertype_simple.cpp
.. _this example: https://github.com/ThePhD/sol2/blob/develop/examples/containers_as_table.cpp

View File

@ -66,7 +66,7 @@ After loading that file in or putting it in a string and reading the string dire
int changed_value = z; // now it's 20!
We don't recommend the above to be used across classes or between function: it's more of something you can do to save a reference to a value you like, call a script or run a lua function, and then get it afterwards. You can also set functions (and function objects :ref:`*<note 1>`) this way, and retrieve them as well.
We don't recommend the above to be used across classes or between function: it's more of something you can do to save a reference to a value you like, call a script or run a lua function, and then get it afterwards. You can also set functions (and function objects) this way, and retrieve them as well.
.. code-block:: c++
:linenos:
@ -133,7 +133,7 @@ Returns whether this proxy actually refers to a valid object. It uses :ref:`sol:
template <typename Fx>
proxy& operator=( Fx&& function );
Sets the value associated with the keys the proxy was generated with to ``value``. If this is a function, calls ``set_function``. If it is not, just calls ``set``. Does not exist on :ref:`unsage_function_result<unsafe-function-result>` or :ref:`protected_function_result<protected-function-result>`. See :ref:`note<note 1>` for caveats.
Sets the value associated with the keys the proxy was generated with to ``value``. If this is a function, calls ``set_function``. If it is not, just calls ``set``. Does not exist on :ref:`unsage_function_result<unsafe-function-result>` or :ref:`protected_function_result<protected-function-result>`.
.. code-block:: c++
:caption: function: set a callable
@ -154,6 +154,8 @@ Sets the value associated with the keys the proxy was generated with to a functi
Sets the value associated with the keys the proxy was generated with to ``value``. Does not exist on :ref:`unsafe_function_result<unsafe-function-result>` or :ref:`protected_function_result<protected-function-result>`.
.. _stack-proxy:
stack_proxy
-----------
@ -169,6 +171,8 @@ unsafe_function_result
This type does, however, allow access to multiple underlying values. Use ``result.get<Type>(index_offset)`` to retrieve an object of ``Type`` at an offset of ``index_offset`` in the results. Offset is 0 based. Not specifying an argument defaults the value to 0.
``unsafe_function_result`` also has ``begin()`` and ``end()`` functions that return (almost) "random-acess" iterators. These return a proxy type that can be implicitly converted to :ref:`stack_proxy<stack-proxy>`.
.. _protected-function-result:
protected_function_result
@ -179,11 +183,23 @@ protected_function_result
This type does, however, allow access to multiple underlying values. Use ``result.get<Type>(index_offset)`` to retrieve an object of ``Type`` at an offset of ``index_offset`` in the results. Offset is 0 based. Not specifying an argument defaults the value to 0.
``unsafe_function_result`` also has ``begin()`` and ``end()`` functions that return (almost) "random-acess" iterators. These return a proxy type that can be implicitly converted to :ref:`stack_proxy<stack-proxy>`.
.. _note 1:
on function objects and proxies
-------------------------------
.. note::
As of recent versions of sol2 (2.18.2 and above), this is no longer an issue, as even bound classes will have any detectable function call operator automatically bound to the object, to allow this to work without having to use ``.set`` or ``.set_function``. The note here is kept for posterity and information for older versions.
.. warning::
*The below information is outdated.*
Consider the following:
.. code-block:: cpp

View File

@ -23,6 +23,16 @@ A myriad of compiler errors can occur when something goes wrong. Here is some ba
* Sometimes, using ``__stdcall`` in a 32-bit (x86) environment on VC++ can cause problems binding functions because of a compiler bug. We have a prelimanry fix in, but if it doesn't work and there are still problems: put the function in a ``std::function`` to make the compiler errors and other problems go away. Also see `this __stdcall issue report`_ for more details.
Mac OSX Crashes
---------------
On LuaJIT, your code may crash at seemingly random points when using Mac OSX. Make sure that your build has these flags, as advised by the LuaJIT website::
-pagezero_size 10000 -image_base 100000000
These will allow your code to run properly, without crashing arbitrarily. Please read the LuaJIT documentation on compiling and running with LuaJIT for more information.
"compiler out of heap space"
----------------------------
@ -41,7 +51,7 @@ Linker Errors
There are lots of reasons for compiler linker errors. A common one is not knowing that you've compiled the Lua library as C++: when building with C++, it is important to note that every typical (static or dynamic) library expects the C calling convention to be used and that Sol includes the code using ``extern 'C'`` where applicable.
However, when the target Lua library is compiled with C++, one must change the calling convention and name mangling scheme by getting rid of the ``extern 'C'`` block. This can be achieved by adding ``#define SOL_USING_CXX_LUA`` before including sol2, or by adding it to your compilation's command line. If you build LuaJIT in C++ mode (how you would even, is beyond me), then you need to ``#define SOL_USING_CXX_LUAJIT`` as well.
However, when the target Lua library is compiled with C++, one must change the calling convention and name mangling scheme by getting rid of the ``extern 'C'`` block. This can be achieved by adding ``#define SOL_USING_CXX_LUA`` before including sol2, or by adding it to your compilation's command line. If you build LuaJIT in C++ mode (how you would even, is beyond me), then you need to ``#define SOL_USING_CXX_LUAJIT`` as well. Typically, there is never a need to use this last one.
Note that you should not be defining these with standard builds of either Lua or LuaJIT. See the :ref:`config page<config-linker>` for more details.

View File

@ -10,29 +10,63 @@ You'll need to ``#include <sol.hpp>``/``#include "sol.hpp"`` somewhere in your c
After you learn the basics of sol, it is usually advised that if you think something can work, you should TRY IT. It will probably work!
.. note::
All of the code below is available at the `sol2 tutorial examples`_.
opening a state
---------------
.. code-block:: cpp
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
int main (int argc, char* argv[]) {
sol::state lua;
// open some common libraries
lua.open_libraries(sol::lib::base, sol::lib::package);
// go!
lua.script( "print('bark bark bark!')" );
}
sol::state on lua_State*
------------------------
.. _sol-state-on-lua-state:
For your system/game that already has lua, but you'd like something nice:
using sol2 on a lua_State*
--------------------------
For your system/game that already has Lua or uses an in-house or pre-rolled Lua system (LuaBridge, kaguya, Luwra, etc.), but you'd still like sol2 and nice things:
.. code-block:: cpp
int pre_existing_system( lua_State* L ) {
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <iostream>
int use_sol2(lua_State* L) {
sol::state_view lua(L);
lua.script( "print('bark bark bark!')" );
lua.script("print('bark bark bark!')");
return 0;
}
int main(int, char*[]) {
std::cout << "=== opening sol::state_view on raw Lua example ===" << std::endl;
lua_State* L = luaL_newstate();
luaL_openlibs(L);
lua_pushcclosure(L, &use_sol2, 0);
lua_setglobal(L, "use_sol2");
if (luaL_dostring(L, "use_sol2()")) {
lua_error(L);
return -1;
}
std::cout << std::endl;
return 0;
}
@ -42,74 +76,53 @@ running lua code
.. code-block:: cpp
sol::state lua;
// load and execute from string
lua.script("a = 'test'");
// load and execute from file
lua.script_file("path/to/luascript.lua");
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
// run a script, get the result
int value = lua.script("return 54");
// value == 54
#include <iostream>
#include <cassert>
int main(int, char*[]) {
std::cout << "=== running lua code (low level) example ===" << std::endl;
sol::state lua;
lua.open_libraries(sol::lib::base);
sol::state lua;
// load and execute from string
lua.script("a = 'test'");
// load and execute from file
lua.script_file("a_lua_script.lua");
// run a script, get the result
int value = lua.script("return 54");
assert(value == 54);
/* ... continued in next block */
To run Lua code but have an error handler in case things go wrong:
.. code-block:: cpp
sol::state lua;
// the default handler panics or throws, depending on your settings
auto result1 = lua.script("bad.code", &sol::default_on_error);
/* ... from previous block */
auto bad_code_result = lua.script("123 herp.derp", [](lua_State* L, sol::protected_function_result pfr) {
// pfr will contain things that went wrong, for either loading or executing the script
// Can throw your own custom error
// You can also just return it, and let the call-site handle the error if necessary.
return pfr;
});
// it did not work
assert(!bad_code_result.valid());
// the default handler panics or throws, depending on your settings
// uncomment for explosions:
//auto bad_code_result_2 = lua.script("bad.code", &sol::script_default_on_error);
auto result2 = lua.script("123 herp.derp", [](lua_State* L, sol::protected_function_result pfr) {
// pfr will contain things that went wrong, for either loading or executing the script
// Can throw your own custom error
// You can also just return it, and let the call-site handle the error if necessary.
return pfr;
});
std::cout << std::endl;
To check the success of a loading operation:
.. code-block:: cpp
// load file without execute
sol::load_result script1 = lua.load_file("path/to/luascript.lua");
script1(); //execute
// load string without execute
sol::load_result script2 = lua.load("a = 'test'");
sol::protected_function_result script2result = script2(); //execute
// optionally, check if it worked
if (script2result.valid()) {
// yay!
}
else {
// aww
return 0;
}
sol::load_result script3 = lua.load("return 24");
int value2 = script3(); // execute, get return value
// value2 == 24
To check whether a script was successfully run or not (if the actual loading is successful):
.. code-block:: cpp
// execute and return result
sol::protected_function_result result1 = lua.do_string("return 24");
if (result1.valid()) {
int value = result1;
// value == 24
// yay!
}
else {
// ahhh :c
}
There is also ``lua.do_file("path/to/luascript.lua");``.
set and get variables
---------------------
@ -168,10 +181,12 @@ Retrieve these variables using this syntax:
// get a function
sol::function a_function = lua["a_function"];
int value_is_100 = a_function();
// get a std::function
std::function<int()> a_std_function = lua["a_function"];
// value_is_100 == 100
// convertible to std::function
std::function<int()> a_std_function = a_function;
int value_is_still_100 = a_std_function();
// value_is_still_100 == 100
Retrieve Lua types using ``object`` and other ``sol::`` types.
@ -312,12 +327,13 @@ They're great. Use them:
lua.script("function f (a, b, c, d) return 1 end");
lua.script("function g (a, b) return a + b end");
// fixed signature std::function<...>
std::function<int(int, double, int, std::string)> stdfx = lua["f"];
// sol::function is often easier:
// takes a variable number/types of arguments...
sol::function fx = lua["f"];
// fixed signature std::function<...>
// can be used to tie a sol::function down
std::function<int(int, double, int, std::string)> stdfx = fx;
int is_one = stdfx(1, 34.5, 3, "bark");
int is_also_one = fx(1, "boop", 3, "bark");
@ -497,7 +513,7 @@ Everything that is not a:
* string type: ``std::string``, ``const char*``
* function type: function pointers, ``lua_CFunction``, ``std::function``, :doc:`sol::function/sol::protected_function<../api/function>`, :doc:`sol::coroutine<../api/coroutine>`, member variable, member function
* designated sol type: :doc:`sol::table<../api/table>`, :doc:`sol::thread<../api/thread>`, :doc:`sol::error<../api/error>`, :doc:`sol::object<../api/object>`
* transparent argument type: :doc:`sol::variadic_arg<../api/variadic_args>`, :doc:`sol::this_state<../api/this_state>`
* transparent argument type: :doc:`sol::variadic_arg<../api/variadic_args>`, :doc:`sol::this_state<../api/this_state>`, :doc:`sol::this_environment<../api/this_environment>`
* usertype<T> class: :doc:`sol::usertype<../api/usertype>`
Is set as a :doc:`userdata + usertype<../api/usertype>`.
@ -665,4 +681,4 @@ Some more things you can do/read about:
.. _a basic example: https://github.com/ThePhD/sol2/blob/develop/examples/usertype.cpp
.. _special functions: https://github.com/ThePhD/sol2/blob/develop/examples/usertype_special_functions.cpp
.. _initializers: https://github.com/ThePhD/sol2/blob/develop/examples/usertype_initializers.cpp
.. _sol2 tutorial examples: https://github.com/ThePhD/sol2/tree/develop/examples/tutorials/quick 'n' dirty

View File

@ -10,6 +10,7 @@ int main(int, char*[]) {
std::cout << "=== require from DLL example ===" << std::endl;
sol::state lua;
lua.open_libraries(sol::lib::package);
lua.script_file(R"(
mo = require("my_object")

View File

@ -0,0 +1,81 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <cassert>
#include <iostream>
void some_function() {
std::cout << "some function!" << std::endl;
}
void some_other_function() {
std::cout << "some other function!" << std::endl;
}
struct some_class {
int variable = 30;
double member_function() {
return 24.5;
}
};
int main(int, char*[]) {
std::cout << "=== functions (all) example ===" << std::endl;
sol::state lua;
lua.open_libraries(sol::lib::base);
// put an instance of "some_class" into lua
// (we'll go into more detail about this later
// just know here that it works and is
// put into lua as a userdata
lua.set("sc", some_class());
// binds a plain function
lua["f1"] = some_function;
lua.set_function("f2", &some_other_function);
// binds just the member function
lua["m1"] = &some_class::member_function;
// binds the class to the type
lua.set_function("m2", &some_class::member_function, some_class{});
// binds just the member variable as a function
lua["v1"] = &some_class::variable;
// binds class with member variable as function
lua.set_function("v2", &some_class::variable, some_class{});
lua.script(R"(
f1() -- some function!
f2() -- some other function!
-- need class instance if you don't bind it with the function
print(m1(sc)) -- 24.5
-- does not need class instance: was bound to lua with one
print(m2()) -- 24.5
-- need class instance if you
-- don't bind it with the function
print(v1(sc)) -- 30
-- does not need class instance:
-- it was bound with one
print(v2()) -- 30
-- can set, still
-- requires instance
v1(sc, 212)
-- can set, does not need
-- class instance: was bound with one
v2(254)
print(v1(sc)) -- 212
print(v2()) -- 254
)");
std::cout << std::endl;
return 0;
}

View File

@ -0,0 +1,32 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <cassert>
int main(int, char*[]) {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.script("function f (a, b, c, d) return 1 end");
lua.script("function g (a, b) return a + b end");
// sol::function is often easier:
// takes a variable number/types of arguments...
sol::function fx = lua["f"];
// fixed signature std::function<...>
// can be used to tie a sol::function down
std::function<int(int, double, int, std::string)> stdfx = fx;
int is_one = stdfx(1, 34.5, 3, "bark");
assert(is_one == 1);
int is_also_one = fx(1, "boop", 3, "bark");
assert(is_also_one == 1);
// call through operator[]
int is_three = lua["g"](1, 2);
assert(is_three == 3);
double is_4_8 = lua["g"](2.4, 2.4);
assert(is_4_8 == 4.8);
return 0;
}

View File

@ -0,0 +1,35 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <cassert>
int main(int, char* []) {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua["abc_sol2"] = lua.create_table_with(
0, 24);
lua.create_named_table("def_sol2",
"ghi", lua.create_table_with("bark", 50,
// can reference other existing stuff too
"woof", lua["abc"]));
std::string code = R"(
abc = { [0] = 24 }
def = {
ghi = {
bark = 50,
woof = abc
}
}
)";
lua.script(code);
lua.script(R"(
assert(abc_sol2[0] == abc[0])
assert(def_sol2.ghi.bark == def.ghi.bark)
)");
return 0;
}

View File

@ -0,0 +1,23 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <cassert>
int main(int, char* []) {
sol::state lua;
lua.script("function f (a, b, c) return a, b, c end");
std::tuple<int, int, int> result;
result = lua["f"](100, 200, 300);
// result == { 100, 200, 300 }
int a;
int b;
std::string c;
sol::tie(a, b, c) = lua["f"](100, 200, "bark");
assert(a == 100);
assert(b == 200);
assert(c == "bark");
return 0;
}

View File

@ -0,0 +1,39 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <cassert>
int main(int, char* []) {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua["f"] = [](int a, int b, sol::object c) {
// sol::object can be anything here: just pass it through
return std::make_tuple(a, b, c);
};
std::tuple<int, int, int> result = lua["f"](100, 200, 300);
const std::tuple<int, int, int> expected(100, 200, 300);
assert(result == expected);
std::tuple<int, int, std::string> result2;
result2 = lua["f"](100, 200, "BARK BARK BARK!");
const std::tuple<int, int, std::string> expected2(100, 200, "BARK BARK BARK!");
assert(result2 == expected2);
int a, b;
std::string c;
sol::tie(a, b, c) = lua["f"](100, 200, "bark");
assert(a == 100);
assert(b == 200);
assert(c == "bark");
lua.script(R"(
a, b, c = f(150, 250, "woofbark")
assert(a == 150)
assert(b == 250)
assert(c == "woofbark")
)");
return 0;
}

View File

@ -0,0 +1,18 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <iostream>
#include <cassert>
int main(int, char*[]) {
std::cout << "=== opening a state example ===" << std::endl;
sol::state lua;
// open some common libraries
lua.open_libraries(sol::lib::base, sol::lib::package);
lua.script("print('bark bark bark!')");
std::cout << std::endl;
return 0;
}

View File

@ -0,0 +1,29 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <iostream>
int use_sol2(lua_State* L) {
sol::state_view lua(L);
lua.script("print('bark bark bark!')");
return 0;
}
int main(int, char*[]) {
std::cout << "=== opening sol::state_view on raw Lua example ===" << std::endl;
lua_State* L = luaL_newstate();
luaL_openlibs(L);
lua_pushcclosure(L, &use_sol2, 0);
lua_setglobal(L, "use_sol2");
if (luaL_dostring(L, "use_sol2()")) {
lua_error(L);
return -1;
}
std::cout << std::endl;
return 0;
}

View File

@ -0,0 +1,44 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <fstream>
#include <iostream>
#include <cassert>
int main(int, char*[]) {
std::cout << "=== running lua code example ===" << std::endl;
{
std::ofstream out("a_lua_script.lua");
out << "print('hi from a lua script file')";
}
sol::state lua;
lua.open_libraries(sol::lib::base);
// load and execute from string
lua.script("a = 'test'");
// load and execute from file
lua.script_file("a_lua_script.lua");
// run a script, get the result
int value = lua.script("return 54");
assert(value == 54);
auto bad_code_result = lua.script("123 herp.derp", [](lua_State*, sol::protected_function_result pfr) {
// pfr will contain things that went wrong, for either loading or executing the script
// Can throw your own custom error
// You can also just return it, and let the call-site handle the error if necessary.
return pfr;
});
// it did not work
assert(!bad_code_result.valid());
// the default handler panics or throws, depending on your settings
// uncomment for explosions:
//auto bad_code_result_2 = lua.script("bad.code", &sol::script_default_on_error);
std::cout << std::endl;
return 0;
}

View File

@ -0,0 +1,44 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <fstream>
#include <iostream>
#include <cassert>
int main(int, char*[]) {
std::cout << "=== running lua code (low level) example ===" << std::endl;
{
std::ofstream out("a_lua_script.lua");
out << "print('hi from a lua script file')";
}
sol::state lua;
lua.open_libraries(sol::lib::base);
// load file without execute
sol::load_result script1 = lua.load_file("a_lua_script.lua");
//execute
script1();
// load string without execute
sol::load_result script2 = lua.load("a = 'test'");
//execute
sol::protected_function_result script2result = script2();
// optionally, check if it worked
if (script2result.valid()) {
// yay!
}
else {
// aww
}
sol::load_result script3 = lua.load("return 24");
// execute, get return value
int value2 = script3();
assert(value2 == 24);
std::cout << std::endl;
return 0;
}

View File

@ -1,14 +1,12 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <cassert>
#include <iostream>
int main() {
std::cout << "=== self_call example ===" << std::endl;
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::package, sol::lib::table);
// a small script using 'self' syntax
@ -33,4 +31,6 @@ int main() {
lua["print_some_val"]();
std::cout << std::endl;
return 0;
}

View File

@ -0,0 +1,83 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <cassert>
int main(int, char*[]) {
sol::state lua;
lua.open_libraries(sol::lib::base);
// integer types
lua.set("number", 24);
// floating point numbers
lua["number2"] = 24.5;
// string types
lua["important_string"] = "woof woof";
// is callable, therefore gets stored as a function that can be called
lua["a_function"] = []() { return 100; };
// make a table
lua["some_table"] = lua.create_table_with("value", 24);
// equivalent to this code
std::string equivalent_code = R"(
t = {
number = 24,
number2 = 24.5,
important_string = "woof woof",
a_function = function () return 100 end,
some_table = { value = 24 }
}
)";
// check in Lua
lua.script(equivalent_code);
lua.script(R"(
assert(t.number == number)
assert(t.number2 == number2)
assert(t.important_string == important_string)
assert(t.a_function() == a_function())
assert(t.some_table.value == some_table.value)
)");
// implicit conversion
int number = lua["number"];
assert(number == 24);
// explicit get
auto number2 = lua.get<double>("number2");
assert(number2 == 24.5);
// strings too
std::string important_string = lua["important_string"];
assert(important_string == "woof woof");
// dig into a table
int value = lua["some_table"]["value"];
assert(value == 24);
// get a function
sol::function a_function = lua["a_function"];
int value_is_100 = a_function();
// convertible to std::function
std::function<int()> a_std_function = a_function;
int value_is_still_100 = a_std_function();
assert(value_is_100 == 100);
assert(value_is_still_100 == 100);
sol::object number_obj = lua.get<sol::object>("number");
// sol::type::number
sol::type t1 = number_obj.get_type();
assert(t1 == sol::type::number);
sol::object function_obj = lua["a_function"];
// sol::type::function
sol::type t2 = function_obj.get_type();
assert(t2 == sol::type::function);
bool is_it_really = function_obj.is<std::function<int()>>();
assert(is_it_really);
// will not contain data
sol::optional<int> check_for_me = lua["a_function"];
assert(check_for_me == sol::nullopt);
return 0;
}

View File

@ -0,0 +1,20 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <cassert>
int main(int, char*[]) {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.script("exists = 250");
int first_try = lua.get_or("exists", 322);
assert(first_try == 250);
lua.set("exists", sol::lua_nil);
int second_try = lua.get_or("exists", 322);
assert(second_try == 322);
return 0;
}

View File

@ -0,0 +1,46 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <cassert>
int main(int, char*[]) {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.script(R"(
abc = { [0] = 24 }
def = {
ghi = {
bark = 50,
woof = abc
}
}
)");
sol::table abc = lua["abc"];
sol::table def = lua["def"];
sol::table ghi = lua["def"]["ghi"];
int bark1 = def["ghi"]["bark"];
int bark2 = lua["def"]["ghi"]["bark"];
assert(bark1 == 50);
assert(bark2 == 50);
int abcval1 = abc[0];
int abcval2 = ghi["woof"][0];
assert(abcval1 == 24);
assert(abcval2 == 24);
sol::optional<int> will_not_error = lua["abc"]["DOESNOTEXIST"]["ghi"];
assert(will_not_error == sol::nullopt);
int also_will_not_error = lua["abc"]["def"]["ghi"]["jklm"].get_or(25);
assert(also_will_not_error == 25);
// if you don't go safe,
// will throw (or do at_panic if no exceptions)
//int aaaahhh = lua["boom"]["the_dynamite"];
return 0;
}

View File

@ -0,0 +1,99 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <iostream>
struct Doge {
int tailwag = 50;
Doge() {
}
Doge(int wags)
: tailwag(wags) {
}
~Doge() {
std::cout << "Dog at " << this << " is being destroyed..." << std::endl;
}
};
int main(int, char* []) {
std::cout << "=== userdata example ===" << std::endl;
sol::state lua;
Doge dog{ 30 };
// fresh one put into Lua
lua["dog"] = Doge{};
// Copy into lua: destroyed by Lua VM during garbage collection
lua["dog_copy"] = dog;
// OR: move semantics - will call move constructor if present instead
// Again, owned by Lua
lua["dog_move"] = std::move(dog);
lua["dog_unique_ptr"] = std::make_unique<Doge>(25);
lua["dog_shared_ptr"] = std::make_shared<Doge>(31);
// Identical to above
Doge dog2{ 30 };
lua.set("dog2", Doge{});
lua.set("dog2_copy", dog2);
lua.set("dog2_move", std::move(dog2));
lua.set("dog2_unique_ptr", std::unique_ptr<Doge>(new Doge(25)));
lua.set("dog2_shared_ptr", std::shared_ptr<Doge>(new Doge(31)));
// Note all of them can be retrieved the same way:
Doge& lua_dog = lua["dog"];
Doge& lua_dog_copy = lua["dog_copy"];
Doge& lua_dog_move = lua["dog_move"];
Doge& lua_dog_unique_ptr = lua["dog_unique_ptr"];
Doge& lua_dog_shared_ptr = lua["dog_shared_ptr"];
assert(lua_dog.tailwag == 50);
assert(lua_dog_copy.tailwag == 30);
assert(lua_dog_move.tailwag == 30);
assert(lua_dog_unique_ptr.tailwag == 25);
assert(lua_dog_shared_ptr.tailwag == 31);
// lua will treat these types as opaque, and you will be able to pass them around
// to C++ functions and Lua functions alike
// Use a C++ reference to handle memory directly
// otherwise take by value, without '&'
lua["f"] = [](Doge& dog) {
std::cout << "dog wags its tail " << dog.tailwag << " times!" << std::endl;
};
// if you bind a function using a pointer,
// you can handle when `nil` is passed
lua["handling_f"] = [](Doge* dog) {
if (dog == nullptr) {
std::cout << "dog was nil!" << std::endl;
return;
}
std::cout << "dog wags its tail " << dog->tailwag << " times!" << std::endl;
};
lua.script(R"(
f(dog)
f(dog_copy)
f(dog_move)
f(dog_unique_ptr)
f(dog_shared_ptr)
-- C++ arguments that are pointers can handle nil
handling_f(dog)
handling_f(dog_copy)
handling_f(dog_move)
handling_f(dog_unique_ptr)
handling_f(dog_shared_ptr)
handling_f(nil)
-- never do this
-- f(nil)
)");
std::cout << std::endl;
return 0;
}

View File

@ -0,0 +1,66 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <iostream>
struct Doge {
int tailwag = 50;
Doge() {
}
Doge(int wags)
: tailwag(wags) {
}
~Doge() {
std::cout << "Dog at " << this << " is being destroyed..." << std::endl;
}
};
int main(int, char* []) {
std::cout << "=== usertypes example ===" << std::endl;
sol::state lua;
lua.open_libraries(sol::lib::base);
Doge dog{ 30 };
lua["dog"] = Doge{};
lua["dog_copy"] = dog;
lua["dog_move"] = std::move(dog);
lua["dog_unique_ptr"] = std::make_unique<Doge>(21);
lua["dog_shared_ptr"] = std::make_shared<Doge>(51);
// now we can access these types in Lua
lua.new_usertype<Doge>( "Doge",
sol::constructors<Doge(), Doge(int)>(),
"tailwag", &Doge::tailwag
);
lua.script(R"(
function f (dog)
if dog == nil then
print('dog was nil!')
return
end
print('dog wags its tail ' .. dog.tailwag .. ' times!')
end
)");
lua.script(R"(
dog_lua = Doge.new()
f(dog_lua)
f(dog)
f(dog_copy)
f(dog_move)
f(dog)
f(dog_unique_ptr)
f(dog_shared_ptr)
f(nil)
)");
std::cout << std::endl;
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-11-08 01:20:39.160314 UTC
// This header was generated with sol v2.18.6 (revision 10b1bb0)
// Generated 2017-11-09 22:36:14.826447 UTC
// This header was generated with sol v2.18.6 (revision 90bbead)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_HPP
@ -253,6 +253,8 @@ namespace sol {
using stack_thread = basic_thread<stack_reference>;
using stack_coroutine = basic_coroutine<stack_reference>;
struct stack_proxy_base;
struct stack_proxy;
struct variadic_args;
struct variadic_results;
struct stack_count;
@ -4399,11 +4401,12 @@ namespace sol {
#else
template <lua_CFunction f>
int static_trampoline(lua_State* L) {
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION)
#if defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) && !defined(SOL_LUAJIT)
return f(L);
#else
try {
#endif
return f(L);
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION)
}
catch (const char* s) {
lua_pushstring(L, s);
@ -4411,10 +4414,14 @@ namespace sol {
catch (const std::exception& e) {
lua_pushstring(L, e.what());
}
#if defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) && defined(SOL_LUAJIT)
// LuaJIT cannot have the catchall when the safe propagation is on
// but LuaJIT will swallow all C++ errors
// if we don't at least catch std::exception ones
catch (...) {
lua_pushstring(L, "caught (...) exception");
}
#endif // LuaJIT cannot have the catchall, but we must catch std::exceps for it
return lua_error(L);
#endif
}
@ -4446,11 +4453,11 @@ namespace sol {
if (meta::bind_traits<meta::unqualified_t<Fx>>::is_noexcept) {
return f(L, std::forward<Args>(args)...);
}
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION)
#if defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) && !defined(SOL_LUAJIT)
return f(L, std::forward<Args>(args)...);
#else
try {
#endif
return f(L, std::forward<Args>(args)...);
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION)
}
catch (const char* s) {
lua_pushstring(L, s);
@ -4458,10 +4465,14 @@ namespace sol {
catch (const std::exception& e) {
lua_pushstring(L, e.what());
}
#if defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) && !defined(SOL_LUAJIT)
// LuaJIT cannot have the catchall when the safe propagation is on
// but LuaJIT will swallow all C++ errors
// if we don't at least catch std::exception ones
catch (...) {
lua_pushstring(L, "caught (...) exception");
}
#endif
return lua_error(L);
#endif
}
@ -5410,6 +5421,16 @@ namespace sol {
template <typename T>
struct is_stack_based : std::is_base_of<stack_reference, T> {};
template <>
struct is_stack_based<variadic_args> : std::true_type {};
template <>
struct is_stack_based<unsafe_function_result> : std::true_type {};
template <>
struct is_stack_based<protected_function_result> : std::true_type {};
template <>
struct is_stack_based<stack_proxy> : std::true_type {};
template <>
struct is_stack_based<stack_proxy_base> : std::true_type {};
template <typename T>
struct is_lua_primitive<T*> : std::true_type {};
@ -10497,6 +10518,251 @@ namespace sol {
// end of sol/proxy_base.hpp
// beginning of sol/stack_iterator.hpp
namespace sol {
template <typename proxy_t, bool is_const>
struct stack_iterator : std::iterator<std::random_access_iterator_tag, std::conditional_t<is_const, const proxy_t, proxy_t>, std::ptrdiff_t, std::conditional_t<is_const, const proxy_t*, proxy_t*>, std::conditional_t<is_const, const proxy_t, proxy_t>> {
typedef std::iterator<std::random_access_iterator_tag, std::conditional_t<is_const, const proxy_t, proxy_t>, std::ptrdiff_t, std::conditional_t<is_const, const proxy_t*, proxy_t*>, std::conditional_t<is_const, const proxy_t, proxy_t>> base_t;
typedef typename base_t::reference reference;
typedef typename base_t::pointer pointer;
typedef typename base_t::value_type value_type;
typedef typename base_t::difference_type difference_type;
typedef typename base_t::iterator_category iterator_category;
lua_State* L;
int index;
int stacktop;
proxy_t sp;
stack_iterator()
: L(nullptr), index((std::numeric_limits<int>::max)()), stacktop((std::numeric_limits<int>::max)()), sp() {
}
stack_iterator(const stack_iterator<proxy_t, true>& r)
: L(r.L), index(r.index), stacktop(r.stacktop), sp(r.sp) {
}
stack_iterator(lua_State* luastate, int idx, int topidx)
: L(luastate), index(idx), stacktop(topidx), sp(luastate, idx) {
}
reference operator*() {
return proxy_t(L, index);
}
reference operator*() const {
return proxy_t(L, index);
}
pointer operator->() {
sp = proxy_t(L, index);
return &sp;
}
pointer operator->() const {
const_cast<proxy_t&>(sp) = proxy_t(L, index);
return &sp;
}
stack_iterator& operator++() {
++index;
return *this;
}
stack_iterator operator++(int) {
auto r = *this;
this->operator++();
return r;
}
stack_iterator& operator--() {
--index;
return *this;
}
stack_iterator operator--(int) {
auto r = *this;
this->operator--();
return r;
}
stack_iterator& operator+=(difference_type idx) {
index += static_cast<int>(idx);
return *this;
}
stack_iterator& operator-=(difference_type idx) {
index -= static_cast<int>(idx);
return *this;
}
difference_type operator-(const stack_iterator& r) const {
return index - r.index;
}
stack_iterator operator+(difference_type idx) const {
stack_iterator r = *this;
r += idx;
return r;
}
reference operator[](difference_type idx) const {
return proxy_t(L, index + static_cast<int>(idx));
}
bool operator==(const stack_iterator& r) const {
if (stacktop == (std::numeric_limits<int>::max)()) {
return r.index == r.stacktop;
}
else if (r.stacktop == (std::numeric_limits<int>::max)()) {
return index == stacktop;
}
return index == r.index;
}
bool operator!=(const stack_iterator& r) const {
return !(this->operator==(r));
}
bool operator<(const stack_iterator& r) const {
return index < r.index;
}
bool operator>(const stack_iterator& r) const {
return index > r.index;
}
bool operator<=(const stack_iterator& r) const {
return index <= r.index;
}
bool operator>=(const stack_iterator& r) const {
return index >= r.index;
}
};
template <typename proxy_t, bool is_const>
inline stack_iterator<proxy_t, is_const> operator+(typename stack_iterator<proxy_t, is_const>::difference_type n, const stack_iterator<proxy_t, is_const>& r) {
return r + n;
}
} // namespace sol
// end of sol/stack_iterator.hpp
// beginning of sol/stack_proxy.hpp
// beginning of sol/stack_proxy_base.hpp
namespace sol {
struct stack_proxy_base : public proxy_base<stack_proxy_base> {
private:
lua_State* L;
int index;
public:
stack_proxy_base()
: L(nullptr), index(0) {
}
stack_proxy_base(lua_State* L, int index)
: L(L), index(index) {
}
template <typename T>
decltype(auto) get() const {
return stack::get<T>(L, stack_index());
}
template <typename T>
bool is() const {
return stack::check<T>(L, stack_index());
}
template <typename T>
decltype(auto) as() const {
return get<T>();
}
type get_type() const noexcept {
return type_of(lua_state(), stack_index());
}
int push() const {
return push(L);
}
int push(lua_State* Ls) const {
lua_pushvalue(Ls, index);
return 1;
}
lua_State* lua_state() const {
return L;
}
int stack_index() const {
return index;
}
};
namespace stack {
template <>
struct getter<stack_proxy_base> {
static stack_proxy_base get(lua_State* L, int index = -1) {
return stack_proxy_base(L, index);
}
};
template <>
struct pusher<stack_proxy_base> {
static int push(lua_State*, const stack_proxy_base& ref) {
return ref.push();
}
};
} // namespace stack
} // namespace sol
// end of sol/stack_proxy_base.hpp
namespace sol {
struct stack_proxy : public stack_proxy_base {
private:
lua_State* L;
int index;
public:
stack_proxy()
: stack_proxy_base() {
}
stack_proxy(lua_State* L, int index)
: stack_proxy_base(L, index) {
}
template <typename... Ret, typename... Args>
decltype(auto) call(Args&&... args);
template <typename... Args>
decltype(auto) operator()(Args&&... args) {
return call<>(std::forward<Args>(args)...);
}
};
namespace stack {
template <>
struct getter<stack_proxy> {
static stack_proxy get(lua_State* L, int index = -1) {
return stack_proxy(L, index);
}
};
template <>
struct pusher<stack_proxy> {
static int push(lua_State*, const stack_proxy& ref) {
return ref.push();
}
};
} // namespace stack
} // namespace sol
// end of sol/stack_proxy.hpp
#include <cstdint>
namespace sol {
@ -10549,6 +10815,16 @@ namespace sol {
}
public:
typedef stack_proxy reference_type;
typedef stack_proxy value_type;
typedef stack_proxy* pointer;
typedef std::ptrdiff_t difference_type;
typedef std::size_t size_type;
typedef stack_iterator<stack_proxy, false> iterator;
typedef stack_iterator<stack_proxy, true> const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
protected_function_result() = default;
protected_function_result(lua_State* Ls, int idx = -1, int retnum = 0, int popped = 0, call_status pferr = call_status::ok) noexcept
: L(Ls), index(idx), returncount(retnum), popcount(popped), err(pferr) {
@ -10593,6 +10869,52 @@ namespace sol {
return tagged_get(types<meta::unqualified_t<T>>(), index_offset);
}
type get_type(difference_type index_offset = 0) const noexcept {
return type_of(L, index + static_cast<int>(index_offset));
}
stack_proxy operator[](difference_type index_offset) const {
return stack_proxy(L, index + static_cast<int>(index_offset));
}
iterator begin() {
return iterator(L, index, stack_index() + return_count());
}
iterator end() {
return iterator(L, stack_index() + return_count(), stack_index() + return_count());
}
const_iterator begin() const {
return const_iterator(L, index, stack_index() + return_count());
}
const_iterator end() const {
return const_iterator(L, stack_index() + return_count(), stack_index() + return_count());
}
const_iterator cbegin() const {
return begin();
}
const_iterator cend() const {
return end();
}
reverse_iterator rbegin() {
return std::reverse_iterator<iterator>(begin());
}
reverse_iterator rend() {
return std::reverse_iterator<iterator>(end());
}
const_reverse_iterator rbegin() const {
return std::reverse_iterator<const_iterator>(begin());
}
const_reverse_iterator rend() const {
return std::reverse_iterator<const_iterator>(end());
}
const_reverse_iterator crbegin() const {
return std::reverse_iterator<const_iterator>(cbegin());
}
const_reverse_iterator crend() const {
return std::reverse_iterator<const_iterator>(cend());
}
lua_State* lua_state() const noexcept {
return L;
};
@ -10644,6 +10966,16 @@ namespace sol {
int returncount;
public:
typedef stack_proxy reference_type;
typedef stack_proxy value_type;
typedef stack_proxy* pointer;
typedef std::ptrdiff_t difference_type;
typedef std::size_t size_type;
typedef stack_iterator<stack_proxy, false> iterator;
typedef stack_iterator<stack_proxy, true> const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
unsafe_function_result() = default;
unsafe_function_result(lua_State* Ls, int idx = -1, int retnum = 0)
: L(Ls), index(idx), returncount(retnum) {
@ -10674,8 +11006,54 @@ namespace sol {
unsafe_function_result& operator=(protected_function_result&& o) noexcept;
template <typename T>
decltype(auto) get(int index_offset = 0) const {
return stack::get<T>(L, index + index_offset);
decltype(auto) get(difference_type index_offset = 0) const {
return stack::get<T>(L, index + static_cast<int>(index_offset));
}
type get_type(difference_type index_offset = 0) const noexcept {
return type_of(L, index + static_cast<int>(index_offset));
}
stack_proxy operator[](difference_type index_offset) const {
return stack_proxy(L, index + static_cast<int>(index_offset));
}
iterator begin() {
return iterator(L, index, stack_index() + return_count());
}
iterator end() {
return iterator(L, stack_index() + return_count(), stack_index() + return_count());
}
const_iterator begin() const {
return const_iterator(L, index, stack_index() + return_count());
}
const_iterator end() const {
return const_iterator(L, stack_index() + return_count(), stack_index() + return_count());
}
const_iterator cbegin() const {
return begin();
}
const_iterator cend() const {
return end();
}
reverse_iterator rbegin() {
return std::reverse_iterator<iterator>(begin());
}
reverse_iterator rend() {
return std::reverse_iterator<iterator>(end());
}
const_reverse_iterator rbegin() const {
return std::reverse_iterator<const_iterator>(begin());
}
const_reverse_iterator rend() const {
return std::reverse_iterator<const_iterator>(end());
}
const_reverse_iterator crbegin() const {
return std::reverse_iterator<const_iterator>(cbegin());
}
const_reverse_iterator crend() const {
return std::reverse_iterator<const_iterator>(cend());
}
call_status status() const noexcept {
@ -10722,6 +11100,52 @@ namespace sol {
// end of sol/unsafe_function_result.hpp
namespace sol {
namespace detail {
template <>
struct is_speshul<unsafe_function_result> : std::true_type {};
template <>
struct is_speshul<protected_function_result> : std::true_type {};
template <std::size_t I, typename... Args, typename T>
stack_proxy get(types<Args...>, index_value<0>, index_value<I>, const T& fr) {
return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I));
}
template <std::size_t I, std::size_t N, typename Arg, typename... Args, typename T, meta::enable<meta::boolean<(N > 0)>> = meta::enabler>
stack_proxy get(types<Arg, Args...>, index_value<N>, index_value<I>, const T& fr) {
return get(types<Args...>(), index_value<N - 1>(), index_value<I + lua_size<Arg>::value>(), fr);
}
} // namespace detail
template <>
struct tie_size<unsafe_function_result> : std::integral_constant<std::size_t, SIZE_MAX> {};
template <>
struct tie_size<protected_function_result> : std::integral_constant<std::size_t, SIZE_MAX> {};
template <std::size_t I>
stack_proxy get(const unsafe_function_result& fr) {
return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I));
}
template <std::size_t I, typename... Args>
stack_proxy get(types<Args...> t, const unsafe_function_result& fr) {
return detail::get(t, index_value<I>(), index_value<0>(), fr);
}
template <std::size_t I>
stack_proxy get(const protected_function_result& fr) {
return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I));
}
template <std::size_t I, typename... Args>
stack_proxy get(types<Args...> t, const protected_function_result& fr) {
return detail::get(t, index_value<I>(), index_value<0>(), fr);
}
} // namespace sol
// end of sol/function_result.hpp
// beginning of sol/function_types.hpp
@ -13119,7 +13543,7 @@ namespace sol {
stack::push(lua_state(), error);
}
};
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION)
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) || defined(SOL_LUAJIT)
try {
#endif
#endif // No Exceptions
@ -13128,7 +13552,7 @@ namespace sol {
poststacksize = lua_gettop(lua_state()) - static_cast<int>(h.valid());
returncount = poststacksize - (firstreturn - 1);
#ifndef SOL_NO_EXCEPTIONS
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION)
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) || defined(SOL_LUAJIT)
}
// Handle C++ errors thrown from C++ functions bound inside of lua
catch (const char* error) {
@ -13141,11 +13565,16 @@ namespace sol {
firstreturn = lua_gettop(lua_state());
return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);
}
#if !defined(SOL_LUAJIT)
// LuaJIT cannot have the catchall when the safe propagation is on
// but LuaJIT will swallow all C++ errors
// if we don't at least catch std::exception ones
catch (...) {
onexcept("caught (...) unknown error during protected_function call");
firstreturn = lua_gettop(lua_state());
return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);
}
#endif // LuaJIT
#else
// do not handle exceptions: they can be propogated into C++ and keep all type information / rich information
#endif // about as safe as possible
@ -13326,6 +13755,11 @@ namespace sol {
// end of sol/protected_function.hpp
namespace sol {
template <typename... Ret, typename... Args>
inline decltype(auto) stack_proxy::call(Args&&... args) {
stack_function sf(this->lua_state(), this->stack_index());
return sf.template call<Ret...>(std::forward<Args>(args)...);
}
inline protected_function_result::protected_function_result(unsafe_function_result&& o) noexcept
: L(o.lua_state()), index(o.stack_index()), returncount(o.return_count()), popcount(o.return_count()), err(o.status()) {
@ -13845,254 +14279,7 @@ namespace sol {
// beginning of sol/variadic_args.hpp
// beginning of sol/stack_proxy.hpp
namespace sol {
struct stack_proxy : public proxy_base<stack_proxy> {
private:
lua_State* L;
int index;
public:
stack_proxy()
: L(nullptr), index(0) {
}
stack_proxy(lua_State* L, int index)
: L(L), index(index) {
}
template <typename T>
decltype(auto) get() const {
return stack::get<T>(L, stack_index());
}
template <typename T>
bool is() const {
return stack::check<T>(L, stack_index());
}
template <typename T>
decltype(auto) as() const {
return get<T>();
}
type get_type() const noexcept {
return type_of(lua_state(), stack_index());
}
int push() const {
return push(L);
}
int push(lua_State* Ls) const {
lua_pushvalue(Ls, index);
return 1;
}
lua_State* lua_state() const {
return L;
}
int stack_index() const {
return index;
}
template <typename... Ret, typename... Args>
decltype(auto) call(Args&&... args) {
return get<function>().template call<Ret...>(std::forward<Args>(args)...);
}
template <typename... Args>
decltype(auto) operator()(Args&&... args) {
return call<>(std::forward<Args>(args)...);
}
};
namespace stack {
template <>
struct getter<stack_proxy> {
static stack_proxy get(lua_State* L, int index = -1) {
return stack_proxy(L, index);
}
};
template <>
struct pusher<stack_proxy> {
static int push(lua_State*, const stack_proxy& ref) {
return ref.push();
}
};
} // namespace stack
namespace detail {
template <>
struct is_speshul<unsafe_function_result> : std::true_type {};
template <>
struct is_speshul<protected_function_result> : std::true_type {};
template <std::size_t I, typename... Args, typename T>
stack_proxy get(types<Args...>, index_value<0>, index_value<I>, const T& fr) {
return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I));
}
template <std::size_t I, std::size_t N, typename Arg, typename... Args, typename T, meta::enable<meta::boolean<(N > 0)>> = meta::enabler>
stack_proxy get(types<Arg, Args...>, index_value<N>, index_value<I>, const T& fr) {
return get(types<Args...>(), index_value<N - 1>(), index_value<I + lua_size<Arg>::value>(), fr);
}
} // namespace detail
template <>
struct tie_size<unsafe_function_result> : std::integral_constant<std::size_t, SIZE_MAX> {};
template <std::size_t I>
stack_proxy get(const unsafe_function_result& fr) {
return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I));
}
template <std::size_t I, typename... Args>
stack_proxy get(types<Args...> t, const unsafe_function_result& fr) {
return detail::get(t, index_value<I>(), index_value<0>(), fr);
}
template <>
struct tie_size<protected_function_result> : std::integral_constant<std::size_t, SIZE_MAX> {};
template <std::size_t I>
stack_proxy get(const protected_function_result& fr) {
return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I));
}
template <std::size_t I, typename... Args>
stack_proxy get(types<Args...> t, const protected_function_result& fr) {
return detail::get(t, index_value<I>(), index_value<0>(), fr);
}
} // namespace sol
// end of sol/stack_proxy.hpp
namespace sol {
template <bool is_const>
struct va_iterator : std::iterator<std::random_access_iterator_tag, std::conditional_t<is_const, const stack_proxy, stack_proxy>, std::ptrdiff_t, std::conditional_t<is_const, const stack_proxy*, stack_proxy*>, std::conditional_t<is_const, const stack_proxy, stack_proxy>> {
typedef std::iterator<std::random_access_iterator_tag, std::conditional_t<is_const, const stack_proxy, stack_proxy>, std::ptrdiff_t, std::conditional_t<is_const, const stack_proxy*, stack_proxy*>, std::conditional_t<is_const, const stack_proxy, stack_proxy>> base_t;
typedef typename base_t::reference reference;
typedef typename base_t::pointer pointer;
typedef typename base_t::value_type value_type;
typedef typename base_t::difference_type difference_type;
typedef typename base_t::iterator_category iterator_category;
lua_State* L;
int index;
int stacktop;
stack_proxy sp;
va_iterator()
: L(nullptr), index((std::numeric_limits<int>::max)()), stacktop((std::numeric_limits<int>::max)()) {
}
va_iterator(const va_iterator<true>& r)
: L(r.L), index(r.index), stacktop(r.stacktop) {
}
va_iterator(lua_State* luastate, int idx, int topidx)
: L(luastate), index(idx), stacktop(topidx), sp(luastate, idx) {
}
reference operator*() {
return stack_proxy(L, index);
}
reference operator*() const {
return stack_proxy(L, index);
}
pointer operator->() {
sp = stack_proxy(L, index);
return &sp;
}
pointer operator->() const {
const_cast<stack_proxy&>(sp) = stack_proxy(L, index);
return &sp;
}
va_iterator& operator++() {
++index;
return *this;
}
va_iterator operator++(int) {
auto r = *this;
this->operator++();
return r;
}
va_iterator& operator--() {
--index;
return *this;
}
va_iterator operator--(int) {
auto r = *this;
this->operator--();
return r;
}
va_iterator& operator+=(difference_type idx) {
index += static_cast<int>(idx);
return *this;
}
va_iterator& operator-=(difference_type idx) {
index -= static_cast<int>(idx);
return *this;
}
difference_type operator-(const va_iterator& r) const {
return index - r.index;
}
va_iterator operator+(difference_type idx) const {
va_iterator r = *this;
r += idx;
return r;
}
reference operator[](difference_type idx) const {
return stack_proxy(L, index + static_cast<int>(idx));
}
bool operator==(const va_iterator& r) const {
if (stacktop == (std::numeric_limits<int>::max)()) {
return r.index == r.stacktop;
}
else if (r.stacktop == (std::numeric_limits<int>::max)()) {
return index == stacktop;
}
return index == r.index;
}
bool operator!=(const va_iterator& r) const {
return !(this->operator==(r));
}
bool operator<(const va_iterator& r) const {
return index < r.index;
}
bool operator>(const va_iterator& r) const {
return index > r.index;
}
bool operator<=(const va_iterator& r) const {
return index <= r.index;
}
bool operator>=(const va_iterator& r) const {
return index >= r.index;
}
};
template <bool is_const>
inline va_iterator<is_const> operator+(typename va_iterator<is_const>::difference_type n, const va_iterator<is_const>& r) {
return r + n;
}
struct variadic_args {
private:
lua_State* L;
@ -14105,22 +14292,22 @@ namespace sol {
typedef stack_proxy* pointer;
typedef std::ptrdiff_t difference_type;
typedef std::size_t size_type;
typedef va_iterator<false> iterator;
typedef va_iterator<true> const_iterator;
typedef stack_iterator<stack_proxy, false> iterator;
typedef stack_iterator<stack_proxy, true> const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
variadic_args() = default;
variadic_args(lua_State* luastate, int stackindex = -1)
: L(luastate), index(lua_absindex(luastate, stackindex)), stacktop(lua_gettop(luastate)) {
: L(luastate), index(lua_absindex(luastate, stackindex)), stacktop(lua_gettop(luastate)) {
}
variadic_args(lua_State* luastate, int stackindex, int lastindex)
: L(luastate), index(lua_absindex(luastate, stackindex)), stacktop(lastindex) {
: L(luastate), index(lua_absindex(luastate, stackindex)), stacktop(lastindex) {
}
variadic_args(const variadic_args&) = default;
variadic_args& operator=(const variadic_args&) = default;
variadic_args(variadic_args&& o)
: L(o.L), index(o.index), stacktop(o.stacktop) {
: L(o.L), index(o.index), stacktop(o.stacktop) {
// Must be manual, otherwise destructor will screw us
// return count being 0 is enough to keep things clean
// but will be thorough
@ -14196,16 +14383,16 @@ namespace sol {
}
template <typename T>
decltype(auto) get(difference_type start = 0) const {
return stack::get<T>(L, index + static_cast<int>(start));
decltype(auto) get(difference_type index_offset = 0) const {
return stack::get<T>(L, index + static_cast<int>(index_offset));
}
type get_type(difference_type start = 0) const noexcept {
return type_of(L, index + static_cast<int>(start));
type get_type(difference_type index_offset = 0) const noexcept {
return type_of(L, index + static_cast<int>(index_offset));
}
stack_proxy operator[](difference_type start) const {
return stack_proxy(L, index + static_cast<int>(start));
stack_proxy operator[](difference_type index_offset) const {
return stack_proxy(L, index + static_cast<int>(index_offset));
}
lua_State* lua_state() const {

View File

@ -126,6 +126,8 @@ namespace sol {
using stack_thread = basic_thread<stack_reference>;
using stack_coroutine = basic_coroutine<stack_reference>;
struct stack_proxy_base;
struct stack_proxy;
struct variadic_args;
struct variadic_results;
struct stack_count;

View File

@ -28,6 +28,11 @@
#include <functional>
namespace sol {
template <typename... Ret, typename... Args>
inline decltype(auto) stack_proxy::call(Args&&... args) {
stack_function sf(this->lua_state(), this->stack_index());
return sf.template call<Ret...>(std::forward<Args>(args)...);
}
inline protected_function_result::protected_function_result(unsafe_function_result&& o) noexcept
: L(o.lua_state()), index(o.stack_index()), returncount(o.return_count()), popcount(o.return_count()), err(o.status()) {

View File

@ -25,4 +25,50 @@
#include "protected_function_result.hpp"
#include "unsafe_function_result.hpp"
namespace sol {
namespace detail {
template <>
struct is_speshul<unsafe_function_result> : std::true_type {};
template <>
struct is_speshul<protected_function_result> : std::true_type {};
template <std::size_t I, typename... Args, typename T>
stack_proxy get(types<Args...>, index_value<0>, index_value<I>, const T& fr) {
return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I));
}
template <std::size_t I, std::size_t N, typename Arg, typename... Args, typename T, meta::enable<meta::boolean<(N > 0)>> = meta::enabler>
stack_proxy get(types<Arg, Args...>, index_value<N>, index_value<I>, const T& fr) {
return get(types<Args...>(), index_value<N - 1>(), index_value<I + lua_size<Arg>::value>(), fr);
}
} // namespace detail
template <>
struct tie_size<unsafe_function_result> : std::integral_constant<std::size_t, SIZE_MAX> {};
template <>
struct tie_size<protected_function_result> : std::integral_constant<std::size_t, SIZE_MAX> {};
template <std::size_t I>
stack_proxy get(const unsafe_function_result& fr) {
return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I));
}
template <std::size_t I, typename... Args>
stack_proxy get(types<Args...> t, const unsafe_function_result& fr) {
return detail::get(t, index_value<I>(), index_value<0>(), fr);
}
template <std::size_t I>
stack_proxy get(const protected_function_result& fr) {
return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I));
}
template <std::size_t I, typename... Args>
stack_proxy get(types<Args...> t, const protected_function_result& fr) {
return detail::get(t, index_value<I>(), index_value<0>(), fr);
}
} // namespace sol
#endif // SOL_FUNCTION_RESULT_HPP

View File

@ -150,7 +150,7 @@ namespace sol {
stack::push(lua_state(), error);
}
};
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION)
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) || defined(SOL_LUAJIT)
try {
#endif
#endif // No Exceptions
@ -159,7 +159,7 @@ namespace sol {
poststacksize = lua_gettop(lua_state()) - static_cast<int>(h.valid());
returncount = poststacksize - (firstreturn - 1);
#ifndef SOL_NO_EXCEPTIONS
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION)
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) || defined(SOL_LUAJIT)
}
// Handle C++ errors thrown from C++ functions bound inside of lua
catch (const char* error) {
@ -172,11 +172,16 @@ namespace sol {
firstreturn = lua_gettop(lua_state());
return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);
}
#if !defined(SOL_LUAJIT)
// LuaJIT cannot have the catchall when the safe propagation is on
// but LuaJIT will swallow all C++ errors
// if we don't at least catch std::exception ones
catch (...) {
onexcept("caught (...) unknown error during protected_function call");
firstreturn = lua_gettop(lua_state());
return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);
}
#endif // LuaJIT
#else
// do not handle exceptions: they can be propogated into C++ and keep all type information / rich information
#endif // about as safe as possible

View File

@ -26,6 +26,8 @@
#include "tuple.hpp"
#include "stack.hpp"
#include "proxy_base.hpp"
#include "stack_iterator.hpp"
#include "stack_proxy.hpp"
#include <cstdint>
namespace sol {
@ -78,6 +80,16 @@ namespace sol {
}
public:
typedef stack_proxy reference_type;
typedef stack_proxy value_type;
typedef stack_proxy* pointer;
typedef std::ptrdiff_t difference_type;
typedef std::size_t size_type;
typedef stack_iterator<stack_proxy, false> iterator;
typedef stack_iterator<stack_proxy, true> const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
protected_function_result() = default;
protected_function_result(lua_State* Ls, int idx = -1, int retnum = 0, int popped = 0, call_status pferr = call_status::ok) noexcept
: L(Ls), index(idx), returncount(retnum), popcount(popped), err(pferr) {
@ -122,6 +134,52 @@ namespace sol {
return tagged_get(types<meta::unqualified_t<T>>(), index_offset);
}
type get_type(difference_type index_offset = 0) const noexcept {
return type_of(L, index + static_cast<int>(index_offset));
}
stack_proxy operator[](difference_type index_offset) const {
return stack_proxy(L, index + static_cast<int>(index_offset));
}
iterator begin() {
return iterator(L, index, stack_index() + return_count());
}
iterator end() {
return iterator(L, stack_index() + return_count(), stack_index() + return_count());
}
const_iterator begin() const {
return const_iterator(L, index, stack_index() + return_count());
}
const_iterator end() const {
return const_iterator(L, stack_index() + return_count(), stack_index() + return_count());
}
const_iterator cbegin() const {
return begin();
}
const_iterator cend() const {
return end();
}
reverse_iterator rbegin() {
return std::reverse_iterator<iterator>(begin());
}
reverse_iterator rend() {
return std::reverse_iterator<iterator>(end());
}
const_reverse_iterator rbegin() const {
return std::reverse_iterator<const_iterator>(begin());
}
const_reverse_iterator rend() const {
return std::reverse_iterator<const_iterator>(end());
}
const_reverse_iterator crbegin() const {
return std::reverse_iterator<const_iterator>(cbegin());
}
const_reverse_iterator crend() const {
return std::reverse_iterator<const_iterator>(cend());
}
lua_State* lua_state() const noexcept {
return L;
};

154
sol/stack_iterator.hpp Normal file
View File

@ -0,0 +1,154 @@
// The MIT License (MIT)
// Copyright (c) 2013-2017 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_STACK_ITERATOR_HPP
#define SOL_STACK_ITERATOR_HPP
#include "stack.hpp"
#include <limits>
#include <iterator>
namespace sol {
template <typename proxy_t, bool is_const>
struct stack_iterator : std::iterator<std::random_access_iterator_tag, std::conditional_t<is_const, const proxy_t, proxy_t>, std::ptrdiff_t, std::conditional_t<is_const, const proxy_t*, proxy_t*>, std::conditional_t<is_const, const proxy_t, proxy_t>> {
typedef std::iterator<std::random_access_iterator_tag, std::conditional_t<is_const, const proxy_t, proxy_t>, std::ptrdiff_t, std::conditional_t<is_const, const proxy_t*, proxy_t*>, std::conditional_t<is_const, const proxy_t, proxy_t>> base_t;
typedef typename base_t::reference reference;
typedef typename base_t::pointer pointer;
typedef typename base_t::value_type value_type;
typedef typename base_t::difference_type difference_type;
typedef typename base_t::iterator_category iterator_category;
lua_State* L;
int index;
int stacktop;
proxy_t sp;
stack_iterator()
: L(nullptr), index((std::numeric_limits<int>::max)()), stacktop((std::numeric_limits<int>::max)()), sp() {
}
stack_iterator(const stack_iterator<proxy_t, true>& r)
: L(r.L), index(r.index), stacktop(r.stacktop), sp(r.sp) {
}
stack_iterator(lua_State* luastate, int idx, int topidx)
: L(luastate), index(idx), stacktop(topidx), sp(luastate, idx) {
}
reference operator*() {
return proxy_t(L, index);
}
reference operator*() const {
return proxy_t(L, index);
}
pointer operator->() {
sp = proxy_t(L, index);
return &sp;
}
pointer operator->() const {
const_cast<proxy_t&>(sp) = proxy_t(L, index);
return &sp;
}
stack_iterator& operator++() {
++index;
return *this;
}
stack_iterator operator++(int) {
auto r = *this;
this->operator++();
return r;
}
stack_iterator& operator--() {
--index;
return *this;
}
stack_iterator operator--(int) {
auto r = *this;
this->operator--();
return r;
}
stack_iterator& operator+=(difference_type idx) {
index += static_cast<int>(idx);
return *this;
}
stack_iterator& operator-=(difference_type idx) {
index -= static_cast<int>(idx);
return *this;
}
difference_type operator-(const stack_iterator& r) const {
return index - r.index;
}
stack_iterator operator+(difference_type idx) const {
stack_iterator r = *this;
r += idx;
return r;
}
reference operator[](difference_type idx) const {
return proxy_t(L, index + static_cast<int>(idx));
}
bool operator==(const stack_iterator& r) const {
if (stacktop == (std::numeric_limits<int>::max)()) {
return r.index == r.stacktop;
}
else if (r.stacktop == (std::numeric_limits<int>::max)()) {
return index == stacktop;
}
return index == r.index;
}
bool operator!=(const stack_iterator& r) const {
return !(this->operator==(r));
}
bool operator<(const stack_iterator& r) const {
return index < r.index;
}
bool operator>(const stack_iterator& r) const {
return index > r.index;
}
bool operator<=(const stack_iterator& r) const {
return index <= r.index;
}
bool operator>=(const stack_iterator& r) const {
return index >= r.index;
}
};
template <typename proxy_t, bool is_const>
inline stack_iterator<proxy_t, is_const> operator+(typename stack_iterator<proxy_t, is_const>::difference_type n, const stack_iterator<proxy_t, is_const>& r) {
return r + n;
}
} // namespace sol
#endif // SOL_STACK_ITERATOR_HPP

View File

@ -22,64 +22,24 @@
#ifndef SOL_STACK_PROXY_HPP
#define SOL_STACK_PROXY_HPP
#include "stack.hpp"
#include "function.hpp"
#include "protected_function.hpp"
#include "proxy_base.hpp"
#include "stack_proxy_base.hpp"
namespace sol {
struct stack_proxy : public proxy_base<stack_proxy> {
struct stack_proxy : public stack_proxy_base {
private:
lua_State* L;
int index;
public:
stack_proxy()
: L(nullptr), index(0) {
: stack_proxy_base() {
}
stack_proxy(lua_State* L, int index)
: L(L), index(index) {
}
template <typename T>
decltype(auto) get() const {
return stack::get<T>(L, stack_index());
}
template <typename T>
bool is() const {
return stack::check<T>(L, stack_index());
}
template <typename T>
decltype(auto) as() const {
return get<T>();
}
type get_type() const noexcept {
return type_of(lua_state(), stack_index());
}
int push() const {
return push(L);
}
int push(lua_State* Ls) const {
lua_pushvalue(Ls, index);
return 1;
}
lua_State* lua_state() const {
return L;
}
int stack_index() const {
return index;
: stack_proxy_base(L, index) {
}
template <typename... Ret, typename... Args>
decltype(auto) call(Args&&... args) {
return get<function>().template call<Ret...>(std::forward<Args>(args)...);
}
decltype(auto) call(Args&&... args);
template <typename... Args>
decltype(auto) operator()(Args&&... args) {
@ -102,49 +62,6 @@ namespace sol {
}
};
} // namespace stack
namespace detail {
template <>
struct is_speshul<unsafe_function_result> : std::true_type {};
template <>
struct is_speshul<protected_function_result> : std::true_type {};
template <std::size_t I, typename... Args, typename T>
stack_proxy get(types<Args...>, index_value<0>, index_value<I>, const T& fr) {
return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I));
}
template <std::size_t I, std::size_t N, typename Arg, typename... Args, typename T, meta::enable<meta::boolean<(N > 0)>> = meta::enabler>
stack_proxy get(types<Arg, Args...>, index_value<N>, index_value<I>, const T& fr) {
return get(types<Args...>(), index_value<N - 1>(), index_value<I + lua_size<Arg>::value>(), fr);
}
} // namespace detail
template <>
struct tie_size<unsafe_function_result> : std::integral_constant<std::size_t, SIZE_MAX> {};
template <std::size_t I>
stack_proxy get(const unsafe_function_result& fr) {
return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I));
}
template <std::size_t I, typename... Args>
stack_proxy get(types<Args...> t, const unsafe_function_result& fr) {
return detail::get(t, index_value<I>(), index_value<0>(), fr);
}
template <>
struct tie_size<protected_function_result> : std::integral_constant<std::size_t, SIZE_MAX> {};
template <std::size_t I>
stack_proxy get(const protected_function_result& fr) {
return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I));
}
template <std::size_t I, typename... Args>
stack_proxy get(types<Args...> t, const protected_function_result& fr) {
return detail::get(t, index_value<I>(), index_value<0>(), fr);
}
} // namespace sol
#endif // SOL_STACK_PROXY_HPP

96
sol/stack_proxy_base.hpp Normal file
View File

@ -0,0 +1,96 @@
// The MIT License (MIT)
// Copyright (c) 2013-2017 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_STACK_PROXY_BASE_HPP
#define SOL_STACK_PROXY_BASE_HPP
#include "stack.hpp"
#include "proxy_base.hpp"
namespace sol {
struct stack_proxy_base : public proxy_base<stack_proxy_base> {
private:
lua_State* L;
int index;
public:
stack_proxy_base()
: L(nullptr), index(0) {
}
stack_proxy_base(lua_State* L, int index)
: L(L), index(index) {
}
template <typename T>
decltype(auto) get() const {
return stack::get<T>(L, stack_index());
}
template <typename T>
bool is() const {
return stack::check<T>(L, stack_index());
}
template <typename T>
decltype(auto) as() const {
return get<T>();
}
type get_type() const noexcept {
return type_of(lua_state(), stack_index());
}
int push() const {
return push(L);
}
int push(lua_State* Ls) const {
lua_pushvalue(Ls, index);
return 1;
}
lua_State* lua_state() const {
return L;
}
int stack_index() const {
return index;
}
};
namespace stack {
template <>
struct getter<stack_proxy_base> {
static stack_proxy_base get(lua_State* L, int index = -1) {
return stack_proxy_base(L, index);
}
};
template <>
struct pusher<stack_proxy_base> {
static int push(lua_State*, const stack_proxy_base& ref) {
return ref.push();
}
};
} // namespace stack
} // namespace sol
#endif // SOL_STACK_PROXY_BASE_HPP

View File

@ -70,11 +70,12 @@ namespace sol {
#else
template <lua_CFunction f>
int static_trampoline(lua_State* L) {
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION)
#if defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) && !defined(SOL_LUAJIT)
return f(L);
#else
try {
#endif
return f(L);
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION)
}
catch (const char* s) {
lua_pushstring(L, s);
@ -82,10 +83,14 @@ namespace sol {
catch (const std::exception& e) {
lua_pushstring(L, e.what());
}
#if defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) && defined(SOL_LUAJIT)
// LuaJIT cannot have the catchall when the safe propagation is on
// but LuaJIT will swallow all C++ errors
// if we don't at least catch std::exception ones
catch (...) {
lua_pushstring(L, "caught (...) exception");
}
#endif // LuaJIT cannot have the catchall, but we must catch std::exceps for it
return lua_error(L);
#endif
}
@ -117,11 +122,11 @@ namespace sol {
if (meta::bind_traits<meta::unqualified_t<Fx>>::is_noexcept) {
return f(L, std::forward<Args>(args)...);
}
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION)
#if defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) && !defined(SOL_LUAJIT)
return f(L, std::forward<Args>(args)...);
#else
try {
#endif
return f(L, std::forward<Args>(args)...);
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION)
}
catch (const char* s) {
lua_pushstring(L, s);
@ -129,10 +134,14 @@ namespace sol {
catch (const std::exception& e) {
lua_pushstring(L, e.what());
}
#if defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) && !defined(SOL_LUAJIT)
// LuaJIT cannot have the catchall when the safe propagation is on
// but LuaJIT will swallow all C++ errors
// if we don't at least catch std::exception ones
catch (...) {
lua_pushstring(L, "caught (...) exception");
}
#endif
return lua_error(L);
#endif
}
@ -1081,6 +1090,16 @@ namespace sol {
template <typename T>
struct is_stack_based : std::is_base_of<stack_reference, T> {};
template <>
struct is_stack_based<variadic_args> : std::true_type {};
template <>
struct is_stack_based<unsafe_function_result> : std::true_type {};
template <>
struct is_stack_based<protected_function_result> : std::true_type {};
template <>
struct is_stack_based<stack_proxy> : std::true_type {};
template <>
struct is_stack_based<stack_proxy_base> : std::true_type {};
template <typename T>
struct is_lua_primitive<T*> : std::true_type {};

View File

@ -26,6 +26,8 @@
#include "tuple.hpp"
#include "stack.hpp"
#include "proxy_base.hpp"
#include "stack_iterator.hpp"
#include "stack_proxy.hpp"
#include <cstdint>
namespace sol {
@ -36,6 +38,16 @@ namespace sol {
int returncount;
public:
typedef stack_proxy reference_type;
typedef stack_proxy value_type;
typedef stack_proxy* pointer;
typedef std::ptrdiff_t difference_type;
typedef std::size_t size_type;
typedef stack_iterator<stack_proxy, false> iterator;
typedef stack_iterator<stack_proxy, true> const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
unsafe_function_result() = default;
unsafe_function_result(lua_State* Ls, int idx = -1, int retnum = 0)
: L(Ls), index(idx), returncount(retnum) {
@ -66,8 +78,54 @@ namespace sol {
unsafe_function_result& operator=(protected_function_result&& o) noexcept;
template <typename T>
decltype(auto) get(int index_offset = 0) const {
return stack::get<T>(L, index + index_offset);
decltype(auto) get(difference_type index_offset = 0) const {
return stack::get<T>(L, index + static_cast<int>(index_offset));
}
type get_type(difference_type index_offset = 0) const noexcept {
return type_of(L, index + static_cast<int>(index_offset));
}
stack_proxy operator[](difference_type index_offset) const {
return stack_proxy(L, index + static_cast<int>(index_offset));
}
iterator begin() {
return iterator(L, index, stack_index() + return_count());
}
iterator end() {
return iterator(L, stack_index() + return_count(), stack_index() + return_count());
}
const_iterator begin() const {
return const_iterator(L, index, stack_index() + return_count());
}
const_iterator end() const {
return const_iterator(L, stack_index() + return_count(), stack_index() + return_count());
}
const_iterator cbegin() const {
return begin();
}
const_iterator cend() const {
return end();
}
reverse_iterator rbegin() {
return std::reverse_iterator<iterator>(begin());
}
reverse_iterator rend() {
return std::reverse_iterator<iterator>(end());
}
const_reverse_iterator rbegin() const {
return std::reverse_iterator<const_iterator>(begin());
}
const_reverse_iterator rend() const {
return std::reverse_iterator<const_iterator>(end());
}
const_reverse_iterator crbegin() const {
return std::reverse_iterator<const_iterator>(cbegin());
}
const_reverse_iterator crend() const {
return std::reverse_iterator<const_iterator>(cend());
}
call_status status() const noexcept {

View File

@ -24,133 +24,11 @@
#include "stack.hpp"
#include "stack_proxy.hpp"
#include "stack_iterator.hpp"
#include <limits>
#include <iterator>
namespace sol {
template <bool is_const>
struct va_iterator : std::iterator<std::random_access_iterator_tag, std::conditional_t<is_const, const stack_proxy, stack_proxy>, std::ptrdiff_t, std::conditional_t<is_const, const stack_proxy*, stack_proxy*>, std::conditional_t<is_const, const stack_proxy, stack_proxy>> {
typedef std::iterator<std::random_access_iterator_tag, std::conditional_t<is_const, const stack_proxy, stack_proxy>, std::ptrdiff_t, std::conditional_t<is_const, const stack_proxy*, stack_proxy*>, std::conditional_t<is_const, const stack_proxy, stack_proxy>> base_t;
typedef typename base_t::reference reference;
typedef typename base_t::pointer pointer;
typedef typename base_t::value_type value_type;
typedef typename base_t::difference_type difference_type;
typedef typename base_t::iterator_category iterator_category;
lua_State* L;
int index;
int stacktop;
stack_proxy sp;
va_iterator()
: L(nullptr), index((std::numeric_limits<int>::max)()), stacktop((std::numeric_limits<int>::max)()) {
}
va_iterator(const va_iterator<true>& r)
: L(r.L), index(r.index), stacktop(r.stacktop) {
}
va_iterator(lua_State* luastate, int idx, int topidx)
: L(luastate), index(idx), stacktop(topidx), sp(luastate, idx) {
}
reference operator*() {
return stack_proxy(L, index);
}
reference operator*() const {
return stack_proxy(L, index);
}
pointer operator->() {
sp = stack_proxy(L, index);
return &sp;
}
pointer operator->() const {
const_cast<stack_proxy&>(sp) = stack_proxy(L, index);
return &sp;
}
va_iterator& operator++() {
++index;
return *this;
}
va_iterator operator++(int) {
auto r = *this;
this->operator++();
return r;
}
va_iterator& operator--() {
--index;
return *this;
}
va_iterator operator--(int) {
auto r = *this;
this->operator--();
return r;
}
va_iterator& operator+=(difference_type idx) {
index += static_cast<int>(idx);
return *this;
}
va_iterator& operator-=(difference_type idx) {
index -= static_cast<int>(idx);
return *this;
}
difference_type operator-(const va_iterator& r) const {
return index - r.index;
}
va_iterator operator+(difference_type idx) const {
va_iterator r = *this;
r += idx;
return r;
}
reference operator[](difference_type idx) const {
return stack_proxy(L, index + static_cast<int>(idx));
}
bool operator==(const va_iterator& r) const {
if (stacktop == (std::numeric_limits<int>::max)()) {
return r.index == r.stacktop;
}
else if (r.stacktop == (std::numeric_limits<int>::max)()) {
return index == stacktop;
}
return index == r.index;
}
bool operator!=(const va_iterator& r) const {
return !(this->operator==(r));
}
bool operator<(const va_iterator& r) const {
return index < r.index;
}
bool operator>(const va_iterator& r) const {
return index > r.index;
}
bool operator<=(const va_iterator& r) const {
return index <= r.index;
}
bool operator>=(const va_iterator& r) const {
return index >= r.index;
}
};
template <bool is_const>
inline va_iterator<is_const> operator+(typename va_iterator<is_const>::difference_type n, const va_iterator<is_const>& r) {
return r + n;
}
struct variadic_args {
private:
lua_State* L;
@ -163,22 +41,22 @@ namespace sol {
typedef stack_proxy* pointer;
typedef std::ptrdiff_t difference_type;
typedef std::size_t size_type;
typedef va_iterator<false> iterator;
typedef va_iterator<true> const_iterator;
typedef stack_iterator<stack_proxy, false> iterator;
typedef stack_iterator<stack_proxy, true> const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
variadic_args() = default;
variadic_args(lua_State* luastate, int stackindex = -1)
: L(luastate), index(lua_absindex(luastate, stackindex)), stacktop(lua_gettop(luastate)) {
: L(luastate), index(lua_absindex(luastate, stackindex)), stacktop(lua_gettop(luastate)) {
}
variadic_args(lua_State* luastate, int stackindex, int lastindex)
: L(luastate), index(lua_absindex(luastate, stackindex)), stacktop(lastindex) {
: L(luastate), index(lua_absindex(luastate, stackindex)), stacktop(lastindex) {
}
variadic_args(const variadic_args&) = default;
variadic_args& operator=(const variadic_args&) = default;
variadic_args(variadic_args&& o)
: L(o.L), index(o.index), stacktop(o.stacktop) {
: L(o.L), index(o.index), stacktop(o.stacktop) {
// Must be manual, otherwise destructor will screw us
// return count being 0 is enough to keep things clean
// but will be thorough
@ -254,16 +132,16 @@ namespace sol {
}
template <typename T>
decltype(auto) get(difference_type start = 0) const {
return stack::get<T>(L, index + static_cast<int>(start));
decltype(auto) get(difference_type index_offset = 0) const {
return stack::get<T>(L, index + static_cast<int>(index_offset));
}
type get_type(difference_type start = 0) const noexcept {
return type_of(L, index + static_cast<int>(start));
type get_type(difference_type index_offset = 0) const noexcept {
return type_of(L, index + static_cast<int>(index_offset));
}
stack_proxy operator[](difference_type start) const {
return stack_proxy(L, index + static_cast<int>(start));
stack_proxy operator[](difference_type index_offset) const {
return stack_proxy(L, index + static_cast<int>(index_offset));
}
lua_State* lua_state() const {

View File

@ -1,4 +1,5 @@
#define SOL_CHECK_ARGUMENTS
#define SOL_CHECK_ARGUMENTS 1
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp>

View File

@ -1,4 +1,5 @@
#define SOL_CHECK_ARGUMENTS
#define SOL_CHECK_ARGUMENTS 1
#define SOL_ENABLE_INTEROP 1
#include <catch.hpp>
#include <sol.hpp>

View File

@ -1,4 +1,5 @@
#define SOL_CHECK_ARGUMENTS
#define SOL_CHECK_ARGUMENTS 1
#define SOL_ENABLE_INTEROP 1
#include <catch.hpp>
#include <sol.hpp>

View File

@ -1,4 +1,5 @@
#define SOL_CHECK_ARGUMENTS
#define SOL_CHECK_ARGUMENTS 1
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp>

View File

@ -1,7 +1,10 @@
#define SOL_CHECK_ARGUMENTS
#define SOL_CHECK_ARGUMENTS 1
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp>
#include <cstdint>
#include <limits>

View File

@ -1,7 +1,9 @@
#define SOL_CHECK_ARGUMENTS
#define SOL_CHECK_ARGUMENTS 1
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp>
#include <sol.hpp>
TEST_CASE("issues/stack overflow", "make sure various operations repeated don't trigger stack overflow") {
sol::state lua;

31
tests/test_proxies.cpp Normal file
View File

@ -0,0 +1,31 @@
#define SOL_CHECK_ARGUMENTS 1
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp>
#include <iostream>
#include "test_stack_guard.hpp"
TEST_CASE("proxy/function results", "make sure that function results return proper proxies and can be indexed nicely") {
sol::state lua;
SECTION("unsafe_function_result") {
auto ufr = lua.script("return 1, 2, 3, 4");
int accum = 0;
for (const auto& r : ufr) {
int v = r;
accum += v;
}
REQUIRE(accum == 10);
}
SECTION("protected_function_result") {
auto pfr = lua.safe_script("return 1, 2, 3, 4");
int accum = 0;
for (const auto& r : pfr) {
int v = r;
accum += v;
}
REQUIRE(accum == 10);
}
}

View File

@ -1,6 +1,8 @@
#define SOL_CHECK_ARGUMENTS
#define SOL_CHECK_ARGUMENTS 1
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp>
#include <iostream>

View File

@ -1,7 +1,10 @@
#define SOL_CHECK_ARGUMENTS
#define SOL_CHECK_ARGUMENTS 1
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp>
#include <sol.hpp>
#include <iostream>
#include <fstream>
#include <chrono>

View File

@ -1,7 +1,9 @@
#define SOL_CHECK_ARGUMENTS
#define SOL_CHECK_ARGUMENTS 1
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp>
#include <sol.hpp>
TEST_CASE("storage/registry construction", "ensure entries from the registry can be retrieved") {
const auto& code = R"(

View File

@ -1,7 +1,9 @@
#define SOL_CHECK_ARGUMENTS
#define SOL_CHECK_ARGUMENTS 1
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp>
#include <sol.hpp>
#include <iostream>

View File

@ -1,7 +1,9 @@
#define SOL_CHECK_ARGUMENTS
#define SOL_CHECK_ARGUMENTS 1
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp>
#include <sol.hpp>
#include <iostream>
#include <algorithm>

View File

@ -1,6 +1,8 @@
#define SOL_CHECK_ARGUMENTS
#define SOL_CHECK_ARGUMENTS 1
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp>
#include <iostream>

View File

@ -1,7 +1,9 @@
#define SOL_CHECK_ARGUMENTS
#define SOL_CHECK_ARGUMENTS 1
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp>
#include <sol.hpp>
#include <mutex>
#include <thread>

View File

@ -1,7 +1,9 @@
#define SOL_CHECK_ARGUMENTS
#define SOL_CHECK_ARGUMENTS 1
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp>
#include <sol.hpp>
#include <deque>
#include <set>

View File

@ -1,8 +1,10 @@
#define CATCH_CONFIG_MAIN
#define SOL_CHECK_ARGUMENTS
#define SOL_CHECK_ARGUMENTS 1
#define SOL_ENABLE_INTEROP 1
#include <sol.hpp>
#include <catch.hpp>
#include <sol.hpp>
#include <fstream>
#include <iostream>