this mega commit prepares to fix all of the issues listed in the repository for the past 3 weeks

This commit is contained in:
ThePhD 2017-08-05 19:20:28 -04:00
parent 16fc7d87ff
commit 104485bebd
98 changed files with 3712 additions and 1334 deletions

View File

@ -1,7 +1,7 @@
as_args
=======
turn an iterable argument into multiple arguments
-------------------------------------------------
*turn an iterable argument into multiple arguments*
.. code-block:: cpp

View File

@ -1,7 +1,7 @@
as_function
===========
make sure an object is pushed as a function
-------------------------------------------
*make sure an object is pushed as a function*
.. code-block:: cpp

View File

@ -1,7 +1,7 @@
as_returns
==========
turn an iterable argument into a multiple-return type
-----------------------------------------------------
*turn an iterable argument into a multiple-return type*
.. code-block:: cpp

View File

@ -1,7 +1,7 @@
as_table
===========
make sure an object is pushed as a table
----------------------------------------
*make sure an object is pushed as a table*
.. code-block:: cpp

View File

@ -1,7 +1,7 @@
c_call
======
Templated type to transport functions through templates
-------------------------------------------------------
*templated type to transport functions through templates*
.. code-block:: cpp

View File

@ -1,7 +1,7 @@
compatibility.hpp
=================
Lua 5.3/5.2 compatibility for Lua 5.1/LuaJIT
--------------------------------------------
*Lua 5.3/5.2 compatibility for Lua 5.1/LuaJIT*
This is a detail header used to maintain compatability with the 5.2 and 5.3+ APIs. It contains code from the MIT-Licensed `Lua code`_ in some places and also from the `lua-compat`_ repository by KeplerProject.

View File

@ -1,11 +1,13 @@
containers
==========
for handling ``std::vector/map/set`` and others
-----------------------------------------------
*for handling ``std::vector/map/set`` and others*
Sol2 automatically converts containers (detected using the ``sol::is_container<T>`` type trait, which simply looks for begin / end) to be a special kind of userdata with metatable on it. For Lua 5.2 and 5.3, this is extremely helpful as you can make typical containers behave like Lua tables without losing the actual container that they came from, as well as a small amount of indexing and other operations that behave properly given the table type.
If you need to deal with these things from Lua as tables, please consider :doc:`sol::as_table<as_table>` and :doc:`sol::nested<nested>`.
Sol2 automatically converts containers (detected using the ``sol::is_container<T>`` type trait, which simply looks for ``begin`` / ``end``) to be a special kind of userdata with metatable on it. For Lua 5.2 and 5.3, this is extremely helpful as you can make typical containers behave like Lua tables without losing the actual container that they came from, as well as a small amount of indexing and other operations that behave properly given the table type.
An overview of these traits and additional information can be found :doc:`at the top level container page<../containers>`.
If you need to deal with these things from and in Lua to be **actual**, true-blue, Lua tables, please consider :doc:`sol::as_table<as_table>` and :doc:`sol::nested<nested>` for serialization and deserialization into and out of the VM with sol2 operations.
a complete example
@ -65,42 +67,5 @@ Note that this will not work well in Lua 5.1, as it has explicit table checks an
print(i, vec[i])
end
There are also other ways to iterate over key/values, but they can be difficult due to not having proper support in Lua 5.1. We recommend that you upgrade to Lua 5.2 or 5.3 if this is integral to your infrastructure.
There are also other ways to iterate over key/values, but they can be difficult AND cost your performance due to not having proper support in Lua 5.1. We recommend that you upgrade to Lua 5.2 or 5.3 if this is integral to your infrastructure.
additional functions
--------------------
Based on the type pushed, a few additional functions are added as "member functions" (``self`` functions called with ``obj:func()`` or ``obj.func(obj)`` syntax) within a Lua script:
* ``my_container:clear()``: This will call the underlying containers ``clear`` function.
* ``my_container:add( key, value )`` or ``my_container:add( value )``: this will add to the end of the container, or if it is an associative or ordered container, simply put in an expected key-value pair into it.
* ``my_contaner:insert( where, value )`` or ``my_contaner:insert( key, value )``: similar to add, but it only takes two arguments. In the case of ``std::vector`` and the like, the first argument is a ``where`` integer index. The second argument is the value. For associative containers, a key and value argument are expected.
* ``my_container:find( value )``: This will call the underlying containers ``find`` function if it exists, or in case of associative containers, it will work just like an index call. This is meant to give a fast membership check for ``std::set`` and ``std::unordered_set`` containers.
* ``my_container:get( key )``: This function can return multiple values when the value type is a ``std::pair`` or ``std::tuple``, which is not the case for ``obj[key]``! This will call the underlying containers ``find`` function if it exists, index into a regular container, or in case of certain associative containers, it will work just like an index call. This is meant to give a fast membership check for ``std::set`` and ``std::unordered_set`` containers.
.. _container-detection:
too-eager container detection?
------------------------------
If you have a type that has ``begin`` or ``end`` member functions but don't provide iterators, you can specialize ``sol::is_container<T>`` to be ``std::false_type``, and that will treat the type as a regular usertype and push it as a regular userdata:
.. code-block:: cpp
:caption: specialization.hpp
struct not_container {
void begin() {
}
void end() {
}
};
namespace sol {
template <>
struct is_container<not_container> : std::false_type {};
}

View File

@ -1,7 +1,7 @@
coroutine
=========
resumable/yielding functions from Lua
-------------------------------------
*resumable/yielding functions from Lua*
A ``coroutine`` is a :doc:`reference<reference>` to a function in Lua that can be called multiple times to yield a specific result. It is run on the :doc:`lua_State<state>` that was used to create it (see :doc:`thread<thread>` for an example on how to get a coroutine that runs on a thread separate from your usual "main" :doc:`lua_State<state>`).

View File

@ -1,7 +1,7 @@
environment
===========
encapsulation table for script sandboxing
-----------------------------------------
*encapsulation table for script sandboxing*
.. code-block:: cpp
:caption: environment

View File

@ -1,7 +1,7 @@
error
=====
the single error/exception type
-------------------------------
*the single error/exception type*
.. code-block:: cpp

View File

@ -1,7 +1,7 @@
function
========
calling functions bound to Lua
------------------------------
*calling functions bound to Lua*
.. note::

View File

@ -1,7 +1,7 @@
make_object/make_reference
==========================
Create a value on the Lua stack and return it
---------------------------------------------
*create a value in the lua registry / on the Lua stack and return it*
.. code-block:: cpp
:caption: function: make_reference

View File

@ -1,7 +1,7 @@
metatable_key
=============
A key for setting and getting an object's metatable
---------------------------------------------------
*a key for setting and getting an object's metatable*
.. code-block:: cpp

View File

@ -1,6 +1,7 @@
nested
======
.. code-block:: cpp
template <typename T>

View File

@ -1,7 +1,7 @@
new_table
=========
a table creation hint to environment/table
------------------------------------------
*a table creation hint to environment/table*
.. code-block:: cpp

View File

@ -1,7 +1,7 @@
object
======
general-purpose safety reference to an existing object
------------------------------------------------------
*general-purpose safety reference to an existing object*
.. code-block:: cpp

View File

@ -1,9 +1,19 @@
overload
========
calling different functions based on argument number/type
---------------------------------------------------------
*calling different functions based on argument number/type*
This function helps users make overloaded functions that can be called from Lua using 1 name but multiple arguments. It is meant to replace the spaghetti of code whre users mock this up by doing strange if statements and switches on what version of a function to call based on `luaL_check{number/udata/string}`_.
.. code-block:: cpp
:caption: function: create overloaded set
:linenos:
template <typename... Args>
struct overloaded_set : std::tuple<Args...> { /* ... */ };
template <typename... Args>
overloaded_set<Args...> overload( Args&&... args );
The actual class produced by ``sol::overload`` is essentially a type-wrapper around ``std::tuple`` that signals to the library that an overload is being created. The function helps users make overloaded functions that can be called from Lua using 1 name but multiple arguments. It is meant to replace the spaghetti of code whre users mock this up by doing strange if statements and switches on what version of a function to call based on `luaL_check{number/udata/string}`_.
.. note::
@ -77,20 +87,15 @@ Thusly, doing the following in Lua:
bark(pup, 20) -- calls ultra_bark
local nowherebark = bark() -- calls lambda which returns that string
The actual class produced by ``sol::overload`` is essentially a type-wrapper around ``std::tuple`` that signals to the library that an overload is being created:
.. note::
.. code-block:: cpp
:caption: function: create overloaded set
:linenos:
Overloading is done on a first-come, first-serve system. This means if two overloads are compatible, workable overloads, it will choose the first one in the list.
template <typename... Args>
struct overloaded_set : std::tuple<Args...> { /* ... */ };
template <typename... Args>
overloaded_set<Args...> overload( Args&&... args );
Note that because of this system, you can use :doc:`sol::variadic_args<variadic_args>` to make a function that serves as a "fallback". Be sure that it is the last specified function in the listed functions for ``sol::overload( ... )``. `This example shows how`_.
.. note::
Please keep in mind that doing this bears a runtime cost to find the proper overload. The cost scales directly not exactly with the number of overloads, but the number of functions that have the same argument count as each other (Sol will early-eliminate any functions that do not match the argument count).
.. _luaL_check{number/udata/string}: http://www.Lua.org/manual/5.3/manual.html#luaL_checkinteger
.. _This example shows how: https://github.com/ThePhD/sol2/blob/develop/examples/overloading_with_fallback.cpp

View File

@ -1,5 +1,6 @@
property
========
*wrapper to specify read and write variable functionality using functions*
.. code-block:: cpp

View File

@ -1,7 +1,7 @@
protect
=======
Routine to mark a function / variable as requiring safety
---------------------------------------------------------
*routine to mark a function / variable as requiring safety*
.. code-block:: cpp

View File

@ -1,7 +1,6 @@
protected_function
==================
Lua function calls that trap errors and provide error handling
--------------------------------------------------------------
*Lua function calls that trap errors and provide error handling*
.. code-block:: cpp

View File

@ -1,9 +1,9 @@
proxy, (protected\_)function_result - proxy_base derivatives
============================================================
``table[x]`` and ``function(...)`` conversion struct
----------------------------------------------------
*``table[x]`` and ``function(...)`` conversion struct*
.. code-block:: c++
.. code-block:: cpp
template <typename Recurring>
struct proxy_base;

View File

@ -1,14 +1,13 @@
readonly
========
routine to mark a member variable as read-only
----------------------------------------------
*routine to mark a member variable as read-only*
.. code-block:: cpp
template <typename T>
auto readonly( T&& value );
The goal of read-only is to protect a variable set on a usertype or a function. Simply wrap it around a member variable, e.g. ``sol::readonly( &my_class::my_member_variable )`` in the appropriate place to use it. If someone tries to set it, it will throw an error.
The goal of read-only is to protect a variable set on a usertype or a function. Simply wrap it around a member variable, e.g. ``sol::readonly( &my_class::my_member_variable )`` in the appropriate place to use it. If someone tries to set it, it will error their code.
``sol::readonly`` is especially important when you're working with types that do not have a copy constructor. Lua does not understand move semantics, and therefore setters to user-defined-types require a C++ copy constructor. Containers as member variables that contain types that are not copyable but movable -- e.g. ``std::vector<my_move_only_type>`` amongst others -- also can erroneously state they are copyable but fail with compiler errors. If your type does not fit a container's definition of being copyable or is just not copyable in general and it is a member variable, please use ``sol::readonly``.

View File

@ -1,7 +1,7 @@
reference
=========
general purpose reference to Lua object in registry
---------------------------------------------------
*general purpose reference to Lua object in registry*
.. code-block:: cpp
:caption: reference
@ -10,11 +10,11 @@ general purpose reference to Lua object in registry
This type keeps around a reference to something inside of Lua, whether that object was on the stack or already present as an object in the Lua Runtime. It places the object Lua registry and will keep it alive.
It is the backbone for all things that reference items on the stack and needs to keep them around beyond their appearance and lifetime on said Lua stack or need to be kept alive outside of a script beyond garbage collection times. Its progeny include :doc:`sol::coroutine<coroutine>`, :doc:`sol::function<function>`, :doc:`sol::protected_function<protected_function>`, :doc:`sol::object<object>`, :doc:`sol::table<table>`/:doc:`sol::global_table<table>`, :doc:`sol::thread<thread>`, and :doc:`sol::userdata<userdata>`, which are type-specific versions of ``sol::reference``.
It is the backbone for all things that reference items on the stack that need to be kept around beyond their appearance and lifetime on said Lua stack or need to be kept alive outside of a script beyond garbage collection times. Its progeny include :doc:`sol::coroutine<coroutine>`, :doc:`sol::function<function>`, :doc:`sol::protected_function<protected_function>`, :doc:`sol::object<object>`, :doc:`sol::table<table>`/:doc:`sol::global_table<table>`, :doc:`sol::thread<thread>`, and :doc:`sol::(light_)userdata<userdata>`, which are type-specific versions of ``sol::reference``.
Note that if you need to keep a reference to something inside of Lua, it is better to use ``sol::reference`` or :doc:`sol::object<object>` to keep a reference to it and then use the ``obj.as<T>()`` member function to retrieve what you need than to take a direct dependency on the memory by retrieving a pointer or reference to the userdata itself. This will ensure that if a script or the Lua Runtime is finished with an object, it will not be garbage collected. Do this only if you need long-term storage.
For all of these types, there's also a ``sol::stack_{x}`` version of them, such as ``sol::stack_table``.
For all of these types, there's also a ``sol::stack_{x}`` version of them, such as ``sol::stack_table``. They are useful for a small performance boost at the cost of not having a strong reference, which has implications for what happens when the item is moved off of the stack. See :doc:`sol::stack_reference<stack_reference>` for more details.
members

View File

@ -1,7 +1,7 @@
resolve
=======
utility to pick overloaded C++ function calls
---------------------------------------------
*utility to pick overloaded C++ function calls*
.. code-block:: cpp
:caption: function: resolve C++ overload

View File

@ -1,14 +1,17 @@
simple_usertype<T>
==================
structures and classes from C++ made available to Lua code (simpler)
--------------------------------------------------------------------
*structures and classes from C++ made available to Lua code (simpler)*
This type is no different from :doc:`regular usertype<usertype>`, but allows much of its work to be done at runtime instead of compile-time. You can reduce compilation times from a plain ``usertype`` when you have an exceedingly bulky registration listing.
This usertype is no difference from :doc:`regular usertype<usertype>`, but allows much of its work to be done at runtime instead of compile-time. You can reduce compilation times from a plain ``usertype`` when you have an exceedingly bulky registration listing.
You can set functions incrementally to reduce compile-time burden with ``simple_usertype`` as well, as shown in `this example`_. This means both adding incrementally during registration.
You can set functions incrementally to reduce compile-time burden with ``simple_usertype`` as well, as shown in `this example`_. This means both adding incrementally during registration and even adding at runt=time.
You can add functions to both regular and simple usertypes afterwards by adding items to the metatable directly at runtime (e.g., with :doc:`metatable_key<metatable_key>` or by accessing the named metatable yourself).
You can add functions to both regular and simple usertypes afterwards by adding items to the metatable directly at runtime (e.g., by accessing the named metatable yourself and setting functions on it).
.. note::
You cannot add functions to an individual object. You can only add functions to the whole class / usertype.
Some developers used ``simple_usertype`` in older versions to have variables automatically be functions. To achieve this behavior, wrap the desired variable into :doc:`sol::as_function<as_function>`.

View File

@ -1,7 +1,7 @@
stack namespace
===============
the nitty-gritty core abstraction layer over Lua
------------------------------------------------
*the nitty-gritty core abstraction layer over Lua*
.. code-block:: cpp
@ -9,6 +9,8 @@ the nitty-gritty core abstraction layer over Lua
If you find that the higher level abstractions are not meeting your needs, you may want to delve into the ``stack`` namespace to try and get more out of Sol. ``stack.hpp`` and the ``stack`` namespace define several utilities to work with Lua, including pushing / popping utilities, getters, type checkers, Lua call helpers and more. This namespace is not thoroughly documented as the majority of its interface is mercurial and subject to change between releases to either heavily boost performance or improve the Sol :doc:`api<api-top>`.
Working at this level of the stack can be enhanced by understanding how the `Lua stack works in general`_ and then supplementing it with the objects and items here.
There are, however, a few :ref:`template customization points<extension_points>` that you may use for your purposes and a handful of potentially handy functions. These may help if you're trying to slim down the code you have to write, or if you want to make your types behave differently throughout the Sol stack. Note that overriding the defaults **can** throw out many of the safety guarantees Sol provides: therefore, modify the :ref:`extension points<extension_points>` at your own discretion.
structures
@ -31,9 +33,33 @@ When overriding the :doc:`customization points<../tutorial/customization>`, plea
Note that customizations can also be put up on a separate page here, if individuals decide to make in-depth custom ones for their framework or other places.
.. code-block:: cpp
:caption: struct: probe
:name: stack-probe-struct
struct probe {
bool success;
int levels;
probe(bool s, int l);
operator bool() const;
};
This struct is used for showing whether or not a :ref:`probing get_field<stack-probe-get-field>` was successful or not.
members
-------
.. code-block:: cpp
:caption: function: call_lua
:name: stack-call-lua
template<bool check_args = stack_detail::default_check_arguments, typename Fx, typename... FxArgs>
inline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs);
This function is helpful for when you bind to a raw C function but need sol's abstractions to save you the agony of setting up arguments and know how `calling C functions works`_. The ``start`` parameter tells the function where to start pulling arguments from. The parameter ``fx`` is what's supposed to be called. Extra arguments are passed to the function directly. There are intermediate versions of this (``sol::stack::call_into_lua`` and similar) for more advanced users, but they are not documented as they are subject to change to improve performance or adjust the API accordingly in later iterations of sol2. Use the more advanced versions at your own peril.
.. code-block:: cpp
:caption: function: get
:name: stack-get
@ -57,7 +83,10 @@ You may also retrieve an :doc:`sol::optional\<T><optional>` from this as well, t
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 ``lua_State*``, ``int index``, ``type`` expected, and ``type`` actual as arguments.
template <typename T, typename Handler>
bool check( lua_State* L, int index, Handler&& handler, record& tracking )
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. If you do not pass your own handler, a ``no_panic`` handler will be passed.
.. code-block:: cpp
:caption: function: check_get
@ -111,11 +140,18 @@ These functinos behave similarly to the ones above, but they check for specific
:caption: function: pop
:name: stack-pop
// push T inferred from call site, pass args... through to extension point
template <typename... Args>
auto pop( lua_State* L, int index, ... )
auto pop( lua_State* L );
Pops an object off the stack. Will remove a fixed number of objects off the stack, generally determined by the ``sol::lua_size<T>`` traits of the arguments supplied. Generally a simplicity function, used for convenience.
.. code-block:: cpp
:caption: function: top
:name: stack-top
int top( lua_State* L );
Returns the number of values on the stack.
.. code-block:: cpp
:caption: function: set_field
@ -149,20 +185,6 @@ Gets the field referenced by the key ``k``, by pushing the key onto the stack, a
This function leaves the retrieved value on the stack.
.. code-block:: cpp
:caption: struct: probe
:name: stack-probe-struct
struct probe {
bool success;
int levels;
probe(bool s, int l);
operator bool() const;
};
This struct is used for showing whether or not a :ref:`probing get_field<stack-probe-get-field>` was successful or not.
.. _extension_points:
objects (extension points)
@ -224,3 +246,5 @@ This is an SFINAE-friendly struct that is meant to expose static function ``push
This is an SFINAE-friendly struct that is meant to expose static function ``check`` that returns the number of things pushed onto the stack. The default implementation simply checks whether the expected type passed in through the template is equal to the type of the object at the specified index in the Lua stack. The default implementation for types which are considered ``userdata`` go through a myriad of checks to support checking if a type is *actually* of type ``T`` or if its the base class of what it actually stored as a userdata in that index. Down-casting from a base class to a more derived type is, unfortunately, impossible to do.
.. _lua_CFunction: http://www.Lua.org/manual/5.3/manual.html#lua_CFunction
.. _Lua stack works in general: https://www.lua.org/pil/24.2.html
.. _calling C functions works: https://www.lua.org/pil/26.html

View File

@ -1,10 +1,16 @@
stack_reference
===============
zero-overhead object on the stack
---------------------------------
*zero-overhead object on the stack*
When you work with a :doc:`sol::reference<reference>`, the object gotten from the stack has a reference to it made in the registry, keeping it alive. If you want to work with the Lua stack directly without having any additional references made, ``sol::stack_reference`` is for you. Its API is identical to ``sol::reference`` in every way, except it contains a ``int stack_index()`` member function that allows you to retrieve the stack index.
Note that this will not pin the object since a copy is not made in the registry, meaning things can be pulled out from under it, the stack can shrink under it, things can be added onto the stack before this object's position, and what ``sol::stack_reference`` will point to will change. Please know what the Lua stack is and have discipline while managing your Lua stack when working at this level.
All of the base types have ``stack`` versions of themselves, and the APIs are identical to their non-stack forms. This includes :doc:`sol::stack_table<table>`, :doc:`sol::stack_function<function>`, :doc:`sol::stack_protected_function<protected_function>`, :doc:`sol::stack_(light\_)userdata<userdata>` and :doc:`sol::stack_object<object>`.
All of the base types have ``stack`` versions of themselves, and the APIs are identical to their non-stack forms. This includes :doc:`sol::stack_table<table>`, :doc:`sol::stack_function<function>`, :doc:`sol::stack_protected_function<protected_function>`, :doc:`sol::stack_(light\_)userdata<userdata>` and :doc:`sol::stack_object<object>`. There is a special case for ``sol::stack_function``, which has an extra type called ``sol::stack_aligned_function`` (and similar ``sol::stack_aligned_protected_function``).
stack_aligned_function
----------------------
This type is particular to working with the stack. It does not push the function object on the stack before pushing the arguments, assuming that the function present is already on the stack before going ahead and invoking the function it is targeted at. It is identical to :doc:`sol::function<function>` and has a protected counterpart as well. If you are working with the stack and know there is a callable object in the right place (i.e., at the top of the Lua stack), use this abstraction to work with the very top of the stack and have it call your function while still having the easy-to-use Lua abstractions on top.

View File

@ -1,7 +1,7 @@
state
=====
owning and non-owning state holders for registry and globals
------------------------------------------------------------
*owning and non-owning state holders for registry and globals*
.. code-block:: cpp
@ -9,9 +9,9 @@ owning and non-owning state holders for registry and globals
class state : state_view, std::unique_ptr<lua_State*, deleter>;
The most important class here is ``state_view``. This structure takes a ``lua_State*`` that was already created and gives you simple, easy access to Lua's interfaces without taking ownership. ``state`` derives from ``state_view``, inheriting all of this functionality, but has the additional purpose of creating a fresh ``lua_State*`` and managing its lifetime for you in the default constructor.
The most important class here is ``state_view``. This structure takes a ``lua_State*`` that was already created and gives you simple, easy access to Lua's interfaces without taking ownership. ``state`` derives from ``state_view``, inheriting all of this functionality, but has the additional purpose of creating a fresh ``lua_State*`` and managing its lifetime for you in its constructors.
The majority of the members between ``state_view`` and :doc:`sol::table<table>` are identical, with added for this higher-level type. Therefore, all of the examples and notes in :doc:`sol::table<table>` apply here as well.
The majority of the members between ``state_view`` and :doc:`sol::table<table>` are identical, with a few added for this higher-level type. Therefore, all of the examples and notes in :doc:`sol::table<table>` apply here as well.
enumerations
------------
@ -111,8 +111,9 @@ Thanks to `Eric (EToreo) for the suggestion on this one`_!
:caption: function: load / load_file
:name: state-load-code
sol::load_result load(const std::string& code);
sol::load_result load_file(const std::string& filename);
sol::load_result load(lua_Reader reader, void* data, const std::string& chunk_name = "[string]", load_mode mode = load_mode::any);
sol::load_result load(const string_view& code, const std::string& chunk_name = "[string]", load_mode mode = load_mode::any);
sol::load_result load_file(const std::string& filename, load_mode mode = load_mode::any);
These functions *load* the desired blob of either code that is in a string, or code that comes from a filename, on the ``lua_State*``. That blob will be turned into a Lua Function. It will not be run: it returns a ``load_result`` proxy that can be called to actually run the code, when you are ready. It can also be turned into a ``sol::function``, a ``sol::protected_function``, or some other abstraction that can serve to call the function. If it is called, it will run on the object's current ``lua_State*``: it is not isolated. If you need isolation, consider using :doc:`sol::environment<environment>`, creating a new state, or other Lua sandboxing techniques.

View File

@ -1,7 +1,7 @@
table
=====
a representation of a Lua (meta)table
-------------------------------------
*a representation of a Lua (meta)table*
.. code-block:: cpp

View File

@ -1,7 +1,7 @@
this_environment
================
retrieving the environment of the calling function
--------------------------------------------------
*retrieving the environment of the calling function*
Sometimes in C++ it's useful to know where a Lua call is coming from and what :doc:`environment<environment>` it is from. The former is covered by Lua's Debug API, which is extensive and is not fully wrapped up by sol2. But, sol2 covers the latter in letting you get the environment of the calling script / function, if it has one. ``sol::this_environment`` is a *transparent argument* and does not need to be passed in Lua scripts or provided when using :doc:`sol::function<function>`, similar to :doc:`sol::this_state<this_state>`:

View File

@ -1,7 +1,7 @@
this_state
==========
transparent state argument for the current state
------------------------------------------------
*transparent state argument for the current state*
.. code-block:: cpp

View File

@ -1,7 +1,6 @@
thread
======
a separate state that can contain and run functions
---------------------------------------------------
*a separate state that can contain and run functions*
.. code-block:: cpp

View File

