documentation fixes from feedback and fixes!

This commit is contained in:
ThePhD 2016-03-14 02:34:02 -04:00
parent d3ccfa7426
commit 62f082d999
20 changed files with 211 additions and 124 deletions

View File

@ -49,4 +49,10 @@ The call ``woof(20)`` generates a :ref:`function_result<function-result>`, which
template<typename... Ret, typename... Args>
decltype(auto) operator()( types<Ret...>, Args&&... args );
Calls the function. The second ``operator()`` lets you specify the templated return types using the ``my_func(sol::types<int, std::string>, ...)`` syntax. Function assumes there are no runtime errors, and thusly will call the ``atpanic`` function if an error does occur.
Calls the function. The second ``operator()`` lets you specify the templated return types using the ``my_func(sol::types<int, std::string>, ...)`` syntax. Function assumes there are no runtime errors, and thusly will call the ``atpanic`` function if an error does occur.
safety
------
You can have functions here and on usertypes check to definitely make sure that the types passed to C++ functions are what they're supposed to be by adding a ``#define SOL_CHECK_ARGUMENTS`` before including Sol, or passing it on the command line. Otherwise, for speed reasons, these checks are only used where absolutely necessary (like discriminating between :doc:`overloads<overload>`)

View File

@ -20,7 +20,7 @@ members
template<typename T>
decltype(auto) as() const;
Performs a cast of the item this reference refers to into the type ``T`` and returns it. It obeys the same rules as :doc:`sol::stack::get\<T><stack>`.
Performs a cast of the item this reference refers to into the type ``T`` and returns it. It obeys the same rules as :ref:`sol::stack::get\<T><getter>`.
.. code-block:: cpp
:caption: function: type check

View File

@ -62,10 +62,10 @@ Thusly, doing the following in Lua:
:linenos:
local barker = pup.new()
pup.bark() -- calls member function pup::bark
pup.bark(20) -- calls ultra_bark
pup.bark("meow") -- picky_bark, no bark
pup.bark("bark") -- picky_bark, bark
pup:bark() -- calls member function pup::bark
pup:bark(20) -- calls ultra_bark
pup:bark("meow") -- picky_bark, no bark
pup:bark("bark") -- picky_bark, bark
bark(pup, 20) -- calls ultra_bark
local nowherebark = bark() -- calls lambda which returns that string

View File

@ -25,6 +25,7 @@ Retrieves the value of the object at ``index`` in the stack. The return type var
.. code-block:: cpp
:caption: function: check
:name: stack-check
template <typename T>
bool check( lua_State* L, int index = -1 )
@ -32,10 +33,11 @@ Retrieves the value of the object at ``index`` in the stack. The return type var
template <typename T, typename Handler>
bool check( lua_State* L, int index, Handler&& handler )
Checks if the object at ``index`` is of type ``T``. If it is not, it will call the ``handler`` function with the index, expected, and actual types.
Checks if the object at ``index`` is of type ``T``. If it is not, it will call the ``handler`` function with ``lua_State*``, ``int index``, ``type`` expected, and ``type`` actual as arguments.
.. code-block:: cpp
:caption: function: push
:name: stack-push
// push T inferred from call site, pass args... through to extension point
template <typename T, typename... Args>
@ -91,7 +93,7 @@ The structs below are already overriden for a handful of types. If you try to me
}
};
This is an SFINAE-friendly struct that is meant to expose static function ``get`` that returns a ``T``, or something convertible to it. The default implementation assumes ``T`` is a usertype and pulls out a userdata from Lua before attempting to cast it to the desired ``T``. There are implementations for getting numbers (``std::is_floating``, ``std::is_integral``-matching types), getting ``std::string`` and ``const char*``, getting raw userdata with :doc:`userdata_value<types>` and anything as upvalues with :doc:`upvalue_index<types>`, getting raw `lua_CFunction`_ s, and finally pulling out Lua functions into ``std::function<R(Args...)>``. It is also defined for anything that derives from :doc:`sol::reference<reference>`.
This is an SFINAE-friendly struct that is meant to expose static function ``get`` that returns a ``T``, or something convertible to it. The default implementation assumes ``T`` is a usertype and pulls out a userdata from Lua before attempting to cast it to the desired ``T``. There are implementations for getting numbers (``std::is_floating``, ``std::is_integral``-matching types), getting ``std::string`` and ``const char*``, getting raw userdata with :doc:`userdata_value<types>` and anything as upvalues with :doc:`upvalue_index<types>`, getting raw `lua_CFunction`_ s, and finally pulling out Lua functions into ``std::function<R(Args...)>``. It is also defined for anything that derives from :doc:`sol::reference<reference>`. It also has a special implementation for the 2 standard library smart pointers (see :doc:`usertype memory<usertype_memory>`).
.. code-block:: cpp
:caption: struct: pusher
@ -99,7 +101,7 @@ This is an SFINAE-friendly struct that is meant to expose static function ``get`
template <typename X, typename = void>
struct pusher {
template <typename T>
template <typename T>
static int push ( lua_State* L, T&&, ... ) {
// can optionally take more than just 1 argument
// ...
@ -107,7 +109,7 @@ This is an SFINAE-friendly struct that is meant to expose static function ``get`
}
};
This is an SFINAE-friendly struct that is meant to expose static function ``push`` that returns the number of things pushed onto the stack. The default implementation assumes ``T`` is a usertype and pushes a userdata into Lua with a :ref:`usertype_traits\<T><usertype-traits>` metatable associated with it. There are implementations for pushing numbers (``std::is_floating``, ``std::is_integral``-matching types), getting ``std::string`` and ``const char*``, getting raw userdata with :doc:`userdata<types>` and raw upvalues with :doc:`upvalue<types>`, getting raw `lua_CFunction`_ s, and finally pulling out Lua functions into ``sol::function``. It is also defined for anything that derives from :doc:`sol::reference<reference>`.
This is an SFINAE-friendly struct that is meant to expose static function ``push`` that returns the number of things pushed onto the stack. The default implementation assumes ``T`` is a usertype and pushes a userdata into Lua with a :ref:`usertype_traits\<T><usertype-traits>` metatable associated with it. There are implementations for pushing numbers (``std::is_floating``, ``std::is_integral``-matching types), getting ``std::string`` and ``const char*``, getting raw userdata with :doc:`userdata<types>` and raw upvalues with :doc:`upvalue<types>`, getting raw `lua_CFunction`_ s, and finally pulling out Lua functions into ``sol::function``. It is also defined for anything that derives from :doc:`sol::reference<reference>`. It also has a special implementation for the 2 standard library smart pointers (see :doc:`usertype memory<usertype_memory>`).
.. code-block:: cpp
:caption: struct: checker

View File

@ -45,6 +45,7 @@ These functions set items into the table. The first one (``set``) can set *mult
.. code-block:: cpp
:caption: function: setting a usertype
:name: new-usertype
template<typename Class, typename... Args>
table& new_usertype(const std::string& name, Args&&... args);
@ -59,6 +60,7 @@ This class of functions creates a new :doc:`usertype<usertype>` with the specifi
.. code-block:: cpp
:caption: function: setting a pre-created usertype
:name: set-usertype
template<typename T>
table& set_usertype(usertype<T>& user);

View File

@ -27,3 +27,4 @@ Browse the various function and classes :doc:`Sol<../index>` utilizes to make yo
types
usertype
userdata
usertype_memory

View File

@ -123,6 +123,16 @@ special types
A tag type that, when used with :doc:`stack::get\<non_null\<T*>><stack>`, does not perform a ``nil`` check when attempting to retrieve the userdata pointer.
.. code-block:: cpp
:caption: unique_usertype
:name: unique-usertype
template <typename T, typename Real>
struct unique_usertype {};
A tag type for alerting the framewok that a certain type is to be pushed as a special userdata with special deletion semantics. Is automatically applied to ``std::unique_ptr<T, D>`` and ``std::shared_ptr<T>``.
.. code-block:: cpp
:caption: type list
:name: type-list

View File