@ -1,7 +1,7 @@
tie
===
An improved version of ``std::tie``
-----------------------------------
*improved version of ``std::tie``*
`std::tie()`_ does not work well with :doc:`sol::function<function>`'s ``sol::function_result`` returns. Use ``sol::tie`` instead. Because they're both named `tie`, you'll need to be explicit when you use Sol's by naming it with the namespace (``sol::tie``), even with a ``using namespace sol;``. Here's an example:

View File

@ -1,7 +1,6 @@
types
=====
nil, lua_primitive type traits, and other fundamentals
------------------------------------------------------
*nil, lua_primitive type traits, and other fundamentals*
The ``types.hpp`` header contains various fundamentals and utilities of Sol.

View File

@ -1,7 +1,7 @@
unique_usertype_traits<T>
=========================
A trait for hooking special handles / pointers
----------------------------------------------
*trait for hooking special handles / pointers*
.. code-block:: cpp
:caption: unique_usertype

View File

@ -1,7 +1,7 @@
light<T>/user<T>
================
Utility class for the cheapest form of (light) userdata
-------------------------------------------------------
*utility class for the cheapest form of (light) userdata*
.. code-block:: cpp

View File

@ -1,7 +1,6 @@
userdata
========
reference to a userdata
-----------------------
*reference to a userdata*
.. code-block:: cpp
:caption: (light\_)userdata reference

View File

@ -1,7 +1,7 @@
usertype<T>
===========
structures and classes from C++ made available to Lua code
----------------------------------------------------------
*structures and classes from C++ made available to Lua code*
*Note: ``T`` refers to the type being turned into a usertype.*
@ -230,6 +230,44 @@ usertype arguments - simple usertype
- Should probably not be used directly. Use ``sol::table::new_usertype`` or ``sol::table::new_simple_usertype`` instead
runtime functions
-----------------
You can add functions at runtime **to the whole class**. Set a name under the metatable name you bound using ``new_usertype``/``new_simple_usertype`` to an object. For example:
.. code-block:: cpp
:linenos:
:caption: runtime_extension.cpp
:name: runtime-extension
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
struct object {
int value = 0;
};
int main (int, char*[]) {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_usertype<object>( "object" );
// runtime additions: through the sol API
lua["object"]["func"] = [](object& o) { return o.value; };
// runtime additions: through a lua script
lua.script("function object:print () print(self:func()) end");
// see it work
lua.script("local obj = object.new() \n obj:print()");
}
.. note::
You cannot add functions to an individual object. You can only add functions to the whole class / usertype.
overloading
-----------

View File

@ -1,5 +1,6 @@
usertype memory
===============
*memory layout of usertypes*
.. note::

View File

@ -1,7 +1,7 @@
var
===
For hooking up static / global variables to Lua usertypes
---------------------------------------------------------
*For hooking up static / global variables to Lua usertypes*
The sole purpose of this tagging type is to work with :doc:`usertypes<usertype>` to provide ``my_class.my_static_var`` access, and to also provide reference-based access as well.

View File

@ -1,7 +1,6 @@
variadic_args
=============
transparent argument to deal with multiple parameters to a function
-------------------------------------------------------------------
*transparent argument to deal with multiple parameters to a function*
.. code-block:: cpp

View File

@ -1,7 +1,6 @@
variadic_results
================
push multiple disparate arguments into lua
------------------------------------------
*push multiple disparate arguments into lua*
.. code-block:: cpp

169
docs/source/containers.rst Normal file
View File

@ -0,0 +1,169 @@
containers
==========
Containers are objects that are meant to be inspected and iterated and whose job is to typically provide storage to a collection of items. The ``std::`` library has several containers of varying types, and all of them have ``begin()`` and ``end()`` function which return iterators. C-style arrays are also containers, and sol2 will detect all of them for use and bestow them with special properties and functions.
.. _container-c-array:
.. note::
Please note that c-style arrays must be added to Lua using ``lua["my_arr"] = &my_c_array;`` or ``lua["my_arr"] = std::ref(my_c_array);`` to be bestowed these properties. No, a plain ``T*`` pointer is **not** considered an array. This is important because ``lua["my_string"] = "some string";`` is also typed as an array (``const char[n]``) and thusly we can only use ``std::reference_wrapper``s or pointers to arrays to work for us.
.. _container-detection:
container detection
-------------------
containers are detected by the type trait ``sol::is_container<T>``. If that turns out to be true, sol2 will attempt to push a userdata into Lua for the specified type ``T``, and bestow it with some of the functions and properties listed below. These functions and properties are provided by a template struct ``sol::container_traits<T>``, which has a number of static Lua C functions bound to a safety metatable. If you want to override the behavior for a specific container, you must first specialize ``sol::is_container<T>`` to drive from ``std::true_type``, then override the functions you want to change. Any function you do not override will call the default implementation or equivalent. The default implementation for unrecognized containers is simply errors.
You can also specialize ``sol::is_container<T>`` to turn off container detection, if you find it too eager for a type that just happens to have ``begin`` and ``end`` functions, like so:
.. code-block:: cpp
:caption: not_container.hpp
struct not_container {
void begin() {
}
void end() {
}
};
namespace sol {
template <>
struct is_container<not_container> : std::false_type {};
}
This will let the type be pushed as a regular userdata.
container overriding
--------------------
If you **want** it to participate as a table, use ``std::true_type`` instead of ``std::false_type`` from the :ref:`containter detection<container-detection>` example. and provide the appropriate ``iterator`` and ``value_type`` definitions on the type. Failure to do so will result in a container whose operations fail by default (or compilation will fail).
If you need a type whose declaration and definition you do not have control over to be a container, then you must override the default behavior by specializing container traits, like so:
.. code-block:: cpp
:caption: specializing.hpp
struct not_my_type { ... };
namespace sol {
template <>
struct is_container<not_my_type> : std::true_type {};
template <>
struct container_traits<not_my_type> {
...
// see below for implemetation details
};
}
The various operations provided by ``container_traits<T>`` are expected to be like so, below. Ability to override them requires familiarity with the Lua stack and how it operates, as well as knowledge of Lua's :ref:`raw C functions<raw-function-note>`. You can read up on raw C functions by looking at the "Programming in Lua" book. The `online version's information`_ about the stack and how to return information is still relevant, and you can combine that by also using sol's low-level :doc:`stack API<api/stack>` to achieve whatever behavior you need.
.. warning::
Exception handling **WILL** be provided around these particular raw C functions, so you do not need to worry about exceptions or errors bubbling through and handling that part. It is specifically handled for you in this specific instance, and **ONLY** in this specific instance. The raw note still applies to every other raw C function you make manually.
container operations
-------------------------
Below are the many container operations and their override points for ``container_traits<T>``. Please use these to understand how to use any part of the implementation.
+-----------+-------------------------------------------+---------------------------------------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| operation | lua syntax | container_traits<T> | stack argument order | notes/caveats |
| | | extension point | | |
+-----------+-------------------------------------------+---------------------------------------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| set | ``c:set(key, value)`` | ``static int set(lua_State*);`` | 1 self | - if ``value`` is nil, it performs an erase in default implementation |
| | | | 2 key | - if this is a sequence container and it support insertion and ``key``,is an index equal to the size of the container,+ 1, it will insert at,the end of the container (this is a Lua idiom) |
| | | | 3 value | |
+-----------+-------------------------------------------+---------------------------------------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| index_set | ``c[key] = value`` | ``static int index_set(lua_State*);`` | 1 self | - default implementation calls "set" |
| | | | 2 key | - if this is a sequence container and it support insertion and ``key`` is an index equal to the size of the container + 1, it will insert at the end of the container (this is a Lua idiom) |
| | | | 3 value | |
+-----------+-------------------------------------------+---------------------------------------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| get | ``v = c:get(key)`` | ``static int get(lua_State*);`` | 1 self | - can return multiple values |
| | | | 2 key | - default implementation increments iterators linearly for non-random-access |
+-----------+-------------------------------------------+---------------------------------------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| index_get | ``v = c[key]`` | ``static int index_get(lua_State*);`` | 1 self | - can only return 1 value |
| | | | 2 key | - default implementation just calls "get" |
| | | | | - if ``key`` is a string and ``key`` is one of the other member functions, it will return that member function rather than perform a lookup / index get |
+-----------+-------------------------------------------+---------------------------------------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| find | ``c:find(target)`` | ``static int find(lua_State*);`` | 1 self | - ``target`` is a value for non-lookup containers (fixed containers, sequence containers, non-associative and non-ordered containers) |
| | | | 2 target | |
+-----------+-------------------------------------------+---------------------------------------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| erase | ``c:erase(target)`` | ``static int erase(lua_State*);`` | 1 self | - for sequence containers, ``target`` is an index to erase |
| | | | 2 target | - for lookup containers, ``target`` is the key type |
| | | | | - uses linear incrementation to spot for sequence containers that do not have random access iterators (``std::list``, ``std::forward_list``, and similar) |
| | | | | - invalidates iteration |
+-----------+-------------------------------------------+---------------------------------------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| insert | ``c:insert(target, value)`` | | 1 self | - for sequence containers, ``target`` is an index, otherwise it is the key type |
| | | | 2 target | - inserts into a container if possible at the specified location |
| | | | 3 key | |
+-----------+-------------------------------------------+---------------------------------------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| add | ``c:add(key, value)`` or ``c:add(value)`` | ``static int add(lua_State*);`` | 1 self | - 2nd argument (3rd on stack) is provided for associative containers to add |
| | | | 2 key/value | - ordered containers will insert into the appropriate spot, not necessarily at the end |
| | | | 3 value | |
+-----------+-------------------------------------------+---------------------------------------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| size | ``#c`` | ``static int size(lua_State*);`` | 1 self | - default implementation calls ``.size()`` if present |
| | | | | - otherwise, default implementation uses ``std::distance(begin(L, self), end(L, self))`` |
+-----------+-------------------------------------------+---------------------------------------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| clear | ``c:clear()`` | ``static int clear(lua_State*);`` | 1 self | - default implementation provides no fallback if there's no ``clear`` operation |
+-----------+-------------------------------------------+---------------------------------------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| begin | n/a | ``static int begin(lua_State*, T&);`` | n/a | - called by default implementation |
+-----------+-------------------------------------------+---------------------------------------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| end | n/a | ``static int end(lua_State*, T&);`` | n/a | - called by default implementation |
+-----------+-------------------------------------------+---------------------------------------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| pairs | | ``static int pairs(lua_State*);`` | 1 self | - implement if advanced user only that understands caveats |
| | | | | - override begin and end instead and leave this to default implementation if you do not know what ``__pairs`` is for or how to implement it and the ``next`` function |
| | | | | - works only in Lua 5.2+ |
| | | | | - calling ``pairs( c )`` in Lua 5.1 / LuaJIT will crash with assertion failure (Lua expects ``c`` to be a table) |
+-----------+-------------------------------------------+---------------------------------------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
.. _container-classifications:
container classifications
-------------------------
When you serialize a container into sol2, the default container handler deals with the containers by inspecting various properties, functions, and typedefs on them. Here are the broad implications of containers sol2's defaults will recognize, and which already-known containers fall into their categories:
+------------------------+----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------+
| container type | requirements | known containers | notes/caveats |
+------------------------+----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------+
| sequence | ``erase(iterator)`` | std::vector | - ``find`` operation is linear in size of list (searches all elements) |
| | ``push_back``/``insert(value_type)`` | std::deque | - std::forward_list has forward-only iterators: set/find is a linear operation |
| | | std::list | - std::forward_list uses "insert_after" idiom, requires special handling internally |
| | | std::forward_list | |
+------------------------+----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------+
| fixed | lacking ``push_back``/``insert`` | std::array<T, n> | - regular c-style arrays must be set with |
| | lacking ``erase`` | T[n] (fixed arrays) | ``std::ref( arr )`` or ``&arr`` |
| | | | to be used as a container type with sol2 |
+------------------------+----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------+
| ordered | ``key_type`` typedef | std::set | - ``container[key] = stuff`` operation erases when ``stuff`` is nil, inserts/sets when not |
| | ``erase(key)`` | std::multi_set | - ``container.get(key)`` returns the key itself |
| | ``find(key)`` | | |
| | ``insert(key)`` | | |
+------------------------+----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------+
| associative, ordered | ``key_type``, ``mapped_type`` typedefs | std::map | |
| | ``erase(key)`` | std::multi_map | |
| | ``find(key)`` | | |
| | ``insert({ key, value })`` | | |
+------------------------+----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------+
| unordered | same as ordered | std::unordered_set | - ``container[key] = stuff`` operation erases when ``stuff`` is nil, inserts/sets when not |
| | | std::unordered_multiset | - ``container.get(key)`` returns the key itself |
| | | | - iteration not guaranteed to be in order of insertion, just like in C++ container |
| | | | |
+------------------------+----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------+
| unordered, associative | same as ordered, associative | std::unordered_map | - iteration not guaranteed to be in order of insertion, just like in C++ container |
| | | std::unordered_multimap | |
+------------------------+----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------+
.. _online version's information: https://www.lua.org/pil/26.html

View File

@ -20,6 +20,8 @@ A myriad of compiler errors can occur when something goes wrong. Here is some ba
* Template depth errors may also be a problem on earlier versions of clang++ and g++. Use ``-ftemplate-depth`` compiler flag and specify really high number (something like 2048 or even double that amount) to let the compiler work freely. Also consider potentially using :doc:`simple usertypes<api/simple_usertype>` to save compilation speed.
* If you have a move-only type, that type may need to be made ``readonly`` if it is bound as a member variable on a usertype or bound using ``state_view::set_function``. See :doc:`sol::readonly<api/readonly>` for more details.
* Assigning a ``std::string`` or a ``std::pair<T1, T2>`` using ``operator=`` after it's been constructed can result in compiler errors when working with ``sol::function`` and its results. See `this issue for fixes to this behavior`_.
* Sometimes, using ``__stdcall`` in a 32-bit (x86) environment on VC++ can cause problems binding functions because of a compiler bug. 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.
Linker Errors
-------------
@ -63,3 +65,4 @@ Iteration
Tables may have other junk on them that makes iterating through their numeric part difficult when using a bland ``for-each`` loop, or when calling sol's ``for_each`` function. Use a numeric look to iterate through a table. Iteration does not iterate in any defined order also: see :ref:`this note in the table documentation for more explanation<iteration_note>`.
.. _this issue for fixes to this behavior: https://github.com/ThePhD/sol2/issues/414#issuecomment-306839439
.. _this __stdcall issue report: https://github.com/ThePhD/sol2/issues/463

View File

@ -1,7 +1,7 @@
features
========
what does Sol (and other libraries) support?
--------------------------------------------
*what does Sol (and other libraries) support?*
The goal of Sol is to provide an incredibly clean API that provides high performance (comparable or better than the C it was written on) and extreme ease of use. That is, users should be able to say: "this works pretty much how I expected it to."

View File

@ -1,7 +1,6 @@
functions
=========
working with functions in sol2
------------------------------
*working with functions in sol2*
There are a number of examples dealing with functions and how they can be bound to sol2:
@ -9,15 +8,18 @@ There are a number of examples dealing with functions and how they can be bound
* For a quicker walkthrough that demonstrates almost everything, see `the examples`_ and the :doc:`the quick and dirty tutorial<tutorial/all-the-things>`
* For a full explanation, :doc:`read the tutorial<tutorial/functions>` and consult the subjects below
* If you have bindings and set-ups that want to leverage the C API without sol2's interference, you can push a raw function, which has certain implications (noted :ref:`below<raw-function-note>`)
* You return multiple values by returning a `std::tuple`
* Return multiple values into Lua by:
- returning a ``std::tuple``
- using :doc:`sol::variadic_results<api/variadic_results>`
* :doc:`Overload function calls with different argument types and count on a single name<api/overload>` (first-bound, first-serve overloading)
- Note: because of this feature, automatic number to string conversion from Lua is not permitted for overloads and does not work when safeties are turned on
- Use C++ captures and lambdas to bind member functions tied to a single object /
* You can work with **transparent arguments** that provide you with special information, such as
- :doc:`sol::variadic_args<api/variadic_args>`, for handling variable number of arguments at runtime
- :doc:`sol::this_state<api/this_state>`, for getting the current Lua state
- :doc:`sol::this_environment<api/this_environment>`, for potentially retrieving the current Lua environment
* :doc:`Overload function calls on a single name<api/overload>`, discriminating by argument number and type (first-come, first-serve overloading)
- Note: because of this feature, automatic number to string conversion from Lua is not permitted
* Control serialization of arguments and return types with :doc:`sol::nested<api/nested>`, :doc:`sol::as_table<api/nested>`, :doc:`sol::as_args<api/as_args>` and :doc:`sol::as_function<api/as_function>`
* Set environments for Lua functions and scrips with :doc:`sol::environment<api/environment>`
* Set environments for Lua functions and scripts with :doc:`sol::environment<api/environment>`
.. _binding-callable-objects:
@ -25,9 +27,13 @@ There are a number of examples dealing with functions and how they can be bound
working with callables/lambdas
------------------------------
To be explicit about wanting a struct to be interpreted as a function, use ``mytable.set_function( key, func_value );``. You can be explicit about wanting a function as well by using the :doc:`sol::as_function<../api/as_function>` call, which will wrap and identify your type as a function.
.. note::
Function objects ``obj`` -- a struct with a ``return_type operator()( ... )`` member defined on them, like all C++ lambdas -- are not interpreted as functions when you use ``set`` for ``mytable.set( key, value )`` and ``state.create_table(_with)( ... )``. This only happens automagically with ``mytable[key] = obj``. To be explicit about wanting a struct to be interpreted as a function, use ``mytable.set_function( key, func_value );``. You can be explicit about wanting a function as well by using the :doc:`sol::as_function<../api/as_function>` call, which will wrap and identify your type as a function.
Function objects ``obj`` -- a struct with a ``return_type operator()( ... )`` member defined on them, like all C++ lambdas -- are not interpreted as functions when you use ``set`` for ``mytable.set( key, value )`` and ``state.create_table(_with)( ... )``. This only happens automagically with ``mytable[key] = obj``.
Note that this also applies to calling functions, for example: ``my_state["table"]["sort"]( some_table, sorting_object );``.
.. _function-exception-handling:

View File

@ -9,8 +9,8 @@
Sol |version|
=============
a fast, simple C++ and Lua Binding
----------------------------------
*a fast, simple C++ and Lua Binding*
When you need to hit the ground running with Lua and C++, `Sol`_ is the go-to framework for high-performance binding with an easy to use API.
@ -37,6 +37,7 @@ get going:
features
functions
usertypes
containers
threading
traits
api/api-top

View File

@ -1,7 +1,6 @@
mentions
========
so does anyone cool use this thing...?
--------------------------------------
*so does anyone cool use this thing...?*
First off, feel free to `tell me about your uses!`_
@ -26,6 +25,7 @@ Okay, so the features don't convince you, the documentation doesn't convince you
* The `Multiple Arcade Machine Emulator (MAME)`_ project switched from using LuaBridge to sol2!
- `The pull request`_ in which it was introduced to the master branch.
* For scripting, in `OpenMPT`_
* (CppNow) sol2 was mentioned in a comparison to other scripting languages by ChaiScript developer, Jason Turner (@lefticus), at a conference!
- `Jason Turner's presentation`_
* (CppCast) Showed up in CppCast with Elias Daler!
@ -60,3 +60,4 @@ Are you using sol2 for something neat? Want it to be featured here or think it's
.. _"sol2 saved my life.": https://twitter.com/EliasDaler/status/739215685264494593
.. _Multiple Arcade Machine Emulator (MAME): http://www.mamedev.org/index.php
.. _The pull request: https://github.com/mamedev/mame/pull/1626
.. _OpenMPT: https://openmpt.org/

View File

@ -1,7 +1,6 @@
getting performance
===================
things to make Sol as fast as possible
--------------------------------------
*things to make Sol as fast as possible*
As shown by the :doc:`benchmarks<benchmarks>`, Sol is very performant with its abstractions. However, in the case where you need every last drop of performance from Sol, a number of tips and API usage tricks will be documented here. PLEASE benchmark / profile your code before you start invoking these, as some of them trade in readability / clarity for performance.

View File

@ -1,7 +1,6 @@
run-time type information (rtti)
================================
because somebody's going to want to shut this off, too...
---------------------------------------------------------
*because somebody's going to want to shut this off, too...*
Sol does not use RTTI anymore.

View File

@ -12,6 +12,8 @@ To learn more about usertypes, visit:
The examples folder also has a number of really great examples for you to see. There are also some notes about guarantees you can find about usertypes, and their associated userdata, below:
* Containers get pushed as special usertypes, but can be disabled if problems arise as detailed :doc:`here<api/containers>`.
* You can use bitfields but it requires some finesse on your part. We have an example to help you get started `here, that uses a few tricks`_.
* All usertypes are runtime extensible in both `Lua`_ and `C++`_
* Please note that the semi-colon is necessary to "automatically" pass the ``this``/``self`` argument to Lua methods
- ``obj:method_name()`` is how you call "member" methods in Lua
@ -37,8 +39,6 @@ The examples folder also has a number of really great examples for you to see. T
- Work on a copy by taking arguments or returning by value. Do not use r-value references: they do not mean anything in Lua code.
* The actual metatable associated with the usertype has a long name and is defined to be opaque by the Sol implementation.
* The actual metatable inner workings is opaque and defined by the Sol implementation, and there are no internal docs because optimizations on the operations are applied based on heuristics we discover from performance testing the system.
* Containers get pushed as special usertypes, but can be disabled if problems arise as detailed :doc:`here<api/containers>`.
* You can use bitfields but it requires some finesse on your part. We have an example to help you get started `here, that uses a few tricks`_.
.. _here, that uses a few tricks: https://github.com/ThePhD/sol2/blob/develop/examples/usertype_bitfields.cpp
.. _Lua: https://github.com/ThePhD/sol2/blob/develop/examples/usertype_advanced.cpp#L81

View File