@ -231,7 +231,6 @@ traits
.. code-block:: cpp
:caption: usertype_traits<T>
:linenos:
:name: usertype-traits
template<typename T>
@ -245,10 +244,9 @@ traits
This trait is used to provide names for the various metatables and global tables used to perform cleanup and lookup. They are automatically generated at runtime. In the case of RTTI being present, Sol will attempt to demangle the name from ``std::type_info`` to produce a valid name. If RTTI is disabled, Sol attempts to parse the output of ``__PRETTY_FUCNTION__`` (``g++``/``clang++``) or ``_FUNCDSIG`` (``vc++``) to get the proper type name. If you have a special need you can override the names for your specific type.
performance note
----------------
.. note::
Note that performance for member function calls goes down by a fixed overhead if you also bind variables as well as member functions. This is purely a limitation of the lua implementation and there's, unfortunately, nothing that can be done about it. If you bind only functions and no variables, however, Sol will automatically optimize the lua runtime and give you the maximum performance possible. *Please consider ease of use and maintenance of code before you make everything into functions.*
Note that performance for member function calls goes down by a fixed overhead if you also bind variables as well as member functions. This is purely a limitation of the lua implementation and there's, unfortunately, nothing that can be done about it. If you bind only functions and no variables, however, Sol will automatically optimize the Lua runtime and give you the maximum performance possible. *Please consider ease of use and maintenance of code before you make everything into functions.*

View File

@ -0,0 +1,43 @@
usertype memory
===============
The userdata generated by Sol has a specific layout, depending on how Sol recognizes userdata passed into it. All of the referred to metatable names are generated from :ref:`usertype_traits\<T><usertype-traits>`
In general, we always insert a T* in the first `sizeof(T*)` bytes, so the any framework that pulls out those first bytes expecting a pointer will work. The rest of the data has some different alignments and contents based on what it's used for and how it's used.
For ``T``
---------
These are classified with the metatable from ``
The data layout for references is as follows::
| T* | T |
^-sizeof(T*) bytes-^-sizeof(T) bytes, actual data-^
Lua will clean up the memory itself but does not know about any destruction semantics T may have imposed, so when we destroy this data we simply call the destructor to destroy the object and leave the memory changes to for lua to handle after the "__gc" method exits.
For ``T*``
----------
These are classified as a separate ``T*`` metatable, essentially the "reference" table. Things passed to Sol as a pointer or as a ``std::reference<T>`` are considered to be references, and thusly do not have a ``__gc`` (garbage collection) method by default. All raw pointers are non-owning pointers in C++. If you're working with a C API, provide a wrapper around pointers that are supposed to own data and use the constructor/destructor idioms (e.g., with an internal ``std::unique_ptr``) to keep things clean.
The data layout for data that only refers is as follows::
| T* |
^-sizeof(T*) bytes-^
That is it. No destruction semantics need to be called.
For ``std::unique_ptr<T, D>`` and ``std::shared_ptr<T>``
--------------------------------------------------------
These are classified as :ref:`"unique usertypes"<unique-usertype>`, and have a special metatable for them as well. The special metatable is either generated when you add the usertype to Lua using :ref:`set_usertype<set-usertype>` or when you first push one of these special types. In addition to the data, a deleter function that understands the following layout is injected into the usertype.
The data layout for these kinds of types is as follows::
| T* | void(*)(void*) function_pointer | T |
^-sizeof(T*) bytes-^-sizeof(void(*)(void*)) bytes, deleter-^- sizeof(T) bytes, actal data -^
Note that we put a special deleter function before the actual data. This is because the custom deleter must know where the offset to the data is, not the rest of the library. Sol just needs to know about ``T*`` and the userdata (and userdata metatable) to work, everything else is for preserving construction / destruction syntax.

View File

@ -87,13 +87,13 @@ The below feature table checks for the presence of something. It, however, does
+---------------------------+-------------+------------+----------+---------+----------+-----------+-----------+----------------+----------+
| overloading | ~ | ✗ | ✗ | ✗ | ✗ | ✔ | ✗ | ✗ | ✗ |
+---------------------------+-------------+------------+----------+---------+----------+-----------+-----------+----------------+----------+
| thread | ✔ | ✗ | ✗ | ✗ | ✗ | ✔ | | ✗ | ✔ |
| thread | ✔ | ✗ | ✗ | ✗ | ✗ | ✔ | | ✗ | ✔ |
+---------------------------+-------------+------------+----------+---------+----------+-----------+-----------+----------------+----------+
| coroutines | ✔ | ✗ | ✗ | ✔ | ✔ | ✔ | ✗ | ✗ | ✔ |
+---------------------------+-------------+------------+----------+---------+----------+-----------+-----------+----------------+----------+
| no-rtti support | ✔ | ✗ | ~ | ✗ | ✗ | ✔ | | ✗ | ✔ |
| no-rtti support | ✔ | ✗ | ~ | ✗ | ✗ | ✔ | | ✗ | ✔ |
+---------------------------+-------------+------------+----------+---------+----------+-----------+-----------+----------------+----------+
| no-exception support | ✔ | ✗ | ~ | ~ | ✗ | ✔ | | ✗ | ✔ |
| no-exception support | ✔ | ✗ | ~ | ~ | ✗ | ✔ | | ✗ | ✔ |
+---------------------------+-------------+------------+----------+---------+----------+-----------+-----------+----------------+----------+
| Lua 5.1 | ✔ | ✔ | ~ | ✔ | ✗ | ✔ | ✔ | ✔ | ✔ |
+---------------------------+-------------+------------+----------+---------+----------+-----------+-----------+----------------+----------+
@ -140,7 +140,7 @@ luabind -
Selene -
* member variables are automatically turned into ``obj:set_x( value )`` to set and ``obj:x()`` to get
* Registering classes/"modules" in using C++ code is extremely verbose
* Registering classes/"modules" using C++ code is extremely verbose
Sol -
@ -151,6 +151,7 @@ Sol -
oolua -
* The syntax for this library is thicker than a brick. No, seriously. `Go read the docs.`_
* Supports not having exceptions or rtti turned on (shiny!)
.. _ fn1:
@ -167,5 +168,10 @@ kaguya -
* Library author (satoren) is a nice guy!
* C++11/14, or boostified (which makes it C++03 compatible)
TODO:
* SWIG - http://www.swig.org/Doc1.3/Lua.html#Lua_nn2
* SLB3 - https://code.google.com/archive/p/slb/
* Luwra - https://github.com/vapourismo/luwra
.. _Go read the docs.: https://oolua.org/docs/index.html

View File

@ -83,7 +83,7 @@ the basics:
"bop", &vars::bop);
lua.script("beep = vars.new()\n"
"beep.boop = 1\n"
"bopvalue = beep.bop()");
"bopvalue = beep:bop()");
vars& beep = lua["beep"];
int bopvalue = lua["bopvalue"];

View File