@ -19,7 +19,7 @@ int main() {
lua.script("print('hello world')");
// call lua code, and check to make sure it has loaded and run properly:
auto handler = &sol::default_on_error;
auto handler = &sol::script_default_on_error;
lua.script("print('hello again, world')", handler);
// Use a custom error handler if you need it

View File

@ -0,0 +1,49 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <iostream>
int func_1(int value) {
return 20 + value;
}
std::string func_2(std::string text) {
return "received: " + text;
}
sol::variadic_results fallback(sol::this_state ts, sol::variadic_args args) {
sol::variadic_results r;
if (args.size() == 2) {
r.push_back({ ts, sol::in_place, args.get<int>(0) + args.get<int>(1) });
}
else {
r.push_back({ ts, sol::in_place, 52 });
}
return r;
}
int main(int, char*[]) {
std::cout << "=== calling lua functions example ===" << std::endl;
sol::state lua;
lua.open_libraries();
sol::table mLuaPackets = lua.create_named_table("mLuaPackets");
mLuaPackets[1] = lua.create_table_with("timestamp", 0LL);
mLuaPackets[2] = lua.create_table_with("timestamp", 3LL);
mLuaPackets[3] = lua.create_table_with("timestamp", 1LL);
lua.script("print('--- pre sort ---')");
lua.script("for i=1,#mLuaPackets do print(i, mLuaPackets[i].timestamp) end");
lua["table"]["sort"](mLuaPackets, sol::as_function([](sol::table l, sol::table r) {
std::uint64_t tl = l["timestamp"];
std::uint64_t tr = r["timestamp"];
return tl < tr;
}));
lua.script("print('--- post sort ---')");
lua.script("for i=1,#mLuaPackets do print(i, mLuaPackets[i].timestamp) end");
return 0;
}

View File

@ -0,0 +1,43 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <iostream>
int func_1(int value) {
return 20 + value;
}
std::string func_2(std::string text) {
return "received: " + text;
}
sol::variadic_results fallback(sol::this_state ts, sol::variadic_args args) {
sol::variadic_results r;
if (args.size() == 2) {
r.push_back({ ts, sol::in_place, args.get<int>(0) + args.get<int>(1) });
}
else {
r.push_back({ ts, sol::in_place, 52 });
}
return r;
}
int main(int, char*[]) {
std::cout << "=== overloading with fallback example ===" << std::endl;
sol::state lua;
lua.open_libraries();
lua.set_function("f", sol::overload(
func_1,
func_2,
fallback
));
lua.script("print(f(1))"); // func_1
lua.script("print(f('hi'))"); // func_2
lua.script("print(f(22, 11))"); // fallback
lua.script("print(f({}))"); // fallback
return 0;
}

View File

@ -0,0 +1,28 @@
#include "my_object.hpp"
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
namespace my_object {
sol::table open_my_object(sol::this_state L) {
sol::state_view lua(L);
sol::table module = lua.create_table();
module.new_usertype<test>("test",
sol::constructors<test(), test(int)>(),
"value", &test::value
);
return module;
}
}
extern "C" int luaopen_my_object(lua_State* L) {
// pass the lua_State,
// the index to start grabbing arguments from,
// and the function itself
// optionally, you can pass extra arguments to the function if that's necessary,
// but that's advanced usage and is generally reserved for internals only
return sol::stack::call_lua(L, 1, my_object::open_my_object );
}

View File

@ -0,0 +1,20 @@
#pragma once
#include "my_object_api.hpp"
namespace my_object {
struct test {
int value;
test() = default;
test(int val) : value(val) {}
};
} // my_object
// this function needs to be exported from your
// dll. "extern 'C'" should do the trick, but
// we're including platform-specific stuff here to help
// see my_object_api.hpp for details
extern "C" MY_OBJECT_API int luaopen_my_object(lua_State* L);

View File

@ -0,0 +1,32 @@
#pragma once
namespace my_object {
#if defined _MSC_VER
#define MY_OBJECT_VC
#elif defined __GNUC__
#define MY_OBJECT_GCC
#elif defined __clang__
#define MY_OBJECT_CLANG
#endif
#if !defined(_NDEBUG)
#define MY_OBJECT_DEBUG
#else
#endif // Debug || Not-Debug
#if defined MY_OBJECT_VC
#if defined MY_OBJECT_DLL
#if defined MY_OBJECT_BUILD
#define MY_OBJECT_API __declspec(dllexport)
#else
#define MY_OBJECT_API __declspec(dllexport)
#endif // MY_OBJECT_BUILD - Building the Library vs. Using the Library
#else
#define MY_OBJECT_API
#endif // Building a DLL vs. Static Library
#else
#define MY_OBJECT_API
#endif
} // my_object

View File

@ -0,0 +1,25 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include "my_object.hpp"
#include <iostream>
#include <cassert>
int main(int, char*[]) {
std::cout << "=== require from DLL example ===" << std::endl;
sol::state lua;
lua.script_file(R"(
mo = require("my_object")
obj = mo.test.new(24)
print(obj.value)
)");
my_object::test& obj = lua["obj"];
assert(obj.value == 24);
return 0;
}

View File

@ -0,0 +1,41 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <cassert>
#include <iostream>
struct object {
int value = 0;
};
int main(int, char*[]) {
std::cout << "=== runtime_additions example ===" << std::endl;
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_usertype<object>("object");
// runtime additions: through the sol API
lua["object"]["func"] = [](object& o) {
++o.value;
return o.value;
};
// runtime additions: through a lua script
lua.script(R"(
function object:print ()
print(self:func())
end
)");
// see it work
lua.script(R"(
obj = object.new()
obj:print()
)");
object& obj = lua["obj"];
assert(obj.value == 1);
return 0;
}

View File

@ -0,0 +1,52 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <iostream>
int main(int, char*[]) {
std::cout << "=== usertype call from C++ example ===" << std::endl;
sol::state lua;
lua.open_libraries(sol::lib::base);
struct cpp_object {
int value = 5;
};
struct test {
int value = 0;
int func(const cpp_object& obj) {
std::cout << "func\t" << obj.value << std::endl;
value += obj.value;
return value;
}
};
lua.new_usertype<cpp_object>("test",
"value", &cpp_object::value
);
lua.new_usertype<test>("test",
"func", &test::func
);
lua.script("function test:lua_func(obj) print('lua_func', obj.value) end");
lua["obj"] = test{};
cpp_object cppobj;
lua["obj"]["func"](lua["obj"], cppobj);
lua["obj"]["lua_func"](lua["obj"], cppobj);
lua["test"]["func"](lua["obj"], cppobj);
lua["test"]["lua_func"](lua["obj"], cppobj);
// crashes
//lua["obj"]["func"](cppobj);
//lua["obj"]["lua_func"](cppobj);
// crashes
//lua["test"]["func"](cppobj);
//lua["test"]["lua_func"](cppobj);
return 0;
}

View File

@ -18,7 +18,8 @@ int main() {
int r = 0;
for (auto v : va) {
int value = v; // get argument out (implicit conversion)
// can also do int v = va.get<int>(i); with index i
// can also do int v = v.as<int>();
// can also do int v = va.get<int>(i); with index i
r += value;
}
// Only have to add a, b was included from variadic_args and beyond

View File

@ -79,7 +79,7 @@ namespace sol {
typedef meta::tuple_types<typename traits::return_type> return_types;
typedef typename traits::free_args_list args_list;
// compile-time eliminate any functions that we know ahead of time are of improper arity
if (meta::find_in_pack_v<index_value<traits::free_arity>, index_value<M>...>::value) {
if (!traits::runtime_variadics_t::value && meta::find_in_pack_v<index_value<traits::free_arity>, index_value<M>...>::value) {
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
}
if (!traits::runtime_variadics_t::value && traits::free_arity != fxarity) {
@ -103,7 +103,7 @@ namespace sol {
typedef meta::tuple_types<typename traits::return_type> return_types;
typedef typename traits::free_args_list args_list;
// compile-time eliminate any functions that we know ahead of time are of improper arity
if (meta::find_in_pack_v<index_value<traits::free_arity>, index_value<M>...>::value) {
if (!traits::runtime_variadics_t::value && meta::find_in_pack_v<index_value<traits::free_arity>, index_value<M>...>::value) {
return overload_match_arity(types<>(), std::index_sequence<>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
}
if (!traits::runtime_variadics_t::value && traits::free_arity != fxarity) {
@ -118,7 +118,7 @@ namespace sol {
typedef meta::tuple_types<typename traits::return_type> return_types;
typedef typename traits::free_args_list args_list;
// compile-time eliminate any functions that we know ahead of time are of improper arity
if (meta::find_in_pack_v<index_value<traits::free_arity>, index_value<M>...>::value) {
if (!traits::runtime_variadics_t::value && meta::find_in_pack_v<index_value<traits::free_arity>, index_value<M>...>::value) {
return overload_match_arity(types<Fx1, Fxs...>(), std::index_sequence<I1, In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
}
if (!traits::runtime_variadics_t::value && traits::free_arity != fxarity) {
@ -239,6 +239,7 @@ namespace sol {
return f(L);
}
};
#ifdef SOL_NOEXCEPT_FUNCTION_TYPE
template <bool is_index, bool is_variable, bool checked, int boost, typename C>
struct agnostic_lua_call_wrapper<detail::lua_CFunction_noexcept, is_index, is_variable, checked, boost, C> {

View File

@ -167,6 +167,10 @@ inline int luaL_loadbufferx(lua_State* L, const char* buff, size_t size, const c
return lua_load(L, kepler_lua_compat_get_string, &ls, name/*, mode*/);
}
inline int luaL_loadfilex(lua_State* L, const char* filename, const char*) {
return luaL_loadfile(L, filename/*, mode*/);
}
#endif // LuaJIT 2.1.x beta and beyond
#endif /* Lua 5.1 */

File diff suppressed because it is too large Load Diff

View File

@ -19,461 +19,179 @@
// 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_CONTAINER_USERTYPE_HPP
#define SOL_CONTAINER_USERTYPE_HPP
#ifndef SOL_CONTAINER_USERTYPE_METATABLE_HPP
#define SOL_CONTAINER_USERTYPE_METATABLE_HPP
#include "stack.hpp"
#include "container_traits.hpp"
#include <unordered_map>
namespace sol {
namespace detail {
template <typename T>
struct has_find {
private:
typedef std::array<char, 1> one;
typedef std::array<char, 2> two;
template <typename C> static one test(decltype(std::declval<C>().find(std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);
template <typename C> static two test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(char);
};
template <typename T>
struct has_push_back {
private:
typedef std::array<char, 1> one;
typedef std::array<char, 2> two;
template <typename C> static one test(decltype(std::declval<C>().push_back(std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);
template <typename C> static two test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(char);
};
template <typename T>
struct has_clear {
private:
typedef std::array<char, 1> one;
typedef std::array<char, 2> two;
template <typename C> static one test(decltype(&C::clear));
template <typename C> static two test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(char);
};
template <typename T>
struct has_insert {
private:
typedef std::array<char, 1> one;
typedef std::array<char, 2> two;
template <typename C> static one test(decltype(std::declval<C>().insert(std::declval<std::add_rvalue_reference_t<typename C::const_iterator>>(), std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);
template <typename C> static two test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(char);
};
template <typename T>
T& get_first(const T& t) {
return std::forward<T>(t);
}
template <typename A, typename B>
decltype(auto) get_first(const std::pair<A, B>& t) {
return t.first;
}
template <typename C, typename I, meta::enable<has_find<meta::unqualified_t<C>>> = meta::enabler>
auto find(C& c, I&& i) {
return c.find(std::forward<I>(i));
}
template <typename C, typename I, meta::disable<has_find<meta::unqualified_t<C>>> = meta::enabler>
auto find(C& c, I&& i) {
using std::begin;
using std::end;
return std::find_if(begin(c), end(c), [&i](auto&& x) {
return i == get_first(x);
});
}
}
template <typename Raw, typename C = void>
template <typename X, typename C = void>
struct container_usertype_metatable {
typedef meta::is_associative<std::remove_pointer_t<meta::unqualified_t<Raw>>> is_associative;
typedef meta::unqualified_t<Raw> T;
typedef typename T::iterator I;
typedef std::conditional_t<is_associative::value, typename T::value_type, std::pair<std::size_t, typename T::value_type>> KV;
typedef typename KV::first_type K;
typedef typename KV::second_type V;
typedef std::remove_reference_t<decltype(*std::declval<I&>())> IR;
typedef typename meta::iterator_tag<I>::type tag_t;
typedef std::conditional_t<std::is_same<tag_t, std::input_iterator_tag>::value,
V,
std::conditional_t<is_associative::value,
V,
decltype(*std::declval<I&>())
>
> push_type;
typedef std::remove_pointer_t<meta::unqualified_t<X>> T;
typedef container_traits<T> traits;
typedef container_detail::container_traits_default<T> default_traits;
struct iter {
T& source;
I it;
iter(T& source, I it) : source(source), it(std::move(it)) {}
};
static auto& get_src(lua_State* L) {
#ifdef SOL_SAFE_USERTYPE
auto p = stack::check_get<T*>(L, 1);
if (!p || p.value() == nullptr) {
luaL_error(L, "sol: 'self' argument is not the proper type (pass 'self' as first argument with ':' or call on proper type)");
}
return *p.value();
#else
return stack::get<T>(L, 1);
#endif // Safe getting with error
static int real_index_get_traits(std::true_type, lua_State* L) {
return traits::index_get(L);
}
static int delegate_call(lua_State* L) {
static int real_index_get_traits(std::false_type, lua_State* L) {
return default_traits::index_get(L);
}
static int real_index_call(lua_State* L) {
static std::unordered_map<std::string, lua_CFunction> calls{
{ "get", &real_get_call },
{ "set", &real_set_call },
{ "add", &real_add_call },
{ "insert", &real_insert_call },
{ "clear", &real_clear_call },
{ "find", &real_find_call },
{ "get", &real_get_call }
{ "erase", &real_erase_call }
};
auto maybename = stack::check_get<std::string>(L, 2);
if (maybename) {
auto& name = *maybename;
const std::string& name = *maybename;
auto it = calls.find(name);
if (it != calls.cend()) {
return stack::push(L, it->second);
}
}
return stack::push(L, lua_nil);
return real_index_get_traits(container_detail::has_traits_index_get<traits>(), L);
}
static int real_index_call_associative(std::true_type, lua_State* L) {
auto k = stack::check_get<K>(L, 2);
if (k) {
auto& src = get_src(L);
using std::end;
auto it = detail::find(src, *k);
if (it != end(src)) {
auto& v = *it;
return stack::stack_detail::push_reference<push_type>(L, v.second);
}
}
return delegate_call(L);
static int real_get_traits(std::true_type, lua_State* L) {
return traits::get(L);
}
static int real_index_call_associative(std::false_type, lua_State* L) {
auto& src = get_src(L);
auto maybek = stack::check_get<K>(L, 2);
if (maybek) {
using std::begin;
auto it = begin(src);
K k = *maybek;
if (k > src.size() || k < 1) {
return stack::push(L, lua_nil);
}
--k;
std::advance(it, k);
return stack::stack_detail::push_reference<push_type>(L, *it);
}
return delegate_call(L);
}
static int real_index_call(lua_State* L) {
return real_index_call_associative(is_associative(), L);
static int real_get_traits(std::false_type, lua_State* L) {
return default_traits::get(L);
}
static int real_get_call(lua_State* L) {
return real_index_call_associative(is_associative(), L);
return real_get_traits(container_detail::has_traits_get<traits>(), L);
}
static int real_new_index_call_const(std::false_type, std::false_type, lua_State* L) {
return luaL_error(L, "sol: cannot write to a const value type or an immutable iterator (e.g., std::set)");
static int real_set_traits(std::true_type, lua_State* L) {
return traits::set(L);
}
static int real_new_index_call_const(std::false_type, std::true_type, lua_State* L) {
return luaL_error(L, "sol: cannot write to a const value type or an immutable iterator (e.g., std::set)");
static int real_set_traits(std::false_type, lua_State* L) {
return default_traits::set(L);
}
static int real_new_index_call_fixed(std::true_type, lua_State* L) {
auto& src = get_src(L);
#ifdef SOL_CHECK_ARGUMENTS
auto maybek = stack::check_get<K>(L, 2);
if (!maybek) {
return luaL_error(L, "sol: improper key of type %s for %s", lua_typename(L, static_cast<int>(type_of(L, 2))), detail::demangle<T>().c_str());
}
K& k = *maybek;
#else
K k = stack::get<K>(L, 2);
#endif
using std::end;
auto it = detail::find(src, k);
if (it != end(src)) {
auto& v = *it;
v.second = stack::get<V>(L, 3);
}
else {
src.insert(it, { std::move(k), stack::get<V>(L, 3) });
}
return 0;
static int real_set_call(lua_State* L) {
return real_set_traits(container_detail::has_traits_set<traits>(), L);
}
static int real_new_index_call_fixed(std::false_type, lua_State* L) {
auto& src = get_src(L);
#ifdef SOL_CHECK_ARGUMENTS
auto maybek = stack::check_get<K>(L, 2);
if (!maybek) {
return luaL_error(L, "sol: improper key of type %s for %s", lua_typename(L, static_cast<int>(type_of(L, 2))), detail::demangle<T>().c_str());
}
K& k = *maybek;
#else
K k = stack::get<K>(L, 2);
#endif
using std::end;
auto it = detail::find(src, k);
if (it != end(src)) {
auto& v = *it;
v.second = stack::get<V>(L, 3);
}
else {
return luaL_error(L, "sol: cannot insert key of type %s to into %s", lua_typename(L, static_cast<int>(type_of(L, 2))), detail::demangle<T>().c_str());
}
return 0;
static int real_index_set_traits(std::true_type, lua_State* L) {
return traits::index_set(L);
}
static int real_new_index_call_const(std::true_type, std::true_type, lua_State* L) {
return real_new_index_call_fixed(std::integral_constant<bool, detail::has_insert<T>::value>(), L);
}
static int real_new_index_call_const(std::true_type, std::false_type, lua_State* L) {
auto& src = get_src(L);
#ifdef SOL_CHECK_ARGUMENTS
auto maybek = stack::check_get<K>(L, 2);
if (!maybek) {
return luaL_error(L, "sol: improper index of type %s to a %s", lua_typename(L, static_cast<int>(type_of(L, 2))), detail::demangle<T>().c_str());
}
K& k = *maybek;
#else
K k = stack::get<K>(L, 2);
#endif
using std::begin;
auto it = begin(src);
#ifdef SOL_CHECK_ARGUMENTS
if (k < 1) {
return luaL_error(L, "sol: out of bounds index to a %s", detail::demangle<T>().c_str());
}
#endif
--k;
if (k == src.size()) {
real_add_call_push(std::integral_constant<bool, detail::has_push_back<T>::value && std::is_copy_constructible<V>::value>(), L, src, 1);
return 0;
}
#ifdef SOL_CHECK_ARGUMENTS
if (k > src.size()) {
return luaL_error(L, "sol: out of bounds index to a %s", detail::demangle<T>().c_str());
}
#endif
std::advance(it, k);
*it = stack::get<V>(L, 3);
return 0;
static int real_index_set_traits(std::false_type, lua_State* L) {
return default_traits::index_set(L);
}
static int real_new_index_call(lua_State* L) {
return real_new_index_call_const(meta::neg<meta::any<std::is_const<V>, std::is_const<IR>, meta::neg<std::is_copy_assignable<V>>>>(), meta::all<is_associative, detail::has_insert<T>>(), L);
return real_index_set_traits(container_detail::has_traits_index_set<traits>(), L);
}
static int real_pairs_next_call_assoc(std::true_type, lua_State* L) {
using std::end;
iter& i = stack::get<user<iter>>(L, 1);
auto& source = i.source;
auto& it = i.it;
if (it == end(source)) {
return 0;
}
int p;
p = stack::push_reference(L, it->first);
p += stack::stack_detail::push_reference<push_type>(L, it->second);
std::advance(it, 1);
return p;
static int real_pairs_traits(std::true_type, lua_State* L) {
return traits::pairs(L);
}
static int real_pairs_call_assoc(std::true_type, lua_State* L) {
auto& src = get_src(L);
using std::begin;
stack::push(L, pairs_next_call);
stack::push<user<iter>>(L, src, begin(src));
stack::push(L, 1);
return 3;
}
static int real_pairs_next_call_assoc(std::false_type, lua_State* L) {
using std::end;
iter& i = stack::get<user<iter>>(L, 1);
auto& source = i.source;
auto& it = i.it;
K k = stack::get<K>(L, 2);
if (it == end(source)) {
return 0;
}
int p;
p = stack::push_reference(L, k + 1);
p += stack::stack_detail::push_reference<push_type>(L, *it);
std::advance(it, 1);
return p;
}
static int real_pairs_call_assoc(std::false_type, lua_State* L) {
auto& src = get_src(L);
using std::begin;
stack::push(L, pairs_next_call);
stack::push<user<iter>>(L, src, begin(src));
stack::push(L, 0);
return 3;
}
static int real_pairs_next_call(lua_State* L) {
return real_pairs_next_call_assoc(is_associative(), L);
static int real_pairs_traits(std::false_type, lua_State* L) {
return default_traits::pairs(L);
}
static int real_pairs_call(lua_State* L) {
return real_pairs_call_assoc(is_associative(), L);
return real_pairs_traits(container_detail::has_traits_pairs<traits>(), L);
}
static int real_length_call(lua_State*L) {
auto& src = get_src(L);
return stack::push(L, src.size());
static int real_size_traits(std::true_type, lua_State* L) {
return traits::size(L);
}
static int real_add_call_insert(std::true_type, lua_State*L, T& src, int boost = 0) {
using std::end;
src.insert(end(src), stack::get<V>(L, 2 + boost));
return 0;
static int real_size_traits(std::false_type, lua_State* L) {
return default_traits::size(L);
}
static int real_add_call_insert(std::false_type, lua_State*L, T&, int = 0) {
static const std::string& s = detail::demangle<T>();
return luaL_error(L, "sol: cannot call insert on type %s", s.c_str());
static int real_length_call(lua_State* L) {
return real_size_traits(container_detail::has_traits_size<traits>(), L);
}
static int real_add_call_push(std::true_type, lua_State*L, T& src, int boost = 0) {
src.push_back(stack::get<V>(L, 2 + boost));
return 0;
static int real_add_traits(std::true_type, lua_State* L) {
return traits::add(L);
}
static int real_add_call_push(std::false_type, lua_State*L, T& src, int boost = 0) {
return real_add_call_insert(std::integral_constant<bool, detail::has_insert<T>::value && std::is_copy_constructible<V>::value>(), L, src, boost);
}
static int real_add_call_associative(std::true_type, lua_State* L) {
return real_insert_call(L);
}
static int real_add_call_associative(std::false_type, lua_State* L) {
auto& src = get_src(L);
return real_add_call_push(std::integral_constant<bool, detail::has_push_back<T>::value && std::is_copy_constructible<V>::value>(), L, src);
}
static int real_add_call_capable(std::true_type, lua_State* L) {
return real_add_call_associative(is_associative(), L);
}
static int real_add_call_capable(std::false_type, lua_State* L) {
static const std::string& s = detail::demangle<T>();
return luaL_error(L, "sol: cannot call add on type %s", s.c_str());
static int real_add_traits(std::false_type, lua_State* L) {
return default_traits::add(L);
}
static int real_add_call(lua_State* L) {
return real_add_call_capable(std::integral_constant<bool, (detail::has_push_back<T>::value || detail::has_insert<T>::value) && std::is_copy_constructible<V>::value>(), L);
return real_add_traits(container_detail::has_traits_add<traits>(), L);
}
static int real_insert_call_capable(std::false_type, std::false_type, lua_State*L) {
static const std::string& s = detail::demangle<T>();
return luaL_error(L, "sol: cannot call insert on type %s", s.c_str());
static int real_insert_traits(std::true_type, lua_State* L) {
return traits::insert(L);
}
static int real_insert_call_capable(std::false_type, std::true_type, lua_State*L) {
return real_insert_call_capable(std::false_type(), std::false_type(), L);
static int real_insert_traits(std::false_type, lua_State* L) {
return default_traits::insert(L);
}
static int real_insert_call_capable(std::true_type, std::false_type, lua_State* L) {
using std::begin;
auto& src = get_src(L);
src.insert(std::next(begin(src), stack::get<K>(L, 2)), stack::get<V>(L, 3));
return 0;
static int real_insert_call(lua_State* L) {
return real_insert_traits(container_detail::has_traits_insert<traits>(), L);
}
static int real_insert_call_capable(std::true_type, std::true_type, lua_State* L) {
return real_new_index_call(L);
static int real_clear_traits(std::true_type, lua_State* L) {
return traits::clear(L);
}
static int real_insert_call(lua_State*L) {
return real_insert_call_capable(std::integral_constant<bool, detail::has_insert<T>::value && std::is_copy_assignable<V>::value>(), is_associative(), L);
static int real_clear_traits(std::false_type, lua_State* L) {
return default_traits::clear(L);
}
static int real_clear_call_capable(std::false_type, lua_State* L) {
static const std::string& s = detail::demangle<T>();
return luaL_error(L, "sol: cannot call clear on type %s", s.c_str());
static int real_clear_call(lua_State* L) {
return real_clear_traits(container_detail::has_traits_clear<traits>(), L);
}
static int real_clear_call_capable(std::true_type, lua_State* L) {
auto& src = get_src(L);
src.clear();
return 0;
static int real_erase_traits(std::true_type, lua_State* L) {
return traits::erase(L);
}
static int real_clear_call(lua_State*L) {
return real_clear_call_capable(std::integral_constant<bool, detail::has_clear<T>::value>(), L);
static int real_erase_traits(std::false_type, lua_State* L) {
return default_traits::erase(L);
}
static int real_find_call_capable(std::false_type, std::false_type, lua_State*L) {
static const std::string& s = detail::demangle<T>();
return luaL_error(L, "sol: cannot call find on type %s", s.c_str());
static int real_erase_call(lua_State* L) {
return real_erase_traits(container_detail::has_traits_erase<traits>(), L);
}
static int real_find_call_capable(std::false_type, std::true_type, lua_State*L) {
return real_index_call(L);
static int real_find_traits(std::true_type, lua_State* L) {
return traits::find(L);
}
static int real_find_call_capable(std::true_type, std::false_type, lua_State* L) {
auto k = stack::check_get<V>(L, 2);
if (k) {
auto& src = get_src(L);
auto it = src.find(*k);
if (it != src.end()) {
auto& v = *it;
return stack::stack_detail::push_reference<push_type>(L, v);
}
}
return stack::push(L, lua_nil);
static int real_find_traits(std::false_type, lua_State* L) {
return default_traits::find(L);
}
static int real_find_call_capable(std::true_type, std::true_type, lua_State* L) {
return real_index_call(L);
}
static int real_find_call(lua_State*L) {
return real_find_call_capable(std::integral_constant<bool, detail::has_find<T>::value>(), is_associative(), L);
static int real_find_call(lua_State* L) {
return real_find_traits(container_detail::has_traits_find<traits>(), L);
}
static int add_call(lua_State*L) {
return detail::typed_static_trampoline<decltype(&real_add_call), (&real_add_call)>(L);
}
static int erase_call(lua_State*L) {
return detail::typed_static_trampoline<decltype(&real_erase_call), (&real_erase_call)>(L);
}
static int insert_call(lua_State*L) {
return detail::typed_static_trampoline<decltype(&real_insert_call), (&real_insert_call)>(L);
}
@ -490,10 +208,6 @@ namespace sol {
return detail::typed_static_trampoline<decltype(&real_length_call), (&real_length_call)>(L);
}
static int pairs_next_call(lua_State*L) {
return detail::typed_static_trampoline<decltype(&real_pairs_next_call), (&real_pairs_next_call)>(L);
}
static int pairs_call(lua_State*L) {
return detail::typed_static_trampoline<decltype(&real_pairs_call), (&real_pairs_call)>(L);
}
@ -502,6 +216,10 @@ namespace sol {
return detail::typed_static_trampoline<decltype(&real_get_call), (&real_get_call)>(L);
}
static int set_call(lua_State*L) {
return detail::typed_static_trampoline<decltype(&real_set_call), (&real_set_call)>(L);
}
static int index_call(lua_State*L) {
return detail::typed_static_trampoline<decltype(&real_index_call), (&real_index_call)>(L);
}
@ -513,37 +231,6 @@ namespace sol {
namespace stack {
namespace stack_detail {
template <typename T>
inline auto container_metatable() {
typedef container_usertype_metatable<std::remove_pointer_t<T>> meta_cumt;
std::array<luaL_Reg, 12> reg = { {
{ "__index", &meta_cumt::index_call },
{ "__newindex", &meta_cumt::new_index_call },
{ "__pairs", &meta_cumt::pairs_call },
{ "__ipairs", &meta_cumt::pairs_call },
{ "__len", &meta_cumt::length_call },
{ "get", &meta_cumt::get_call },
{ "clear", &meta_cumt::clear_call },
{ "insert", &meta_cumt::insert_call },
{ "add", &meta_cumt::add_call },
{ "find", &meta_cumt::find_call },
std::is_pointer<T>::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ "__gc", &detail::usertype_alloc_destroy<T> },
{ nullptr, nullptr }
} };
return reg;
}
template <typename T>
inline auto container_metatable_behind() {
typedef container_usertype_metatable<std::remove_pointer_t<T>> meta_cumt;
std::array<luaL_Reg, 3> reg = { {
{ "__index", &meta_cumt::index_call },
{ "__newindex", &meta_cumt::new_index_call },
{ nullptr, nullptr }
} };
return reg;
}
template <typename T>
struct metatable_setup {
lua_State* L;
@ -551,20 +238,28 @@ namespace sol {
metatable_setup(lua_State* L) : L(L) {}
void operator()() {
static const auto reg = container_metatable<T>();
static const auto containerreg = container_metatable_behind<T>();
typedef container_usertype_metatable<std::remove_pointer_t<T>> meta_cumt;
static const char* metakey = &usertype_traits<T>::metatable()[0];
static const std::array<luaL_Reg, 14> reg = { {
{ "__pairs", &meta_cumt::pairs_call },
{ "__ipairs", &meta_cumt::pairs_call },
{ "__len", &meta_cumt::length_call },
{ "__index", &meta_cumt::index_call },
{ "__newindex", &meta_cumt::new_index_call },
{ "get", &meta_cumt::get_call },
{ "set", &meta_cumt::set_call },
{ "clear", &meta_cumt::clear_call },
{ "insert", &meta_cumt::insert_call },
{ "add", &meta_cumt::add_call },
{ "find", &meta_cumt::find_call },
{ "erase", &meta_cumt::erase_call },
std::is_pointer<T>::value ? luaL_Reg{ nullptr, nullptr } : luaL_Reg{ "__gc", &detail::usertype_alloc_destroy<T> },
{ nullptr, nullptr }
} };
if (luaL_newmetatable(L, metakey) == 1) {
stack_reference metatable(L, -1);
luaL_setfuncs(L, reg.data(), 0);
lua_createtable(L, 0, static_cast<int>(containerreg.size()));
stack_reference metabehind(L, -1);
luaL_setfuncs(L, containerreg.data(), 0);
stack::set_field(L, metatable_key, metabehind, metatable.stack_index());
metabehind.pop();
}
lua_setmetatable(L, -2);
}
@ -573,21 +268,25 @@ namespace sol {
template<typename T>
struct pusher<T, std::enable_if_t<meta::all<is_container<meta::unqualified_t<T>>, meta::neg<meta::any<std::is_base_of<reference, meta::unqualified_t<T>>, std::is_base_of<stack_reference, meta::unqualified_t<T>>>>>::value>> {
typedef meta::unqualified_t<T> C;
static int push(lua_State* L, const T& cont) {
stack_detail::metatable_setup<T> fx(L);
stack_detail::metatable_setup<C> fx(L);
return pusher<detail::as_value_tag<T>>{}.push_fx(L, fx, cont);
}
static int push(lua_State* L, T&& cont) {
stack_detail::metatable_setup<T> fx(L);
stack_detail::metatable_setup<C> fx(L);
return pusher<detail::as_value_tag<T>>{}.push_fx(L, fx, std::move(cont));
}
};
template<typename T>
struct pusher<T*, std::enable_if_t<meta::all<is_container<meta::unqualified_t<T>>, meta::neg<meta::any<std::is_base_of<reference, meta::unqualified_t<T>>, std::is_base_of<stack_reference, meta::unqualified_t<T>>>>>::value>> {
typedef std::add_pointer_t<meta::unqualified_t<std::remove_pointer_t<T>>> C;
static int push(lua_State* L, T* cont) {
stack_detail::metatable_setup<meta::unqualified_t<std::remove_pointer_t<T>>*> fx(L);
stack_detail::metatable_setup<C> fx(L);
return pusher<detail::as_pointer_tag<T>>{}.push_fx(L, fx, cont);
}
};
@ -595,4 +294,4 @@ namespace sol {
} // sol
#endif // SOL_CONTAINER_USERTYPE_HPP
#endif // SOL_CONTAINER_USERTYPE_METATABLE_HPP

View File

@ -32,6 +32,8 @@ namespace sol {
typedef basic_table<base_type> base_t;
public:
using base_t::lua_state;
basic_environment() noexcept = default;
basic_environment(const basic_environment&) = default;
basic_environment(basic_environment&&) = default;
@ -76,7 +78,7 @@ namespace sol {
#ifdef SOL_CHECK_ARGUMENTS
if (!is_environment<meta::unqualified_t<T>>::value) {
auto pp = stack::push_pop(*this);
stack::check<basic_environment>(base_t::lua_state(), -1, type_panic);
stack::check<basic_environment>(lua_state(), -1, type_panic);
}
#endif // Safety
}

View File

@ -28,6 +28,7 @@ namespace sol {
class reference;
class stack_reference;
struct proxy_base_tag;
template <typename Table, typename Key>
struct proxy;
template<typename T>
@ -50,30 +51,38 @@ namespace sol {
struct basic_environment;
using environment = basic_environment<reference>;
using stack_environment = basic_environment<stack_reference>;
template <typename T>
template <typename T, bool>
class basic_function;
template <typename T>
template <typename T, bool>
class basic_protected_function;
using protected_function = basic_protected_function<reference>;
using stack_protected_function = basic_protected_function<stack_reference>;
using unsafe_function = basic_function<reference>;
using safe_function = basic_protected_function<reference>;
using stack_unsafe_function = basic_function<stack_reference>;
using stack_safe_function = basic_protected_function<stack_reference>;
using unsafe_function = basic_function<reference, false>;
using safe_function = basic_protected_function<reference, false>;
using stack_unsafe_function = basic_function<stack_reference, false>;
using stack_safe_function = basic_protected_function<stack_reference, false>;
using stack_aligned_unsafe_function = basic_function<stack_reference, true>;
using stack_aligned_safe_function = basic_protected_function<stack_reference, true>;
using protected_function = safe_function;
using stack_protected_function = stack_safe_function;
using stack_aligned_protected_function = stack_aligned_safe_function;
#ifdef SOL_SAFE_FUNCTIONS
using function = protected_function;
using stack_function = stack_protected_function;
using stack_aligned_function = stack_aligned_safe_function;
#else
using function = unsafe_function;
using stack_function = stack_unsafe_function;
using stack_aligned_function = stack_aligned_unsafe_function;
#endif
struct function_result;
struct protected_function_result;
using safe_function_result = protected_function_result;
using unsafe_function_result = function_result;
template <typename base_t>
class basic_object;
template <typename base_t>
class basic_userdata;
template <typename base_t>
class basic_lightuserdata;
struct variadic_args;
using object = basic_object<reference>;
using stack_object = basic_object<stack_reference>;
using userdata = basic_userdata<reference>;
@ -84,9 +93,14 @@ namespace sol {
class thread;
struct variadic_args;
struct variadic_results;
struct stack_count;
struct this_state;
struct this_environment;
template <typename T>
struct as_table_t;
template <typename T>
struct nested;
template <typename T>
struct light;
template <typename T>
struct user;

View File

@ -22,9 +22,9 @@
#ifndef SOL_FUNCTION_HPP
#define SOL_FUNCTION_HPP
#include "stack.hpp"
#include "unsafe_function.hpp"
#include "protected_function.hpp"
#include "stack.hpp"
#include <functional>
namespace sol {

View File

@ -78,11 +78,26 @@ namespace sol {
lua_State* lua_state() const { return L; };
int stack_index() const { return index; };
int return_count() const { return returncount; };
~function_result() {
lua_pop(L, returncount);
}
};
namespace stack {
template <>
struct pusher<function_result> {
static int push(lua_State* L, const function_result& fr) {
int p = 0;
for (int i = 0; i < fr.return_count(); ++i) {
lua_pushvalue(L, i + fr.stack_index());
++p;
}
return p;
}
};
} // stack
} // sol
#endif // SOL_FUNCTION_RESULT_HPP

View File

@ -78,6 +78,8 @@ namespace sol {
template <typename Super>
basic_object(proxy_base<Super>&& r) noexcept : basic_object(r.operator basic_object()) {}
basic_object(lua_State* L, int index = -1) noexcept : base_t(L, index) {}
basic_object(lua_State* L, absolute_index index) noexcept : base_t(L, index) {}
basic_object(lua_State* L, raw_index index) noexcept : base_t(L, index) {}
basic_object(lua_State* L, ref_index index) noexcept : base_t(L, index) {}
template <typename T, typename... Args>
basic_object(lua_State* L, in_place_type_t<T>, Args&&... args) noexcept

View File

@ -31,9 +31,9 @@
namespace sol {
namespace detail {
inline reference& handler_storage() {
static sol::reference h;
return h;
inline const char (&default_handler_name())[11] {
static const char name[11] = "sol.\xF0\x9F\x94\xA9";
return name;
}
struct handler {
@ -54,36 +54,37 @@ namespace sol {
};
}
template <typename base_t>
template <typename base_t, bool aligned = false>
class basic_protected_function : public base_t {
public:
static reference& get_default_handler() {
return detail::handler_storage();
static reference get_default_handler(lua_State* L) {
if (L == nullptr)
return reference(lua_nil);
lua_getglobal(L, detail::default_handler_name());
auto pp = stack::pop_n(L, 1);
return reference(L, -1);
}
static void set_default_handler(const reference& ref) {
detail::handler_storage() = ref;
}
static void set_default_handler(reference&& ref) {
detail::handler_storage() = std::move(ref);
ref.push();
lua_setglobal(ref.lua_state(), detail::default_handler_name());
}
private:
call_status luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount, detail::handler& h) const {
return static_cast<call_status>(lua_pcallk(base_t::lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount), h.stackindex, 0, nullptr));
return static_cast<call_status>(lua_pcallk(lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount), h.stackindex, 0, nullptr));
}
template<std::size_t... I, typename... Ret>
auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n, detail::handler& h) const {
luacall(n, sizeof...(Ret), h);
return stack::pop<std::tuple<Ret...>>(base_t::lua_state());
return stack::pop<std::tuple<Ret...>>(lua_state());
}
template<std::size_t I, typename Ret>
Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n, detail::handler& h) const {
luacall(n, 1, h);
return stack::pop<Ret>(base_t::lua_state());
return stack::pop<Ret>(lua_state());
}
template <std::size_t I>
@ -92,7 +93,7 @@ namespace sol {
}
protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n, detail::handler& h) const {
int stacksize = lua_gettop(base_t::lua_state());
int stacksize = lua_gettop(lua_state());
int poststacksize = stacksize;
int firstreturn = 1;
int returncount = 0;
@ -102,42 +103,44 @@ namespace sol {
h.stackindex = 0;
if (h.target.valid()) {
h.target.push();
stack::push(base_t::lua_state(), error);
lua_call(base_t::lua_state(), 1, 1);
stack::push(lua_state(), error);
lua_call(lua_state(), 1, 1);
}
else {
stack::push(base_t::lua_state(), error);
stack::push(lua_state(), error);
}
};
try {
#endif // No Exceptions
firstreturn = (std::max)(1, static_cast<int>(stacksize - n - static_cast<int>(h.valid())));
code = luacall(n, LUA_MULTRET, h);
poststacksize = lua_gettop(base_t::lua_state()) - static_cast<int>(h.valid());
poststacksize = lua_gettop(lua_state()) - static_cast<int>(h.valid());
returncount = poststacksize - (firstreturn - 1);
#ifndef SOL_NO_EXCEPTIONS
}
// Handle C++ errors thrown from C++ functions bound inside of lua
catch (const char* error) {
onexcept(error);
firstreturn = lua_gettop(base_t::lua_state());
return protected_function_result(base_t::lua_state(), firstreturn, 0, 1, call_status::runtime);
firstreturn = lua_gettop(lua_state());
return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);
}
catch (const std::exception& error) {
onexcept(error.what());
firstreturn = lua_gettop(base_t::lua_state());
return protected_function_result(base_t::lua_state(), firstreturn, 0, 1, call_status::runtime);
firstreturn = lua_gettop(lua_state());
return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);
}
catch (...) {
onexcept("caught (...) unknown error during protected_function call");
firstreturn = lua_gettop(base_t::lua_state());
return protected_function_result(base_t::lua_state(), firstreturn, 0, 1, call_status::runtime);
firstreturn = lua_gettop(lua_state());
return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);
}
#endif // No Exceptions
return protected_function_result(base_t::lua_state(), firstreturn, returncount, returncount, code);
return protected_function_result(lua_state(), firstreturn, returncount, returncount, code);
}
public:
using base_t::lua_state;
reference error_handler;
basic_protected_function() = default;
@ -146,7 +149,7 @@ namespace sol {
#ifdef SOL_CHECK_ARGUMENTS
if (!is_function<meta::unqualified_t<T>>::value) {
auto pp = stack::push_pop(*this);
stack::check<basic_protected_function>(base_t::lua_state(), -1, type_panic);
stack::check<basic_protected_function>(lua_state(), -1, type_panic);
}
#endif // Safety
}
@ -154,22 +157,42 @@ namespace sol {
basic_protected_function& operator=(const basic_protected_function&) = default;
basic_protected_function(basic_protected_function&&) = default;
basic_protected_function& operator=(basic_protected_function&&) = default;
basic_protected_function(const basic_function<base_t>& b, reference eh = get_default_handler()) : base_t(b), error_handler(std::move(eh)) {}
basic_protected_function(basic_function<base_t>&& b, reference eh = get_default_handler()) : base_t(std::move(b)), error_handler(std::move(eh)) {}
basic_protected_function(const stack_reference& r, reference eh = get_default_handler()) : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) {}
basic_protected_function(stack_reference&& r, reference eh = get_default_handler()) : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) {}
basic_protected_function(const basic_function<base_t>& b) : basic_protected_function(b, get_default_handler(b.lua_state())) {}
basic_protected_function(basic_function<base_t>&& b) : basic_protected_function(std::move(b), get_default_handler(b.lua_state())) {}
basic_protected_function(const basic_function<base_t>& b, reference eh) : base_t(b), error_handler(std::move(eh)) {}
basic_protected_function(basic_function<base_t>&& b, reference eh) : base_t(std::move(b)), error_handler(std::move(eh)) {}
basic_protected_function(const stack_reference& r) : basic_protected_function(r.lua_state(), r.stack_index(), get_default_handler(r.lua_state())) {}
basic_protected_function(stack_reference&& r) : basic_protected_function(r.lua_state(), r.stack_index(), get_default_handler(r.lua_state())) {}
basic_protected_function(const stack_reference& r, reference eh) : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) {}
basic_protected_function(stack_reference&& r, reference eh) : basic_protected_function(r.lua_state(), r.stack_index(), std::move(eh)) {}
template <typename Super>
basic_protected_function(proxy_base<Super>&& p, reference eh = get_default_handler()) : basic_protected_function(p.operator basic_function<base_t>(), std::move(eh)) {}
basic_protected_function(const proxy_base<Super>& p) : basic_protected_function(p.operator basic_function<base_t>(), get_default_handler(p.lua_state())) {}
template <typename Super>
basic_protected_function(const proxy_base<Super>& p, reference eh = get_default_handler()) : basic_protected_function(p.operator basic_function<base_t>(), std::move(eh)) {}
template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<std::is_same<T, ref_index>>> = meta::enabler>
basic_protected_function(proxy_base<Super>&& p) : basic_protected_function(p.operator basic_function<base_t>(), get_default_handler(p.lua_state())) {}
template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<is_lua_index<meta::unqualified_t<T>>>> = meta::enabler>
basic_protected_function(lua_State* L, T&& r) : basic_protected_function(L, std::forward<T>(r), get_default_handler(L)) {}
template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<is_lua_index<meta::unqualified_t<T>>>> = meta::enabler>
basic_protected_function(lua_State* L, T&& r, reference eh) : basic_protected_function(L, sol::ref_index(r.registry_index()), std::move(eh)) {}
basic_protected_function(lua_State* L, int index = -1, reference eh = get_default_handler()) : base_t(L, index), error_handler(std::move(eh)) {
basic_protected_function(lua_State* L, int index = -1) : basic_protected_function(L, index, get_default_handler(L)) {}
basic_protected_function(lua_State* L, int index, reference eh) : base_t(L, index), error_handler(std::move(eh)) {
#ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_protected_function>(L, index, type_panic);
#endif // Safety
}
basic_protected_function(lua_State* L, ref_index index, reference eh = get_default_handler()) : base_t(L, index), error_handler(std::move(eh)) {
basic_protected_function(lua_State* L, absolute_index index) : basic_protected_function(L, index, get_default_handler(L)) {}
basic_protected_function(lua_State* L, absolute_index index, reference eh) : base_t(L, index), error_handler(std::move(eh)) {
#ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_protected_function>(L, index, type_panic);
#endif // Safety
}
basic_protected_function(lua_State* L, raw_index index) : basic_protected_function(L, index, get_default_handler(L)) {}
basic_protected_function(lua_State* L, raw_index index, reference eh) : base_t(L, index), error_handler(std::move(eh)) {
#ifdef SOL_CHECK_ARGUMENTS
stack::check<basic_protected_function>(L, index, type_panic);
#endif // Safety
}
basic_protected_function(lua_State* L, ref_index index) : basic_protected_function(L, index, get_default_handler(L)) {}
basic_protected_function(lua_State* L, ref_index index, reference eh) : base_t(L, index), error_handler(std::move(eh)) {
#ifdef SOL_CHECK_ARGUMENTS
auto pp = stack::push_pop(*this);
stack::check<basic_protected_function>(L, -1, type_panic);
@ -189,8 +212,10 @@ namespace sol {
template<typename... Ret, typename... Args>
decltype(auto) call(Args&&... args) const {
detail::handler h(error_handler);
base_t::push();
int pushcount = stack::multi_push_reference(base_t::lua_state(), std::forward<Args>(args)...);
if (!aligned) {
base_t::push();
}
int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...);
return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount, h);
}
};

View File

@ -120,11 +120,27 @@ namespace sol {
lua_State* lua_state() const noexcept { return L; };
int stack_index() const noexcept { return index; };
int return_count() const noexcept { return returncount; };
int pop_count() const noexcept { return popcount; };
~protected_function_result() {
stack::remove(L, index, popcount);
}
};
namespace stack {
template <>
struct pusher<protected_function_result> {
static int push(lua_State* L, const protected_function_result& pfr) {
int p = 0;
for (int i = 0; i < pfr.pop_count(); ++i) {
lua_pushvalue(L, i + pfr.stack_index());
++p;
}
return p;
}
};
} // stack
} // sol
#endif // SOL_PROTECTED_FUNCTION_RESULT_HPP

View File

@ -114,21 +114,25 @@ namespace sol {
bool valid() const {
auto pp = stack::push_pop(tbl);
auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(tbl.lua_state(), key, lua_gettop(tbl.lua_state()));
lua_pop(tbl.lua_state(), p.levels);
auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, lua_gettop(lua_state()));
lua_pop(lua_state(), p.levels);
return p;
}
type get_type() const {
type t = type::none;
auto pp = stack::push_pop(tbl);
auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(tbl.lua_state(), key, lua_gettop(tbl.lua_state()));
auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(lua_state(), key, lua_gettop(lua_state()));
if (p) {
t = type_of(tbl.lua_state(), -1);
t = type_of(lua_state(), -1);
}
lua_pop(tbl.lua_state(), p.levels);
lua_pop(lua_state(), p.levels);
return t;
}
lua_State* lua_state() const {
return tbl.lua_state();
}
};
template<typename Table, typename Key, typename T>

View File

@ -47,6 +47,11 @@ namespace sol {
const Super& super = *static_cast<const Super*>(static_cast<const void*>(this));
return super.template get<T&>();
}
lua_State* lua_state() const {
const Super& super = *static_cast<const Super*>(static_cast<const void*>(this));
return super.lua_state();
}
};
} // sol

View File

@ -35,6 +35,13 @@
#include <array>
namespace sol {
namespace detail {
inline const std::string& default_chunk_name() {
static const std::string name = "string";
return name;
}
} // detail
namespace stack {
namespace stack_detail {
template<typename T>
@ -156,7 +163,7 @@ namespace sol {
typedef lua_bind_traits<meta::unqualified_t<Fx>> traits_type;
typedef typename traits_type::args_list args_list;
typedef typename traits_type::returns_list returns_list;
return call_into_lua(returns_list(), args_list(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
return call_into_lua<check_args>(returns_list(), args_list(), L, start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...);
}
inline call_syntax get_call_syntax(lua_State* L, const std::string& key, int index) {
@ -171,14 +178,14 @@ namespace sol {
return call_syntax::colon;
}
inline void script(lua_State* L, const std::string& code) {
if (luaL_dostring(L, code.c_str())) {
inline void script(lua_State* L, const string_detail::string_shim& code, string_detail::string_shim name = detail::default_chunk_name(), load_mode mode = load_mode::any) {
if (luaL_loadbufferx(L, code.data(), code.size(), name.data(), to_string(mode).c_str()) || lua_pcall(L, 0, LUA_MULTRET, 0)) {
lua_error(L);
}
}
inline void script_file(lua_State* L, const std::string& filename) {
if (luaL_dofile(L, filename.c_str())) {
inline void script_file(lua_State* L, const std::string& filename, load_mode mode = load_mode::any) {
if (luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str()) || lua_pcall(L, 0, LUA_MULTRET, 0)) {
lua_error(L);
}
}

View File

@ -30,6 +30,7 @@
#include "tie.hpp"
#include "stack_guard.hpp"
#include <vector>
#include <forward_list>
#include <string>
namespace sol {
@ -158,6 +159,18 @@ namespace sol {
#else
false;
#endif
template <typename C>
static int get_size_hint(const C& c) {
return static_cast<int>(c.size());
}
template <typename V, typename Al>
static int get_size_hint(const std::forward_list<V, Al>& c) {
// forward_list makes me sad
return static_cast<int>(32);
}
template<typename T>
inline decltype(auto) unchecked_get(lua_State* L, int index, record& tracking) {
return getter<meta::unqualified_t<T>>{}.get(L, index, tracking);
@ -180,6 +193,10 @@ namespace sol {
return t == type::userdata || t == type::table;
}
inline int top(lua_State* L) {
return lua_gettop(L);
}
template<typename T, typename... Args>
inline int push(lua_State* L, T&& t, Args&&... args) {
return pusher<meta::unqualified_t<T>>{}.push(L, std::forward<T>(t), std::forward<Args>(args)...);
@ -248,7 +265,10 @@ namespace sol {
template<typename T, typename Handler>
inline decltype(auto) check_get(lua_State* L, int index, Handler&& handler, record& tracking) {
return check_getter<meta::unqualified_t<T>>{}.get(L, index, std::forward<Handler>(handler), tracking);
typedef meta::unqualified_t<T> Tu;
check_getter<Tu> cg{};
(void)cg;
return cg.get(L, index, std::forward<Handler>(handler), tracking);
}
template<typename T, typename Handler>

View File

@ -83,21 +83,52 @@ namespace sol {
};
template<typename T>
struct getter<as_table_t<T>, std::enable_if_t<!meta::has_key_value_pair<meta::unqualified_t<T>>::value>> {
struct getter<as_table_t<T>> {
typedef meta::unqualified_t<T> Tu;
template <typename V>
static void push_back_at_end(std::true_type, types<V>, lua_State* L, T& arr, std::size_t) {
arr.push_back(stack::get<V>(L, -lua_size<V>::value));
}
template <typename V>
static void push_back_at_end(std::false_type, types<V> t, lua_State* L, T& arr, std::size_t idx) {
insert_at_end(meta::has_insert<Tu>(), t, L, arr, idx);
}
template <typename V>
static void insert_at_end(std::true_type, types<V>, lua_State* L, T& arr, std::size_t) {
using std::cend;
arr.insert(cend(arr), stack::get<V>(L, -lua_size<V>::value));
}
template <typename V>
static void insert_at_end(std::false_type, types<V>, lua_State* L, T& arr, std::size_t idx) {
arr[idx] = stack::get<V>(L, -lua_size<V>::value);
}
static T get(lua_State* L, int relindex, record& tracking) {
return get(meta::has_key_value_pair<meta::unqualified_t<T>>(), L, relindex, tracking);
}
static T get(std::false_type, lua_State* L, int relindex, record& tracking) {
typedef typename T::value_type V;
return get(types<V>(), L, relindex, tracking);
}
template <typename V>
static T get(types<V>, lua_State* L, int relindex, record& tracking) {
static T get(types<V> t, lua_State* L, int relindex, record& tracking) {
tracking.use(1);
int index = lua_absindex(L, relindex);
T arr;
std::size_t idx = 0;
#if SOL_LUA_VERSION >= 503
// This method is HIGHLY performant over regular table iteration thanks to the Lua API changes in 5.3
for (lua_Integer i = 0; ; i += lua_size<V>::value, lua_pop(L, lua_size<V>::value)) {
if (idx >= arr.max_size()) {
return arr;
}
bool isnil = false;
for (int vi = 0; vi < lua_size<V>::value; ++vi) {
type t = static_cast<type>(lua_geti(L, index, i + vi));
@ -112,7 +143,8 @@ namespace sol {
}
if (isnil)
continue;
arr.push_back(stack::get<V>(L, -lua_size<V>::value));
push_back_at_end(meta::has_push_back<Tu>(), t, L, arr, idx);
++idx;
}
#else
// Zzzz slower but necessary thanks to the lower version API and missing functions qq
@ -133,16 +165,14 @@ namespace sol {
}
if (isnil)
continue;
arr.push_back(stack::get<V>(L, -1));
push_back_at_end(meta::has_push_back<Tu>(), t, L, arr, idx);
++idx;
}
#endif
return arr;
}
};
template<typename T>
struct getter<as_table_t<T>, std::enable_if_t<meta::has_key_value_pair<meta::unqualified_t<T>>::value>> {
static T get(lua_State* L, int index, record& tracking) {
static T get(std::true_type, lua_State* L, int index, record& tracking) {
typedef typename T::value_type P;
typedef typename P::first_type K;
typedef typename P::second_type V;
@ -169,6 +199,104 @@ namespace sol {
}
};
template<typename T, typename Al>
struct getter<as_table_t<std::forward_list<T, Al>>> {
typedef std::forward_list<T, Al> C;
static C get(lua_State* L, int relindex, record& tracking) {
return get(meta::has_key_value_pair<C>(), L, relindex, tracking);
}
static C get(std::true_type, lua_State* L, int index, record& tracking) {
typedef typename T::value_type P;
typedef typename P::first_type K;
typedef typename P::second_type V;
return get(types<K, V>(), L, index, tracking);
}
static C get(std::false_type, lua_State* L, int relindex, record& tracking) {
typedef typename C::value_type V;
return get(types<V>(), L, relindex, tracking);
}
template <typename V>
static C get(types<V> t, lua_State* L, int relindex, record& tracking) {
tracking.use(1);
int index = lua_absindex(L, relindex);
C arr;
auto at = arr.cbefore_begin();
std::size_t idx = 0;
#if SOL_LUA_VERSION >= 503
// This method is HIGHLY performant over regular table iteration thanks to the Lua API changes in 5.3
for (lua_Integer i = 0; ; i += lua_size<V>::value, lua_pop(L, lua_size<V>::value)) {
if (idx >= arr.max_size()) {
return arr;
}
bool isnil = false;
for (int vi = 0; vi < lua_size<V>::value; ++vi) {
type t = static_cast<type>(lua_geti(L, index, i + vi));
isnil = t == type::lua_nil;
if (isnil) {
if (i == 0) {
break;
}
lua_pop(L, (vi + 1));
return arr;
}
}
if (isnil)
continue;
at = arr.insert_after(at, stack::get<V>(L, -lua_size<V>::value));
++idx;
}
#else
// Zzzz slower but necessary thanks to the lower version API and missing functions qq
for (lua_Integer i = 0; ; i += lua_size<V>::value, lua_pop(L, lua_size<V>::value)) {
bool isnil = false;
for (int vi = 0; vi < lua_size<V>::value; ++vi) {
lua_pushinteger(L, i);
lua_gettable(L, index);
type t = type_of(L, -1);
isnil = t == type::lua_nil;
if (isnil) {
if (i == 0) {
break;
}
lua_pop(L, (vi + 1));
return arr;
}
}
if (isnil)
continue;
at = arr.insert_after(at, stack::get<V>(L, -lua_size<V>::value));
++idx;
}
#endif
return arr;
}
template <typename K, typename V>
static C get(types<K, V>, lua_State* L, int relindex, record& tracking) {
tracking.use(1);
C associative;
auto at = associative.cbefore_begin();
int index = lua_absindex(L, relindex);
lua_pushnil(L);
while (lua_next(L, index) != 0) {
decltype(auto) key = stack::check_get<K>(L, -2);
if (!key) {
lua_pop(L, 1);
continue;
}
at = associative.emplace_after(at, std::forward<decltype(*key)>(*key), stack::get<V>(L, -1));
lua_pop(L, 1);
}
return associative;
}
};
template<typename T>
struct getter<nested<T>, std::enable_if_t<!is_container<T>::value>> {
static T get(lua_State* L, int index, record& tracking) {

View File

@ -42,6 +42,16 @@ namespace sol {
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());
}

View File

@ -41,7 +41,7 @@ namespace sol {
namespace stack {
inline int push_environment_of(lua_State* L, int index = -1) {
#if SOL_LUA_VERSION < 502
// Use lua_setfenv
// Use lua_getfenv
lua_getfenv(L, index);
return 1;
#else
@ -199,16 +199,6 @@ namespace sol {
}
};
template<typename T>
struct pusher<T, std::enable_if_t<std::is_enum<T>::value>> {
static int push(lua_State* L, const T& value) {
if (std::is_same<char, T>::value) {
return stack::push(L, static_cast<int>(value));
}
return stack::push(L, static_cast<std::underlying_type_t<T>>(value));
}
};
template<typename T>
struct pusher<T, std::enable_if_t<meta::all<std::is_integral<T>, std::is_unsigned<T>>::value>> {
static int push(lua_State* L, const T& value) {
@ -218,11 +208,35 @@ namespace sol {
};
template<typename T>
struct pusher<as_table_t<T>, std::enable_if_t<!meta::has_key_value_pair<meta::unqualified_t<std::remove_pointer_t<T>>>::value>> {
static int push(lua_State* L, const as_table_t<T>& tablecont) {
auto& cont = detail::deref(detail::unwrap(tablecont.source));
struct pusher<T, std::enable_if_t<std::is_enum<T>::value>> {
static int push(lua_State* L, const T& value) {
if (std::is_same<char, std::underlying_type_t<T>>::value) {
return stack::push(L, static_cast<int>(value));
}
return stack::push(L, static_cast<std::underlying_type_t<T>>(value));
}
};
template<typename T>
struct pusher<as_table_t<T>, std::enable_if_t<is_container<meta::unqualified_t<T>>::value>> {
static int push(lua_State* L, const T& tablecont) {
return push(meta::has_key_value_pair<meta::unqualified_t<std::remove_pointer_t<T>>>(), L, tablecont);
}
static int push(std::true_type, lua_State* L, const T& tablecont) {
auto& cont = detail::deref(detail::unwrap(tablecont));
lua_createtable(L, static_cast<int>(cont.size()), 0);
int tableindex = lua_gettop(L);
for (const auto& pair : cont) {
set_field(L, pair.first, pair.second, tableindex);
}
return 1;
}
static int push(std::false_type, lua_State* L, const T& tablecont) {
auto& cont = detail::deref(detail::unwrap(tablecont));
lua_createtable(L, stack_detail::get_size_hint(tablecont), 0);
int tableindex = lua_gettop(L);
std::size_t index = 1;
for (const auto& i : cont) {
#if SOL_LUA_VERSION >= 503
@ -257,15 +271,19 @@ namespace sol {
};
template<typename T>
struct pusher<as_table_t<T>, std::enable_if_t<meta::has_key_value_pair<meta::unqualified_t<std::remove_pointer_t<T>>>::value>> {
static int push(lua_State* L, const as_table_t<T>& tablecont) {
auto& cont = detail::deref(detail::unwrap(tablecont.source));
lua_createtable(L, static_cast<int>(cont.size()), 0);
int tableindex = lua_gettop(L);
for (const auto& pair : cont) {
set_field(L, pair.first, pair.second, tableindex);
}
return 1;
struct pusher<as_table_t<T>, std::enable_if_t<!is_container<meta::unqualified_t<T>>::value>> {
static int push(lua_State* L, const T& v) {
return stack::push(L, v);
}
};
template<typename T>
struct pusher<nested<T>> {
static int push(lua_State* L, const T& tablecont) {
pusher<as_table_t<T>> p{};
// silence annoying VC++ warning
(void)p;
return p.push(L, tablecont);
}
};
@ -296,6 +314,13 @@ namespace sol {
}
};
template<>
struct pusher<stack_count> {
static int push(lua_State*, stack_count st) {
return st.count;
}
};
template<>
struct pusher<metatable_t> {
static int push(lua_State* L, metatable_t) {

View File

@ -25,55 +25,59 @@
#include "state_view.hpp"
namespace sol {
inline int default_at_panic(lua_State* L) {
namespace detail {
inline int default_at_panic(lua_State* L) {
#ifdef SOL_NO_EXCEPTIONS
(void)L;
return -1;
(void)L;
return -1;
#else
const char* message = lua_tostring(L, -1);
if (message) {
std::string err = message;
const char* message = lua_tostring(L, -1);
if (message) {
std::string err = message;
lua_settop(L, 0);
throw error(err);
}
lua_settop(L, 0);
throw error(err);
}
lua_settop(L, 0);
throw error(std::string("An unexpected error occurred and forced the lua state to call atpanic"));
throw error(std::string("An unexpected error occurred and forced the lua state to call atpanic"));
#endif
}
inline int default_error_handler(lua_State*L) {
using namespace sol;
std::string msg = "An unknown error has triggered the default error handler";
optional<string_detail::string_shim> maybetopmsg = stack::check_get<string_detail::string_shim>(L, 1);
if (maybetopmsg) {
const string_detail::string_shim& topmsg = maybetopmsg.value();
msg.assign(topmsg.data(), topmsg.size());
}
luaL_traceback(L, L, msg.c_str(), 1);
optional<string_detail::string_shim> maybetraceback = stack::check_get<string_detail::string_shim>(L, -1);
if (maybetraceback) {
const string_detail::string_shim& traceback = maybetraceback.value();
msg.assign(traceback.data(), traceback.size());
}
return stack::push(L, msg);
}
inline int default_traceback_error_handler(lua_State*L) {
using namespace sol;
std::string msg = "An unknown error has triggered the default error handler";
optional<string_detail::string_shim> maybetopmsg = stack::check_get<string_detail::string_shim>(L, 1);
if (maybetopmsg) {
const string_detail::string_shim& topmsg = maybetopmsg.value();
msg.assign(topmsg.data(), topmsg.size());
}
luaL_traceback(L, L, msg.c_str(), 1);
optional<string_detail::string_shim> maybetraceback = stack::check_get<string_detail::string_shim>(L, -1);
if (maybetraceback) {
const string_detail::string_shim& traceback = maybetraceback.value();
msg.assign(traceback.data(), traceback.size());
}
return stack::push(L, msg);
}
} // detail
class state : private std::unique_ptr<lua_State, void(*)(lua_State*)>, public state_view {
private:
typedef std::unique_ptr<lua_State, void(*)(lua_State*)> unique_base;
public:
state(lua_CFunction panic = default_at_panic) : unique_base(luaL_newstate(), lua_close),
state(lua_CFunction panic = detail::default_at_panic) : unique_base(luaL_newstate(), lua_close),
state_view(unique_base::get()) {
set_panic(panic);
sol::protected_function::set_default_handler(sol::object(lua_state(), in_place, default_error_handler));
lua_CFunction f = c_call<decltype(&detail::default_traceback_error_handler), &detail::default_traceback_error_handler>;
sol::protected_function::set_default_handler(sol::object(lua_state(), in_place, f));
stack::luajit_exception_handler(unique_base::get());
}
state(lua_CFunction panic, lua_Alloc alfunc, void* alpointer = nullptr) : unique_base(lua_newstate(alfunc, alpointer), lua_close),
state_view(unique_base::get()) {
set_panic(panic);
sol::protected_function::set_default_handler(sol::object(lua_state(), in_place, default_error_handler));
lua_CFunction f = c_call<decltype(&detail::default_traceback_error_handler), &detail::default_traceback_error_handler>;
sol::protected_function::set_default_handler(sol::object(lua_state(), in_place, f));
stack::luajit_exception_handler(unique_base::get());
}
@ -88,12 +92,7 @@ namespace sol {
using state_view::get;
~state() {
auto& handler = protected_function::get_default_handler();
if (handler.lua_state() == this->lua_state()) {
protected_function::set_default_handler(reference());
}
}
~state() {}
};
} // sol

View File

@ -53,24 +53,28 @@ namespace sol {
return kb;
}
inline protected_function_result simple_on_error(lua_State*, sol::protected_function_result result) {
inline protected_function_result script_pass_on_error(lua_State*, sol::protected_function_result result) {
return result;
}
inline protected_function_result default_on_error( lua_State* L, protected_function_result pfr ) {
inline protected_function_result script_default_on_error(lua_State* L, protected_function_result pfr) {
type t = type_of(L, pfr.stack_index());
std::string err = to_string(pfr.status()) + " error";
std::string err = "sol: ";
err += to_string(pfr.status());
err += " error:";
if (t == type::string) {
err += " ";
err += stack::get<std::string>(L, pfr.stack_index());
string_detail::string_shim serr = stack::get<string_detail::string_shim>(L, pfr.stack_index());
err.append(serr.data(), serr.size());
}
#ifdef SOL_NO_EXCEPTIONS
// replacing information of stack error into pfr
if (t != type::nil) {
lua_pop(L, 1);
}
stack::push(L, err);
lua_error(L);
#else
// just throw our error
throw error(detail::direct_error, err);
#endif
return pfr;
@ -146,7 +150,7 @@ namespace sol {
}
state_view(this_state Ls) : state_view(Ls.L){
state_view(this_state Ls) : state_view(Ls.L) {
}
@ -249,17 +253,17 @@ namespace sol {
return stack::pop<object>(L);
}
object require_script(const std::string& key, const std::string& code, bool create_global = true) {
return require_core(key, [this, &code]() {stack::script(L, code); }, create_global);
object require_script(const std::string& key, const string_detail::string_shim& code, bool create_global = true, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
return require_core(key, [this, &code, &chunkname, &mode]() {stack::script(L, code, chunkname, mode); }, create_global);
}
object require_file(const std::string& key, const std::string& filename, bool create_global = true) {
return require_core(key, [this, &filename]() {stack::script_file(L, filename); }, create_global);
object require_file(const std::string& key, const std::string& filename, bool create_global = true, load_mode mode = load_mode::any) {
return require_core(key, [this, &filename, &mode]() {stack::script_file(L, filename, mode); }, create_global);
}
template <typename E>
protected_function_result do_string(const std::string& code, const basic_environment<E>& env) {
load_status x = static_cast<load_status>(luaL_loadstring(L, code.c_str()));
protected_function_result do_string(const string_detail::string_shim& code, const basic_environment<E>& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
load_status x = static_cast<load_status>(luaL_loadbufferx(L, code.data(), code.size(), chunkname.c_str(), to_string(mode).c_str()));
if (x != load_status::ok) {
return protected_function_result(L, -1, 0, 1, static_cast<call_status>(x));
}
@ -270,8 +274,8 @@ namespace sol {
}
template <typename E>
protected_function_result do_file(const std::string& filename, const basic_environment<E>& env) {
load_status x = static_cast<load_status>(luaL_loadfile(L, filename.c_str()));
protected_function_result do_file(const std::string& filename, const basic_environment<E>& env, load_mode mode = load_mode::any) {
load_status x = static_cast<load_status>(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str()));
if (x != load_status::ok) {
return protected_function_result(L, -1, 0, 1, static_cast<call_status>(x));
}
@ -281,8 +285,8 @@ namespace sol {
return pf();
}
protected_function_result do_string(const std::string& code) {
load_status x = static_cast<load_status>(luaL_loadstring(L, code.c_str()));
protected_function_result do_string(const string_detail::string_shim& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
load_status x = static_cast<load_status>(luaL_loadbufferx(L, code.data(), code.size(), chunkname.c_str(), to_string(mode).c_str()));
if (x != load_status::ok) {
return protected_function_result(L, -1, 0, 1, static_cast<call_status>(x));
}
@ -291,8 +295,8 @@ namespace sol {
return pf();
}
protected_function_result do_file(const std::string& filename) {
load_status x = static_cast<load_status>(luaL_loadfile(L, filename.c_str()));
protected_function_result do_file(const std::string& filename, load_mode mode = load_mode::any) {
load_status x = static_cast<load_status>(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str()));
if (x != load_status::ok) {
return protected_function_result(L, -1, 0, 1, static_cast<call_status>(x));
}
@ -301,17 +305,9 @@ namespace sol {
return pf();
}
protected_function_result script(const std::string& code, const environment& env) {
return script(code, env, sol::default_on_error);
}
protected_function_result script_file(const std::string& filename, const environment& env) {
return script_file(filename, env, sol::default_on_error);
}
template <typename Fx, meta::disable<meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler>
protected_function_result script(const std::string& code, Fx&& on_error) {
protected_function_result pfr = do_string(code);
protected_function_result safe_script(const string_detail::string_shim& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
protected_function_result pfr = do_string(code, chunkname, mode);
if (!pfr.valid()) {
return on_error(L, std::move(pfr));
}
@ -319,8 +315,8 @@ namespace sol {
}
template <typename Fx, meta::disable<meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler>
protected_function_result script_file(const std::string& filename, Fx&& on_error) {
protected_function_result pfr = do_file(filename);
protected_function_result safe_script_file(const std::string& filename, Fx&& on_error, load_mode mode = load_mode::any) {
protected_function_result pfr = do_file(filename, mode);
if (!pfr.valid()) {
return on_error(L, std::move(pfr));
}
@ -328,8 +324,8 @@ namespace sol {
}
template <typename Fx, typename E>
protected_function_result script(const std::string& code, const basic_environment<E>& env, Fx&& on_error) {
protected_function_result pfr = do_string(code, env);
protected_function_result safe_script(const string_detail::string_shim& code, const basic_environment<E>& env, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
protected_function_result pfr = do_string(code, env, chunkname, mode);
if (!pfr.valid()) {
return on_error(L, std::move(pfr));
}
@ -337,42 +333,94 @@ namespace sol {
}
template <typename Fx, typename E>
protected_function_result script_file(const std::string& filename, const basic_environment<E>& env, Fx&& on_error) {
protected_function_result pfr = do_file(filename, env);
protected_function_result safe_script_file(const std::string& filename, const basic_environment<E>& env, Fx&& on_error, load_mode mode = load_mode::any) {
protected_function_result pfr = do_file(filename, env, mode);
if (!pfr.valid()) {
return on_error(L, std::move(pfr));
}
return pfr;
}
function_result script(const std::string& code) {
protected_function_result safe_script(const string_detail::string_shim& code, const environment& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
return safe_script(code, env, sol::script_default_on_error, chunkname, mode);
}
protected_function_result safe_script_file(const std::string& filename, const environment& env, load_mode mode = load_mode::any) {
return safe_script_file(filename, env, sol::script_default_on_error, mode);
}
protected_function_result safe_script(const string_detail::string_shim& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
return safe_script(code, sol::script_default_on_error, chunkname, mode);
}
protected_function_result safe_script_file(const std::string& filename, load_mode mode = load_mode::any) {
return safe_script_file(filename, sol::script_default_on_error, mode);
}
function_result unsafe_script(const string_detail::string_shim& code, const std::string& name = detail::default_chunk_name(), load_mode mode = load_mode::any) {
int index = lua_gettop(L);
stack::script(L, code);
stack::script(L, code, name, mode);
int postindex = lua_gettop(L);
int returns = postindex - index;
return function_result(L, (std::max)(postindex - (returns - 1), 1), returns);
}
function_result script_file(const std::string& filename) {
function_result unsafe_script_file(const std::string& filename, load_mode mode = load_mode::any) {
int index = lua_gettop(L);
stack::script_file(L, filename);
stack::script_file(L, filename, mode);
int postindex = lua_gettop(L);
int returns = postindex - index;
return function_result(L, (std::max)(postindex - (returns - 1), 1), returns);
}
load_result load(const std::string& code) {
load_status x = static_cast<load_status>(luaL_loadstring(L, code.c_str()));
template <typename Fx, meta::disable<meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler>
protected_function_result script(const string_detail::string_shim& code, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
return safe_script(code, std::forward<Fx>(on_error), chunkname, mode);
}
template <typename Fx, meta::disable<meta::is_specialization_of<basic_environment, meta::unqualified_t<Fx>>> = meta::enabler>
protected_function_result script_file(const std::string& filename, Fx&& on_error, load_mode mode = load_mode::any) {
return safe_script_file(filename, std::forward<Fx>(on_error), mode);
}
template <typename Fx, typename E>
protected_function_result script(const string_detail::string_shim& code, const basic_environment<E>& env, Fx&& on_error, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
return safe_script(code, env, std::forward<Fx>(on_error), chunkname, mode);
}
template <typename Fx, typename E>
protected_function_result script_file(const std::string& filename, const basic_environment<E>& env, Fx&& on_error, load_mode mode = load_mode::any) {
return safe_script_file(filename, env, std::forward<Fx>(on_error), mode);
}
protected_function_result script(const string_detail::string_shim& code, const environment& env, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
return safe_script(code, env, sol::script_default_on_error, chunkname, mode);
}
protected_function_result script_file(const std::string& filename, const environment& env, load_mode mode = load_mode::any) {
return safe_script_file(filename, env, sol::script_default_on_error, mode);
}
function_result script(const string_detail::string_shim& code, const std::string& chunkname = detail::default_chunk_name(), load_mode mode = load_mode::any) {
return unsafe_script(code, chunkname, mode);
}
function_result script_file(const std::string& filename, load_mode mode = load_mode::any) {
return unsafe_script_file(filename, mode);
}
load_result load(const string_detail::string_shim& code, const std::string& name = detail::default_chunk_name(), load_mode mode = load_mode::any) {
load_status x = static_cast<load_status>(luaL_loadbufferx(L, code.data(), code.size(), name.c_str(), to_string(mode).c_str()));
return load_result(L, lua_absindex(L, -1), 1, 1, x);
}
load_result load_file(const std::string& filename) {
load_status x = static_cast<load_status>(luaL_loadfile(L, filename.c_str()));
load_result load_file(const std::string& filename, load_mode mode = load_mode::any) {
load_status x = static_cast<load_status>(luaL_loadfilex(L, filename.c_str(), to_string(mode).c_str()));
return load_result(L, lua_absindex(L, -1), 1, 1, x);
}
load_result load_buffer(const char *buff, size_t size, const char *name, const char* mode = nullptr) {
load_status x = static_cast<load_status>(luaL_loadbufferx(L, buff, size, name, mode));
load_result load(lua_Reader reader, void* data, const std::string& name = detail::default_chunk_name(), load_mode mode = load_mode::any) {
load_status x = static_cast<load_status>(lua_load(L, reader, data, name.c_str(), to_string(mode).c_str()));
return load_result(L, lua_absindex(L, -1), 1, 1, x);
}

View File

@ -102,13 +102,16 @@ namespace sol {
struct any_same : std::false_type { };
template<class T, class U, class... Args>
struct any_same<T, U, Args...> : std::integral_constant <bool, std::is_same<T, U>::value || any_same<T, Args...>::value> { };
struct any_same<T, U, Args...> : std::integral_constant <bool, std::is_same<T, U>::value || any_same<T, Args...>::value> {};
template<bool B>
using boolean = std::integral_constant<bool, B>;
template<typename T>
using invoke_t = typename T::type;
template<bool B>
using boolean = std::integral_constant<bool, B>;
template <typename T>
using invoke_b = boolean<T::value>;
template<typename T>
using neg = boolean<!T::value>;
@ -326,24 +329,63 @@ namespace sol {
static std::false_type test(...);
};
template <typename T, typename U = T, typename = decltype(std::declval<T&>() < std::declval<U&>())>
std::true_type supports_op_less_test(const T&);
template <typename T>
struct has_push_back_test {
private:
typedef std::array<char, 1> one;
typedef std::array<char, 2> two;
template <typename C> static one test(decltype(std::declval<C>().push_back(std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);
template <typename C> static two test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(char);
};
template <typename T>
struct has_insert_test {
private:
typedef std::array<char, 1> one;
typedef std::array<char, 2> two;
template <typename C> static one test(decltype(std::declval<C>().insert(std::declval<std::add_rvalue_reference_t<typename C::const_iterator>>(), std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);
template <typename C> static two test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(char);
};
template <typename T>
struct has_insert_after_test {
private:
typedef std::array<char, 1> one;
typedef std::array<char, 2> two;
template <typename C> static one test(decltype(std::declval<C>().insert_after(std::declval<std::add_rvalue_reference_t<typename C::const_iterator>>(), std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);
template <typename C> static two test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(char);
};
template <typename T, typename U, typename = decltype(std::declval<T&>() < std::declval<U&>())>
std::true_type supports_op_less_test(const T&, const U&);
std::false_type supports_op_less_test(...);
template <typename T, typename U = T, typename = decltype(std::declval<T&>() == std::declval<U&>())>
std::true_type supports_op_equal_test(const T&);
template <typename T, typename U, typename = decltype(std::declval<T&>() == std::declval<U&>())>
std::true_type supports_op_equal_test(const T&, const U&);
std::false_type supports_op_equal_test(...);
template <typename T, typename U = T, typename = decltype(std::declval<T&>() <= std::declval<U&>())>
std::true_type supports_op_less_equal_test(const T&);
template <typename T, typename U, typename = decltype(std::declval<T&>() <= std::declval<U&>())>
std::true_type supports_op_less_equal_test(const T&, const U&);
std::false_type supports_op_less_equal_test(...);
} // meta_detail
template <typename T>
using supports_op_less = decltype(meta_detail::supports_op_less_test(std::declval<T&>()));
template <typename T>
using supports_op_equal = decltype(meta_detail::supports_op_equal_test(std::declval<T&>()));
template <typename T>
using supports_op_less_equal = decltype(meta_detail::supports_op_less_equal_test(std::declval<T&>()));
template <typename T, typename U = T>
using supports_op_less = decltype(meta_detail::supports_op_less_test(std::declval<T&>(), std::declval<U&>()));
template <typename T, typename U = T>
using supports_op_equal = decltype(meta_detail::supports_op_equal_test(std::declval<T&>(), std::declval<U&>()));
template <typename T, typename U = T>
using supports_op_less_equal = decltype(meta_detail::supports_op_less_equal_test(std::declval<T&>(), std::declval<U&>()));
template<typename T>
struct is_callable : boolean<meta_detail::is_callable<T>::value> {};
@ -367,7 +409,19 @@ namespace sol {
struct has_value_type : decltype(meta_detail::has_value_type_impl::test<T>(0)) {};
template <typename T>
struct is_associative : meta::all<has_key_value_pair<T>, has_mapped_type<T>> {};
using has_push_back = meta::boolean<meta_detail::has_push_back_test<T>::value>;
template <typename T>
using has_insert = meta::boolean<meta_detail::has_insert_test<T>::value>;
template <typename T>
using has_insert_after = meta::boolean<meta_detail::has_insert_after_test<T>::value>;
template <typename T>
struct is_associative : meta::all<has_key_type<T>, has_key_value_pair<T>, has_mapped_type<T>> {};
template <typename T>
struct is_lookup : meta::all<has_key_type<T>, has_value_type<T>> {};
template <typename T>
using is_string_constructible = any<
@ -464,6 +518,16 @@ namespace sol {
return std::forward<T>(item);
}
template<typename T>
inline auto& deref(T(&item)[5]) {
return item;
}
template<typename T>
inline auto& deref(const T(&item)[5]) {
return item;
}
template<typename T>
inline T& deref(T* item) {
return *item;

View File

@ -281,6 +281,12 @@ namespace sol {
}
};
struct stack_count {
int count;
stack_count(int cnt) : count(cnt) {}
};
struct lightuserdata_value {
void* value;
lightuserdata_value(void* data) : value(data) {}
@ -380,8 +386,19 @@ namespace sol {
template <typename T>
struct as_table_t {
T source;
template <typename... Args>
as_table_t(Args&&... args) : source(std::forward<Args>(args)...) {}
as_table_t() = default;
as_table_t(const as_table_t&) = default;
as_table_t(as_table_t&&) = default;
as_table_t& operator=(const as_table_t&) = default;
as_table_t& operator=(as_table_t&&) = default;
template <typename Arg, meta::enable<
meta::neg<std::is_same<meta::unqualified_t<Arg>, as_table_t>>,
meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>
> = meta::enabler>
as_table_t(Arg&& arg) : source(std::forward<Arg>(arg)) {}
template <typename Arg0, typename Arg1, typename... Args>
as_table_t(Arg0&& arg0, Arg1&& arg1, Args&&... args) : source(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) {}
operator std::add_lvalue_reference_t<T> () {
return source;
@ -392,8 +409,18 @@ namespace sol {
struct nested {
T source;
template <typename... Args>
nested(Args&&... args) : source(std::forward<Args>(args)...) {}
nested() = default;
nested(const nested&) = default;
nested(nested&&) = default;
nested& operator=(const nested&) = default;
nested& operator=(nested&&) = default;
template <typename Arg, meta::enable<
meta::neg<std::is_same<meta::unqualified_t<Arg>, nested>>,
meta::neg<std::is_base_of<proxy_base_tag, meta::unqualified_t<Arg>>>
> = meta::enabler>
nested(Arg&& arg) : source(std::forward<Arg>(arg)) {}
template <typename Arg0, typename Arg1, typename... Args>
nested(Arg0&& arg0, Arg1&& arg1, Args&&... args) : source(std::forward<Arg0>(arg0), std::forward<Arg1>(arg1), std::forward<Args>(args)...) {}
operator std::add_lvalue_reference_t<T>() {
return source;
@ -407,7 +434,7 @@ namespace sol {
template <typename T>
nested<T> as_nested(T&& container) {
return as_nested<T>(std::forward<T>(container));
return nested<T>(std::forward<T>(container));
}
struct this_state {
@ -438,6 +465,12 @@ namespace sol {
colon = 1
};
enum class load_mode {
any = 0,
text = 1,
binary = 2,
};
enum class call_status : int {
ok = LUA_OK,
yielded = LUA_YIELD,
@ -518,13 +551,13 @@ namespace sol {
}
inline const std::string& to_string(load_status c) {
static const std::array<std::string, 8> names{ {
"ok",
"memory",
"gc",
"syntax",
"file",
} };
static const std::array<std::string, 8> names{{
"ok",
"memory",
"gc",
"syntax",
"file",
}};
switch (c) {
case load_status::ok:
return names[0];
@ -540,6 +573,15 @@ namespace sol {
return names[0];
}
inline const std::string& to_string(load_mode c) {
static const std::array<std::string, 3> names{{
"bt",
"t",
"b",
}};
return names[static_cast<std::size_t>(c)];
}
enum class meta_function {
construct,
index,
@ -656,6 +698,49 @@ namespace sol {
return lua_typename(L, static_cast<int>(t));
}
namespace detail {
template <typename T, typename C = void>
struct is_container : std::false_type {};
template <>
struct is_container<std::string> : std::false_type {};
template <>
struct is_container<std::wstring> : std::false_type {};
template <>
struct is_container<std::u16string> : std::false_type {};
template <>
struct is_container<std::u32string> : std::false_type {};
#ifdef SOL_CXX17_FEATURES
template <>
struct is_container<std::string_view> : std::false_type {};
template <>
struct is_container<std::wstring_view> : std::false_type {};
template <>
struct is_container<std::u16string_view> : std::false_type {};
template <>
struct is_container<std::u32string_view> : std::false_type {};
#endif // C++ 17
template <typename T>
struct is_container<T, std::enable_if_t<meta::has_begin_end<meta::unqualified_t<T>>::value>> : std::true_type {};
template <typename T>
struct is_container<T, std::enable_if_t<
std::is_array<meta::unqualified_t<T>>::value
&& !meta::any_same<std::remove_all_extents_t<meta::unqualified_t<T>>, char, wchar_t, char16_t, char32_t>::value
>> : std::true_type {};
} // detail
template <typename T>
struct is_container : detail::is_container<T> {};
namespace detail {
template <typename T, typename = void>
struct lua_type_of : std::integral_constant<type, type::userdata> {};
@ -733,7 +818,7 @@ namespace sol {
struct lua_type_of<env_t> : std::integral_constant<type, type::poly> { };
template <>
struct lua_type_of<new_table> : std::integral_constant<type, type::table> { };
struct lua_type_of<new_table> : std::integral_constant<type, type::table> {};
template <typename T>
struct lua_type_of<as_table_t<T>> : std::integral_constant<type, type::table> {};
@ -780,11 +865,11 @@ namespace sol {
template <>
struct lua_type_of<std::remove_pointer_t<lua_CFunction>> : std::integral_constant<type, type::function> {};
template <typename Base>
struct lua_type_of<basic_function<Base>> : std::integral_constant<type, type::function> {};
template <typename Base, bool aligned>
struct lua_type_of<basic_function<Base, aligned>> : std::integral_constant<type, type::function> {};
template <typename Base>
struct lua_type_of<basic_protected_function<Base>> : std::integral_constant<type, type::function> {};
template <typename Base, bool aligned>
struct lua_type_of<basic_protected_function<Base, aligned>> : std::integral_constant<type, type::function> {};
template <>
struct lua_type_of<coroutine> : std::integral_constant<type, type::function> {};
@ -801,6 +886,12 @@ namespace sol {
template <>
struct lua_type_of<variadic_args> : std::integral_constant<type, type::poly> {};
template <>
struct lua_type_of<variadic_results> : std::integral_constant<type, type::poly> {};
template <>
struct lua_type_of<stack_count> : std::integral_constant<type, type::poly> {};
template <>
struct lua_type_of<this_state> : std::integral_constant<type, type::poly> {};
@ -842,38 +933,11 @@ namespace sol {
struct lua_type_of<string_detail::string_shim> : std::integral_constant<type, type::string> {};
#endif // C++ 17 (or not) features
template <typename T, typename C = void>
struct is_container : std::false_type {};
template <>
struct is_container<std::string> : std::false_type {};
template <>
struct is_container<std::wstring> : std::false_type {};
template <>
struct is_container<std::u16string> : std::false_type {};
template <>
struct is_container<std::u32string> : std::false_type {};
#ifdef SOL_CXX17_FEATURES
template <>
struct is_container<std::string_view> : std::false_type {};
template <>
struct is_container<std::wstring_view> : std::false_type {};
template <>
struct is_container<std::u16string_view> : std::false_type {};
template <>
struct is_container<std::u32string_view> : std::false_type {};
#endif // C++ 17
template <typename T>
struct lua_type_of<nested<T>, std::enable_if_t<::sol::is_container<T>::value>> : std::integral_constant<type, type::table> {};
template <typename T>
struct is_container<T, std::enable_if_t<meta::has_begin_end<meta::unqualified_t<T>>::value>> : std::true_type {};
struct lua_type_of<nested<T>, std::enable_if_t<!::sol::is_container<T>::value>> : lua_type_of<T> {};
template <typename C, C v, template <typename...> class V, typename... Args>
struct accumulate : std::integral_constant<C, v> {};
@ -942,6 +1006,10 @@ namespace sol {
struct is_lua_primitive<light<T>> : is_lua_primitive<T*> { };
template <typename T>
struct is_lua_primitive<optional<T>> : std::true_type {};
template <typename T>
struct is_lua_primitive<as_table_t<T>> : std::true_type {};
template <typename T>
struct is_lua_primitive<nested<T>> : std::true_type {};
template <>
struct is_lua_primitive<userdata_value> : std::true_type {};
template <>
@ -954,25 +1022,32 @@ namespace sol {
template <typename T>
struct is_transparent_argument : std::false_type {};
template <>
struct is_transparent_argument<this_state> : std::true_type {};
template <>
struct is_transparent_argument<this_environment> : std::true_type {};
template <>
struct is_transparent_argument<variadic_args> : std::true_type {};
template <typename T>
struct is_variadic_arguments : std::is_same<meta::unqualified_t<T>, variadic_args> {};
template <typename T>
struct is_variadic_arguments : std::is_same<T, variadic_args> {};
struct is_lua_index : std::false_type {};
template <>
struct is_lua_index<raw_index> : std::true_type {};
template <>
struct is_lua_index<absolute_index> : std::true_type {};
template <>
struct is_lua_index<ref_index> : std::true_type {};
template <>
struct is_lua_index<upvalue_index> : std::true_type {};
template <typename Signature>
struct lua_bind_traits : meta::bind_traits<Signature> {
private:
typedef meta::bind_traits<Signature> base_t;
public:
typedef std::integral_constant<bool, meta::count_for<is_transparent_argument, typename base_t::args_list>::value != 0> runtime_variadics_t;
typedef std::integral_constant<bool, meta::count_for<is_variadic_arguments, typename base_t::args_list>::value != 0> runtime_variadics_t;
static const std::size_t true_arity = base_t::arity;
static const std::size_t arity = base_t::arity - meta::count_for<is_transparent_argument, typename base_t::args_list>::value;
static const std::size_t true_free_arity = base_t::free_arity;
@ -986,10 +1061,10 @@ namespace sol {
template <typename T>
struct is_function : std::false_type {};
template <typename T>
struct is_function<basic_function<T>> : std::true_type {};
template <typename T>
struct is_function<basic_protected_function<T>> : std::true_type {};
template <typename T, bool aligned>
struct is_function<basic_function<T, aligned>> : std::true_type {};
template <typename T, bool aligned>
struct is_function<basic_protected_function<T, aligned>> : std::true_type{};
template <typename T>
struct is_lightuserdata : std::false_type {};
@ -1004,21 +1079,10 @@ namespace sol {
template <typename T>
struct is_environment : std::integral_constant<bool, is_userdata<T>::value || is_table<T>::value> {};
template <typename T>
struct is_container : detail::is_container<T>{};
template<typename T>
inline type type_of() {
return lua_type_of<meta::unqualified_t<T>>::value;
}
namespace detail {
template <typename T>
struct lua_type_of<nested<T>, std::enable_if_t<::sol::is_container<T>::value>> : std::integral_constant<type, type::table> {};
template <typename T>
struct lua_type_of<nested<T>, std::enable_if_t<!::sol::is_container<T>::value>> : lua_type_of<T> {};
} // detail
} // sol
#endif // SOL_TYPES_HPP

View File

@ -29,23 +29,23 @@
#include <cstdint>
namespace sol {
template <typename base_t>
template <typename base_t, bool aligned = false>
class basic_function : public base_t {
private:
void luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount) const {
lua_callk(base_t::lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount), 0, nullptr);
lua_callk(lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount), 0, nullptr);
}
template<std::size_t... I, typename... Ret>
auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n) const {
luacall(n, lua_size<std::tuple<Ret...>>::value);
return stack::pop<std::tuple<Ret...>>(base_t::lua_state());
return stack::pop<std::tuple<Ret...>>(lua_state());
}
template<std::size_t I, typename Ret>
Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n) const {
luacall(n, lua_size<Ret>::value);
return stack::pop<Ret>(base_t::lua_state());
return stack::pop<Ret>(lua_state());
}
template <std::size_t I>
@ -54,22 +54,24 @@ namespace sol {
}
function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) const {
int stacksize = lua_gettop(base_t::lua_state());
int stacksize = lua_gettop(lua_state());
int firstreturn = (std::max)(1, stacksize - static_cast<int>(n));
luacall(n, LUA_MULTRET);
int poststacksize = lua_gettop(base_t::lua_state());
int poststacksize = lua_gettop(lua_state());
int returncount = poststacksize - (firstreturn - 1);
return function_result(base_t::lua_state(), firstreturn, returncount);
return function_result(lua_state(), firstreturn, returncount);
}
public:
using base_t::lua_state;
basic_function() = default;
template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_function>>, meta::neg<std::is_same<base_t, stack_reference>>, std::is_base_of<base_t, meta::unqualified_t<T>>> = meta::enabler>
basic_function(T&& r) noexcept : base_t(std::forward<T>(r)) {
#ifdef SOL_CHECK_ARGUMENTS
if (!is_function<meta::unqualified_t<T>>::value) {
auto pp = stack::push_pop(*this);
stack::check<basic_function>(base_t::lua_state(), -1, type_panic);
stack::check<basic_function>(lua_state(), -1, type_panic);
}
#endif // Safety
}
@ -105,8 +107,10 @@ namespace sol {
template<typename... Ret, typename... Args>
decltype(auto) call(Args&&... args) const {
base_t::push();
int pushcount = stack::multi_push_reference(base_t::lua_state(), std::forward<Args>(args)...);
if (!aligned) {
base_t::push();
}
int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...);
return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount);
}
};

View File

@ -30,13 +30,15 @@ namespace sol {
class basic_userdata : public basic_table<base_type> {
typedef basic_table<base_type> base_t;
public:
using base_t::lua_state;
basic_userdata() noexcept = default;
template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_userdata>>, meta::neg<std::is_same<base_t, stack_reference>>, std::is_base_of<base_type, meta::unqualified_t<T>>> = meta::enabler>
basic_userdata(T&& r) noexcept : base_t(std::forward<T>(r)) {
#ifdef SOL_CHECK_ARGUMENTS
if (!is_userdata<meta::unqualified_t<T>>::value) {
auto pp = stack::push_pop(*this);
type_assert(base_t::lua_state(), -1, type::userdata);
type_assert(lua_state(), -1, type::userdata);
}
#endif // Safety
}
@ -65,13 +67,15 @@ namespace sol {
class basic_lightuserdata : public basic_object_base<base_type> {
typedef basic_object_base<base_type> base_t;
public:
using base_t::lua_state;
basic_lightuserdata() noexcept = default;
template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_lightuserdata>>, meta::neg<std::is_same<base_t, stack_reference>>, std::is_base_of<base_type, meta::unqualified_t<T>>> = meta::enabler>
basic_lightuserdata(T&& r) noexcept : base_t(std::forward<T>(r)) {
#ifdef SOL_CHECK_ARGUMENTS
if (!is_lightuserdata<meta::unqualified_t<T>>::value) {
auto pp = stack::push_pop(*this);
type_assert(base_t::lua_state(), -1, type::lightuserdata);
type_assert(lua_state(), -1, type::lightuserdata);
}
#endif // Safety
}

View File

@ -0,0 +1,812 @@
#define SOL_CHECK_ARGUMENTS
#include <sol.hpp>
#include <catch.hpp>
#include <iterator>
#include <vector>
#include <list>
#include <forward_list>
#include <deque>
#include <set>
#include <map>
#include <array>
#include <unordered_map>
#include <unordered_set>
template <typename T>
void sequence_container_check(sol::state& lua, T& items) {
{
auto r1 = lua.script(R"(
for i=1,#c do
v = c[i]
assert(v == (i + 10))
end
)", sol::script_pass_on_error);
REQUIRE(r1.valid());
}
{
auto ffind = [&]() {
auto r1 = lua.script("i1 = c:find(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("i2 = c:find(14)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fget = [&]() {
auto r1 = lua.script("v1 = c:get(1)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("v2 = c:get(3)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fset = [&]() {
auto r1 = lua.script("c:set(2, 20)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("c:set(6, 16)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto ferase = [&]() {
auto r5 = lua.script("s1 = #c", sol::script_pass_on_error);
REQUIRE(r5.valid());
auto r1 = lua.script("c:erase(i1)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r3 = lua.script("s2 = #c", sol::script_pass_on_error);
REQUIRE(r3.valid());
auto r2 = lua.script("c:erase(i2)", sol::script_pass_on_error);
REQUIRE(r2.valid());
auto r4 = lua.script("s3 = #c", sol::script_pass_on_error);
REQUIRE(r4.valid());
};
auto fadd = [&]() {
auto r = lua.script("c:add(17)", sol::script_pass_on_error);
REQUIRE(r.valid());
};
auto fopset = [&]() {
auto r = lua.script("c[#c + 1] = 18", sol::script_pass_on_error);
REQUIRE(r.valid());
};
auto fopget = [&]() {
auto r = lua.script("v3 = c[#c]", sol::script_pass_on_error);
REQUIRE(r.valid());
};
REQUIRE_NOTHROW(ffind());
REQUIRE_NOTHROW(fget());
REQUIRE_NOTHROW(fset());
REQUIRE_NOTHROW(ferase());
REQUIRE_NOTHROW(fadd());
REQUIRE_NOTHROW(fopset());
REQUIRE_NOTHROW(fopget());
}
auto backit = items.begin();
std::size_t len = 0;
{
auto e = items.end();
auto last = backit;
for (; backit != e; ++backit, ++len) {
if (backit == e) {
break;
}
last = backit;
}
backit = last;
}
const int& first = *items.begin();
const int& last = *backit;
std::size_t i1 = lua["i1"];
std::size_t i2 = lua["i2"];
std::size_t s1 = lua["s1"];
std::size_t s2 = lua["s2"];
std::size_t s3 = lua["s3"];
int v1 = lua["v1"];
int v2 = lua["v2"];
int v3 = lua["v3"];
int values[6] = {
20, 13, 14, 16, 17, 18
};
{
std::size_t idx = 0;
for (const auto& i : items) {
const auto& v = values[idx];
REQUIRE(i == v);
++idx;
}
}
REQUIRE(s1 == 6);
REQUIRE(s2 == 5);
REQUIRE(s3 == 4);
REQUIRE(len == 6);
REQUIRE(first == 20);
REQUIRE(last == 18);
REQUIRE(i1 == 1);
REQUIRE(i2 == 4);
REQUIRE(v1 == 11);
REQUIRE(v2 == 13);
REQUIRE(v3 == 18);
}
template <typename T>
void ordered_container_check(sol::state& lua, T& items) {
{
auto r1 = lua.script(R"(
for i=1,#c do
v = c[i]
assert(v == (i + 10))
end
)", sol::script_pass_on_error);
REQUIRE(r1.valid());
}
{
auto ffind = [&]() {
auto r1 = lua.script("i1 = c:find(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("i2 = c:find(14)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fget = [&]() {
auto r1 = lua.script("v1 = c:get(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("v2 = c:get(13)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fset = [&]() {
auto r1 = lua.script("c:set(20)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("c:set(16)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto ferase = [&]() {
auto r5 = lua.script("s1 = #c", sol::script_pass_on_error);
REQUIRE(r5.valid());
auto r1 = lua.script("c:erase(i1)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r3 = lua.script("s2 = #c", sol::script_pass_on_error);
REQUIRE(r3.valid());
auto r2 = lua.script("c:erase(i2)", sol::script_pass_on_error);
REQUIRE(r2.valid());
auto r4 = lua.script("s3 = #c", sol::script_pass_on_error);
REQUIRE(r4.valid());
};
auto fadd = [&]() {
auto r = lua.script("c:add(17)", sol::script_pass_on_error);
REQUIRE(r.valid());
};
auto fopset = [&]() {
auto r = lua.script("c[18] = true", sol::script_pass_on_error);
REQUIRE(r.valid());
};
auto fopget = [&]() {
auto r = lua.script("v3 = c[20]", sol::script_pass_on_error);
REQUIRE(r.valid());
};
REQUIRE_NOTHROW(ffind());
REQUIRE_NOTHROW(fget());
REQUIRE_NOTHROW(fset());
REQUIRE_NOTHROW(ferase());
REQUIRE_NOTHROW(fadd());
REQUIRE_NOTHROW(fopset());
REQUIRE_NOTHROW(fopget());
}
auto backit = items.begin();
std::size_t len = 0;
{
auto e = items.end();
auto last = backit;
for (; backit != e; ++backit, ++len) {
if (backit == e) {
break;
}
last = backit;
}
backit = last;
}
const int& first = *items.begin();
const int& last = *backit;
int i1 = lua["i1"];
int i2 = lua["i2"];
std::size_t s1 = lua["s1"];
std::size_t s2 = lua["s2"];
std::size_t s3 = lua["s3"];
int v1 = lua["v1"];
int v2 = lua["v2"];
int v3 = lua["v3"];
int values[] = {
12, 13, 15, 16, 17, 18, 20
};
{
std::size_t idx = 0;
for (const auto& i : items) {
const auto& v = values[idx];
REQUIRE(i == v);
++idx;
}
}
REQUIRE(s1 == 7);
REQUIRE(s2 == 6);
REQUIRE(s3 == 5);
REQUIRE(len == 7);
REQUIRE(first == 12);
REQUIRE(last == 20);
REQUIRE(i1 == 11);
REQUIRE(i2 == 14);
REQUIRE(v1 == 11);
REQUIRE(v2 == 13);
REQUIRE(v3 == 20);
}
template <typename T>
void unordered_container_check(sol::state& lua, T& items) {
{
auto ffind = [&]() {
auto r1 = lua.script("i1 = c:find(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("i2 = c:find(14)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fget = [&]() {
auto r1 = lua.script("v1 = c:get(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("v2 = c:get(13)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fset = [&]() {
auto r1 = lua.script("c:set(20)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("c:set(16)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto ferase = [&]() {
auto r5 = lua.script("s1 = #c", sol::script_pass_on_error);
REQUIRE(r5.valid());
auto r1 = lua.script("c:erase(i1)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r3 = lua.script("s2 = #c", sol::script_pass_on_error);
REQUIRE(r3.valid());
auto r2 = lua.script("c:erase(i2)", sol::script_pass_on_error);
REQUIRE(r2.valid());
auto r4 = lua.script("s3 = #c", sol::script_pass_on_error);
REQUIRE(r4.valid());
};
auto fadd = [&]() {
auto r = lua.script("c:add(17)", sol::script_pass_on_error);
REQUIRE(r.valid());
};
auto fopset = [&]() {
auto r = lua.script("c[18] = true", sol::script_pass_on_error);
REQUIRE(r.valid());
};
auto fopget = [&]() {
auto r = lua.script("v3 = c[20]", sol::script_pass_on_error);
REQUIRE(r.valid());
};
REQUIRE_NOTHROW(ffind());
REQUIRE_NOTHROW(fget());
REQUIRE_NOTHROW(fset());
REQUIRE_NOTHROW(ferase());
REQUIRE_NOTHROW(fadd());
REQUIRE_NOTHROW(fopset());
REQUIRE_NOTHROW(fopget());
}
std::size_t len = items.size();
int i1 = lua["i1"];
int i2 = lua["i2"];
std::size_t s1 = lua["s1"];
std::size_t s2 = lua["s2"];
std::size_t s3 = lua["s3"];
int v1 = lua["v1"];
int v2 = lua["v2"];
int v3 = lua["v3"];
int values[] = {
12, 13, 15, 16, 17, 18, 20
};
{
std::size_t idx = 0;
for (const auto& i : items) {
const auto& v = values[idx];
auto it = items.find(v);
REQUIRE(it != items.cend());
REQUIRE(*it == v);
++idx;
}
}
REQUIRE(s1 == 7);
REQUIRE(s2 == 6);
REQUIRE(s3 == 5);
REQUIRE(len == 7);
REQUIRE(i1 == 11);
REQUIRE(i2 == 14);
REQUIRE(v1 == 11);
REQUIRE(v2 == 13);
REQUIRE(v3 == 20);
}
template <typename T>
void associative_ordered_container_check(sol::state& lua, T& items) {
{
auto r1 = lua.script(R"(
for i=1,#c do
v = c[i]
assert(v == (i + 10))
end
)", sol::script_pass_on_error);
REQUIRE(r1.valid());
}
{
auto ffind = [&]() {
auto r1 = lua.script("i1 = c:find(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("i2 = c:find(14)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fget = [&]() {
auto r1 = lua.script("v1 = c:get(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("v2 = c:get(13)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fset = [&]() {
auto r1 = lua.script("c:set(20, 30)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("c:set(16, 26)", sol::script_pass_on_error);
REQUIRE(r2.valid());
auto r3 = lua.script("c:set(12, 31)", sol::script_pass_on_error);
REQUIRE(r3.valid());
};
auto ferase = [&]() {
auto r5 = lua.script("s1 = #c", sol::script_pass_on_error);
REQUIRE(r5.valid());
auto r1 = lua.script("c:erase(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r3 = lua.script("s2 = #c", sol::script_pass_on_error);
REQUIRE(r3.valid());
auto r2 = lua.script("c:erase(14)", sol::script_pass_on_error);
REQUIRE(r2.valid());
auto r4 = lua.script("s3 = #c", sol::script_pass_on_error);
REQUIRE(r4.valid());
};
auto fadd = [&]() {
auto r = lua.script("c:add(17, 27)", sol::script_pass_on_error);
REQUIRE(r.valid());
};
auto fopset = [&]() {
auto r = lua.script("c[18] = 28", sol::script_pass_on_error);
REQUIRE(r.valid());
};
auto fopget = [&]() {
auto r = lua.script("v3 = c[20]", sol::script_pass_on_error);
REQUIRE(r.valid());
};
REQUIRE_NOTHROW(ffind());
REQUIRE_NOTHROW(fget());
REQUIRE_NOTHROW(fset());
REQUIRE_NOTHROW(ferase());
REQUIRE_NOTHROW(fadd());
REQUIRE_NOTHROW(fopset());
REQUIRE_NOTHROW(fopget());
}
auto backit = items.begin();
std::size_t len = 0;
{
auto e = items.end();
auto last = backit;
for (; backit != e; ++backit, ++len) {
if (backit == e) {
break;
}
last = backit;
}
backit = last;
}
const std::pair<const short, int>& first = *items.begin();
const std::pair<const short, int>& last = *backit;
int i1 = lua["i1"];
int i2 = lua["i2"];
std::size_t s1 = lua["s1"];
std::size_t s2 = lua["s2"];
std::size_t s3 = lua["s3"];
int v1 = lua["v1"];
int v2 = lua["v2"];
int v3 = lua["v3"];
std::pair<const short, int> values[] = {
{ 12, 31 },
{ 13, 23 },
{ 15, 25 },
{ 16, 26 },
{ 17, 27 },
{ 18, 28 },
{ 20, 30 }
};
{
std::size_t idx = 0;
for (const auto& i : items) {
const auto& v = values[idx];
REQUIRE(i == v);
++idx;
}
}
REQUIRE(s1 == 7);
REQUIRE(s2 == 6);
REQUIRE(s3 == 5);
REQUIRE(len == 7);
REQUIRE(first.first == 12);
REQUIRE(last.first == 20);
REQUIRE(first.second == 31);
REQUIRE(last.second == 30);
REQUIRE(i1 == 21);
REQUIRE(i2 == 24);
REQUIRE(v1 == 21);
REQUIRE(v2 == 23);
REQUIRE(v3 == 30);
}
template <typename T>
void associative_unordered_container_check(sol::state& lua, T& items) {
{
auto ffind = [&]() {
auto r1 = lua.script("i1 = c:find(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("i2 = c:find(14)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fget = [&]() {
auto r1 = lua.script("v1 = c:get(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("v2 = c:get(13)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fset = [&]() {
auto r1 = lua.script("c:set(20, 30)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("c:set(16, 26)", sol::script_pass_on_error);
REQUIRE(r2.valid());
auto r3 = lua.script("c:set(12, 31)", sol::script_pass_on_error);
REQUIRE(r3.valid());
};
auto ferase = [&]() {
auto r5 = lua.script("s1 = #c", sol::script_pass_on_error);
REQUIRE(r5.valid());
auto r1 = lua.script("c:erase(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r3 = lua.script("s2 = #c", sol::script_pass_on_error);
REQUIRE(r3.valid());
auto r2 = lua.script("c:erase(14)", sol::script_pass_on_error);
REQUIRE(r2.valid());
auto r4 = lua.script("s3 = #c", sol::script_pass_on_error);
REQUIRE(r4.valid());
};
auto fadd = [&]() {
auto r = lua.script("c:add(17, 27)", sol::script_pass_on_error);
REQUIRE(r.valid());
};
auto fopset = [&]() {
auto r = lua.script("c[18] = 28", sol::script_pass_on_error);
REQUIRE(r.valid());
};
auto fopget = [&]() {
auto r = lua.script("v3 = c[20]", sol::script_pass_on_error);
REQUIRE(r.valid());
};
REQUIRE_NOTHROW(ffind());
REQUIRE_NOTHROW(fget());
REQUIRE_NOTHROW(fset());
REQUIRE_NOTHROW(ferase());
REQUIRE_NOTHROW(fadd());
REQUIRE_NOTHROW(fopset());
REQUIRE_NOTHROW(fopget());
}
std::size_t len = items.size();
int i1 = lua["i1"];
int i2 = lua["i2"];
std::size_t s1 = lua["s1"];
std::size_t s2 = lua["s2"];
std::size_t s3 = lua["s3"];
int v1 = lua["v1"];
int v2 = lua["v2"];
int v3 = lua["v3"];
std::pair<const short, int> values[] = {
{ 12, 31 },
{ 13, 23 },
{ 15, 25 },
{ 16, 26 },
{ 17, 27 },
{ 18, 28 },
{ 20, 30 }
};
std::pair<const short, int> item_values[7];
{
std::size_t idx = 0;
for (const auto& i : items) {
const auto& v = values[idx];
auto it = items.find(v.first);
REQUIRE(it != items.cend());
REQUIRE(it->second == v.second);
++idx;
}
}
REQUIRE(s1 == 7);
REQUIRE(s2 == 6);
REQUIRE(s3 == 5);
REQUIRE(len == 7);
REQUIRE(i1 == 21);
REQUIRE(i2 == 24);
REQUIRE(v1 == 21);
REQUIRE(v2 == 23);
REQUIRE(v3 == 30);
}
template <typename T>
void fixed_container_check(sol::state& lua, T& items) {
{
auto r1 = lua.script(R"(
for i=1,#c do
v = c[i]
assert(v == (i + 10))
end
)", sol::script_pass_on_error);
REQUIRE(r1.valid());
}
{
auto ffind = [&]() {
auto r1 = lua.script("i1 = c:find(11)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("i2 = c:find(14)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fget = [&]() {
auto r1 = lua.script("v1 = c:get(2)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("v2 = c:get(5)", sol::script_pass_on_error);
REQUIRE(r2.valid());
};
auto fset = [&]() {
auto r1 = lua.script("c:set(2, 20)", sol::script_pass_on_error);
REQUIRE(r1.valid());
auto r2 = lua.script("c:set(6, 16)", sol::script_pass_on_error);
REQUIRE_FALSE(r2.valid());
};
auto ferase = [&]() {
auto r5 = lua.script("s1 = #c", sol::script_pass_on_error);
REQUIRE(r5.valid());
auto r1 = lua.script("c:erase(i1)", sol::script_pass_on_error);
REQUIRE_FALSE(r1.valid());
auto r3 = lua.script("s2 = #c", sol::script_pass_on_error);
REQUIRE(r3.valid());
auto r2 = lua.script("c:erase(i2)", sol::script_pass_on_error);
REQUIRE_FALSE(r2.valid());
auto r4 = lua.script("s3 = #c", sol::script_pass_on_error);
REQUIRE(r4.valid());
};
auto fadd = [&]() {
auto r = lua.script("c:add(17)", sol::script_pass_on_error);
REQUIRE_FALSE(r.valid());
};
auto fopset = [&]() {
auto r = lua.script("c[5] = 18", sol::script_pass_on_error);
REQUIRE(r.valid());
};
auto fopget = [&]() {
auto r = lua.script("v3 = c[4]", sol::script_pass_on_error);
REQUIRE(r.valid());
};
REQUIRE_NOTHROW(ffind());
REQUIRE_NOTHROW(fget());
REQUIRE_NOTHROW(fset());
REQUIRE_NOTHROW(ferase());
REQUIRE_NOTHROW(fadd());
REQUIRE_NOTHROW(fopset());
REQUIRE_NOTHROW(fopget());
}
auto backit = std::begin(items);
std::size_t len = 0;
{
auto e = std::end(items);
auto last = backit;
for (; backit != e; ++backit, ++len) {
if (backit == e) {
break;
}
last = backit;
}
backit = last;
}
const int& first = *std::begin(items);
const int& last = *backit;
int i1 = lua["i1"];
int i2 = lua["i2"];
std::size_t s1 = lua["s1"];
std::size_t s2 = lua["s2"];
std::size_t s3 = lua["s3"];
int v1 = lua["v1"];
int v2 = lua["v2"];
int v3 = lua["v3"];
int values[] = {
11, 20, 13, 14, 18
};
{
std::size_t idx = 0;
for (const auto& i : items) {
const auto& v = values[idx];
REQUIRE(i == v);
++idx;
}
}
REQUIRE(first == 11);
REQUIRE(last == 18);
REQUIRE(s1 == 5);
REQUIRE(s2 == 5);
REQUIRE(s3 == 5);
REQUIRE(len == 5);
REQUIRE(i1 == 1);
REQUIRE(i2 == 4);
REQUIRE(v1 == 12);
REQUIRE(v2 == 15);
REQUIRE(v3 == 14);
}
TEST_CASE("containers/sequence containers", "check all of the functinos for every single container") {
SECTION("vector") {
sol::state lua;
lua.open_libraries(sol::lib::base);
std::vector<int> items{ 11, 12, 13, 14, 15 };
lua["c"] = &items;
sequence_container_check(lua, items);
}
SECTION("list") {
sol::state lua;
lua.open_libraries(sol::lib::base);
std::list<int> items{ 11, 12, 13, 14, 15 };
lua["c"] = &items;
sequence_container_check(lua, items);
}
SECTION("forward_list") {
sol::state lua;
lua.open_libraries(sol::lib::base);
std::forward_list<int> items{ 11, 12, 13, 14, 15 };
lua["c"] = &items;
sequence_container_check(lua, items);
}
SECTION("deque") {
sol::state lua;
lua.open_libraries(sol::lib::base);
std::deque<int> items{ 11, 12, 13, 14, 15 };
lua["c"] = &items;
sequence_container_check(lua, items);
}
}
TEST_CASE("containers/fixed containers", "check immutable container types") {
SECTION("array") {
sol::state lua;
lua.open_libraries(sol::lib::base);
std::array<int, 5> items{ 11, 12, 13, 14, 15 };
lua["c"] = &items;
fixed_container_check(lua, items);
}
SECTION("array ref") {
sol::state lua;
lua.open_libraries(sol::lib::base);
std::array<int, 5> items{ 11, 12, 13, 14, 15 };
lua["c"] = std::ref(items);
fixed_container_check(lua, items);
}
SECTION("c array") {
sol::state lua;
lua.open_libraries(sol::lib::base);
int items[5] = { 11, 12, 13, 14, 15 };
lua["c"] = &items;
fixed_container_check(lua, items);
}
SECTION("c array ref") {
sol::state lua;
lua.open_libraries(sol::lib::base);
int items[5] = { 11, 12, 13, 14, 15 };
lua["c"] = std::ref(items);
fixed_container_check(lua, items);
}
}
TEST_CASE("containers/ordered lookup containers", "check ordered container types") {
SECTION("set") {
sol::state lua;
lua.open_libraries(sol::lib::base);
std::set<int> items{ 11, 12, 13, 14, 15 };
lua["c"] = &items;
ordered_container_check(lua, items);
}
SECTION("multiset") {
sol::state lua;
lua.open_libraries(sol::lib::base);
std::multiset<int> items{ 11, 12, 13, 14, 15 };
lua["c"] = &items;
ordered_container_check(lua, items);
}
}
TEST_CASE("containers/unordered lookup containers", "check ordered container types") {
SECTION("unordered_set") {
sol::state lua;
lua.open_libraries(sol::lib::base);
std::unordered_set<int> items{ 11, 12, 13, 14, 15 };
lua["c"] = &items;
unordered_container_check(lua, items);
}
SECTION("unordered_multiset") {
sol::state lua;
lua.open_libraries(sol::lib::base);
std::unordered_multiset<int> items{ 11, 12, 13, 14, 15 };
lua["c"] = &items;
unordered_container_check(lua, items);
}
}
TEST_CASE("containers/associative ordered containers", "check associative (map) containers that are ordered fulfill basic functionality requirements") {
SECTION("map") {
sol::state lua;
lua.open_libraries(sol::lib::base);
std::map<short, int> items{
{ 11, 21 },
{ 12, 22 },
{ 13, 23 },
{ 14, 24 },
{ 15, 25 }
};
lua["c"] = &items;
associative_ordered_container_check(lua, items);
}
SECTION("multimap") {
sol::state lua;
lua.open_libraries(sol::lib::base);
std::multimap<short, int> items{
{ 11, 21 },
{ 12, 22 },
{ 13, 23 },
{ 14, 24 },
{ 15, 25 }
};
lua["c"] = &items;
associative_ordered_container_check(lua, items);
}
}
TEST_CASE("containers/associative unordered containers", "check associative (map) containers that are ordered that they fulfill basic functionality requirements") {
SECTION("unordered_map") {
sol::state lua;
lua.open_libraries(sol::lib::base);
std::unordered_map<short, int> items{
{ 11, 21 },
{ 12, 22 },
{ 13, 23 },
{ 14, 24 },
{ 15, 25 }
};
lua["c"] = &items;
associative_unordered_container_check(lua, items);
}
SECTION("unordered_multimap") {
sol::state lua;
lua.open_libraries(sol::lib::base);
std::unordered_multimap<short, int> items{
{ 11, 21 },
{ 12, 22 },
{ 13, 23 },
{ 14, 24 },
{ 15, 25 }
};
lua["c"] = &items;
associative_unordered_container_check(lua, items);
}
}

View File

@ -6,7 +6,10 @@
#include <iterator>
#include <vector>
#include <list>
#include <forward_list>
#include <map>
#include <deque>
#include <array>
#include <unordered_map>
#include <set>
#include <unordered_set>
@ -47,6 +50,29 @@ TEST_CASE("containers/returns", "make sure that even references to vectors are b
REQUIRE(matching);
}
TEST_CASE("containers/table conversion", "test table conversions with as_table and nested") {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.set_function("bark", []() {
return sol::as_nested(std::vector<std::string>{"bark", "woof"});
});
lua.set_function("woof", []() {
return sol::as_nested(std::vector<std::string>{"bark", "woof"});
});
lua.script("v1 = bark()");
lua.script("v2 = woof()");
sol::as_table_t<std::vector<std::string>> as_table_strings = lua["v"];
sol::nested<std::vector<std::string>> nested_strings = lua["v"];
std::vector<std::string> expected_values{"bark", "woof"};
REQUIRE(as_table_strings.source == expected_values);
REQUIRE(nested_strings.source == expected_values);
}
TEST_CASE("containers/vector roundtrip", "make sure vectors can be round-tripped") {
sol::state lua;
std::vector<int> v{ 1, 2, 3 };
@ -59,6 +85,30 @@ TEST_CASE("containers/vector roundtrip", "make sure vectors can be round-tripped
REQUIRE(areequal);
}
TEST_CASE("containers/deque roundtrip", "make sure deques can be round-tripped") {
sol::state lua;
std::deque<int> v{ 1, 2, 3 };
lua.set_function("f", [&]() -> std::deque<int>& {
return v;
});
lua.script("x = f()");
std::deque<int> x = lua["x"];
bool areequal = x == v;
REQUIRE(areequal);
}
TEST_CASE("containers/array roundtrip", "make sure arrays can be round-tripped") {
sol::state lua;
std::array<int, 3> v{ 1, 2, 3 };
lua.set_function("f", [&]() -> std::array<int, 3>& {
return v;
});
lua.script("x = f()");
std::array<int, 3> x = lua["x"];
bool areequal = x == v;
REQUIRE(areequal);
}
TEST_CASE("containers/list roundtrip", "make sure lists can be round-tripped") {
sol::state lua;
std::list<int> v{ 1, 2, 3 };
@ -71,6 +121,18 @@ TEST_CASE("containers/list roundtrip", "make sure lists can be round-tripped") {
REQUIRE(areequal);
}
TEST_CASE("containers/forward_list roundtrip", "make sure forward_lists can be round-tripped") {
sol::state lua;
std::forward_list<int> v{ 1, 2, 3 };
lua.set_function("f", [&]() -> std::forward_list<int>& {
return v;
});
lua.script("x = f()");
std::forward_list <int> x = lua["x"];
bool areequal = x == v;
REQUIRE(areequal);
}
TEST_CASE("containers/map roundtrip", "make sure maps can be round-tripped") {
sol::state lua;
std::map<std::string, int> v{ { "a", 1 },{ "b", 2 },{ "c", 3 } };
@ -119,6 +181,114 @@ TEST_CASE("containers/set roundtrip", "make sure sets can be round-tripped") {
REQUIRE(areequal);
}
TEST_CASE("containers/vector table roundtrip", "make sure vectors can be round-tripped") {
sol::state lua;
std::vector<int> v{ 1, 2, 3 };
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.script("x = f()");
sol::as_table_t<std::vector<int>> x = lua["x"];
bool areequal = x.source == v;
REQUIRE(areequal);
}
TEST_CASE("containers/deque table roundtrip", "make sure deques can be round-tripped") {
sol::state lua;
std::deque<int> v{ 1, 2, 3 };
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.script("x = f()");
sol::as_table_t<std::deque<int>> x = lua["x"];
bool areequal = x.source == v;
REQUIRE(areequal);
}
TEST_CASE("containers/array table roundtrip", "make sure arrays can be round-tripped") {
sol::state lua;
std::array<int, 3> v{ 1, 2, 3 };
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.script("x = f()");
sol::as_table_t<std::array<int, 3>> x = lua["x"];
bool areequal = x.source == v;
REQUIRE(areequal);
}
TEST_CASE("containers/list table roundtrip", "make sure lists can be round-tripped") {
sol::state lua;
std::list<int> v{ 1, 2, 3 };
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.script("x = f()");
sol::as_table_t<std::list <int>> x = lua["x"];
bool areequal = x.source == v;
REQUIRE(areequal);
}
TEST_CASE("containers/forward_list table roundtrip", "make sure forward_lists can be round-tripped") {
sol::state lua;
std::forward_list<int> v{ 1, 2, 3 };
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.script("x = f()");
sol::as_table_t<std::forward_list<int>> x = lua["x"];
bool areequal = x.source == v;
REQUIRE(areequal);
}
TEST_CASE("containers/map table roundtrip", "make sure maps can be round-tripped") {
sol::state lua;
std::map<std::string, int> v{ { "a", 1 },{ "b", 2 },{ "c", 3 } };
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.script("x = f()");
sol::as_table_t<std::map<std::string, int>> x = lua["x"];
bool areequal = x.source == v;
REQUIRE(areequal);
}
TEST_CASE("containers/unordered_map table roundtrip", "make sure unordered_maps can be round-tripped") {
sol::state lua;
std::unordered_map<std::string, int> v{ { "a", 1 },{ "b", 2 },{ "c", 3 } };
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.script("x = f()");
sol::as_table_t<std::unordered_map<std::string, int>> x = lua["x"];
bool areequal = x.source == v;
REQUIRE(areequal);
}
TEST_CASE("containers/unordered_set table roundtrip", "make sure unordered_sets can be round-tripped") {
sol::state lua;
std::unordered_set<int> v{ 1, 2, 3 };
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.script("x = f()");
sol::as_table_t<std::unordered_set<int>> x = lua["x"];
bool areequal = x.source == v;
REQUIRE(areequal);
}
TEST_CASE("containers/set table roundtrip", "make sure sets can be round-tripped") {
sol::state lua;
std::set<int> v{ 1, 2, 3 };
lua.set_function("f", [&]() {
return sol::as_table(v);
});
lua.script("x = f()");
sol::as_table_t<std::set<int>> x = lua["x"];
bool areequal = x.source == v;
REQUIRE(areequal);
}
TEST_CASE("containers/custom usertype", "make sure container usertype metatables can be overridden") {
typedef std::unordered_map<int, int> bark;
@ -176,8 +346,8 @@ TEST_CASE("containers/basic serialization", "make sure containers are turned int
);
}
#if 0 // glibc is a fuccboi
TEST_CASE("containers/const-serialization", "make sure containers are turned into proper userdata and the basic hooks respect const-ness") {
#if 0 // LUL const int holders
TEST_CASE("containers/const serialization", "make sure containers are turned into proper userdata and the basic hooks respect const-ness") {
typedef std::vector<const int> woof;
sol::state lua;
lua.open_libraries();
@ -187,7 +357,7 @@ TEST_CASE("containers/const-serialization", "make sure containers are turned int
);
REQUIRE_THROWS(lua.script("b[1] = 20"));
}
#endif // Fuck you, glibc
#endif
TEST_CASE("containers/table serialization", "ensure types can be serialized as tables still") {
typedef std::vector<int> woof;
@ -665,7 +835,7 @@ TEST_CASE("containers/non_copyable", "make sure non-copyable types in containers
}
TEST_CASE("containers/input_iterators", "test shitty input iterators that are all kinds of B L E H") {
TEST_CASE("containers/input iterators", "test shitty input iterators that are all kinds of B L E H") {
class int_shim {
public:
int_shim() = default;
@ -734,8 +904,7 @@ TEST_CASE("containers/input_iterators", "test shitty input iterators that are al
value_type fuck_off_gcc_warning() {
// "typedef not used locally"
// but it's used elsewhere in the code GCC
// so maybe your shitty warning should go
// fuck itself???
// so maybe your warning should sod off
return int_shim();
}

View File

@ -96,7 +96,7 @@ TEST_CASE("environments/shadowing", "Environments can properly shadow and fallba
}
SECTION("fallback") {
sol::environment env_with_fallback(lua, sol::create, lua.globals());
lua.script("a = 56", env_with_fallback, sol::default_on_error);
lua.script("a = 56", env_with_fallback, sol::script_default_on_error);
sol::optional<int> maybe_env_a = env_with_fallback["a"];
sol::optional<int> maybe_global_a = lua["a"];
sol::optional<int> maybe_env_b = env_with_fallback["b"];
@ -115,7 +115,7 @@ TEST_CASE("environments/shadowing", "Environments can properly shadow and fallba
sol::environment env_with_fallback(lua, sol::create, lua.globals());
lua["env"] = env_with_fallback;
sol::environment env = lua["env"];
lua.script("a = 56", env, sol::default_on_error);
lua.script("a = 56", env, sol::script_default_on_error);
sol::optional<int> maybe_env_a = env["a"];
sol::optional<int> maybe_global_a = lua["a"];
sol::optional<int> maybe_env_b = env["b"];

View File

@ -317,7 +317,7 @@ TEST_CASE("functions/function_result and protected_function_result", "Function r
auto nontrampolinefx = [](lua_State*) -> int { throw "x"; };
lua_CFunction c_nontrampolinefx = nontrampolinefx;
lua.set("nontrampoline", c_nontrampolinefx);
lua.set_function("bark", []() -> int {return 100; });
lua.set_function("bark", []() -> int { return 100; });
sol::function luahandler = lua["luahandler"];
sol::function cpphandler = lua["cpphandler"];
@ -866,7 +866,7 @@ TEST_CASE("overloading/c_call", "Make sure that overloading works with c_call fu
REQUIRE(r5 == 1);
}
TEST_CASE("functions/stack-protect", "make sure functions don't impede on the stack") {
TEST_CASE("functions/stack atomic", "make sure functions don't impede on the stack") {
//setup sol/lua
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::string);
@ -920,7 +920,7 @@ TEST_CASE("functions/stack-protect", "make sure functions don't impede on the st
REQUIRE(sg.check_stack());
}
TEST_CASE("functions/same-type-closures", "make sure destructions are per-object, not per-type, by destroying one type multiple times") {
TEST_CASE("functions/same type closures", "make sure destructions are per-object, not per-type, by destroying one type multiple times") {
static std::set<void*> last_my_closures;
static bool checking_closures = false;
static bool check_failed = false;
@ -959,7 +959,7 @@ TEST_CASE("functions/same-type-closures", "make sure destructions are per-object
REQUIRE(last_my_closures.size() == 2);
}
TEST_CASE("functions/stack-multi-return", "Make sure the stack is protected after multi-returns") {
TEST_CASE("functions/stack multi-return", "Make sure the stack is protected after multi-returns") {
sol::state lua;
lua.script("function f () return 1, 2, 3, 4, 5 end");
@ -982,7 +982,7 @@ TEST_CASE("functions/stack-multi-return", "Make sure the stack is protected afte
}
}
TEST_CASE("functions/protected-stack-multi-return", "Make sure the stack is protected after multi-returns") {
TEST_CASE("functions/protected stack multi-return", "Make sure the stack is protected after multi-returns") {
sol::state lua;
lua.script("function f () return 1, 2, 3, 4, 5 end");
@ -1005,7 +1005,65 @@ TEST_CASE("functions/protected-stack-multi-return", "Make sure the stack is prot
}
}
TEST_CASE("functions/overloaded-variadic", "make sure variadics work to some degree with overloading") {
TEST_CASE("functions/function_result as arguments", "ensure that function_result can be pushed as its results and not a userdata") {
sol::state lua;
lua.open_libraries();
lua.script("function f () return 1, 2, 3, 4, 5 end");
lua.script("function g (a, b, c, d, e) assert(a == 1) assert(b == 2) assert(c == 3) assert(d == 4) assert(e == 5) end");
{
sol::stack_guard sg(lua);
sol::stack::push(lua, double(256.78));
{
int a, b, c, d, e;
sol::stack_guard sg2(lua);
sol::function pf = lua["f"];
sol::tie(a, b, c, d, e) = pf();
REQUIRE(a == 1);
REQUIRE(b == 2);
REQUIRE(c == 3);
REQUIRE(d == 4);
REQUIRE(e == 5);
REQUIRE_NOTHROW([&]() {
lua["g"](pf());
}());
}
double f = sol::stack::pop<double>(lua);
REQUIRE(f == 256.78);
}
}
TEST_CASE("functions/protected_function_result as arguments", "ensure that protected_function_result can be pushed as its results and not a userdata") {
sol::state lua;
lua.open_libraries();
lua.script("function f () return 1, 2, 3, 4, 5 end");
lua.script("function g (a, b, c, d, e) assert(a == 1) assert(b == 2) assert(c == 3) assert(d == 4) assert(e == 5) end");
{
sol::stack_guard sg(lua);
sol::stack::push(lua, double(256.78));
{
int a, b, c, d, e;
sol::stack_guard sg2(lua);
sol::protected_function pf = lua["f"];
sol::tie(a, b, c, d, e) = pf();
REQUIRE(a == 1);
REQUIRE(b == 2);
REQUIRE(c == 3);
REQUIRE(d == 4);
REQUIRE(e == 5);
REQUIRE_NOTHROW([&]() {
lua["g"](pf());
}());
}
double f = sol::stack::pop<double>(lua);
REQUIRE(f == 256.78);
}
}
TEST_CASE("functions/overloaded variadic", "make sure variadics work to some degree with overloading") {
sol::state lua;
lua.open_libraries();
@ -1024,7 +1082,7 @@ TEST_CASE("functions/overloaded-variadic", "make sure variadics work to some deg
REQUIRE(c == 2.2);
}
TEST_CASE("functions/sectioning-variadic", "make sure variadics can bite off chunks of data") {
TEST_CASE("functions/sectioning variadic", "make sure variadics can bite off chunks of data") {
sol::state lua;
lua.open_libraries(sol::lib::base);
@ -1047,7 +1105,7 @@ TEST_CASE("functions/sectioning-variadic", "make sure variadics can bite off chu
lua.script("print(x3) assert(x3 == 18)");
}
TEST_CASE("functions/set_function-already-wrapped", "setting a function returned from Lua code that is already wrapped into a sol::function or similar") {
TEST_CASE("functions/set_function already wrapped", "setting a function returned from Lua code that is already wrapped into a sol::function or similar") {
SECTION("test different types") {
sol::state lua;
lua.open_libraries(sol::lib::base);
@ -1118,7 +1176,7 @@ TEST_CASE("functions/set_function-already-wrapped", "setting a function returned
}
}
TEST_CASE("functions/pointer-nil", "ensure specific semantics for handling pointer-nils passed through sol") {
TEST_CASE("functions/pointer nullptr + nil", "ensure specific semantics for handling pointer-nils passed through sol") {
struct nil_test {
static void f(nil_test* p) {
@ -1282,7 +1340,7 @@ TEST_CASE("functions/pointer-nil", "ensure specific semantics for handling point
}
}
TEST_CASE("functions/unique_usertype-overloading", "make sure overloading can work with ptr vs. specifically asking for a unique_usertype") {
TEST_CASE("functions/unique_usertype overloading", "make sure overloading can work with ptr vs. specifically asking for a unique_usertype") {
struct test {
int special_value = 17;
test() : special_value(17) {}

View File

@ -58,7 +58,7 @@ TEST_CASE("inheritance/basic", "test that metatables are properly inherited") {
REQUIRE(a == 5);
}
TEST_CASE("inheritance/multi-base", "test that multiple bases all work and overloading for constructors works with them") {
TEST_CASE("inheritance/multi base", "test that multiple bases all work and overloading for constructors works with them") {
class TestClass00 {
public:
int Thing() const { return 123; }
@ -153,7 +153,7 @@ tc3 = TestClass03(tc1)
REQUIRE(tc3.c == 1);
}
TEST_CASE("inheritance/simple-multi-base", "test that multiple bases all work and overloading for constructors works with them") {
TEST_CASE("inheritance/simple multi base", "test that multiple bases all work and overloading for constructors works with them") {
class TestClass00 {
public:
int Thing() const { return 123; }

View File

@ -4,7 +4,7 @@
#include <sol.hpp>
TEST_CASE("issues/stack-overflow", "make sure various operations repeated don't trigger stack overflow") {
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");
@ -30,7 +30,7 @@ TEST_CASE("issues/stack-overflow", "make sure various operations repeated don't
}
TEST_CASE("issues/stack-overflow-2", "make sure basic iterators clean up properly when they're not iterated through (e.g., with empty())") {
TEST_CASE("issues/stack overflow 2", "make sure basic iterators clean up properly when they're not iterated through (e.g., with empty())") {
sol::state lua;
sol::table t = lua.create_table_with(1, "wut");
int MAX = 50000;

View File

@ -87,7 +87,7 @@ TEST_CASE("simple_usertype/usertypes", "Ensure that simple usertypes properly wo
REQUIRE(z == 29);
}
TEST_CASE("simple_usertype/usertypes-constructors", "Ensure that calls with specific arguments work") {
TEST_CASE("simple_usertype/usertype constructors", "Ensure that calls with specific arguments work") {
struct marker {
bool value = false;
};
@ -173,7 +173,7 @@ TEST_CASE("simple_usertype/usertypes-constructors", "Ensure that calls with spec
REQUIRE(z == 29);
}
TEST_CASE("simple_usertype/shared-ptr-regression", "simple usertype metatables should not screw over unique usertype metatables") {
TEST_CASE("simple_usertype/shared_ptr regression", "simple usertype metatables should not screw over unique usertype metatables") {
static int created = 0;
static int destroyed = 0;
struct test {
@ -322,7 +322,7 @@ TEST_CASE("simple_usertype/variable-control", "test to see if usertypes respond
lua.script("print(sw.pb)assert(sw.pb == 27)");
}
TEST_CASE("simple_usertype/factory-constructor-overload-usage", "simple usertypes should probably invoke types") {
TEST_CASE("simple_usertype/factory constructor overloads", "simple usertypes should invoke the proper factories") {
class A {
public:
virtual void a() { throw std::runtime_error("entered base pure virtual implementation"); };
@ -378,7 +378,7 @@ TEST_CASE("simple_usertype/factory-constructor-overload-usage", "simple usertype
REQUIRE(y4 == 3);
}
TEST_CASE("simple_usertype/runtime-append", "allow extra functions to be appended at runtime directly to the metatable itself") {
TEST_CASE("simple_usertype/runtime append", "allow extra functions to be appended at runtime directly to the metatable itself") {
class A {
};
@ -407,7 +407,7 @@ TEST_CASE("simple_usertype/runtime-append", "allow extra functions to be appende
REQUIRE(w == 100);
}
TEST_CASE("simple_usertype/destruction-test", "make sure usertypes are properly destructed and don't double-delete memory or segfault") {
TEST_CASE("simple_usertype/destruction test", "make sure usertypes are properly destructed and don't double-delete memory or segfault") {
sol::state lua;
class CrashClass {
@ -438,7 +438,7 @@ TEST_CASE("simple_usertype/destruction-test", "make sure usertypes are properly
}
}
TEST_CASE("simple_usertype/table-append", "Ensure that appending to the meta table also affects the internal function table for pointers as well") {
TEST_CASE("simple_usertype/table append", "Ensure that appending to the meta table also affects the internal function table for pointers as well") {
struct A {
int func() {
return 5000;
@ -462,7 +462,7 @@ TEST_CASE("simple_usertype/table-append", "Ensure that appending to the meta tab
}());
}
TEST_CASE("simple_usertype/class-propogation", "make sure methods and variables from base classes work properly in SAFE_USERTYPE mode") {
TEST_CASE("simple_usertype/class call propogation", "make sure methods and variables from base classes work properly in SAFE_USERTYPE mode") {
class A {
public:
int var = 200;
@ -488,7 +488,7 @@ TEST_CASE("simple_usertype/class-propogation", "make sure methods and variables
)");
}
TEST_CASE("simple_usertype/call-constructor", "ensure that all kinds of call-based constructors can be serialized") {
TEST_CASE("simple_usertype/call constructor", "ensure that all kinds of call-based constructors can be serialized") {
struct thing {};
struct v_test {
@ -589,7 +589,7 @@ TEST_CASE("simple_usertype/no_constructor", "make sure simple usertype errors wh
}
}
TEST_CASE("simple_usertype/missing-key", "make sure a missing key returns nil") {
TEST_CASE("simple_usertype/missing key", "make sure a missing key returns nil") {
struct thing {};
sol::state lua;
@ -599,7 +599,7 @@ TEST_CASE("simple_usertype/missing-key", "make sure a missing key returns nil")
REQUIRE_NOTHROW(lua.script("print(thing.missingKey)"));
}
TEST_CASE("simple_usertype/runtime-extensibility", "Check if usertypes are runtime extensible") {
TEST_CASE("simple_usertype/runtime extensibility", "Check if usertypes are runtime extensible") {
struct thing {
int v = 20;
int func(int a) { return a; }
@ -697,7 +697,7 @@ end
}
}
TEST_CASE("simple_usertype/runtime-replacement", "ensure that functions can be properly replaced at runtime for non-indexed things") {
TEST_CASE("simple_usertype/runtime replacement", "ensure that functions can be properly replaced at runtime for non-indexed things") {
struct heart_base_t {};
struct heart_t : heart_base_t {
void func() {}
@ -775,7 +775,7 @@ TEST_CASE("simple_usertype/runtime-replacement", "ensure that functions can be p
}
}
TEST_CASE("simple_usertype/meta-key-retrievals", "allow for special meta keys (__index, __newindex) to trigger methods even if overwritten directly") {
TEST_CASE("simple_usertype/meta key retrievals", "allow for special meta keys (__index, __newindex) to trigger methods even if overwritten directly") {
SECTION("dynamically") {
static int writes = 0;
static std::string keys[4] = {};
@ -841,7 +841,7 @@ TEST_CASE("simple_usertype/meta-key-retrievals", "allow for special meta keys (_
}
}
TEST_CASE("simple_usertype/static-properties", "allow for static functions to get and set things as a property") {
TEST_CASE("simple_usertype/static properties", "allow for static functions to get and set things as a property") {
static int b = 50;
struct test_t {
static double s_func() {
@ -900,7 +900,7 @@ TEST_CASE("simple_usertype/indexing", "make sure simple usertypes can be indexed
}
};
SECTION("no-runtime-additions") {
SECTION("no runtime additions") {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_simple_usertype<indexing_test>("test",
@ -918,7 +918,7 @@ TEST_CASE("simple_usertype/indexing", "make sure simple usertypes can be indexed
REQUIRE(v == 2);
REQUIRE(val == 50);
}
SECTION("runtime-additions") {
SECTION("runtime additions") {
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_simple_usertype<indexing_test>("test",

View File

@ -102,7 +102,7 @@ TEST_CASE("state/require", "opening using a file") {
// REQUIRE(thingy1 == thingy2);
}
TEST_CASE("state/multi-require", "make sure that requires transfers across hand-rolled script implementation and standard requiref") {
TEST_CASE("state/multi require", "make sure that requires transfers across hand-rolled script implementation and standard requiref") {
struct open {
static int open_func(lua_State* L) {
sol::state_view lua = L;
@ -145,7 +145,7 @@ return 'test3')");
REQUIRE(t3 == "test3");
}
TEST_CASE("state/leak-check", "make sure there are no humongous memory leaks in iteration") {
TEST_CASE("state/leak check", "make sure there are no humongous memory leaks in iteration") {
#if 0
sol::state lua;
lua.script(R"(
@ -194,7 +194,7 @@ end
#endif
}
TEST_CASE("state/script-returns", "make sure script returns are done properly") {
TEST_CASE("state/script returns", "make sure script returns are done properly") {
std::string script =
R"(
local example =
@ -271,7 +271,7 @@ return example;
lua.script("bar() bar2() foo(1) foo2(1)");
}
TEST_CASE("state/copy-move", "ensure state can be properly copied and moved") {
TEST_CASE("state/copy and move", "ensure state can be properly copied and moved") {
sol::state lua;
lua["a"] = 1;
@ -292,7 +292,7 @@ TEST_CASE("state/requires-reload", "ensure that reloading semantics do not cause
lua.script("require 'io'\nreturn 'test3'");
}
TEST_CASE("state/script-do-load", "test success and failure cases for loading and running scripts") {
TEST_CASE("state/script, do, and load", "test success and failure cases for loading and running scripts") {
const static std::string bad_syntax = "weird\n%$@symb\nols";
static const char file_bad_syntax[] = "./temp.bad_syntax.lua";
const static std::string bad_runtime = "bad.code = 20";
@ -311,13 +311,13 @@ TEST_CASE("state/script-do-load", "test success and failure cases for loading an
SECTION("script-handler") {
sol::state lua;
sol::stack_guard sg(lua);
auto errbs = lua.script(bad_syntax, sol::simple_on_error);
auto errbs = lua.script(bad_syntax, sol::script_pass_on_error);
REQUIRE(!errbs.valid());
auto errbr = lua.script(bad_runtime, sol::simple_on_error);
auto errbr = lua.script(bad_runtime, sol::script_pass_on_error);
REQUIRE(!errbr.valid());
auto result = lua.script(good, sol::simple_on_error);
auto result = lua.script(good, sol::script_pass_on_error);
int a = lua["a"];
int ar = result;
REQUIRE(result.valid());
@ -381,13 +381,13 @@ TEST_CASE("state/script-do-load", "test success and failure cases for loading an
SECTION("script_file-handler") {
sol::state lua;
sol::stack_guard sg(lua);
auto errbs = lua.script_file(file_bad_syntax, sol::simple_on_error);
auto errbs = lua.script_file(file_bad_syntax, sol::script_pass_on_error);
REQUIRE(!errbs.valid());
auto errbr = lua.script_file(file_bad_runtime, sol::simple_on_error);
auto errbr = lua.script_file(file_bad_runtime, sol::script_pass_on_error);
REQUIRE(!errbr.valid());
auto result = lua.script_file(file_good, sol::simple_on_error);
auto result = lua.script_file(file_good, sol::script_pass_on_error);
int a = lua["a"];
int ar = result;
REQUIRE(result.valid());

View File

@ -27,7 +27,7 @@ int plop_xyz(int x, int y, std::string z) {
return 11;
}
TEST_CASE("tables/as-enums", "Making sure enums can be put in and gotten out as values") {
TEST_CASE("tables/as enums", "Making sure enums can be put in and gotten out as values") {
enum direction {
up,
down,
@ -52,7 +52,7 @@ TEST_CASE("tables/as-enums", "Making sure enums can be put in and gotten out as
REQUIRE(dir == direction::up);
}
TEST_CASE("tables/as-enum-classes", "Making sure enums can be put in and gotten out as values") {
TEST_CASE("tables/as enum classes", "Making sure enums can be put in and gotten out as values") {
enum class direction {
up,
down,
@ -93,7 +93,7 @@ TEST_CASE("tables/cleanup", "make sure tables leave the stack balanced") {
}
}
TEST_CASE("tables/nested-cleanup", "make sure tables leave the stack balanced") {
TEST_CASE("tables/nested cleanup", "make sure tables leave the stack balanced") {
sol::state lua;
lua.open_libraries();
@ -138,7 +138,7 @@ TEST_CASE("tables/new_enum", "Making sure enums can be put in and gotten out as
REQUIRE(d == direction::left);
}
TEST_CASE("tables/for-each", "Testing the use of for_each to get values from a lua table") {
TEST_CASE("tables/for_each", "Testing the use of for_each to get values from a lua table") {
sol::state lua;
lua.open_libraries(sol::lib::base);
@ -195,7 +195,7 @@ TEST_CASE("tables/for-each", "Testing the use of for_each to get values from a l
REQUIRE(iterations == tablesize);
}
TEST_CASE("tables/for-each-empty", "empty tables should not crash") {
TEST_CASE("tables/for_each empty", "empty tables should not crash") {
sol::state lua;
lua.open_libraries(sol::lib::base);
@ -329,7 +329,7 @@ TEST_CASE("tables/create", "Check if creating a table is kosher") {
REQUIRE((testtable[3] == 4));
}
TEST_CASE("tables/create-local", "Check if creating a table is kosher") {
TEST_CASE("tables/create local", "Check if creating a table is kosher") {
sol::state lua;
lua["testtable"] = lua.create_table(0, 0, "Woof", "Bark", 1, 2, 3, 4);
sol::object testobj = lua["testtable"];
@ -340,7 +340,7 @@ TEST_CASE("tables/create-local", "Check if creating a table is kosher") {
REQUIRE((testtable[3] == 4));
}
TEST_CASE("tables/create-local-named", "Check if creating a table is kosher") {
TEST_CASE("tables/create local named", "Check if creating a table is kosher") {
sol::state lua;
sol::table testtable = lua.create_table("testtable", 0, 0, "Woof", "Bark", 1, 2, 3, 4);
sol::object testobj = lua["testtable"];
@ -363,7 +363,7 @@ TEST_CASE("tables/create-with-local", "Check if creating a table is kosher") {
REQUIRE((testtable[3] == 4));
}
TEST_CASE("tables/functions-variables", "Check if tables and function calls work as intended") {
TEST_CASE("tables/function variables", "Check if tables and function calls work as intended") {
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::os);
auto run_script = [](sol::state& lua) -> void {
@ -466,7 +466,7 @@ TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works
REQUIRE_NOTHROW(assert1(lua.globals()));
}
TEST_CASE("tables/operator[]-valid", "Test if proxies on tables can lazily evaluate validity") {
TEST_CASE("tables/operator[] valid", "Test if proxies on tables can lazily evaluate validity") {
sol::state lua;
bool isFullScreen = false;
auto fullscreennopers = lua["fullscreen"]["nopers"];
@ -488,7 +488,7 @@ TEST_CASE("tables/operator[]-valid", "Test if proxies on tables can lazily evalu
REQUIRE_FALSE(isFullScreen);
}
TEST_CASE("tables/operator[]-optional", "Test if proxies on tables can lazily evaluate validity") {
TEST_CASE("tables/operator[] optional", "Test if proxies on tables can lazily evaluate validity") {
sol::state lua;
sol::optional<int> test1 = lua["no_exist_yet"];
@ -547,7 +547,7 @@ TEST_CASE("tables/add", "Basic test to make sure the 'add' feature works") {
}
}
TEST_CASE("tables/bool-keys", "make sure boolean keys don't get caught up in `is_integral` specializations") {
TEST_CASE("tables/boolean keys", "make sure boolean keys don't get caught up in `is_integral` specializations") {
sol::state lua;
lua.open_libraries(sol::lib::base);
@ -573,13 +573,13 @@ print(tbl[1])
REQUIRE(v2 == 40);
}
TEST_CASE("tables/optional-move", "ensure pushing a sol::optional<T> rvalue correctly moves the contained object"){
TEST_CASE("tables/optional move", "ensure pushing a sol::optional<T> rvalue correctly moves the contained object into tables") {
sol::state sol_state;
struct move_only{
struct move_only {
int secret_code;
move_only(const move_only&) = delete;
move_only(move_only&&) = default;
};
sol_state["requires_move"] = sol::optional<move_only>{move_only{0x4D}};
sol_state["requires_move"] = sol::optional<move_only>{ move_only{ 0x4D } };
REQUIRE(sol_state["requires_move"].get<move_only>().secret_code == 0x4D);
}

View File

@ -3,11 +3,30 @@
#include <catch.hpp>
#include <sol.hpp>
#include <thread>
#ifdef SOL_CXX17_FEATURES
#include <string_view>
#include <variant>
#endif
void basic_initialization_and_lib_open() {
sol::state lua;
try {
lua.open_libraries();
lua["a"] = 24;
int a = lua["a"];
REQUIRE(a == 24);
}
catch (const sol::error& e) {
INFO(e.what());
REQUIRE(false);
}
catch (...) {
REQUIRE(false);
}
}
TEST_CASE("utility/variant", "test that variant can be round-tripped") {
#ifdef SOL_CXX17_FEATURES
@ -67,3 +86,64 @@ TEST_CASE("utility/string_view", "test that string_view can be taken as an argum
REQUIRE(true);
#endif // C++17
}
TEST_CASE("utility/thread", "fire up lots of threads at the same time to make sure the initialization changes do not cause horrible crashing data races") {
REQUIRE_NOTHROW([]() {
std::thread thrds[16];
for (int i = 0; i < 16; i++) {
thrds[i] = std::thread(&basic_initialization_and_lib_open);
}
for (int i = 0; i < 16; i++) {
thrds[i].join();
}
}());
}
TEST_CASE("utility/this_state", "Ensure this_state argument can be gotten anywhere in the function.") {
struct bark {
int with_state(sol::this_state l, int a, int b) {
lua_State* L = l;
int c = lua_gettop(L);
return a + b + (c - c);
}
static int with_state_2(int a, sol::this_state l, int b) {
INFO("inside with_state_2");
lua_State* L = l;
INFO("L is" << (void*)L);
int c = lua_gettop(L);
return a * b + (c - c);
}
};
sol::state lua;
INFO("created lua state");
lua.open_libraries(sol::lib::base);
lua.new_usertype<bark>("bark",
"with_state", &bark::with_state
);
INFO("setting b and with_state_2");
bark b;
lua.set("b", &b);
lua.set("with_state_2", bark::with_state_2);
INFO("finished setting");
INFO("getting fx");
sol::function fx = lua["with_state_2"];
INFO("calling fx");
int a = fx(25, 25);
INFO("finished setting fx");
INFO("calling a script");
lua.script("a = with_state_2(25, 25)");
INFO("calling c script");
lua.script("c = b:with_state(25, 25)");
INFO("getting a");
int la = lua["a"];
INFO("getting b");
int lc = lua["c"];
REQUIRE(lc == 50);
REQUIRE(a == 625);
REQUIRE(la == 625);
}

View File

@ -180,3 +180,52 @@ TEST_CASE("variadics/variadic_results", "returning a variable amount of argument
REQUIRE(v7 == "borf");
}
}
TEST_CASE("variadics/fallback_constructor", "ensure constructor matching behaves properly in the presence of variadic fallbacks") {
struct vec2 { float x, y; };
sol::state lua;
lua.new_simple_usertype<vec2>("vec2",
sol::call_constructor, sol::factories([]() {
return vec2{};
}, [](vec2 const& v) {
return vec2{ v };
}, [](sol::variadic_args va) {
vec2 res{};
if (va.size() == 1) {
res.x = va[0].get<float>();
res.y = va[0].get<float>();
}
else if (va.size() == 2) {
res.x = va[0].get<float>();
res.y = va[1].get<float>();
}
else {
throw sol::error("invalid args");
}
return res;
})
);
REQUIRE_NOTHROW([&]() {
lua.script("v0 = vec2();");
lua.script("v1 = vec2(1);");
lua.script("v2 = vec2(1, 2);");
lua.script("v3 = vec2(v2)");
}());
vec2& v0 = lua["v0"];
vec2& v1 = lua["v1"];
vec2& v2 = lua["v2"];
vec2& v3 = lua["v3"];
REQUIRE(v0.x == 0);
REQUIRE(v0.y == 0);
REQUIRE(v1.x == 1);
REQUIRE(v1.y == 1);
REQUIRE(v2.x == 1);
REQUIRE(v2.y == 2);
REQUIRE(v3.x == v2.x);
REQUIRE(v3.y == v2.y);
}

View File

@ -121,7 +121,7 @@ TEST_CASE("simple/get", "Tests if the get function works properly.") {
} REQUIRE(begintop == endtop);
}
TEST_CASE("simple/set-get-global-integer", "Tests if the get function works properly with global integers") {
TEST_CASE("simple/set and get global integer", "Tests if the get function works properly with global integers") {
sol::state lua;
lua[1] = 25.4;
lua.script("b = 1");
@ -148,7 +148,7 @@ TEST_CASE("simple/get_or", "check if table.get_or works correctly") {
REQUIRE(bark == 55.6);
}
TEST_CASE("simple/proxy_get_or", "check if proxy.get_or works correctly") {
TEST_CASE("simple/proxy get_or", "check if proxy.get_or works correctly") {
sol::state lua;
auto bob_table = lua.create_table("bob");
@ -186,7 +186,7 @@ TEST_CASE("simple/if", "check if if statements work through lua") {
REQUIRE((f == lua["f"]));
}
TEST_CASE("negative/basic_errors", "Check if error handling works correctly") {
TEST_CASE("negative/basic errors", "Check if error handling works correctly") {
sol::state lua;
REQUIRE_THROWS(lua.script("nil[5]"));
@ -227,54 +227,6 @@ TEST_CASE("interop/null-to-nil-and-back", "nil should be the given type when a p
"assert(x == nil)"));
}
TEST_CASE("utilities/this_state", "Ensure this_state argument can be gotten anywhere in the function.") {
struct bark {
int with_state(sol::this_state l, int a, int b) {
lua_State* L = l;
int c = lua_gettop(L);
return a + b + (c - c);
}
static int with_state_2(int a, sol::this_state l, int b) {
INFO("inside with_state_2");
lua_State* L = l;
INFO("L is" << (void*)L);
int c = lua_gettop(L);
return a * b + (c - c);
}
};
sol::state lua;
INFO("created lua state");
lua.open_libraries(sol::lib::base);
lua.new_usertype<bark>("bark",
"with_state", &bark::with_state
);
INFO("setting b and with_state_2");
bark b;
lua.set("b", &b);
lua.set("with_state_2", bark::with_state_2);
INFO("finished setting");
INFO("getting fx");
sol::function fx = lua["with_state_2"];
INFO("calling fx");
int a = fx(25, 25);
INFO("finished setting fx");
INFO("calling a script");
lua.script("a = with_state_2(25, 25)");
INFO("calling c script");
lua.script("c = b:with_state(25, 25)");
INFO("getting a");
int la = lua["a"];
INFO("getting b");
int lc = lua["c"];
REQUIRE(lc == 50);
REQUIRE(a == 625);
REQUIRE(la == 625);
}
TEST_CASE("object/conversions", "make sure all basic reference types can be made into objects") {
sol::state lua;
lua.open_libraries(sol::lib::base);
@ -329,7 +281,7 @@ TEST_CASE("object/conversions", "make sure all basic reference types can be made
REQUIRE(oenv.get_type() == sol::type::table);
}
TEST_CASE("feature/indexing-overrides", "make sure index functions can be overridden on types") {
TEST_CASE("feature/indexing overrides", "make sure index functions can be overridden on types") {
struct PropertySet {
sol::object get_property_lua(const char* name, sol::this_state s)
{
@ -374,7 +326,7 @@ print('name = ' .. obj.props.name)
REQUIRE(name == "test name");
}
TEST_CASE("features/indexing-numbers", "make sure indexing functions can be override on usertypes") {
TEST_CASE("features/indexing numbers", "make sure indexing functions can be override on usertypes") {
class vector {
public:
double data[3];
@ -415,7 +367,7 @@ TEST_CASE("features/indexing-numbers", "make sure indexing functions can be over
REQUIRE(v[2] == 3.0);
}
TEST_CASE("features/multiple-inheritance", "Ensure that multiple inheritance works as advertised") {
TEST_CASE("features/multiple inheritance", "Ensure that multiple inheritance works as advertised") {
struct base1 {
int a1 = 250;
};
@ -494,7 +446,7 @@ TEST_CASE("regressions/std::ref", "Ensure that std::reference_wrapper<> isn't co
REQUIRE(vr.a1 == 568);
}
TEST_CASE("optional/left-out-args", "Make sure arguments can be left out of optional without tanking miserably") {
TEST_CASE("optional/left out args", "Make sure arguments can be left out of optional without tanking miserably") {
sol::state lua;
lua.open_libraries(sol::lib::base);
@ -563,7 +515,7 @@ TEST_CASE("proxy/equality", "check to make sure equality tests work") {
REQUIRE((lua["a"] == 2)); //1
}
TEST_CASE("compilation/const-regression", "make sure constness in tables is respected all the way down") {
TEST_CASE("compilation/const regression", "make sure constness in tables is respected all the way down") {
struct State {
public:
State() {
@ -601,7 +553,7 @@ TEST_CASE("numbers/integers", "make sure integers are detectable on most platfor
REQUIRE(b_is_double);
}
TEST_CASE("object/is-method", "test whether or not the is abstraction works properly for a user-defined type") {
TEST_CASE("object/is", "test whether or not the is abstraction works properly for a user-defined type") {
struct thing {};
SECTION("stack_object")