@ -58,9 +58,9 @@ inline std::string get_type_name() {
std::string name = __FUNCSIG__;
std::size_t start = name.find("get_type_name");
if (start == std::string::npos)
start = 0;
start = 0;
else
start += 13;
start += 13;
if (start < name.size() - 1)
start += 1;
std::size_t end = name.find_last_of('>');

View File

@ -207,9 +207,9 @@ struct pusher<function_sig<Sigs...>> {
lua_CFunction freefunc = function_detail::call;
stack::push(L, userdata_value(targetdata));
function_detail::free_function_cleanup(L);
lua_setmetatable(L, -2);
stack::push(L, freefunc, 1);
function_detail::free_function_cleanup(L);
lua_setmetatable(L, -2);
stack::push(L, freefunc, 1);
}
template<typename... Args>

View File

@ -40,7 +40,10 @@ struct implicit_wrapper {
}
};
const static auto& cleanup_key = u8"sol.ƒ.♲.🗑.(/¯◡ ‿ ◡)/¯ ~ ┻━┻ (ノ◕ヮ◕)ノ*:・゚✧";
inline decltype(auto) cleanup_key() {
const auto& name = u8"sol.ƒ.♲.🗑.(/¯◡ ‿ ◡)/¯ ~ ┻━┻ (ノ◕ヮ◕)ノ*:・゚✧";
return name;
}
template<typename T, typename Func, typename = void>
struct functor {
@ -229,8 +232,8 @@ inline int usertype_gc(lua_State* L) {
return 0;
}
void free_function_cleanup(lua_State* L) {
const static char* metatablename = &cleanup_key[0];
inline void free_function_cleanup(lua_State* L) {
const static char* metatablename = &cleanup_key()[0];
int metapushed = luaL_newmetatable(L, metatablename);
if (metapushed == 1) {
stack::set_field(L, "__gc", function_detail::gc);

View File

@ -52,8 +52,15 @@ template <typename T>
const std::size_t id_for<T>::value = unique_id();
#endif // No Runtime Type Information / No Exceptions
const auto& base_class_check_key = u8"♡o。.(✿ฺ。 ✿ฺ)";
const auto& base_class_cast_key = u8"(◕‿◕✿)";
inline decltype(auto) base_class_check_key() {
static const auto& key = u8"♡o。.(✿ฺ。 ✿ฺ)";
return key;
}
inline decltype(auto) base_class_cast_key() {
static const auto& key = u8"(◕‿◕✿)";
return key;
}
#ifndef SOL_NO_EXCEPTIONS

View File

@ -234,7 +234,7 @@ struct getter<T*> {
static T* get_no_nil_from(lua_State* L, void* udata, int index = -1) {
#ifndef SOL_NO_EXCEPTIONS
if (luaL_getmetafield(L, index, &detail::base_class_check_key[0]) != 0) {
if (luaL_getmetafield(L, index, &detail::base_class_check_key()[0]) != 0) {
void* basecastdata = stack::get<light_userdata_value>(L);
detail::throw_cast basecast = (detail::throw_cast)basecastdata;
// use the casting function to properly adjust the pointer for the desired T
@ -242,7 +242,7 @@ struct getter<T*> {
lua_pop(L, 1);
}
#elif !defined(SOL_NO_RTTI)
if (luaL_getmetafield(L, index, &detail::base_class_cast_key[0]) != 0) {
if (luaL_getmetafield(L, index, &detail::base_class_cast_key()[0]) != 0) {
void* basecastdata = stack::get<light_userdata_value>(L);
detail::inheritance_cast_function ic = (detail::inheritance_cast_function)basecastdata;
// use the casting function to properly adjust the pointer for the desired T
@ -251,7 +251,7 @@ struct getter<T*> {
}
#else
// Lol, you motherfucker
if (luaL_getmetafield(L, index, &detail::base_class_cast_key[0]) != 0) {
if (luaL_getmetafield(L, index, &detail::base_class_cast_key()[0]) != 0) {
void* basecastdata = stack::get<light_userdata_value>(L);
detail::inheritance_cast_function ic = (detail::inheritance_cast_function)basecastdata;
// use the casting function to properly adjust the pointer for the desired T
@ -430,12 +430,12 @@ struct checker<T, type::userdata, C> {
}
lua_pop(L, 1);
#ifndef SOL_NO_EXCEPTIONS
lua_getfield(L, -1, &detail::base_class_check_key[0]);
lua_getfield(L, -1, &detail::base_class_check_key()[0]);
void* basecastdata = stack::get<light_userdata_value>(L);
detail::throw_cast basecast = (detail::throw_cast)basecastdata;
bool success = detail::catch_check<T>(basecast);
#elif !defined(SOL_NO_RTTI)
lua_getfield(L, -1, &detail::base_class_check_key[0]);
lua_getfield(L, -1, &detail::base_class_check_key()[0]);
if (stack::get<type>(L) == type::nil) {
lua_pop(L, 2);
return false;
@ -445,7 +445,7 @@ struct checker<T, type::userdata, C> {
bool success = ic(typeid(T));
#else
// Topkek
lua_getfield(L, -1, &detail::base_class_check_key[0]);
lua_getfield(L, -1, &detail::base_class_check_key()[0]);
if (stack::get<type>(L) == type::nil) {
lua_pop(L, 2);
return false;

View File

@ -115,9 +115,9 @@ template <typename... Args>
using has_destructor = meta::Or<is_destructor<meta::Unqualified<Args>>...>;
enum class stage {
normalmeta,
refmeta,
uniquemeta,
normalmeta,
refmeta,
uniquemeta,
};
template<typename T, stage metastage>
@ -127,11 +127,11 @@ inline void push_metatable(lua_State* L, bool needsindexfunction, std::vector<st
int metatableindex = lua_gettop(L);
if (baseclasscheck != nullptr) {
stack::push(L, light_userdata_value(baseclasscheck));
lua_setfield(L, metatableindex, &detail::base_class_check_key[0]);
lua_setfield(L, metatableindex, &detail::base_class_check_key()[0]);
}
if (baseclasscast != nullptr) {
stack::push(L, light_userdata_value(baseclasscast));
lua_setfield(L, metatableindex, &detail::base_class_cast_key[0]);
lua_setfield(L, metatableindex, &detail::base_class_cast_key()[0]);
}
if (funcs.size() < 1 && metafunctable.size() < 2) {
return;

View File

@ -1520,88 +1520,3 @@ TEST_CASE("usertype/overloading", "Check if overloading works properly for usert
REQUIRE_THROWS(lua.script("r:func(1,2,'meow')"));
}
TEST_CASE("threading/coroutines", "ensure calling a coroutine works") {
const auto& script = R"(counter = 20
function loop()
while counter ~= 30
do
coroutine.yield(counter);
counter = counter + 1;
end
return counter
end
)";
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::coroutine);
lua.script(script);
sol::coroutine cr = lua["loop"];
int counter;
for (counter = 20; counter < 31 && cr; ++counter) {
int value = cr();
if (counter != value) {
throw std::logic_error("fuck");
}
}
counter -= 1;
REQUIRE(counter == 30);
}
TEST_CASE("threading/new-thread-coroutines", "ensure calling a coroutine works when the work is put on a different thread") {
const auto& script = R"(counter = 20
function loop()
while counter ~= 30
do
coroutine.yield(counter);
counter = counter + 1;
end
return counter
end
)";
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::coroutine);
lua.script(script);
sol::thread runner = sol::thread::create(lua.lua_state());
sol::state_view runnerstate = runner.state();
sol::coroutine cr = runnerstate["loop"];
int counter;
for (counter = 20; counter < 31 && cr; ++counter) {
int value = cr();
if (counter != value) {
throw std::logic_error("fuck");
}
}
counter -= 1;
REQUIRE(counter == 30);
}
TEST_CASE("issues/stack-overflow", "make sure various operations repeated don't trigger stack overflow") {
sol::state lua;
lua.script("t = {};t[0]=20");
lua.script("lua_function=function(i)return i;end");
sol::function f = lua["lua_function"];
std::string teststring = "testtext";
REQUIRE_NOTHROW(
for (int i = 0; i < 1000000; ++i) {
std::string result = f(teststring);
if (result != teststring) throw std::logic_error("RIP");
}
);
sol::table t = lua["t"];
int expected = 20;
REQUIRE_NOTHROW(
for (int i = 0; i < 1000000; ++i) {
int result = t[0];
t.size();
if (result != expected)
throw std::logic_error("RIP");
}
);
}

64
tests_coroutines.cpp Normal file
View File

@ -0,0 +1,64 @@
#define SOL_CHECK_ARGUMENTS
#include <catch.hpp>
#include <sol.hpp>
TEST_CASE("threading/coroutines", "ensure calling a coroutine works") {
const auto& script = R"(counter = 20
function loop()
while counter ~= 30
do
coroutine.yield(counter);
counter = counter + 1;
end
return counter
end
)";
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::coroutine);
lua.script(script);
sol::coroutine cr = lua["loop"];
int counter;
for (counter = 20; counter < 31 && cr; ++counter) {
int value = cr();
if (counter != value) {
throw std::logic_error("fuck");
}
}
counter -= 1;
REQUIRE(counter == 30);
}
TEST_CASE("threading/new-thread-coroutines", "ensure calling a coroutine works when the work is put on a different thread") {
const auto& script = R"(counter = 20
function loop()
while counter ~= 30
do
coroutine.yield(counter);
counter = counter + 1;
end
return counter
end
)";
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::coroutine);
lua.script(script);
sol::thread runner = sol::thread::create(lua.lua_state());
sol::state_view runnerstate = runner.state();
sol::coroutine cr = runnerstate["loop"];
int counter;
for (counter = 20; counter < 31 && cr; ++counter) {
int value = cr();
if (counter != value) {
throw std::logic_error("fuck");
}
}
counter -= 1;
REQUIRE(counter == 30);
}

30
tests_overflow.cpp Normal file
View File

@ -0,0 +1,30 @@
#define SOL_CHECK_ARGUMENTS
#include <catch.hpp>
#include <sol.hpp>
TEST_CASE("issues/stack-overflow", "make sure various operations repeated don't trigger stack overflow") {
sol::state lua;
lua.script("t = {};t[0]=20");
lua.script("lua_function=function(i)return i;end");
sol::function f = lua["lua_function"];
std::string teststring = "testtext";
REQUIRE_NOTHROW(
for (int i = 0; i < 1000000; ++i) {
std::string result = f(teststring);
if (result != teststring) throw std::logic_error("RIP");
}
);
sol::table t = lua["t"];
int expected = 20;
REQUIRE_NOTHROW(
for (int i = 0; i < 1000000; ++i) {
int result = t[0];
t.size();
if (result != expected)
throw std::logic_error("RIP");
}
);
}