mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
add as_container documentation
improve exception documentation improve state_view default handlers add SAFE_PROPAGATION defines for compiling C++ as Lua add examples for automatic operator registrations and as_container fix tutorial code change tests to not throw unless absolutely necessary provide synchronization for file writing in tests provide thread safety around thread tests for REQUIRE add ostream automatic support change 5.1 compat to only kick in luaL_loadbufferx and luaL_loadfilex when LuaJIT is version 2.0.1 and lower
This commit is contained in:
parent
eef1a32eef
commit
eb1560d12a
31
.travis.yml
31
.travis.yml
|
@ -31,6 +31,8 @@ notifications:
|
|||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
# linux machines
|
||||
# gcc
|
||||
- os: linux
|
||||
env: COMPILER=g++-4.9 LUA_VERSION=lua52
|
||||
compiler: gcc
|
||||
|
@ -44,20 +46,6 @@ matrix:
|
|||
- ninja-build
|
||||
- liblua5.2-dev
|
||||
|
||||
# gcc-4.9
|
||||
- os: linux
|
||||
env: COMPILER=g++-4.9 LUA_VERSION=luajit51
|
||||
compiler: gcc
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-4.9
|
||||
- g++-4.9
|
||||
- ninja-build
|
||||
- libluajit-5.1-dev
|
||||
|
||||
# gcc-5
|
||||
- os: linux
|
||||
env: COMPILER=g++-5 LUA_VERSION=lua52
|
||||
|
@ -254,11 +242,6 @@ matrix:
|
|||
compiler: gcc
|
||||
env: COMPILER=g++-4.9 LUA_VERSION=lua53
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode8.3
|
||||
compiler: gcc
|
||||
env: COMPILER=g++-5 LUA_VERSION=lua53
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode8.3
|
||||
compiler: gcc
|
||||
|
@ -266,8 +249,13 @@ matrix:
|
|||
|
||||
- os: osx
|
||||
osx_image: xcode8.3
|
||||
compiler: clang
|
||||
env: COMPILER=appleclang LUA_VERSION=luajit
|
||||
compiler: gcc
|
||||
env: COMPILER=g++-5 LUA_VERSION=lua52
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode8.3
|
||||
compiler: gcc
|
||||
env: COMPILER=g++-5 LUA_VERSION=lua53
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode8.3
|
||||
|
@ -277,3 +265,4 @@ matrix:
|
|||
allow_failures:
|
||||
- os: osx
|
||||
compiler: clang
|
||||
compiler: gcc
|
||||
|
|
|
@ -20,6 +20,7 @@ Browse the various function and classes :doc:`Sol<../index>` utilizes to make yo
|
|||
this_environment
|
||||
proxy
|
||||
containers
|
||||
as_container
|
||||
nested
|
||||
as_table
|
||||
usertype
|
||||
|
|
23
docs/source/api/as_container.rst
Normal file
23
docs/source/api/as_container.rst
Normal file
|
@ -0,0 +1,23 @@
|
|||
as_container
|
||||
============
|
||||
*force a type to be viewed as a container-type when serialized to Lua*
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
template <typename T>
|
||||
struct as_returns_t { ... };
|
||||
|
||||
template <typename T>
|
||||
as_returns_t<T> as_returns( T&& );
|
||||
|
||||
|
||||
Sometimes, you have a type whose metatable you claim with a usertype metatable via :doc:`usertype semantics<usertype>`. But, it still has parts of it that make it behave like a container in C++: A ``value_type`` typedef, an ``iterator`` typedef, a ``begin``, an ``end``, and other things that satisfy the `Container requirements`_ or the `Sequence Container requirements`_ or behaves like a `forward_list`_.
|
||||
|
||||
Whatever the case is, you need it to be returned to Lua and have many of the traits and functionality described in the :doc:`containers documentation<../containers>`. Wrap a return type or a setter in ``sol::as_container( value );`` to allow for a type to be treated like a container, regardless of whether ``sol::is_container`` triggers or not.
|
||||
|
||||
See `this container example`_ to see how it works.
|
||||
|
||||
.. _this container example: https://github.com/ThePhD/sol2/blob/develop/examples/container_as_container.cpp
|
||||
.. _Container requirements: http://en.cppreference.com/w/cpp/concept/Container
|
||||
.. _Sequence Container requirements: http://en.cppreference.com/w/cpp/concept/SequenceContainer
|
||||
.. _forward_list: http://en.cppreference.com/w/cpp/container/forward_list
|
|
@ -7,7 +7,7 @@ Sol2 automatically converts containers (detected using the ``sol::is_container<T
|
|||
|
||||
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.
|
||||
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. You can also force something that is marked as not-a-container by using :doc:`sol::as_container<as_container>`.
|
||||
|
||||
|
||||
a complete example
|
||||
|
|
|
@ -7,9 +7,15 @@ error
|
|||
|
||||
class error : public std::runtime_error {
|
||||
public:
|
||||
error(const std::string& str): std::runtime_error("Lua: error: " + str) {}
|
||||
error(const std::string& str): std::runtime_error("lua: error: " + str) {}
|
||||
};
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
Please do not throw this error type yourself. It belongs to the library and we do some information appending at the front.
|
||||
|
||||
|
||||
If an eror is thrown by Sol, it is going to be of this type. We use this in a single place: the default ``at_panic`` function we bind on construction of a :ref:`sol::state<set-panic>`. If you turn :doc:`off exceptions<../exceptions>`, the chances of you seeing this error are nil unless you specifically use it to pull errors out of things such as :doc:`sol::protected_function<protected_function>`.
|
||||
|
||||
As it derives from ``std::runtime_error``, which derives from ``std::exception``, you can catch it with a ``catch (const std::exception& )`` clause in your try/catch blocks. You can retrieve a string error from Lua (Lua pushes all its errors as string returns) by using this type with any of the get or lookup functions in Sol.
|
|
@ -13,6 +13,12 @@ The most important class here is ``state_view``. This structure takes a ``lua_St
|
|||
|
||||
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.
|
||||
|
||||
``state_view`` is cheap to construct and creates 2 references to things in the ``lua_State*`` while it is alive: the global Lua table, and the Lua C Registry.
|
||||
|
||||
.. warning::
|
||||
|
||||
It is your responsibility to make sure ``sol::state_view`` goes out of scope before you call ``lua_close`` on a pre-existing state, or before ``sol::state`` goes out of scope and its destructor gets called. Failure to do so can result in intermittent crashes because the ``sol::state_view`` has outstanding references to an already-dead ``lua_State*``, and thusly will try to decrement the reference counts for the Lua Registry and the Global Table on a dead state. Please use ``{`` and ``}`` to create a new scope when you know you are going to call ``lua_close`` to specifically control the lifetime of an object.
|
||||
|
||||
enumerations
|
||||
------------
|
||||
|
||||
|
|
|
@ -189,17 +189,37 @@ If you don't specify anything at all and the type is `destructible`_, then a des
|
|||
- If you just want the default constructor, you can replace the second argument with ``sol::default_destructor``
|
||||
- The usertype will error / throw if you specify a destructor specifically but do not map it to ``sol::meta_function::gc`` or a string equivalent to ``"__gc"``
|
||||
|
||||
.. note::
|
||||
|
||||
You MUST specify ``sol::destructor`` around your destruction function, otherwise it will be ignored.
|
||||
|
||||
|
||||
|
||||
usertype regular function options
|
||||
+++++++++++++++++++++++++++++++++
|
||||
|
||||
If you don't specify anything at all and the type ``T`` supports ``operator <``, ``operator <=``, or ``operator==`` (``const`` or non-``const`` qualified):
|
||||
If you don't specify a ``sol::meta_function`` name (or equivalent string metamethod name) and the type ``T`` supports certain operations, sol2 will generate the following operations provided it can find a good default implementation:
|
||||
|
||||
* for ``operator <`` and ``operator <=``
|
||||
- These two ``sol::meta_function::less_than(_or_equal_to)`` are generated for you and overriden in Lua.
|
||||
* for ``to_string`` operations where ``std::ostream& operator<<( std::ostream&, const T& )`` exists on the C++ type
|
||||
- a ``sol::meta_function::to_string`` operator will be generated
|
||||
- writing is done into a ``std::ostringstream`` before the underlying string is serialized into Lua
|
||||
* for call operations where ``operator()( parameters ... )`` exists on the C++ type
|
||||
- a ``sol::meta_function::call`` operator will be generated
|
||||
- the function call operator in C++ must not be overloaded, otherwise sol will be unable to bind it automagically
|
||||
- the function call operator in C++ must not be templated, otherwise sol will be unable to bind it automagically
|
||||
- if it is overloaded or templated, it is your reponsibility to bind it properly
|
||||
* for automatic iteration where ``begin()`` and ``end()`` exist on the C++ type
|
||||
- a ``sol::meta_function::pairs`` operator is generated for you
|
||||
- Allows you to iterate using ``for k, v in pairs( obj ) do ... end`` in Lua
|
||||
- **Lua 5.2 and better only: LuaJIT does not allow this, Lua 5.1 does NOT allow this**
|
||||
* for comparison operations where ``operator <`` and ``operator <=`` exist on the C++ type
|
||||
- These two ``sol::meta_function::less_than(_or_equal_to)`` are generated for you
|
||||
- ``>`` and ``>=`` operators are generated in Lua based on ``<`` and ``<=`` operators
|
||||
* for ``operator==``
|
||||
- An equality operator will always be generated, doing pointer comparison if ``operator==`` on the two value types is not supported or doing a reference comparison and a value comparison if ``operator==`` is supported
|
||||
* heterogenous operators cannot be supported for equality, as Lua specifically checks if they use the same function to do the comparison: if they do not, then the equality method is not invoked; one way around this would be to write one ``int super_equality_function(lua_State* L) { ... }``, pull out arguments 1 and 2 from the stack for your type, and check all the types and then invoke ``operator==`` yourself after getting the types out of Lua (possibly using :ref:`sol::stack::get<stack-get>` and :ref:`sol::stack::check_get<stack-check-get>`)
|
||||
|
||||
|
||||
Otherwise, the following is used to specify functions to bind on the specific usertype for ``T``.
|
||||
|
||||
* ``"{name}", &free_function``
|
||||
|
|
|
@ -17,7 +17,7 @@ Containers are objects that are meant to be inspected and iterated and whose job
|
|||
|
||||
.. 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.
|
||||
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:
|
||||
|
@ -49,6 +49,10 @@ You can also specialize ``sol::is_container<T>`` to turn off container detection
|
|||
|
||||
This will let the type be pushed as a regular userdata.
|
||||
|
||||
.. note::
|
||||
|
||||
Pushing a new :doc:`usertype<api/usertype>` will prevent a qualifying C++ container type from being treated like a container. To force a type that you've registered to be treated like a container, use :doc:`sol::as_container<api/as_container>`.
|
||||
|
||||
|
||||
.. _container-traits:
|
||||
|
||||
|
@ -83,7 +87,7 @@ The various operations provided by ``container_traits<T>`` are expected to be li
|
|||
|
||||
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::
|
||||
.. _container-operations:
|
||||
|
||||
container operations
|
||||
-------------------------
|
||||
|
@ -155,9 +159,9 @@ When you serialize a container into sol2, the default container handler deals wi
|
|||
| | | 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 |
|
||||
| fixed | lacking ``push_back``/``insert`` | std::array<T, n> | - regular c-style arrays must be set with ``std::ref( arr )`` or ``&arr`` to be usable |
|
||||
| | lacking ``erase`` | T[n] (fixed arrays) | |
|
||||
| | | | |
|
||||
+------------------------+----------------------------------------+-------------------------+-----------------------------------------------------------------------------------------------+
|
||||
| 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 |
|
||||
|
|
|
@ -56,7 +56,11 @@ You can ``#define SOL_EXCEPTIONS_SAFE_PROPAGATION`` before including Sol or defi
|
|||
|
||||
This will prevent sol from catching ``(...)`` errors in platforms and compilers that have full C++ exception interoperability. This means that Lua errors can be caught with ``catch (...)`` in the C++ end of your code after it goes through Lua, and exceptions can pass through the Lua API and Stack safely.
|
||||
|
||||
Currently, the only known platform to do this is the listed "Full" `platforms for LuaJIT`_ and Lua compiled as C++. This define is not turned on automatically, even if Sol detects LuaJIT: *it is your job to define it if you know that your platform supports it*!
|
||||
Currently, the only known platform to do this is the listed "Full" `platforms for LuaJIT`_ and Lua compiled as C++. This define is turned on automatically for compiling Lua as C++.
|
||||
|
||||
.. warning::
|
||||
``SOL_EXCEPTIONS_SAFE_PROPAGATION`` is not defined automatically when Sol detects LuaJIT. *It is your job to define it if you know that your platform supports it*!
|
||||
|
||||
|
||||
.. _issue: https://github.com/ThePhD/sol2/issues/
|
||||
.. _at_panic: http://www.Lua.org/manual/5.3/manual.html#4.6
|
||||
|
|
|
@ -20,8 +20,13 @@ If you're already using lua and you just want to use ``sol`` in some places, you
|
|||
|
||||
:doc:`sol::state_view<../api/state>` is exactly like ``sol::state``, but it doesn't manage the lifetime of a ``lua_State*``. Therefore, you get all the goodies that come with a ``sol::state`` without any of the ownership implications. Sol has no initialization components that need to deliberately remain alive for the duration of the program. It's entirely self-containing and uses lua's garbage collectors and various implementation techniques to require no state C++-side. After you do that, all of the power of `Sol` is available to you, and then some!
|
||||
|
||||
``sol::state_view`` is also helpful when you want to `create a DLL that loads some Lua module`_ via requires.
|
||||
|
||||
You may also want to call ``require`` and supply a string of a script file or something that returns an object that you set equal to something in C++. For that, you can use the :ref:`require functionality<state-require-function>`.
|
||||
|
||||
Remember that Sol can be as lightweight as you want it: almost all of Sol's types take the ``lua_State*`` argument and then a second ``int index`` stack index argument, meaning you can use :doc:`tables<../api/table>`, :doc:`lua functions<../api/function>`, :doc:`coroutines<../api/coroutine>`, and other reference-derived objects that expose the proper constructor for your use. You can also set :doc:`usertypes<../api/usertype>` and other things you need without changing your entire architecture.
|
||||
Remember that Sol can be as lightweight as you want it: almost all of Sol's Lua types take the ``lua_State*`` argument and then a second ``int index`` stack index argument, meaning you can use :doc:`tables<../api/table>`, :doc:`lua functions<../api/function>`, :doc:`coroutines<../api/coroutine>`, and other reference-derived objects that expose the proper constructor for your use. You can also set :doc:`usertypes<../api/usertype>` and other things you need without changing your entire architecture.
|
||||
|
||||
Note that you can also make non-standard pointer and reference types with custom reference counting and such also play nice with the system. See :doc:`unique_usertype_traits\<T><../api/unique_usertype_traits>` to see how! Custom types is also mentioned in the :doc:`customization tutorial<customization>`.
|
||||
Note that you can also make non-standard pointer and reference types with custom reference counting and such also play nice with the system. See :doc:`unique_usertype_traits\<T><../api/unique_usertype_traits>` to see how! Custom types is also mentioned in the :doc:`customization tutorial<customization>`.
|
||||
|
||||
|
||||
.. _create a DLL that loads some Lua module: https://github.com/ThePhD/sol2/tree/develop/examples/require_dll_example
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
tutorial
|
||||
========
|
||||
|
||||
Take some time to learn the framework with thse tutorials. But, if you need to get going FAST, try using the :doc:`quick 'n' dirty<all-the-things>` approach and your browser's / editors search function. It will also serve you well to look at all the `examples`_, which have recently gotten a bit of an overhaul to contain more relevant working examples.
|
||||
Take some time to learn the framework with these tutorials. But, if you need to get going FAST, try using the :doc:`quick 'n' dirty<all-the-things>` approach and your browser's / editors search function. It will also serve you well to look at all the `examples`_, which have recently gotten a bit of an overhaul to contain more relevant working examples and other advanced tricks that you can leverage to have a good time!
|
||||
|
||||
|
||||
.. toctree::
|
||||
|
|
|
@ -18,8 +18,10 @@ reading
|
|||
:caption: main.cpp
|
||||
:name: variables-main-cpp
|
||||
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
|
||||
|
||||
int main () {
|
||||
|
||||
sol::state lua;
|
||||
|
@ -34,7 +36,9 @@ You can interact with the variables like this:
|
|||
:caption: main.cpp extended
|
||||
:name: extended-variables-main-cpp
|
||||
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
#include <tuple>
|
||||
#include <utility> // for std::pair
|
||||
|
||||
|
@ -49,7 +53,7 @@ You can interact with the variables like this:
|
|||
|
||||
// can also get it using the "get" member function
|
||||
// auto replaces the unqualified type name
|
||||
auto resolution = config.get<sol::table>( "config" );
|
||||
auto resolution = config.get<sol::table>( "resolution );
|
||||
|
||||
// table and state can have multiple things pulled out of it too
|
||||
std::pair<int, int> xyresolution = resolution.get<int, int>( "x", "y" );
|
||||
|
@ -116,7 +120,9 @@ Writing gets a lot simpler. Even without scripting a file or a string, you can r
|
|||
:caption: main.cpp
|
||||
:name: writing-main-cpp
|
||||
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main () {
|
||||
|
@ -159,7 +165,9 @@ This example pretty much sums up what can be done. Note that the syntax ``lua["n
|
|||
:caption: main.cpp
|
||||
:name: lazy-main-cpp
|
||||
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main () {
|
||||
|
@ -185,8 +193,9 @@ Finally, it's possible to erase a reference/variable by setting it to ``nil``, u
|
|||
:caption: main.cpp
|
||||
:name: erase-main-cpp
|
||||
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
|
||||
int main () {
|
||||
|
||||
sol::state lua;
|
||||
|
|
|
@ -12,7 +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>`.
|
||||
* Containers get pushed as special usertypes, but can be disabled if problems arise as detailed :doc:`here<containers>`.
|
||||
* `Certain operators`_ are detected and bound automatically for usertypes
|
||||
* 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 colon is necessary to "automatically" pass the ``this``/``self`` argument to Lua methods
|
||||
|
@ -43,3 +44,4 @@ The examples folder also has a number of really great examples for you to see. T
|
|||
.. _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
|
||||
.. _C++: https://github.com/ThePhD/sol2/blob/develop/examples/usertype_simple.cpp#L51
|
||||
.. _Certain operators: https://github.com/ThePhD/sol2/blob/develop/examples/usertype_automatic_operators.cpp
|
||||
|
|
73
examples/container_as_container.cpp
Normal file
73
examples/container_as_container.cpp
Normal file
|
@ -0,0 +1,73 @@
|
|||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <numeric>
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
class number_storage {
|
||||
private:
|
||||
std::vector<int> data;
|
||||
|
||||
public:
|
||||
number_storage(int i) { data.push_back(i); }
|
||||
|
||||
int accumulate() const {
|
||||
return std::accumulate(data.begin(), data.end(), 0);
|
||||
}
|
||||
|
||||
public:
|
||||
using value_type = decltype(data)::value_type;
|
||||
using iterator = decltype(data)::iterator;
|
||||
using size_type = decltype(data)::size_type;
|
||||
iterator begin() { return iterator(data.begin()); }
|
||||
iterator end() { return iterator(data.end()); }
|
||||
size_type size() const noexcept { return data.size(); }
|
||||
size_type max_size() const noexcept { return data.max_size(); }
|
||||
void push_back(int value) { data.push_back(value); }
|
||||
bool empty() const noexcept { return data.empty(); }
|
||||
};
|
||||
|
||||
namespace sol {
|
||||
template <>
|
||||
struct is_container<number_storage> : std::false_type {};
|
||||
}
|
||||
|
||||
int main(int, char*[]) {
|
||||
std::cout << "=== container as container example ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_usertype<number_storage>("number_storage",
|
||||
sol::constructors<number_storage(int)>(),
|
||||
"accumulate", &number_storage::accumulate,
|
||||
"iterable", [](number_storage& ns) {
|
||||
return sol::as_container(ns); // treat like a container, despite is_container specialization
|
||||
}
|
||||
);
|
||||
|
||||
lua.script(R"(
|
||||
ns = number_storage.new(23)
|
||||
print("accumulate before:", ns:accumulate())
|
||||
|
||||
-- reference original usertype like a container
|
||||
ns_container = ns:iterable()
|
||||
ns_container:add(24)
|
||||
ns_container:add(25)
|
||||
|
||||
-- now print to show effect
|
||||
print("accumulate after :", ns:accumulate())
|
||||
)");
|
||||
|
||||
number_storage& ns = lua["ns"];
|
||||
number_storage& ns_container = lua["ns_container"];
|
||||
assert(&ns == &ns_container);
|
||||
assert(ns.size() == 3);
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
struct cpp_class {
|
||||
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<cpp_class>("object");
|
||||
|
||||
// runtime additions: through the sol API
|
||||
lua["object"]["func"] = [](cpp_class& 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()
|
||||
)");
|
||||
|
||||
cpp_class& obj = lua["obj"];
|
||||
assert(obj.value == 1);
|
||||
|
||||
return 0;
|
||||
}
|
116
examples/usertype_automatic_operators.cpp
Normal file
116
examples/usertype_automatic_operators.cpp
Normal file
|
@ -0,0 +1,116 @@
|
|||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
#include <list>
|
||||
#include <iosfwd>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
class automatic {
|
||||
private:
|
||||
std::list<double> data;
|
||||
|
||||
public:
|
||||
using value_type = decltype(data)::value_type;
|
||||
using iterator = decltype(data)::const_iterator;
|
||||
using size_type = decltype(data)::size_type;
|
||||
|
||||
// automatically bound to obj( args... ) [ __call ]
|
||||
void operator()() {
|
||||
data.push_back(static_cast<double>(data.size() + 1) / 3.0);
|
||||
}
|
||||
|
||||
// automatically used for pairs(obj) [ __pairs ], 5.2+
|
||||
iterator begin() const { return data.begin(); }
|
||||
iterator end() const { return data.end(); }
|
||||
|
||||
// automatically bound to #obj [ __len ]
|
||||
size_type size() const { return data.size(); }
|
||||
|
||||
// automatically bound for obj == obj [ __eq ]
|
||||
bool operator== (const automatic& right) const {
|
||||
return data == right.data;
|
||||
}
|
||||
// automatically bound for obj < obj [ __lt ]
|
||||
bool operator< (const automatic& right) const {
|
||||
return data < right.data;
|
||||
}
|
||||
// automatically bound for obj <= obj [ __le ]
|
||||
bool operator<= (const automatic& right) const {
|
||||
return data <= right.data;
|
||||
}
|
||||
// other comparison operators are based off the above in Lua
|
||||
// and cannot be overridden directly
|
||||
};
|
||||
|
||||
// automatically bound to tostring(obj) [ __tostring ]
|
||||
std::ostream& operator<<(std::ostream& os, const automatic& right) {
|
||||
if (right.size() == 0) {
|
||||
os << "{ empty }";
|
||||
return os;
|
||||
}
|
||||
auto b = right.begin();
|
||||
auto e = right.end();
|
||||
os << "{ " << right.size() << " | ";
|
||||
os << *b;
|
||||
++b;
|
||||
while (b != e) {
|
||||
os << ", " << *b;
|
||||
++b;
|
||||
}
|
||||
os << " }";
|
||||
return os;
|
||||
}
|
||||
|
||||
int main(int, char*[]) {
|
||||
std::cout << "=== usertype automatic operators example ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_usertype<automatic>("automatic");
|
||||
|
||||
lua.script(R"(
|
||||
obj1 = automatic.new()
|
||||
obj2 = automatic.new()
|
||||
obj3 = automatic.new()
|
||||
|
||||
print("obj1:", obj1)
|
||||
print("obj2:", obj2)
|
||||
print("obj3:", obj2)
|
||||
|
||||
obj1() obj1() obj1() obj1() obj1() obj1()
|
||||
obj2() obj2() obj2()
|
||||
obj3() obj3() obj3()
|
||||
|
||||
print("#obj1:", #obj1)
|
||||
print("#obj2:", #obj2)
|
||||
print("#obj3:", #obj3)
|
||||
|
||||
)");
|
||||
#if SOL_LUA_VERSION > 501
|
||||
lua.script(R"(
|
||||
for k, v in pairs(obj1) do
|
||||
assert( (k / 3) == v )
|
||||
end
|
||||
)");
|
||||
#endif
|
||||
|
||||
lua.script(R"(
|
||||
print("obj1 == obj2:", obj1 == obj2)
|
||||
print("obj1 < obj2:", obj1 < obj2)
|
||||
print("obj1 >= obj2:", obj1 >= obj2)
|
||||
|
||||
print("obj2 == obj3:", obj1 == obj2)
|
||||
print("obj2 > obj3:", obj1 > obj2)
|
||||
print("obj2 <= obj3:", obj1 <= obj2)
|
||||
|
||||
print("obj1:", obj1)
|
||||
print("obj2:", obj2)
|
||||
print("obj3:", obj2)
|
||||
)");
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
19
examples/wip/lua_inheritance.cpp
Normal file
19
examples/wip/lua_inheritance.cpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
int main(int, char*[]) {
|
||||
std::cout << "=== lua inheritance example ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
/* This example is currently under construction.
|
||||
For inheritance and classes within Lua,
|
||||
consider using kikito's middleclass
|
||||
-- https://github.com/kikito/middleclass */
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -313,6 +313,179 @@ namespace sol {
|
|||
|
||||
#endif // noexcept is part of a function's type
|
||||
|
||||
#if defined(_MSC_VER) && defined(_M_IX86)
|
||||
template<typename R, typename... Args>
|
||||
struct fx_traits<R __stdcall (Args...), false> : basic_traits<false, false, void, R, Args...> {
|
||||
typedef R(__stdcall *function_pointer_type)(Args...);
|
||||
};
|
||||
|
||||
template<typename R, typename... Args>
|
||||
struct fx_traits<R(__stdcall *)(Args...), false> : basic_traits<false, false, void, R, Args...> {
|
||||
typedef R(__stdcall *function_pointer_type)(Args...);
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args...), false> : basic_traits<false, false, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args...);
|
||||
};
|
||||
|
||||
/* Const Volatile */
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args...) const, false> : basic_traits<false, false, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args...) const;
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args...) const volatile, false> : basic_traits<false, false, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args...) const volatile;
|
||||
};
|
||||
|
||||
/* Member Function Qualifiers */
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args...) &, false> : basic_traits<false, false, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args...) &;
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args...) const &, false> : basic_traits<false, false, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args...) const &;
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args...) const volatile &, false> : basic_traits<false, false, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args...) const volatile &;
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args...) && , false> : basic_traits<false, false, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args...) && ;
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args...) const &&, false> : basic_traits<false, false, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args...) const &&;
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args...) const volatile &&, false> : basic_traits<false, false, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args...) const volatile &&;
|
||||
};
|
||||
|
||||
#ifdef SOL_NOEXCEPT_FUNCTION_TYPE
|
||||
|
||||
template<typename R, typename... Args>
|
||||
struct fx_traits<R(Args...) noexcept, false> : basic_traits<true, false, void, R, Args...> {
|
||||
typedef R(__stdcall *function_pointer_type)(Args...) noexcept;
|
||||
};
|
||||
|
||||
template<typename R, typename... Args>
|
||||
struct fx_traits<R(*)(Args...) noexcept, false> : basic_traits<true, false, void, R, Args...> {
|
||||
typedef R(__stdcall *function_pointer_type)(Args...) noexcept;
|
||||
};
|
||||
|
||||
template<typename R, typename... Args>
|
||||
struct fx_traits<R(Args..., ...) noexcept, false> : basic_traits<true, true, void, R, Args...> {
|
||||
typedef R(__stdcall *function_pointer_type)(Args..., ...) noexcept;
|
||||
};
|
||||
|
||||
template<typename R, typename... Args>
|
||||
struct fx_traits<R(*)(Args..., ...) noexcept, false> : basic_traits<true, true, void, R, Args...> {
|
||||
typedef R(__stdcall *function_pointer_type)(Args..., ...) noexcept;
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args...) noexcept, false> : basic_traits<true, false, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args...) noexcept;
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args..., ...) noexcept, false> : basic_traits<true, true, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args..., ...) noexcept;
|
||||
};
|
||||
|
||||
/* Const Volatile */
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args...) const noexcept, false> : basic_traits<true, false, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args...) const noexcept;
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args..., ...) const noexcept, false> : basic_traits<true, true, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args..., ...) const noexcept;
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args...) const volatile noexcept, false> : basic_traits<true, false, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args...) const volatile noexcept;
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args..., ...) const volatile noexcept, false> : basic_traits<true, true, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args..., ...) const volatile noexcept;
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args...) & noexcept, false> : basic_traits<true, false, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args...) & noexcept;
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args..., ...) & noexcept, false> : basic_traits<true, true, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args..., ...) & noexcept;
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args...) const & noexcept, false> : basic_traits<true, false, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args...) const & noexcept;
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args..., ...) const & noexcept, false> : basic_traits<true, true, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args..., ...) const & noexcept;
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args...) const volatile & noexcept, false> : basic_traits<true, false, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args...) const volatile & noexcept;
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args..., ...) const volatile & noexcept, false> : basic_traits<true, true, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args..., ...) const volatile & noexcept;
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args...) && noexcept, false> : basic_traits<true, false, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args...) && noexcept;
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args..., ...) && noexcept, false> : basic_traits<true, true, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args..., ...) && noexcept;
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args...) const && noexcept, false> : basic_traits<true, false, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args...) const && noexcept;
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args..., ...) const && noexcept, false> : basic_traits<true, true, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args..., ...) const && noexcept;
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args...) const volatile && noexcept, false> : basic_traits<true, false, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args...) const volatile && noexcept;
|
||||
};
|
||||
|
||||
template<typename T, typename R, typename... Args>
|
||||
struct fx_traits<R( __stdcall T::*)(Args..., ...) const volatile && noexcept, false> : basic_traits<true, true, T, R, Args...> {
|
||||
typedef R( __stdcall T::* function_pointer_type)(Args..., ...) const volatile && noexcept;
|
||||
};
|
||||
#endif // noexcept is part of a function's type
|
||||
#endif // __stdcall x86 VC++ bug
|
||||
|
||||
template<typename Signature>
|
||||
struct fx_traits<Signature, true> : fx_traits<typename fx_traits<decltype(&Signature::operator())>::function_type, false> {};
|
||||
|
||||
|
|
|
@ -157,8 +157,9 @@ inline const char* kepler_lua_compat_get_string(lua_State* L, void* ud, size_t*
|
|||
return ls->s;
|
||||
}
|
||||
|
||||
#if !defined(SOL_LUAJIT) || (SOL_LUAJIT_VERSION < 20100)
|
||||
// Luajit 2.1.0 has this function already
|
||||
#if !defined(SOL_LUAJIT) || (SOL_LUAJIT_VERSION < 20001)
|
||||
// Luajit 2.1.0, 2.0.1+ has this function already based on the downloads from LuaJIT.org
|
||||
// if you encounter a bug related to this please file a report so we can further check values
|
||||
|
||||
inline int luaL_loadbufferx(lua_State* L, const char* buff, size_t size, const char* name, const char*) {
|
||||
kepler_lua_compat_get_string_view ls;
|
||||
|
@ -171,7 +172,7 @@ 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 // Luajit 2.1.0-beta+, 2.0.1+ beta and beyond
|
||||
|
||||
#endif /* Lua 5.1 */
|
||||
|
||||
|
|
|
@ -31,6 +31,9 @@
|
|||
#ifdef SOL_USING_CXX_LUAJIT
|
||||
#include <luajit.h>
|
||||
#endif // C++ LuaJIT ... whatever that means
|
||||
#ifndef SOL_EXCEPTIONS_SAFE_PROPAGATION
|
||||
#define SOL_EXCEPTIONS_SAFE_PROPAGATION
|
||||
#endif // Exceptions can be propagated safely using C++-compiled Lua
|
||||
#else
|
||||
#include <lua.hpp>
|
||||
#endif // C++ Mangling for Lua
|
||||
|
|
|
@ -31,8 +31,39 @@ namespace sol {
|
|||
template <typename T>
|
||||
struct container_traits;
|
||||
|
||||
template <typename T>
|
||||
struct as_container_t {
|
||||
T source;
|
||||
|
||||
as_container_t(T value) : source(std::move(value)) {}
|
||||
|
||||
operator T() {
|
||||
return std::move(source);
|
||||
}
|
||||
|
||||
operator std::add_const_t<std::add_lvalue_reference_t<T>>() const {
|
||||
return source;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct as_container_t<T&> {
|
||||
std::reference_wrapper<T> source;
|
||||
|
||||
as_container_t(T& value) : source(value) {}
|
||||
|
||||
operator T&() {
|
||||
return source;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
auto as_container(T&& value) {
|
||||
return as_container_t<T>(std::forward<T>(value));
|
||||
}
|
||||
|
||||
namespace container_detail {
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct has_clear_test {
|
||||
private:
|
||||
|
@ -47,12 +78,12 @@ namespace sol {
|
|||
};
|
||||
|
||||
template <typename T>
|
||||
struct has_size_test {
|
||||
struct has_empty_test {
|
||||
private:
|
||||
typedef std::array<char, 1> one;
|
||||
typedef std::array<char, 2> two;
|
||||
|
||||
template <typename C> static one test(decltype(&C::size));
|
||||
template <typename C> static one test(decltype(&C::empty));
|
||||
template <typename C> static two test(...);
|
||||
|
||||
public:
|
||||
|
@ -229,10 +260,10 @@ namespace sol {
|
|||
};
|
||||
|
||||
template <typename T>
|
||||
using has_size = meta::boolean<has_size_test<T>::value>;
|
||||
using has_clear = meta::boolean<has_clear_test<T>::value>;
|
||||
|
||||
template <typename T>
|
||||
using has_clear = meta::boolean<has_clear_test<T>::value>;
|
||||
using has_empty = meta::boolean<has_empty_test<T>::value>;
|
||||
|
||||
template <typename T>
|
||||
using has_find = meta::boolean<has_find_test<T>::value>;
|
||||
|
@ -262,11 +293,14 @@ namespace sol {
|
|||
using has_traits_add = meta::boolean<has_traits_add_test<T>::value>;
|
||||
|
||||
template <typename T>
|
||||
using has_traits_size = has_size<T>;
|
||||
using has_traits_size = meta::has_size<T>;
|
||||
|
||||
template <typename T>
|
||||
using has_traits_clear = has_clear<T>;
|
||||
|
||||
template <typename T>
|
||||
using has_traits_empty = has_empty<T>;
|
||||
|
||||
template <typename T>
|
||||
using has_traits_find = meta::boolean<has_traits_find_test<T>::value>;
|
||||
|
||||
|
@ -279,6 +313,25 @@ namespace sol {
|
|||
template <typename T>
|
||||
using has_traits_erase = meta::boolean<has_traits_erase_test<T>::value>;
|
||||
|
||||
template <typename T>
|
||||
struct is_forced_container : is_container<T> {};
|
||||
|
||||
template <typename T>
|
||||
struct is_forced_container<as_container_t<T>> : std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
struct container_decay {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct container_decay<as_container_t<T>> {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using container_decay_t = typename container_decay<meta::unqualified_t<T>>::type;
|
||||
|
||||
template <typename T>
|
||||
decltype(auto) get_key(std::false_type, T&& t) {
|
||||
return std::forward<T>(t);
|
||||
|
@ -343,6 +396,10 @@ namespace sol {
|
|||
return luaL_error(L, "sol: cannot call 'clear' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str());
|
||||
}
|
||||
|
||||
static int empty(lua_State* L) {
|
||||
return luaL_error(L, "sol: cannot call 'empty' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str());
|
||||
}
|
||||
|
||||
static int erase(lua_State* L) {
|
||||
return luaL_error(L, "sol: cannot call 'erase' on type '%s': it is not recognized as a container", detail::demangle<T>().c_str());
|
||||
}
|
||||
|
@ -365,17 +422,16 @@ namespace sol {
|
|||
template <typename X>
|
||||
struct container_traits_default<X, std::enable_if_t<
|
||||
meta::all<
|
||||
is_container<meta::unqualified_t<X>>
|
||||
, meta::has_value_type<meta::unqualified_t<X>>
|
||||
, meta::has_iterator<meta::unqualified_t<X>>
|
||||
is_forced_container<meta::unqualified_t<X>>
|
||||
, meta::has_value_type<meta::unqualified_t<container_decay_t<X>>>
|
||||
, meta::has_iterator<meta::unqualified_t<container_decay_t<X>>>
|
||||
>::value
|
||||
>> {
|
||||
private:
|
||||
typedef std::remove_pointer_t<meta::unwrap_unqualified_t<X>> T;
|
||||
public:
|
||||
typedef std::true_type is_container;
|
||||
typedef meta::is_associative<T> is_associative;
|
||||
typedef std::remove_pointer_t<meta::unwrap_unqualified_t<container_decay_t<X>>> T;
|
||||
private:
|
||||
typedef container_traits<X> deferred_traits;
|
||||
typedef meta::is_associative<T> is_associative;
|
||||
typedef meta::is_lookup<T> is_lookup;
|
||||
typedef typename T::iterator iterator;
|
||||
typedef typename T::value_type value_type;
|
||||
|
@ -390,7 +446,7 @@ namespace sol {
|
|||
typedef std::is_same<iterator_category, std::input_iterator_tag> is_input_iterator;
|
||||
typedef std::conditional_t<is_input_iterator::value,
|
||||
V,
|
||||
std::conditional_t<is_associative::value, std::add_lvalue_reference_t<V>, iterator_return>
|
||||
decltype(detail::deref(std::declval<std::conditional_t<is_associative::value, std::add_lvalue_reference_t<V>, iterator_return>>()))
|
||||
> push_type;
|
||||
typedef std::is_copy_assignable<V> is_copyable;
|
||||
typedef meta::neg<meta::any<
|
||||
|
@ -409,24 +465,28 @@ namespace sol {
|
|||
};
|
||||
|
||||
static auto& get_src(lua_State* L) {
|
||||
typedef std::remove_pointer_t<meta::unwrap_unqualified_t<X>> Tu;
|
||||
#ifdef SOL_SAFE_USERTYPE
|
||||
auto p = stack::check_get<T*>(L, 1);
|
||||
if (!p || p.value() == nullptr) {
|
||||
luaL_error(L, "sol: 'self' argument is nil or not of type '%s' (pass 'self' as first argument with ':' or call on proper type)", detail::demangle<T>().c_str());
|
||||
auto p = stack::check_get<Tu*>(L, 1);
|
||||
if (!p) {
|
||||
luaL_error(L, "sol: 'self' is not of type '%s' (pass 'self' as first argument with ':' or call on proper type)", detail::demangle<T>().c_str());
|
||||
}
|
||||
if (p.value() == nullptr) {
|
||||
luaL_error(L, "sol: 'self' argument is nil (pass 'self' as first argument with ':' or call on a '%s' type)", detail::demangle<T>().c_str());
|
||||
}
|
||||
return *p.value();
|
||||
#else
|
||||
return stack::get<T>(L, 1);
|
||||
return stack::get<Tu>(L, 1);
|
||||
#endif // Safe getting with error
|
||||
}
|
||||
|
||||
static int get_associative(std::true_type, lua_State* L, iterator& it) {
|
||||
auto& v = *it;
|
||||
return stack::stack_detail::push_reference<push_type>(L, v.second);
|
||||
return stack::stack_detail::push_reference<push_type>(L, detail::deref(v.second));
|
||||
}
|
||||
|
||||
static int get_associative(std::false_type, lua_State* L, iterator& it) {
|
||||
return stack::stack_detail::push_reference<push_type>(L, *it);
|
||||
return stack::stack_detail::push_reference<push_type>(L, detail::deref(*it));
|
||||
}
|
||||
|
||||
static int get_category(std::input_iterator_tag, lua_State* L, T& self, K& key) {
|
||||
|
@ -625,7 +685,7 @@ namespace sol {
|
|||
}
|
||||
|
||||
static int find_comparative(std::true_type, lua_State* L, T& self) {
|
||||
V value = stack::get<V>(L, 2);
|
||||
decltype(auto) value = stack::get<V>(L, 2);
|
||||
auto it = begin(L, self);
|
||||
auto e = end(L, self);
|
||||
std::size_t index = 1;
|
||||
|
@ -773,7 +833,7 @@ namespace sol {
|
|||
}
|
||||
|
||||
static void insert_copyable(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) {
|
||||
insert_has(has_find<T>(), L, self, std::move(key), std::move(value));
|
||||
insert_has(meta::has_insert<T>(), L, self, std::move(key), std::move(value));
|
||||
}
|
||||
|
||||
static void insert_copyable(std::false_type, lua_State* L, T&, stack_object, stack_object) {
|
||||
|
@ -835,7 +895,7 @@ namespace sol {
|
|||
}
|
||||
|
||||
static auto size_has(std::false_type, lua_State* L, T& self) {
|
||||
return std::distance(container_traits<T>::begin(L, self), container_traits<T>::end(L, self));
|
||||
return std::distance(deferred_traits::begin(L, self), deferred_traits::end(L, self));
|
||||
}
|
||||
|
||||
static auto size_has(std::true_type, lua_State*, T& self) {
|
||||
|
@ -850,6 +910,14 @@ namespace sol {
|
|||
luaL_error(L, "sol: cannot call clear on '%s'", detail::demangle<T>().c_str());
|
||||
}
|
||||
|
||||
static bool empty_has(std::true_type, lua_State*, T& self) {
|
||||
return self.empty();
|
||||
}
|
||||
|
||||
static bool empty_has(std::false_type, lua_State* L, T& self) {
|
||||
return deferred_traits::begin(L, self) == deferred_traits::end(L, self);
|
||||
}
|
||||
|
||||
static int get_start(lua_State* L, T& self, K& key) {
|
||||
return get_it(is_linear_integral(), L, self, key);
|
||||
}
|
||||
|
@ -859,13 +927,17 @@ namespace sol {
|
|||
}
|
||||
|
||||
static std::size_t size_start(lua_State* L, T& self) {
|
||||
return size_has(has_size<T>(), L, self);
|
||||
return size_has(meta::has_size<T>(), L, self);
|
||||
}
|
||||
|
||||
static void clear_start(lua_State* L, T& self) {
|
||||
clear_has(has_clear<T>(), L, self);
|
||||
}
|
||||
|
||||
static bool empty_start(lua_State* L, T& self) {
|
||||
return empty_has(has_empty<T>(), L, self);
|
||||
}
|
||||
|
||||
static void erase_start(lua_State* L, T& self, K& key) {
|
||||
erase_has(has_erase<T>(), L, self, key);
|
||||
}
|
||||
|
@ -874,12 +946,12 @@ namespace sol {
|
|||
iter& i = stack::get<user<iter>>(L, 1);
|
||||
auto& source = i.source;
|
||||
auto& it = i.it;
|
||||
if (it == container_traits<T>::end(L, source)) {
|
||||
if (it == deferred_traits::end(L, source)) {
|
||||
return 0;
|
||||
}
|
||||
int p;
|
||||
p = stack::push_reference(L, it->first);
|
||||
p += stack::stack_detail::push_reference<push_type>(L, it->second);
|
||||
p += stack::stack_detail::push_reference<push_type>(L, detail::deref(it->second));
|
||||
std::advance(it, 1);
|
||||
return p;
|
||||
}
|
||||
|
@ -887,7 +959,7 @@ namespace sol {
|
|||
static int pairs_associative(std::true_type, lua_State* L) {
|
||||
auto& src = get_src(L);
|
||||
stack::push(L, next);
|
||||
stack::push<user<iter>>(L, src, container_traits<T>::begin(L, src));
|
||||
stack::push<user<iter>>(L, src, deferred_traits::begin(L, src));
|
||||
stack::push(L, 1);
|
||||
return 3;
|
||||
}
|
||||
|
@ -897,12 +969,12 @@ namespace sol {
|
|||
auto& source = i.source;
|
||||
auto& it = i.it;
|
||||
K k = stack::get<K>(L, 2);
|
||||
if (it == container_traits<T>::end(L, source)) {
|
||||
if (it == deferred_traits::end(L, source)) {
|
||||
return 0;
|
||||
}
|
||||
int p;
|
||||
p = stack::push_reference(L, k + 1);
|
||||
p += stack::stack_detail::push_reference<push_type>(L, *it);
|
||||
p += stack::stack_detail::push_reference<push_type>(L, detail::deref(*it));
|
||||
std::advance(it, 1);
|
||||
return p;
|
||||
}
|
||||
|
@ -910,7 +982,7 @@ namespace sol {
|
|||
static int pairs_associative(std::false_type, lua_State* L) {
|
||||
auto& src = get_src(L);
|
||||
stack::push(L, next);
|
||||
stack::push<user<iter>>(L, src, container_traits<T>::begin(L, src));
|
||||
stack::push<user<iter>>(L, src, deferred_traits::begin(L, src));
|
||||
stack::push(L, 0);
|
||||
return 3;
|
||||
}
|
||||
|
@ -952,7 +1024,7 @@ namespace sol {
|
|||
|
||||
static int insert(lua_State* L) {
|
||||
auto& self = get_src(L);
|
||||
insert_copyable(meta::any<is_associative, is_lookup>(), L, self, stack_object(L, raw_index(2)), stack_object(L, raw_index(3)));
|
||||
insert_copyable(is_copyable(), L, self, stack_object(L, raw_index(2)), stack_object(L, raw_index(3)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -990,6 +1062,11 @@ namespace sol {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int empty(lua_State* L) {
|
||||
auto& self = get_src(L);
|
||||
return stack::push(L, empty_start(L, self));
|
||||
}
|
||||
|
||||
static int pairs(lua_State* L) {
|
||||
return pairs_associative(is_associative(), L);
|
||||
}
|
||||
|
@ -999,6 +1076,7 @@ namespace sol {
|
|||
struct container_traits_default<X, std::enable_if_t<std::is_array<std::remove_pointer_t<meta::unwrap_unqualified_t<X>>>::value>> {
|
||||
private:
|
||||
typedef std::remove_pointer_t<meta::unwrap_unqualified_t<X>> T;
|
||||
typedef container_traits<X> deferred_traits;
|
||||
public:
|
||||
typedef std::remove_extent_t<T> value_type;
|
||||
typedef value_type* iterator;
|
||||
|
@ -1043,12 +1121,12 @@ namespace sol {
|
|||
auto& source = i.source;
|
||||
auto& it = i.it;
|
||||
std::size_t k = stack::get<std::size_t>(L, 2);
|
||||
if (it == container_traits<T>::end(L, source)) {
|
||||
if (it == deferred_traits::end(L, source)) {
|
||||
return 0;
|
||||
}
|
||||
int p;
|
||||
p = stack::push_reference(L, k + 1);
|
||||
p += stack::push_reference(L, *it);
|
||||
p += stack::push_reference(L, detail::deref(*it));
|
||||
std::advance(it, 1);
|
||||
return p;
|
||||
}
|
||||
|
@ -1077,7 +1155,7 @@ namespace sol {
|
|||
return stack::push(L, lua_nil);
|
||||
}
|
||||
--idx;
|
||||
return stack::push_reference(L, self[idx]);
|
||||
return stack::push_reference(L, detail::deref(self[idx]));
|
||||
}
|
||||
|
||||
static int index_get(lua_State* L) {
|
||||
|
@ -1110,10 +1188,14 @@ namespace sol {
|
|||
return stack::push(L, std::extent<T>::value);
|
||||
}
|
||||
|
||||
static int empty(lua_State* L) {
|
||||
return stack::push(L, std::extent<T>::value > 0);
|
||||
}
|
||||
|
||||
static int pairs(lua_State* L) {
|
||||
auto& src = get_src(L);
|
||||
stack::push(L, next);
|
||||
stack::push<user<iter>>(L, src, container_traits<T>::begin(L, src));
|
||||
stack::push<user<iter>>(L, src, deferred_traits::begin(L, src));
|
||||
stack::push(L, 0);
|
||||
return 3;
|
||||
}
|
||||
|
@ -1126,6 +1208,9 @@ namespace sol {
|
|||
return std::addressof(self[0]) + std::extent<T>::value;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename X>
|
||||
struct container_traits_default<container_traits<X>> : container_traits_default<X> {};
|
||||
} // container_detail
|
||||
|
||||
template <typename T>
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
namespace sol {
|
||||
|
||||
template <typename X, typename C = void>
|
||||
template <typename X>
|
||||
struct container_usertype_metatable {
|
||||
typedef std::remove_pointer_t<meta::unqualified_t<X>> T;
|
||||
typedef container_traits<T> traits;
|
||||
|
@ -47,7 +47,9 @@ namespace sol {
|
|||
static std::unordered_map<std::string, lua_CFunction> calls{
|
||||
{ "get", &real_get_call },
|
||||
{ "set", &real_set_call },
|
||||
{ "size", &real_length_call },
|
||||
{ "add", &real_add_call },
|
||||
{ "empty", &real_empty_call },
|
||||
{ "insert", &real_insert_call },
|
||||
{ "clear", &real_clear_call },
|
||||
{ "find", &real_find_call },
|
||||
|
@ -160,6 +162,18 @@ namespace sol {
|
|||
return real_clear_traits(container_detail::has_traits_clear<traits>(), L);
|
||||
}
|
||||
|
||||
static int real_empty_traits(std::true_type, lua_State* L) {
|
||||
return traits::empty(L);
|
||||
}
|
||||
|
||||
static int real_empty_traits(std::false_type, lua_State* L) {
|
||||
return default_traits::empty(L);
|
||||
}
|
||||
|
||||
static int real_empty_call(lua_State* L) {
|
||||
return real_empty_traits(container_detail::has_traits_empty<traits>(), L);
|
||||
}
|
||||
|
||||
static int real_erase_traits(std::true_type, lua_State* L) {
|
||||
return traits::erase(L);
|
||||
}
|
||||
|
@ -200,6 +214,10 @@ namespace sol {
|
|||
return detail::typed_static_trampoline<decltype(&real_clear_call), (&real_clear_call)>(L);
|
||||
}
|
||||
|
||||
static int empty_call(lua_State*L) {
|
||||
return detail::typed_static_trampoline<decltype(&real_empty_call), (&real_empty_call)>(L);
|
||||
}
|
||||
|
||||
static int find_call(lua_State*L) {
|
||||
return detail::typed_static_trampoline<decltype(&real_find_call), (&real_find_call)>(L);
|
||||
}
|
||||
|
@ -231,16 +249,19 @@ namespace sol {
|
|||
|
||||
namespace stack {
|
||||
namespace stack_detail {
|
||||
template <typename T>
|
||||
template <typename T, bool is_shim = false>
|
||||
struct metatable_setup {
|
||||
lua_State* L;
|
||||
|
||||
metatable_setup(lua_State* L) : L(L) {}
|
||||
|
||||
void operator()() {
|
||||
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 = { {
|
||||
typedef container_usertype_metatable<std::conditional_t<is_shim,
|
||||
as_container_t<std::remove_pointer_t<T>>,
|
||||
std::remove_pointer_t<T>
|
||||
>> meta_cumt;
|
||||
static const char* metakey = is_shim ? &usertype_traits<as_container_t<T>>::metatable()[0] : &usertype_traits<T>::metatable()[0];
|
||||
static const std::array<luaL_Reg, 16> reg = { {
|
||||
{ "__pairs", &meta_cumt::pairs_call },
|
||||
{ "__ipairs", &meta_cumt::pairs_call },
|
||||
{ "__len", &meta_cumt::length_call },
|
||||
|
@ -248,6 +269,8 @@ namespace sol {
|
|||
{ "__newindex", &meta_cumt::new_index_call },
|
||||
{ "get", &meta_cumt::get_call },
|
||||
{ "set", &meta_cumt::set_call },
|
||||
{ "size", &meta_cumt::length_call },
|
||||
{ "empty", &meta_cumt::empty_call },
|
||||
{ "clear", &meta_cumt::clear_call },
|
||||
{ "insert", &meta_cumt::insert_call },
|
||||
{ "add", &meta_cumt::add_call },
|
||||
|
@ -264,6 +287,40 @@ namespace sol {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct pusher<as_container_t<T>> {
|
||||
typedef meta::unqualified_t<T> C;
|
||||
|
||||
static int push(std::true_type, lua_State* L, const C& cont) {
|
||||
stack_detail::metatable_setup<C, true> fx(L);
|
||||
return pusher<detail::as_pointer_tag<const C>>{}.push_fx(L, fx, detail::ptr(cont));
|
||||
}
|
||||
|
||||
static int push(std::false_type, lua_State* L, const C& cont) {
|
||||
stack_detail::metatable_setup<C, true> fx(L);
|
||||
return pusher<detail::as_value_tag<C>>{}.push_fx(L, fx, cont);
|
||||
}
|
||||
|
||||
static int push(lua_State* L, const C& cont) {
|
||||
return push(std::is_lvalue_reference<T>(), L, cont);
|
||||
}
|
||||
|
||||
static int push(lua_State* L, C&& cont) {
|
||||
stack_detail::metatable_setup<C, true> fx(L);
|
||||
return pusher<detail::as_value_tag<C>>{}.push_fx(L, fx, std::move(cont));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct pusher<as_container_t<T*>> {
|
||||
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<C> fx(L);
|
||||
return pusher<detail::as_pointer_tag<T>>{}.push_fx(L, fx, 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>> {
|
||||
|
@ -289,6 +346,28 @@ namespace sol {
|
|||
return pusher<detail::as_pointer_tag<T>>{}.push_fx(L, fx, cont);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename C>
|
||||
struct checker<as_container_t<T>, type::userdata, C> {
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
return stack::check<T>(L, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<as_container_t<T>> {
|
||||
static decltype(auto) get(lua_State* L, int index, record& tracking) {
|
||||
return stack::get<T>(L, index, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<as_container_t<T>*> {
|
||||
static decltype(auto) get(lua_State* L, int index, record& tracking) {
|
||||
return stack::get<T*>(L, index, tracking);
|
||||
}
|
||||
};
|
||||
} // stack
|
||||
|
||||
} // sol
|
||||
|
|
|
@ -23,90 +23,89 @@
|
|||
#define SOL_FEATURE_TEST_HPP
|
||||
|
||||
#if (defined(__cplusplus) && __cplusplus == 201703L) || (defined(_MSC_VER) && _MSC_VER > 1900 && (defined(_HAS_CXX17) && _HAS_CXX17 == 1) || (_MSVC_LANG > 201402))
|
||||
#ifndef SOL_CXX17_FEATURES
|
||||
#define SOL_CXX17_FEATURES 1
|
||||
#endif // C++17 features macro
|
||||
#ifndef SOL_CXX17_FEATURES
|
||||
#define SOL_CXX17_FEATURES 1
|
||||
#endif // C++17 features macro
|
||||
#endif // C++17 features check
|
||||
|
||||
#if defined(__cpp_noexcept_function_type)
|
||||
#ifndef SOL_NOEXCEPT_FUNCTION_TYPE
|
||||
#define SOL_NOEXCEPT_FUNCTION_TYPE 1
|
||||
#endif // noexcept is part of a function's type
|
||||
#ifndef SOL_NOEXCEPT_FUNCTION_TYPE
|
||||
#define SOL_NOEXCEPT_FUNCTION_TYPE 1
|
||||
#endif // noexcept is part of a function's type
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(_MSC_VER)
|
||||
#ifndef SOL_CODECVT_SUPPORT
|
||||
#define SOL_CODECVT_SUPPORT 1
|
||||
#endif // sol codecvt support
|
||||
#ifndef SOL_CODECVT_SUPPORT
|
||||
#define SOL_CODECVT_SUPPORT 1
|
||||
#endif // sol codecvt support
|
||||
#elif defined(__GNUC__)
|
||||
#if __GNUC__ >= 5
|
||||
#ifndef SOL_CODECVT_SUPPORT
|
||||
#define SOL_CODECVT_SUPPORT 1
|
||||
#endif // codecvt support
|
||||
#endif // g++ 5.x.x (MinGW too)
|
||||
#if __GNUC__ >= 5
|
||||
#ifndef SOL_CODECVT_SUPPORT
|
||||
#define SOL_CODECVT_SUPPORT 1
|
||||
#endif // codecvt support
|
||||
#endif // g++ 5.x.x (MinGW too)
|
||||
#else
|
||||
// Clang sucks and doesn't really utilize codecvt support,
|
||||
// not without checking the library versions explicitly (and we're not gonna do that, so fuck you)
|
||||
// Clang sucks and doesn't really utilize codecvt support,
|
||||
// not without checking the library versions explicitly (and we're not gonna do that)
|
||||
#endif // Windows/VC++ vs. g++ vs Others
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifdef _DEBUG
|
||||
#ifndef NDEBUG
|
||||
#ifndef SOL_CHECK_ARGUMENTS
|
||||
// Do not define by default: let user turn it on
|
||||
//#define SOL_CHECK_ARGUMENTS
|
||||
#endif // Check Arguments
|
||||
#ifndef SOL_SAFE_USERTYPE
|
||||
#define SOL_SAFE_USERTYPE
|
||||
#endif // Safe Usertypes
|
||||
#endif // NDEBUG
|
||||
#endif // Debug
|
||||
#ifdef _DEBUG
|
||||
#ifndef NDEBUG
|
||||
#ifndef SOL_CHECK_ARGUMENTS
|
||||
// Do not define by default: let user turn it on
|
||||
//#define SOL_CHECK_ARGUMENTS
|
||||
#endif // Check Arguments
|
||||
#ifndef SOL_SAFE_USERTYPE
|
||||
#define SOL_SAFE_USERTYPE
|
||||
#endif // Safe Usertypes
|
||||
#endif // NDEBUG
|
||||
#endif // Debug
|
||||
|
||||
#ifndef _CPPUNWIND
|
||||
#ifndef SOL_NO_EXCEPTIONS
|
||||
#define SOL_NO_EXCEPTIONS 1
|
||||
#endif
|
||||
#endif // Automatic Exceptions
|
||||
|
||||
#ifndef _CPPRTTI
|
||||
#ifndef SOL_NO_RTTI
|
||||
#define SOL_NO_RTTI 1
|
||||
#endif
|
||||
#endif // Automatic RTTI
|
||||
#ifndef _CPPUNWIND
|
||||
#ifndef SOL_NO_EXCEPTIONS
|
||||
#define SOL_NO_EXCEPTIONS 1
|
||||
#endif
|
||||
#endif // Automatic Exceptions
|
||||
|
||||
#ifndef _CPPRTTI
|
||||
#ifndef SOL_NO_RTTI
|
||||
#define SOL_NO_RTTI 1
|
||||
#endif
|
||||
#endif // Automatic RTTI
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
|
||||
#ifndef NDEBUG
|
||||
#ifndef __OPTIMIZE__
|
||||
#ifndef SOL_CHECK_ARGUMENTS
|
||||
// Do not define by default: let user choose
|
||||
//#define SOL_CHECK_ARGUMENTS
|
||||
// But do check userdata by default:
|
||||
#endif // Check Arguments
|
||||
#ifndef SOL_SAFE_USERTYPE
|
||||
#define SOL_SAFE_USERTYPE
|
||||
#endif // Safe Usertypes
|
||||
#endif // g++ optimizer flag
|
||||
#endif // Not Debug
|
||||
#ifndef NDEBUG
|
||||
#ifndef __OPTIMIZE__
|
||||
#ifndef SOL_CHECK_ARGUMENTS
|
||||
// Do not define by default: let user choose
|
||||
//#define SOL_CHECK_ARGUMENTS
|
||||
// But do check userdata by default:
|
||||
#endif // Check Arguments
|
||||
#ifndef SOL_SAFE_USERTYPE
|
||||
#define SOL_SAFE_USERTYPE
|
||||
#endif // Safe Usertypes
|
||||
#endif // g++ optimizer flag
|
||||
#endif // Not Debug
|
||||
|
||||
#ifndef __EXCEPTIONS
|
||||
#ifndef SOL_NO_EXCEPTIONS
|
||||
#define SOL_NO_EXCEPTIONS 1
|
||||
#endif
|
||||
#endif // No Exceptions
|
||||
#ifndef __EXCEPTIONS
|
||||
#ifndef SOL_NO_EXCEPTIONS
|
||||
#define SOL_NO_EXCEPTIONS 1
|
||||
#endif
|
||||
#endif // No Exceptions
|
||||
|
||||
#ifndef __GXX_RTTI
|
||||
#ifndef SOL_NO_RTII
|
||||
#define SOL_NO_RTTI 1
|
||||
#endif
|
||||
#endif // No RTTI
|
||||
#ifndef __GXX_RTTI
|
||||
#ifndef SOL_NO_RTII
|
||||
#define SOL_NO_RTTI 1
|
||||
#endif
|
||||
#endif // No RTTI
|
||||
|
||||
#endif // vc++ || clang++/g++
|
||||
|
||||
#ifndef SOL_SAFE_USERTYPE
|
||||
#ifdef SOL_CHECK_ARGUMENTS
|
||||
#define SOL_SAFE_USERTYPE
|
||||
#endif // Turn on Safety for all
|
||||
#ifdef SOL_CHECK_ARGUMENTS
|
||||
#define SOL_SAFE_USERTYPE
|
||||
#endif // Turn on Safety for all
|
||||
#endif // Safe Usertypes
|
||||
|
||||
#endif // SOL_FEATURE_TEST_HPP
|
||||
|
|
|
@ -184,6 +184,7 @@ namespace sol {
|
|||
void* baseclasscast;
|
||||
bool mustindex;
|
||||
bool secondarymeta;
|
||||
std::array<bool, 29> properties;
|
||||
|
||||
template <typename N>
|
||||
void insert(N&& n, object&& o) {
|
||||
|
@ -327,10 +328,13 @@ namespace sol {
|
|||
indexbase(&usertype_detail::simple_core_indexing_call<T, true>), newindexbase(&usertype_detail::simple_core_indexing_call<T, false>),
|
||||
indexbaseclasspropogation(usertype_detail::walk_all_bases<true>), newindexbaseclasspropogation(&usertype_detail::walk_all_bases<false>),
|
||||
baseclasscheck(nullptr), baseclasscast(nullptr),
|
||||
mustindex(false), secondarymeta(false) {
|
||||
mustindex(false), secondarymeta(false), properties() {
|
||||
(void)detail::swallow{ 0,
|
||||
(add(L, detail::forward_get<I * 2>(args), detail::forward_get<I * 2 + 1>(args)),0)...
|
||||
};
|
||||
std::array<luaL_Reg, 29> regs{};
|
||||
int index = 0;
|
||||
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
|
@ -409,35 +413,35 @@ namespace sol {
|
|||
bool hasindex = umx.indexfunc.valid();
|
||||
bool hasnewindex = umx.newindexfunc.valid();
|
||||
auto& varmap = make_cleanup(L, umx);
|
||||
auto& properties = umx.properties;
|
||||
auto sic = hasindex ? &usertype_detail::simple_index_call<T, true> : &usertype_detail::simple_index_call<T, false>;
|
||||
auto snic = hasnewindex ? &usertype_detail::simple_new_index_call<T, true> : &usertype_detail::simple_new_index_call<T, false>;
|
||||
bool hasequals = false;
|
||||
bool hasless = false;
|
||||
bool haslessequals = false;
|
||||
auto register_kvp = [&](std::size_t i, stack_reference& t, const std::string& first, object& second) {
|
||||
if (first == to_string(meta_function::equal_to)) {
|
||||
hasequals = true;
|
||||
}
|
||||
else if (first == to_string(meta_function::less_than)) {
|
||||
hasless = true;
|
||||
}
|
||||
else if (first == to_string(meta_function::less_than_or_equal_to)) {
|
||||
haslessequals = true;
|
||||
}
|
||||
else if (first == to_string(meta_function::index)) {
|
||||
umx.indexfunc = second;
|
||||
}
|
||||
else if (first == to_string(meta_function::new_index)) {
|
||||
umx.newindexfunc = second;
|
||||
meta_function mf = meta_function::construct;
|
||||
for (std::size_t i = 1; i < properties.size(); ++i) {
|
||||
mf = static_cast<meta_function>(i);
|
||||
const std::string& mfname = to_string(mf);
|
||||
if (mfname == first) {
|
||||
properties[i] = true;
|
||||
switch (mf) {
|
||||
case meta_function::index:
|
||||
umx.indexfunc = second;
|
||||
break;
|
||||
case meta_function::new_index:
|
||||
umx.newindexfunc = second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
switch (i) {
|
||||
case 0:
|
||||
if (first == to_string(meta_function::garbage_collect)) {
|
||||
if (mf == meta_function::garbage_collect) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (first == to_string(meta_function::garbage_collect)) {
|
||||
if (mf == meta_function::garbage_collect) {
|
||||
stack::set_field(L, first, detail::unique_destruct<T>, t.stack_index());
|
||||
return;
|
||||
}
|
||||
|
@ -469,20 +473,34 @@ namespace sol {
|
|||
auto& second = std::get<1>(kvp);
|
||||
register_kvp(i, t, first, second);
|
||||
}
|
||||
luaL_Reg opregs[4]{};
|
||||
luaL_Reg opregs[29]{};
|
||||
int opregsindex = 0;
|
||||
if (!hasless) {
|
||||
if (!properties[static_cast<int>(meta_function::less_than)]) {
|
||||
const char* name = to_string(meta_function::less_than).c_str();
|
||||
usertype_detail::make_reg_op<T, std::less<>, meta::supports_op_less<T>>(opregs, opregsindex, name);
|
||||
}
|
||||
if (!haslessequals) {
|
||||
if (!properties[static_cast<int>(meta_function::less_than_or_equal_to)]) {
|
||||
const char* name = to_string(meta_function::less_than_or_equal_to).c_str();
|
||||
usertype_detail::make_reg_op<T, std::less_equal<>, meta::supports_op_less_equal<T>>(opregs, opregsindex, name);
|
||||
}
|
||||
if (!hasequals) {
|
||||
if (!properties[static_cast<int>(meta_function::equal_to)]) {
|
||||
const char* name = to_string(meta_function::equal_to).c_str();
|
||||
usertype_detail::make_reg_op<T, std::conditional_t<meta::supports_op_equal<T>::value, std::equal_to<>, usertype_detail::no_comp>, std::true_type>(opregs, opregsindex, name);
|
||||
}
|
||||
if (!properties[static_cast<int>(meta_function::pairs)]) {
|
||||
const char* name = to_string(meta_function::pairs).c_str();
|
||||
opregs[opregsindex] = { name, container_usertype_metatable<as_container_t<T>>::pairs_call };
|
||||
++opregsindex;
|
||||
}
|
||||
if (!properties[static_cast<int>(meta_function::length)]) {
|
||||
usertype_detail::make_length_op<T>(opregs, opregsindex);
|
||||
}
|
||||
if (!properties[static_cast<int>(meta_function::to_string)]) {
|
||||
usertype_detail::make_to_string_op<T, meta::supports_ostream_op<T>>(opregs, opregsindex);
|
||||
}
|
||||
if (!properties[static_cast<int>(meta_function::call)]) {
|
||||
usertype_detail::make_call_op<T>(opregs, opregsindex);
|
||||
}
|
||||
t.push();
|
||||
luaL_setfuncs(L, opregs, 0);
|
||||
t.pop();
|
||||
|
|
|
@ -373,6 +373,8 @@ namespace sol {
|
|||
return true;
|
||||
if (stack_detail::check_metatable<detail::unique_usertype<U>>(L, metatableindex))
|
||||
return true;
|
||||
if (stack_detail::check_metatable<as_container_t<U>>(L, metatableindex))
|
||||
return true;
|
||||
bool success = false;
|
||||
if (detail::has_derived<T>::value) {
|
||||
auto pn = stack::pop_n(L, 1);
|
||||
|
|
|
@ -69,7 +69,7 @@ namespace sol {
|
|||
}
|
||||
#ifdef SOL_NO_EXCEPTIONS
|
||||
// replacing information of stack error into pfr
|
||||
if (t != type::nil) {
|
||||
if (t != type::none) {
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
stack::push(L, err);
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <memory>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <iosfwd>
|
||||
#ifdef SOL_CXX17_FEATURES
|
||||
#include <string_view>
|
||||
#endif
|
||||
|
@ -368,6 +369,19 @@ namespace sol {
|
|||
static const bool value = sizeof(test<T>(0)) == sizeof(char);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct has_size_test {
|
||||
private:
|
||||
typedef std::array<char, 1> one;
|
||||
typedef std::array<char, 2> two;
|
||||
|
||||
template <typename C> static one test(decltype(std::declval<C>().size())*);
|
||||
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(...);
|
||||
|
@ -377,6 +391,9 @@ namespace sol {
|
|||
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(...);
|
||||
template <typename T, typename OS, typename = decltype(std::declval<OS&>() << std::declval<T&>())>
|
||||
std::true_type supports_ostream_op(const T&, const OS&);
|
||||
std::false_type supports_ostream_op(...);
|
||||
|
||||
} // meta_detail
|
||||
|
||||
|
@ -386,6 +403,8 @@ namespace sol {
|
|||
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, typename U = std::ostream>
|
||||
using supports_ostream_op = decltype(meta_detail::supports_ostream_op(std::declval<T&>(), std::declval<U&>()));
|
||||
|
||||
template<typename T>
|
||||
struct is_callable : boolean<meta_detail::is_callable<T>::value> {};
|
||||
|
@ -417,6 +436,9 @@ namespace sol {
|
|||
template <typename T>
|
||||
using has_insert_after = meta::boolean<meta_detail::has_insert_after_test<T>::value>;
|
||||
|
||||
template <typename T>
|
||||
using has_size = meta::boolean<meta_detail::has_size_test<T>::value>;
|
||||
|
||||
template <typename T>
|
||||
struct is_associative : meta::all<has_key_type<T>, has_key_value_pair<T>, has_mapped_type<T>> {};
|
||||
|
||||
|
@ -526,7 +548,7 @@ namespace sol {
|
|||
}
|
||||
|
||||
template<typename T, meta::enable<is_pointer_like<meta::unqualified_t<T>>> = meta::enabler>
|
||||
inline auto& deref(T&& item) {
|
||||
inline auto deref(T&& item) -> decltype(*std::forward<T>(item)) {
|
||||
return *std::forward<T>(item);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,8 +32,11 @@
|
|||
#include "raii.hpp"
|
||||
#include "deprecate.hpp"
|
||||
#include "object.hpp"
|
||||
#include "container_usertype_metatable.hpp"
|
||||
#include <unordered_map>
|
||||
#include <cstdio>
|
||||
#include <sstream>
|
||||
#include <cassert>
|
||||
|
||||
namespace sol {
|
||||
namespace usertype_detail {
|
||||
|
@ -99,7 +102,14 @@ namespace sol {
|
|||
index(std::move(i)), newindex(std::move(ni)),
|
||||
indexbaseclasspropogation(index), newindexbaseclasspropogation(newindex) {}
|
||||
};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline int default_to_string(lua_State* L) {
|
||||
std::ostringstream oss;
|
||||
oss << stack::get<T>(L, 1);
|
||||
return stack::push(L, oss.str());
|
||||
}
|
||||
} // usertype_detail
|
||||
|
||||
struct usertype_metatable_core {
|
||||
usertype_detail::mapping_t mapping;
|
||||
|
@ -109,9 +119,8 @@ namespace sol {
|
|||
bool mustindex;
|
||||
|
||||
usertype_metatable_core(lua_CFunction ifx, lua_CFunction nifx) :
|
||||
mapping(), indexfunc(ifx),
|
||||
newindexfunc(nifx), runtime(), mustindex(false)
|
||||
{
|
||||
mapping(), indexfunc(ifx),
|
||||
newindexfunc(nifx), runtime(), mustindex(false) {
|
||||
|
||||
}
|
||||
|
||||
|
@ -423,7 +432,7 @@ namespace sol {
|
|||
|
||||
template <typename T, typename Op, typename Supports, typename Regs, meta::enable<Supports> = meta::enabler>
|
||||
inline void make_reg_op(Regs& l, int& index, const char* name) {
|
||||
l[index] = { name, &operator_wrap<T, Op> };
|
||||
l[index] = { name, &c_call<decltype(&operator_wrap<T, Op>), &operator_wrap<T, Op>> };
|
||||
++index;
|
||||
}
|
||||
|
||||
|
@ -431,6 +440,42 @@ namespace sol {
|
|||
inline void make_reg_op(Regs&, int&, const char*) {
|
||||
// Do nothing if there's no support
|
||||
}
|
||||
|
||||
template <typename T, typename Supports, typename Regs, meta::enable<Supports> = meta::enabler>
|
||||
inline void make_to_string_op(Regs& l, int& index) {
|
||||
const char* name = to_string(meta_function::to_string).c_str();
|
||||
l[index] = { name, &c_call<decltype(&default_to_string<T>), &default_to_string<T>> };
|
||||
++index;
|
||||
}
|
||||
|
||||
template <typename T, typename Supports, typename Regs, meta::disable<Supports> = meta::enabler>
|
||||
inline void make_to_string_op(Regs&, int&) {
|
||||
// Do nothing if there's no support
|
||||
}
|
||||
|
||||
template <typename T, typename Regs, meta::enable<meta::has_deducible_signature<T>> = meta::enabler>
|
||||
inline void make_call_op(Regs& l, int& index) {
|
||||
const char* name = to_string(meta_function::call).c_str();
|
||||
l[index] = { name, &c_call<decltype(&T::operator()), &T::operator()> };
|
||||
++index;
|
||||
}
|
||||
|
||||
template <typename T, typename Regs, meta::disable<meta::has_deducible_signature<T>> = meta::enabler>
|
||||
inline void make_call_op(Regs&, int&) {
|
||||
// Do nothing if there's no support
|
||||
}
|
||||
|
||||
template <typename T, typename Regs, meta::enable<meta::has_size<T>> = meta::enabler>
|
||||
inline void make_length_op(Regs& l, int& index) {
|
||||
const char* name = to_string(meta_function::length).c_str();
|
||||
l[index] = { name, &c_call<decltype(&T::size), &T::size> };
|
||||
++index;
|
||||
}
|
||||
|
||||
template <typename T, typename Regs, meta::disable<meta::has_size<T>> = meta::enabler>
|
||||
inline void make_length_op(Regs&, int&) {
|
||||
// Do nothing if there's no support
|
||||
}
|
||||
} // usertype_detail
|
||||
|
||||
template <typename T>
|
||||
|
@ -448,7 +493,7 @@ namespace sol {
|
|||
struct usertype_metatable<T, std::index_sequence<I...>, Tn...> : usertype_metatable_core, usertype_detail::registrar {
|
||||
typedef std::make_index_sequence<sizeof...(I) * 2> indices;
|
||||
typedef std::index_sequence<I...> half_indices;
|
||||
typedef std::array<luaL_Reg, sizeof...(Tn) / 2 + 1 + 3> regs_t;
|
||||
typedef std::array<luaL_Reg, sizeof...(Tn) / 2 + 1 + 29> regs_t;
|
||||
typedef std::tuple<Tn...> RawTuple;
|
||||
typedef std::tuple<clean_type_t<Tn> ...> Tuple;
|
||||
template <std::size_t Idx>
|
||||
|
@ -463,9 +508,7 @@ namespace sol {
|
|||
void* baseclasscheck;
|
||||
void* baseclasscast;
|
||||
bool secondarymeta;
|
||||
bool hasequals;
|
||||
bool hasless;
|
||||
bool haslessequals;
|
||||
std::array<bool, 29> properties;
|
||||
|
||||
template <std::size_t Idx, meta::enable<std::is_same<lua_CFunction, meta::unqualified_tuple_element<Idx + 1, RawTuple>>> = meta::enabler>
|
||||
lua_CFunction make_func() const {
|
||||
|
@ -490,18 +533,32 @@ namespace sol {
|
|||
}
|
||||
|
||||
int finish_regs(regs_t& l, int& index) {
|
||||
if (!hasless) {
|
||||
if (!properties[static_cast<int>(meta_function::less_than)]) {
|
||||
const char* name = to_string(meta_function::less_than).c_str();
|
||||
usertype_detail::make_reg_op<T, std::less<>, meta::supports_op_less<T>>(l, index, name);
|
||||
}
|
||||
if (!haslessequals) {
|
||||
if (!properties[static_cast<int>(meta_function::less_than_or_equal_to)]) {
|
||||
const char* name = to_string(meta_function::less_than_or_equal_to).c_str();
|
||||
usertype_detail::make_reg_op<T, std::less_equal<>, meta::supports_op_less_equal<T>>(l, index, name);
|
||||
}
|
||||
if (!hasequals) {
|
||||
if (!properties[static_cast<int>(meta_function::equal_to)]) {
|
||||
const char* name = to_string(meta_function::equal_to).c_str();
|
||||
usertype_detail::make_reg_op<T, std::conditional_t<meta::supports_op_equal<T>::value, std::equal_to<>, usertype_detail::no_comp>, std::true_type>(l, index, name);
|
||||
}
|
||||
if (!properties[static_cast<int>(meta_function::pairs)]) {
|
||||
const char* name = to_string(meta_function::pairs).c_str();
|
||||
l[index] = { name, container_usertype_metatable<as_container_t<T>>::pairs_call };
|
||||
++index;
|
||||
}
|
||||
if (!properties[static_cast<int>(meta_function::length)]) {
|
||||
usertype_detail::make_length_op<T>(l, index);
|
||||
}
|
||||
if (!properties[static_cast<int>(meta_function::to_string)]) {
|
||||
usertype_detail::make_to_string_op<T, meta::supports_ostream_op<T>>(l, index);
|
||||
}
|
||||
if (!properties[static_cast<int>(meta_function::call)]) {
|
||||
usertype_detail::make_call_op<T>(l, index);
|
||||
}
|
||||
if (destructfunc != nullptr) {
|
||||
l[index] = { to_string(meta_function::garbage_collect).c_str(), destructfunc };
|
||||
++index;
|
||||
|
@ -538,31 +595,37 @@ namespace sol {
|
|||
return;
|
||||
}
|
||||
luaL_Reg reg = usertype_detail::make_reg(std::forward<N>(n), make_func<Idx>());
|
||||
// Returnable scope
|
||||
// That would be a neat keyword for C++
|
||||
// returnable { ... };
|
||||
if (reg.name == to_string(meta_function::equal_to)) {
|
||||
hasequals = true;
|
||||
}
|
||||
if (reg.name == to_string(meta_function::less_than)) {
|
||||
hasless = true;
|
||||
}
|
||||
if (reg.name == to_string(meta_function::less_than_or_equal_to)) {
|
||||
haslessequals = true;
|
||||
}
|
||||
if (reg.name == to_string(meta_function::garbage_collect)) {
|
||||
destructfunc = reg.func;
|
||||
return;
|
||||
}
|
||||
else if (reg.name == to_string(meta_function::index)) {
|
||||
indexfunc = reg.func;
|
||||
mustindex = true;
|
||||
return;
|
||||
}
|
||||
else if (reg.name == to_string(meta_function::new_index)) {
|
||||
newindexfunc = reg.func;
|
||||
mustindex = true;
|
||||
return;
|
||||
for (std::size_t i = 1; i < properties.size(); ++i) {
|
||||
meta_function mf = static_cast<meta_function>(i);
|
||||
const std::string& mfname = to_string(mf);
|
||||
if (mfname == reg.name) {
|
||||
switch (mf) {
|
||||
case meta_function::garbage_collect:
|
||||
if (destructfunc != nullptr) {
|
||||
#ifdef SOL_NO_EXCEPTIONS
|
||||
throw sol::error("sol: 2 separate garbage_collect functions were set on this type. Please specify only 1 sol::meta_function::gc type AND wrap the function in a sol::destruct call, as shown by the documentation and examples");
|
||||
#else
|
||||
assert(false && "sol: 2 separate garbage_collect functions were set on this type. Please specify only 1 sol::meta_function::gc type AND wrap the function in a sol::destruct call, as shown by the documentation and examples");
|
||||
#endif
|
||||
}
|
||||
destructfunc = reg.func;
|
||||
return;
|
||||
case meta_function::index:
|
||||
indexfunc = reg.func;
|
||||
mustindex = true;
|
||||
properties[i] = true;
|
||||
return;
|
||||
case meta_function::new_index:
|
||||
newindexfunc = reg.func;
|
||||
mustindex = true;
|
||||
properties[i] = true;
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
properties[i] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
l[index] = reg;
|
||||
++index;
|
||||
|
@ -576,7 +639,7 @@ namespace sol {
|
|||
indexbaseclasspropogation(usertype_detail::walk_all_bases<true>), newindexbaseclasspropogation(usertype_detail::walk_all_bases<false>),
|
||||
baseclasscheck(nullptr), baseclasscast(nullptr),
|
||||
secondarymeta(contains_variable()),
|
||||
hasequals(false), hasless(false), haslessequals(false) {
|
||||
properties({}) {
|
||||
std::initializer_list<typename usertype_detail::mapping_t::value_type> ilist{ {
|
||||
std::pair<std::string, usertype_detail::call_information>( usertype_detail::make_string(std::get<I * 2>(functions)),
|
||||
usertype_detail::call_information(&usertype_metatable::real_find_call<I * 2, I * 2 + 1, true>,
|
||||
|
|
|
@ -13,6 +13,83 @@
|
|||
#include <array>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <numeric> // std::iota
|
||||
|
||||
struct my_object {
|
||||
private:
|
||||
std::vector<int> mdata;
|
||||
|
||||
public:
|
||||
static const void* last_printed;
|
||||
|
||||
my_object(int sz) : mdata() {
|
||||
mdata.resize(sz);
|
||||
std::iota(mdata.begin(), mdata.end(), 1);
|
||||
}
|
||||
|
||||
void operator() (std::size_t count, int value) {
|
||||
for (; count > 0; --count) {
|
||||
mdata.push_back(value);
|
||||
}
|
||||
}
|
||||
|
||||
public: // Container requirements, as per the C++ standard
|
||||
using value_type = int;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using iterator = decltype(mdata)::iterator;
|
||||
using const_iterator = decltype(mdata)::const_iterator;
|
||||
using difference_type = decltype(mdata)::difference_type;
|
||||
using size_type = decltype(mdata)::size_type;
|
||||
|
||||
iterator begin() { return iterator(mdata.begin()); }
|
||||
iterator end() { return iterator(mdata.end()); }
|
||||
const_iterator begin() const { return const_iterator(mdata.begin()); }
|
||||
const_iterator end() const { return const_iterator(mdata.end()); }
|
||||
const_iterator cbegin() const { return begin(); }
|
||||
const_iterator cend() const { return end(); }
|
||||
size_type size() const noexcept { return mdata.size(); }
|
||||
size_type max_size() const noexcept { return mdata.max_size(); }
|
||||
void push_back(const value_type& v) { mdata.push_back(v); }
|
||||
void insert(const_iterator where, const value_type& v) { mdata.insert(where, v); }
|
||||
bool empty() const noexcept { return mdata.empty(); }
|
||||
bool operator== (const my_object& right) const { return mdata == right.mdata; }
|
||||
bool operator!=(const my_object& right) const noexcept { return mdata != right.mdata; }
|
||||
|
||||
std::vector<int>& data() {
|
||||
return mdata;
|
||||
}
|
||||
|
||||
const std::vector<int>& data() const {
|
||||
return mdata;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const void* my_object::last_printed = nullptr;
|
||||
|
||||
std::ostream& operator<< (std::ostream& ostr, const my_object& mo) {
|
||||
my_object::last_printed = static_cast<const void*>(&mo);
|
||||
ostr << "{ ";
|
||||
const auto& v = mo.data();
|
||||
if (v.empty()) {
|
||||
ostr << "empty";
|
||||
}
|
||||
else {
|
||||
ostr << v[0];
|
||||
for (std::size_t i = 1; i < v.size(); ++i) {
|
||||
ostr << ", " << v[i];
|
||||
}
|
||||
}
|
||||
ostr << " }";
|
||||
|
||||
return ostr;
|
||||
}
|
||||
|
||||
namespace sol {
|
||||
template <>
|
||||
struct is_container<my_object> : std::false_type {};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void sequence_container_check(sol::state& lua, T& items) {
|
||||
|
@ -914,3 +991,97 @@ c_arr[-1] = 7
|
|||
}
|
||||
#endif // Something is wrong with g++'s lower versions: it always fails this test...
|
||||
}
|
||||
|
||||
TEST_CASE("containers/as_container", "test that we can force a container to be treated like one despite the trait being false using the proper marker") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_usertype<my_object>("my_object",
|
||||
sol::constructors<my_object(int)>(),
|
||||
sol::call_constructor, sol::constructors<my_object(int)>(),
|
||||
"size", &my_object::size,
|
||||
"iterable", [](my_object& mo) {
|
||||
return sol::as_container(mo);
|
||||
}
|
||||
);
|
||||
|
||||
#if SOL_LUA_VERSION > 501
|
||||
REQUIRE_NOTHROW([&]() {
|
||||
lua.script(R"(
|
||||
mop = my_object.new(20)
|
||||
for i, v in pairs(mop) do
|
||||
assert(i == v)
|
||||
end
|
||||
print(mop)
|
||||
)");
|
||||
}());
|
||||
{
|
||||
const my_object& mo = lua["mop"];
|
||||
REQUIRE((&mo == my_object::last_printed));
|
||||
}
|
||||
#endif
|
||||
REQUIRE_NOTHROW([&]() {
|
||||
lua.safe_script(R"(
|
||||
mo = my_object(10)
|
||||
c_mo = mo
|
||||
c_iterable = mo:iterable()
|
||||
)");
|
||||
}());
|
||||
my_object& mo = lua["c_mo"];
|
||||
my_object& mo_iterable = lua["c_iterable"];
|
||||
REQUIRE(&mo == &mo_iterable);
|
||||
REQUIRE(mo == mo_iterable);
|
||||
|
||||
REQUIRE_NOTHROW([&]() {
|
||||
lua.safe_script(R"(
|
||||
s1 = c_mo:size()
|
||||
s1_len = #c_mo
|
||||
s1_iterable = c_iterable:size()
|
||||
s1_iterable_len = #c_iterable
|
||||
)");
|
||||
}());
|
||||
|
||||
std::size_t s1 = lua["s1"];
|
||||
std::size_t s1_len = lua["s1_len"];
|
||||
std::size_t s1_iterable = lua["s1_iterable"];
|
||||
std::size_t s1_iterable_len = lua["s1_iterable_len"];
|
||||
REQUIRE(s1 == 10);
|
||||
REQUIRE(s1 == s1_len);
|
||||
REQUIRE(s1 == s1_iterable_len);
|
||||
REQUIRE(s1_iterable == s1_iterable_len);
|
||||
|
||||
REQUIRE_NOTHROW([&]() {
|
||||
lua.safe_script(R"(
|
||||
for i=1,#c_mo do
|
||||
v_iterable = c_iterable[i]
|
||||
assert(v_iterable == i)
|
||||
end
|
||||
)");
|
||||
}());
|
||||
|
||||
REQUIRE_NOTHROW([&]() {
|
||||
lua.safe_script(R"(
|
||||
mo(5, 20)
|
||||
c_iterable:insert(1, 100)
|
||||
v1 = c_iterable[1]
|
||||
s2 = c_mo:size()
|
||||
s2_len = #c_mo
|
||||
s2_iterable = c_iterable:size()
|
||||
s2_iterable_len = #c_iterable
|
||||
print(mo)
|
||||
)");
|
||||
}());
|
||||
|
||||
int v1 = lua["v1"];
|
||||
std::size_t s2 = lua["s2"];
|
||||
std::size_t s2_len = lua["s2_len"];
|
||||
std::size_t s2_iterable = lua["s2_iterable"];
|
||||
std::size_t s2_iterable_len = lua["s2_iterable_len"];
|
||||
|
||||
REQUIRE(v1 == 100);
|
||||
REQUIRE(s2 == 16);
|
||||
REQUIRE(s2 == s2_len);
|
||||
REQUIRE(s2 == s2_iterable_len);
|
||||
REQUIRE(s2_iterable == s2_iterable_len);
|
||||
REQUIRE(&mo == my_object::last_printed);
|
||||
}
|
||||
|
|
|
@ -319,7 +319,8 @@ TEST_CASE("containers/const serialization kvp", "make sure const keys / values a
|
|||
bark obj{ { 24, 50 } };
|
||||
lua.set("a", &obj);
|
||||
REQUIRE_NOTHROW(lua.script("assert(a[24] == 50)"));
|
||||
REQUIRE_THROWS(lua.script("a[24] = 51"));
|
||||
auto result = lua.safe_script("a[24] = 51", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
REQUIRE_NOTHROW(lua.script("assert(a[24] == 50)"));
|
||||
}
|
||||
|
||||
|
@ -355,7 +356,8 @@ TEST_CASE("containers/const serialization", "make sure containers are turned int
|
|||
REQUIRE_NOTHROW(
|
||||
lua.script("for k, v in pairs(b) do assert(k == v) end");
|
||||
);
|
||||
REQUIRE_THROWS(lua.script("b[1] = 20"));
|
||||
auto result = lua.safe_script("b[1] = 20", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -716,9 +718,8 @@ TEST_CASE("containers/non_copyable", "make sure non-copyable types in containers
|
|||
|
||||
lua["v"] = std::vector<non_copyable>{};
|
||||
|
||||
REQUIRE_THROWS([&lua]() {
|
||||
lua.script("t = test.new()\nt.b = v");
|
||||
}());
|
||||
auto pfr = lua.safe_script("t = test.new()\nt.b = v", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(pfr.valid());
|
||||
}
|
||||
SECTION("simple") {
|
||||
sol::state lua;
|
||||
|
@ -728,9 +729,8 @@ TEST_CASE("containers/non_copyable", "make sure non-copyable types in containers
|
|||
|
||||
lua["v"] = std::vector<non_copyable>{};
|
||||
|
||||
REQUIRE_THROWS([&lua]() {
|
||||
lua.script("t = test.new()\nt.b = v");
|
||||
}());
|
||||
auto pfr = lua.safe_script("t = test.new()\nt.b = v", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(pfr.valid());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -801,10 +801,7 @@ TEST_CASE("containers/input iterators", "test shitty input iterators that are al
|
|||
|
||||
const_iterator end() const { return iterator(); }
|
||||
|
||||
value_type fuck_off_gcc_warning() {
|
||||
// "typedef not used locally"
|
||||
// but it's used elsewhere in the code GCC
|
||||
// so maybe your warning should sod off
|
||||
value_type gcc_warning_block() {
|
||||
return int_shim();
|
||||
}
|
||||
|
||||
|
@ -835,57 +832,107 @@ end
|
|||
}
|
||||
|
||||
TEST_CASE("containers/pairs", "test how well pairs work with the underlying system") {
|
||||
typedef std::pair<std::string, int> pair_arr_t[5];
|
||||
typedef int arr_t[5];
|
||||
|
||||
sol::state lua;
|
||||
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
std::vector<std::pair<std::string, int>> a{ { "one", 1 },{ "two", 2 },{ "three", 3 },{ "four", 4 },{ "five", 5 } };
|
||||
std::array<std::pair<std::string, int>, 5> b{ { { "one", 1 },{ "two", 2 },{ "three", 3 },{ "four", 4 },{ "five", 5 } } };
|
||||
//std::pair<std::string, int> c[5]{ { "one", 1 },{ "two", 2 },{ "three", 3 },{ "four", 4 },{ "five", 5 } };
|
||||
//int d[5] = { 1, 2, 3, 4, 5 };
|
||||
pair_arr_t c{ { "one", 1 },{ "two", 2 },{ "three", 3 },{ "four", 4 },{ "five", 5 } };
|
||||
arr_t d = { 1, 2, 3, 4, 5 };
|
||||
|
||||
lua["a"] = std::ref(a);
|
||||
lua["b"] = &b;
|
||||
//lua["c"] = std::ref(c);
|
||||
//lua["d"] = &d;
|
||||
lua["c"] = std::ref(c);
|
||||
lua["d"] = &d;
|
||||
|
||||
lua.script("av1, av2 = a:get(1)");
|
||||
lua.script("bv1, bv2 = b:get(1)");
|
||||
//lua.script("cv1, cv2 = c:get(1)");
|
||||
//lua.script("dv1, dv2 = d:get(1)");
|
||||
lua.script("cv1, cv2 = c:get(1)");
|
||||
lua.script("dv1, dv2 = d:get(1)");
|
||||
|
||||
std::vector<std::pair<std::string, int>>& la = lua["a"];
|
||||
std::array<std::pair<std::string, int>, 5>& lb = lua["b"];
|
||||
//std::pair<std::string, int> (&lc)[5] = lua["c"];
|
||||
//int (&lc)[5] = lua["d"];
|
||||
pair_arr_t* plc = lua["c"];
|
||||
pair_arr_t& lc = *plc;
|
||||
arr_t* pld = lua["d"];
|
||||
arr_t& ld = *pld;
|
||||
|
||||
std::pair<std::string, int>& va = la[0];
|
||||
std::pair<std::string, int>& vb = lb[0];
|
||||
//std::pair<std::string, int>& vc = lc[0];
|
||||
//int vd = ld[0];
|
||||
std::pair<std::string, int>& vc = lc[0];
|
||||
int& vd = ld[0];
|
||||
|
||||
std::string av1 = lua["av1"];
|
||||
int av2 = lua["av2"];
|
||||
std::string bv1 = lua["bv1"];
|
||||
int bv2 = lua["bv2"];
|
||||
//std::string cv1 = lua["cv1"];
|
||||
//int cv2 = lua["cv2"];
|
||||
//int dv1 = lua["dv1"];
|
||||
//sol::lua_nil_t dv2 = lua["dv2"];
|
||||
std::string cv1 = lua["cv1"];
|
||||
int cv2 = lua["cv2"];
|
||||
int dv1 = lua["dv1"];
|
||||
sol::lua_nil_t dv2 = lua["dv2"];
|
||||
|
||||
REQUIRE(va.first == "one");
|
||||
REQUIRE(va.second == 1);
|
||||
REQUIRE(vb.first == "one");
|
||||
REQUIRE(vb.second == 1);
|
||||
//REQUIRE(vc.first == "one");
|
||||
//REQUIRE(vc.second == 1);
|
||||
//REQUIRE(vd == 1);
|
||||
REQUIRE(vc.first == "one");
|
||||
REQUIRE(vc.second == 1);
|
||||
REQUIRE(vd == 1);
|
||||
|
||||
REQUIRE(av1 == "one");
|
||||
REQUIRE(av2 == 1);
|
||||
REQUIRE(bv1 == "one");
|
||||
REQUIRE(bv2 == 1);
|
||||
//REQUIRE(cv1 == "one");
|
||||
//REQUIRE(cv2 == 1);
|
||||
//REQUIRE(dv1 == 1);
|
||||
//REQUIRE(dv2 == sol::lua_nil);
|
||||
REQUIRE(cv1 == "one");
|
||||
REQUIRE(cv2 == 1);
|
||||
REQUIRE(dv1 == 1);
|
||||
REQUIRE(dv2 == sol::lua_nil);
|
||||
}
|
||||
|
||||
TEST_CASE("containers/pointer types", "check that containers with unique usertypes and pointers or something") {
|
||||
struct base_t {
|
||||
virtual int get() const = 0;
|
||||
};
|
||||
|
||||
struct derived_1_t : base_t {
|
||||
virtual int get() const override {
|
||||
return 250;
|
||||
}
|
||||
};
|
||||
|
||||
struct derived_2_t : base_t {
|
||||
virtual int get() const override {
|
||||
return 500;
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
derived_1_t d1;
|
||||
derived_2_t d2;
|
||||
|
||||
std::vector<std::unique_ptr<base_t>> v1;
|
||||
v1.push_back(std::make_unique<derived_1_t>());
|
||||
v1.push_back(std::make_unique<derived_2_t>());
|
||||
|
||||
std::vector<base_t*> v2;
|
||||
v2.push_back(&d1);
|
||||
v2.push_back(&d2);
|
||||
|
||||
lua["c1"] = std::move(v1);
|
||||
lua["c2"] = &v2;
|
||||
|
||||
lua.safe_script("b1 = c1[1]");
|
||||
base_t* b1 = lua["b1"];
|
||||
int val1 = b1->get();
|
||||
REQUIRE(val1 == 250);
|
||||
|
||||
lua.safe_script("b2 = c2[2]");
|
||||
base_t* b2 = lua["b2"];
|
||||
int val2 = b2->get();
|
||||
REQUIRE(val2 == 500);
|
||||
}
|
||||
|
|
|
@ -655,12 +655,25 @@ N = n(1, 2, 3)
|
|||
lua.set("v", &nested::i);
|
||||
lua.set("nested", nested());
|
||||
lua.set("inner", inner());
|
||||
REQUIRE_THROWS(lua.script("s(o2, 2)"));
|
||||
REQUIRE_THROWS(lua.script("t(2)"));
|
||||
REQUIRE_THROWS(lua.script("u(inner)"));
|
||||
REQUIRE_THROWS(lua.script("v(nested, inner)"));
|
||||
{
|
||||
auto result = lua.safe_script("s(o2, 2)", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
{
|
||||
auto result = lua.safe_script("t(2)", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
{
|
||||
auto result = lua.safe_script("u(inner)", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
{
|
||||
auto result = lua.safe_script("v(nested, inner)", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("simple/call with parameters", "Lua function is called with a few parameters from C++") {
|
||||
sol::state lua;
|
||||
|
||||
|
@ -668,11 +681,18 @@ TEST_CASE("simple/call with parameters", "Lua function is called with a few para
|
|||
auto f = lua.get<sol::function>("my_add");
|
||||
REQUIRE_NOTHROW(lua.script("function my_nothing(i, j, k) end"));
|
||||
auto fvoid = lua.get<sol::function>("my_nothing");
|
||||
int a;
|
||||
REQUIRE_NOTHROW(fvoid(1, 2, 3));
|
||||
REQUIRE_NOTHROW(a = f.call<int>(1, 2, 3));
|
||||
REQUIRE(a == 6);
|
||||
REQUIRE_THROWS(a = f(1, 2, "arf"));
|
||||
REQUIRE_NOTHROW([&]() {
|
||||
fvoid(1, 2, 3);
|
||||
}());
|
||||
REQUIRE_NOTHROW([&]() {
|
||||
int a = f.call<int>(1, 2, 3);
|
||||
REQUIRE(a == 6);
|
||||
}());
|
||||
sol::protected_function pf = f;
|
||||
REQUIRE_NOTHROW([&]() {
|
||||
sol::protected_function_result pfr = pf(1, 2, "arf");
|
||||
REQUIRE_FALSE(pfr.valid());
|
||||
}());
|
||||
}
|
||||
|
||||
TEST_CASE("simple/call c++ function", "C++ function is called from lua") {
|
||||
|
@ -837,7 +857,8 @@ TEST_CASE("functions/overloading", "Check if overloading works properly for regu
|
|||
REQUIRE((lua["b"] == string_bark));
|
||||
REQUIRE((lua["c"] == 2));
|
||||
|
||||
REQUIRE_THROWS(lua.script("func(1,2,'meow')"));
|
||||
auto result = lua.safe_script("func(1,2,'meow')", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
|
||||
TEST_CASE("overloading/c_call", "Make sure that overloading works with c_call functionality") {
|
||||
|
@ -1247,18 +1268,16 @@ TEST_CASE("functions/pointer nullptr + nil", "ensure specific semantics for hand
|
|||
lua["v2"] = std::unique_ptr<nil_test>();
|
||||
lua["g"] = &nil_test::g;
|
||||
|
||||
REQUIRE_THROWS([&]() {
|
||||
lua.script("g(v2)");
|
||||
}());
|
||||
auto result = lua.safe_script("g(v2)", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
SECTION("throw shared argument") {
|
||||
sol::state lua;
|
||||
lua["v1"] = sptr;
|
||||
lua["h"] = &nil_test::h;
|
||||
|
||||
REQUIRE_THROWS([&]() {
|
||||
lua.script("h(v1)");
|
||||
}());
|
||||
auto result = lua.safe_script("h(v1)", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
SECTION("throw ref") {
|
||||
REQUIRE_THROWS([&]() {
|
||||
|
@ -1406,9 +1425,8 @@ TEST_CASE("functions/unique_usertype overloading", "make sure overloading can wo
|
|||
lua.set_function("f", print_up_test);
|
||||
lua["v3"] = test(17);
|
||||
|
||||
REQUIRE_THROWS([&]() {
|
||||
lua.script("f(v3)");
|
||||
}());
|
||||
auto result = lua.safe_script("f(v3)", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
};
|
||||
SECTION("throws-shared_ptr") {
|
||||
sol::state lua;
|
||||
|
@ -1416,9 +1434,8 @@ TEST_CASE("functions/unique_usertype overloading", "make sure overloading can wo
|
|||
lua.set_function("f", print_up_test);
|
||||
lua["v2"] = std::make_shared<test>(44);
|
||||
|
||||
REQUIRE_THROWS([&]() {
|
||||
lua.script("f(v2)");
|
||||
}());
|
||||
auto result = lua.safe_script("f(v2)", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
};
|
||||
SECTION("throws-ptr") {
|
||||
sol::state lua;
|
||||
|
@ -1426,9 +1443,8 @@ TEST_CASE("functions/unique_usertype overloading", "make sure overloading can wo
|
|||
lua.set_function("f", print_up_test);
|
||||
lua["v4"] = ut.get();
|
||||
|
||||
REQUIRE_THROWS([&]() {
|
||||
lua.script("f(v4)");
|
||||
}());
|
||||
auto result = lua.safe_script("f(v4)", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
#define SOL_CHECK_ARGUMENTS
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
|
||||
#include <sol.hpp>
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
TEST_CASE("operators/default", "test that generic equality operators and all sorts of equality tests can be used") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <iostream>
|
||||
|
||||
TEST_CASE("operators/default", "test that generic equality operators and all sorts of equality tests can be used") {
|
||||
struct T {};
|
||||
struct U {
|
||||
int a;
|
||||
|
@ -22,9 +24,9 @@ TEST_CASE("operators/default", "test that generic equality operators and all sor
|
|||
return a == r.a;
|
||||
}
|
||||
};
|
||||
lua.new_usertype<T>("T");
|
||||
lua.new_usertype<U>("U");
|
||||
lua.new_usertype<V>("V");
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
T t1;
|
||||
T& t2 = t1;
|
||||
|
@ -45,39 +47,227 @@ TEST_CASE("operators/default", "test that generic equality operators and all sor
|
|||
lua["v2"] = &v2;
|
||||
lua["v3"] = &v3;
|
||||
|
||||
// Can only compare identity here
|
||||
REQUIRE_NOTHROW([&]{
|
||||
lua.script("assert(t1 == t1)");
|
||||
lua.script("assert(t2 == t2)");
|
||||
lua.script("assert(t3 == t3)");
|
||||
}());
|
||||
REQUIRE_NOTHROW([&]{
|
||||
lua.script("assert(t1 == t2)");
|
||||
lua.script("assert(not (t1 == t3))");
|
||||
lua.script("assert(not (t2 == t3))");
|
||||
}());
|
||||
// Object should compare equal to themselves
|
||||
// (and not invoke operator==; pointer test should be sufficient)
|
||||
REQUIRE_NOTHROW([&]{
|
||||
lua.script("assert(u1 == u1)");
|
||||
lua.script("assert(u2 == u2)");
|
||||
lua.script("assert(u3 == u3)");
|
||||
}());
|
||||
REQUIRE_NOTHROW([&]{
|
||||
lua.script("assert(not (u1 == u2))");
|
||||
lua.script("assert(u1 == u3)");
|
||||
lua.script("assert(not (u2 == u3))");
|
||||
}());
|
||||
// Object should compare equal to themselves
|
||||
// (and not invoke operator==; pointer test should be sufficient)
|
||||
REQUIRE_NOTHROW([&]{
|
||||
lua.script("assert(v1 == v1)");
|
||||
lua.script("assert(v2 == v2)");
|
||||
lua.script("assert(v3 == v3)");
|
||||
}());
|
||||
REQUIRE_NOTHROW([&]{
|
||||
lua.script("assert(not (v1 == v2))");
|
||||
lua.script("assert(v1 == v3)");
|
||||
lua.script("assert(not (v2 == v3))");
|
||||
}());
|
||||
SECTION("regular") {
|
||||
lua.new_usertype<T>("T");
|
||||
lua.new_usertype<U>("U");
|
||||
lua.new_usertype<V>("V");
|
||||
|
||||
// Can only compare identity here
|
||||
REQUIRE_NOTHROW([&] {
|
||||
lua.script("assert(t1 == t1)");
|
||||
lua.script("assert(t2 == t2)");
|
||||
lua.script("assert(t3 == t3)");
|
||||
}());
|
||||
REQUIRE_NOTHROW([&] {
|
||||
lua.script("assert(t1 == t2)");
|
||||
lua.script("assert(not (t1 == t3))");
|
||||
lua.script("assert(not (t2 == t3))");
|
||||
}());
|
||||
// Object should compare equal to themselves
|
||||
// (and not invoke operator==; pointer test should be sufficient)
|
||||
REQUIRE_NOTHROW([&] {
|
||||
lua.script("assert(u1 == u1)");
|
||||
lua.script("assert(u2 == u2)");
|
||||
lua.script("assert(u3 == u3)");
|
||||
}());
|
||||
REQUIRE_NOTHROW([&] {
|
||||
lua.script("assert(not (u1 == u2))");
|
||||
lua.script("assert(u1 == u3)");
|
||||
lua.script("assert(not (u2 == u3))");
|
||||
}());
|
||||
// Object should compare equal to themselves
|
||||
// (and not invoke operator==; pointer test should be sufficient)
|
||||
REQUIRE_NOTHROW([&] {
|
||||
lua.script("assert(v1 == v1)");
|
||||
lua.script("assert(v2 == v2)");
|
||||
lua.script("assert(v3 == v3)");
|
||||
}());
|
||||
REQUIRE_NOTHROW([&] {
|
||||
lua.script("assert(not (v1 == v2))");
|
||||
lua.script("assert(v1 == v3)");
|
||||
lua.script("assert(not (v2 == v3))");
|
||||
}());
|
||||
}
|
||||
SECTION("simple") {
|
||||
lua.new_simple_usertype<T>("T");
|
||||
lua.new_simple_usertype<U>("U");
|
||||
lua.new_simple_usertype<V>("V");
|
||||
|
||||
// Can only compare identity here
|
||||
REQUIRE_NOTHROW([&] {
|
||||
lua.script("assert(t1 == t1)");
|
||||
lua.script("assert(t2 == t2)");
|
||||
lua.script("assert(t3 == t3)");
|
||||
}());
|
||||
REQUIRE_NOTHROW([&] {
|
||||
lua.script("assert(t1 == t2)");
|
||||
lua.script("assert(not (t1 == t3))");
|
||||
lua.script("assert(not (t2 == t3))");
|
||||
}());
|
||||
// Object should compare equal to themselves
|
||||
// (and not invoke operator==; pointer test should be sufficient)
|
||||
REQUIRE_NOTHROW([&] {
|
||||
lua.script("assert(u1 == u1)");
|
||||
lua.script("assert(u2 == u2)");
|
||||
lua.script("assert(u3 == u3)");
|
||||
}());
|
||||
REQUIRE_NOTHROW([&] {
|
||||
lua.script("assert(not (u1 == u2))");
|
||||
lua.script("assert(u1 == u3)");
|
||||
lua.script("assert(not (u2 == u3))");
|
||||
}());
|
||||
// Object should compare equal to themselves
|
||||
// (and not invoke operator==; pointer test should be sufficient)
|
||||
REQUIRE_NOTHROW([&] {
|
||||
lua.script("assert(v1 == v1)");
|
||||
lua.script("assert(v2 == v2)");
|
||||
lua.script("assert(v3 == v3)");
|
||||
}());
|
||||
REQUIRE_NOTHROW([&] {
|
||||
lua.script("assert(not (v1 == v2))");
|
||||
lua.script("assert(v1 == v3)");
|
||||
lua.script("assert(not (v2 == v3))");
|
||||
}());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("operators/call", "test call operator generation") {
|
||||
struct callable {
|
||||
int operator ()(int a, std::string b) {
|
||||
return a + b.length();
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
SECTION("regular") {
|
||||
lua.new_usertype<callable>("callable");
|
||||
{
|
||||
lua.safe_script("obj = callable.new()");
|
||||
lua.safe_script("v = obj(2, 'bark woof')");
|
||||
int v = lua["v"];
|
||||
REQUIRE(v == 11);
|
||||
}
|
||||
}
|
||||
SECTION("simple") {
|
||||
lua.new_simple_usertype<callable>("callable");
|
||||
{
|
||||
lua.safe_script("obj = callable.new()");
|
||||
lua.safe_script("v = obj(2, 'bark woof')");
|
||||
int v = lua["v"];
|
||||
REQUIRE(v == 11);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct stringable {
|
||||
static const void* last_print_ptr;
|
||||
};
|
||||
const void* stringable::last_print_ptr = nullptr;
|
||||
|
||||
std::ostream& operator<< (std::ostream& ostr, const stringable& o) {
|
||||
stringable::last_print_ptr = static_cast<const void*>(&o);
|
||||
return ostr << " { stringable! }";
|
||||
}
|
||||
|
||||
TEST_CASE("operators/stringable", "test std::ostream stringability") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
SECTION("regular") {
|
||||
lua.new_usertype<stringable>("stringable");
|
||||
{
|
||||
lua.safe_script("obj = stringable.new()");
|
||||
lua.safe_script("print(obj)");
|
||||
stringable& obj = lua["obj"];
|
||||
REQUIRE(stringable::last_print_ptr == &obj);
|
||||
}
|
||||
}
|
||||
SECTION("simple") {
|
||||
lua.new_simple_usertype<stringable>("stringable");
|
||||
{
|
||||
lua.safe_script("obj = stringable.new()");
|
||||
lua.safe_script("print(obj)");
|
||||
stringable& obj = lua["obj"];
|
||||
REQUIRE(stringable::last_print_ptr == &obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("operators/container-like", "test that generic begin/end and iterator are automatically bound") {
|
||||
#if SOL_LUA_VERSION > 501
|
||||
struct container {
|
||||
typedef int* iterator;
|
||||
typedef int value_type;
|
||||
|
||||
int values[10];
|
||||
|
||||
container() {
|
||||
std::iota(begin(), end(), 1);
|
||||
}
|
||||
|
||||
iterator begin() {
|
||||
return &values[0];
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
return &values[0] + 10;
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
SECTION("regular") {
|
||||
lua.new_usertype<container>("container");
|
||||
{
|
||||
lua.safe_script("obj = container.new()");
|
||||
lua.safe_script("i = 0 for k, v in pairs(obj) do i = i + 1 assert(k == v) end");
|
||||
std::size_t i = lua["i"];
|
||||
REQUIRE(i == 10);
|
||||
}
|
||||
}
|
||||
SECTION("simple") {
|
||||
lua.new_simple_usertype<container>("container");
|
||||
{
|
||||
lua.safe_script("obj = container.new()");
|
||||
lua.safe_script("i = 0 for k, v in pairs(obj) do i = i + 1 assert(k == v) end");
|
||||
std::size_t i = lua["i"];
|
||||
REQUIRE(i == 10);
|
||||
}
|
||||
}
|
||||
#else
|
||||
REQUIRE(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("operators/length", "test that size is automatically bound to the length operator") {
|
||||
struct sizable {
|
||||
std::size_t size() const {
|
||||
return 6;
|
||||
}
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
SECTION("regular") {
|
||||
lua.new_usertype<sizable>("sizable");
|
||||
{
|
||||
lua.safe_script("obj = sizable.new()");
|
||||
lua.safe_script("s = #obj");
|
||||
std::size_t s = lua["s"];
|
||||
REQUIRE(s == 6);
|
||||
}
|
||||
}
|
||||
SECTION("simple") {
|
||||
lua.new_simple_usertype<sizable>("sizable");
|
||||
{
|
||||
lua.safe_script("obj = sizable.new()");
|
||||
lua.safe_script("s = #obj");
|
||||
std::size_t s = lua["s"];
|
||||
REQUIRE(s == 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -575,7 +575,8 @@ TEST_CASE("simple_usertype/no_constructor", "make sure simple usertype errors wh
|
|||
lua.new_simple_usertype<thing>("thing",
|
||||
sol::meta_function::construct, sol::no_constructor
|
||||
);
|
||||
REQUIRE_THROWS(lua.script("a = thing.new()"));
|
||||
auto result = lua.safe_script("a = thing.new()", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
|
||||
SECTION("call no_constructor") {
|
||||
|
@ -585,7 +586,8 @@ TEST_CASE("simple_usertype/no_constructor", "make sure simple usertype errors wh
|
|||
lua.new_simple_usertype<thing>("thing",
|
||||
sol::call_constructor, sol::no_constructor
|
||||
);
|
||||
REQUIRE_THROWS(lua.script("a = thing()"));
|
||||
auto result = lua.safe_script("a = thing()", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -618,21 +620,23 @@ TEST_CASE("simple_usertype/runtime extensibility", "Check if usertypes are runti
|
|||
t = thing.new()
|
||||
)");
|
||||
|
||||
REQUIRE_THROWS([&lua]() {
|
||||
lua.script(R"(
|
||||
{
|
||||
auto result = lua.safe_script(R"(
|
||||
t.runtime_func = function (a)
|
||||
return a + 50
|
||||
end
|
||||
)");
|
||||
}());
|
||||
)", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
|
||||
REQUIRE_THROWS([&lua]() {
|
||||
lua.script(R"(
|
||||
{
|
||||
auto result = lua.safe_script(R"(
|
||||
function t:runtime_func(a)
|
||||
return a + 52
|
||||
end
|
||||
)");
|
||||
}());
|
||||
)", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
|
||||
lua.script("val = t:func(2)");
|
||||
val = lua["val"];
|
||||
|
@ -663,20 +667,22 @@ end
|
|||
t = thing.new()
|
||||
)");
|
||||
|
||||
REQUIRE_THROWS([&lua]() {
|
||||
lua.script(R"(
|
||||
{
|
||||
auto result = lua.safe_script(R"(
|
||||
t.runtime_func = function (a)
|
||||
return a + 50
|
||||
end
|
||||
)");
|
||||
}());
|
||||
)", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
|
||||
REQUIRE_THROWS([&lua]() {
|
||||
lua.script(R"(
|
||||
REQUIRE_NOTHROW([&lua]() {
|
||||
auto result = lua.safe_script(R"(
|
||||
function t:runtime_func(a)
|
||||
return a + 52
|
||||
end
|
||||
)");
|
||||
)", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}());
|
||||
|
||||
lua.script("val = t:func(2)");
|
||||
|
@ -910,9 +916,9 @@ TEST_CASE("simple_usertype/indexing", "make sure simple usertypes can be indexed
|
|||
|
||||
lua.script(R"(
|
||||
local t = test.new()
|
||||
v = t.a;
|
||||
v = t.a
|
||||
print(v)
|
||||
t.unknown = 50;
|
||||
t.unknown = 50
|
||||
)");
|
||||
int v = lua["v"];
|
||||
REQUIRE(v == 2);
|
||||
|
|
146
test_state.cpp
146
test_state.cpp
|
@ -4,61 +4,92 @@
|
|||
#include <sol.hpp>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
|
||||
#include "test_stack_guard.hpp"
|
||||
|
||||
template <typename Name, typename Data>
|
||||
void write_file_attempt(Name&& filename, Data&& data) {
|
||||
bool success = false;
|
||||
for (std::size_t i = 0; i < 20; ++i) {
|
||||
try {
|
||||
std::ofstream file(std::forward<Name>(filename), std::ios::out);
|
||||
file.exceptions(std::ios_base::badbit | std::ios_base::failbit);
|
||||
file << std::forward<Data>(data) << std::endl;
|
||||
file.close();
|
||||
}
|
||||
catch (const std::exception&) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
continue;
|
||||
}
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
if (!success) {
|
||||
throw std::runtime_error("cannot open file or write out");
|
||||
}
|
||||
}
|
||||
|
||||
struct write_file_attempt_object {
|
||||
template <typename... Args>
|
||||
void operator()(Args&&... args) {
|
||||
write_file_attempt(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("state/require_file", "opening files as 'requires'") {
|
||||
static const char FILE_NAME[] = "./tmp_thingy.lua";
|
||||
static const char FILE_NAME_USER[] = "./tmp_thingy_user.lua";
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
SECTION("with usertypes")
|
||||
{
|
||||
SECTION("with usertypes") {
|
||||
write_file_attempt(FILE_NAME_USER, "return { modfunc = function () return foo.new(221) end }");
|
||||
|
||||
struct foo {
|
||||
foo(int bar) : bar(bar) {}
|
||||
|
||||
const int bar;
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_usertype<foo>("foo",
|
||||
sol::constructors<sol::types<int>>{},
|
||||
"bar", &foo::bar
|
||||
);
|
||||
|
||||
std::fstream file(FILE_NAME, std::ios::out);
|
||||
file << "return { modfunc = function () return foo.new(221) end }" << std::endl;
|
||||
file.close();
|
||||
const sol::table thingy1 = lua.require_file("thingy", FILE_NAME_USER);
|
||||
|
||||
const sol::table thingy1 = lua.require_file("thingy", FILE_NAME);
|
||||
|
||||
CHECK(thingy1.valid());
|
||||
REQUIRE(thingy1.valid());
|
||||
|
||||
const foo foo_v = thingy1["modfunc"]();
|
||||
|
||||
int val1 = foo_v.bar;
|
||||
|
||||
CHECK(val1 == 221);
|
||||
REQUIRE(val1 == 221);
|
||||
}
|
||||
|
||||
SECTION("simple")
|
||||
{
|
||||
std::fstream file(FILE_NAME, std::ios::out);
|
||||
file << "return { modfunc = function () return 221 end }" << std::endl;
|
||||
file.close();
|
||||
SECTION("simple") {
|
||||
write_file_attempt(FILE_NAME, "return { modfunc = function () return 221 end }");
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
const sol::table thingy1 = lua.require_file("thingy", FILE_NAME);
|
||||
const sol::table thingy2 = lua.require_file("thingy", FILE_NAME);
|
||||
|
||||
CHECK(thingy1.valid());
|
||||
CHECK(thingy2.valid());
|
||||
REQUIRE(thingy1.valid());
|
||||
REQUIRE(thingy2.valid());
|
||||
|
||||
int val1 = thingy1["modfunc"]();
|
||||
int val2 = thingy2["modfunc"]();
|
||||
|
||||
CHECK(val1 == 221);
|
||||
CHECK(val2 == 221);
|
||||
REQUIRE(val1 == 221);
|
||||
REQUIRE(val2 == 221);
|
||||
// must have loaded the same table
|
||||
CHECK(thingy1 == thingy2);
|
||||
REQUIRE((thingy1 == thingy2));
|
||||
}
|
||||
|
||||
std::remove(FILE_NAME);
|
||||
|
@ -77,10 +108,10 @@ TEST_CASE("state/require_script", "opening strings as 'requires' clauses") {
|
|||
REQUIRE(val1 == 221);
|
||||
REQUIRE(val2 == 221);
|
||||
// must have loaded the same table
|
||||
REQUIRE(thingy1 == thingy2);
|
||||
REQUIRE((thingy1 == thingy2));
|
||||
}
|
||||
|
||||
TEST_CASE("state/require", "opening using a file") {
|
||||
TEST_CASE("state/require", "require using a function") {
|
||||
struct open {
|
||||
static int open_func(lua_State* L) {
|
||||
sol::state_view lua = L;
|
||||
|
@ -127,7 +158,7 @@ TEST_CASE("state/multi require", "make sure that requires transfers across hand-
|
|||
//REQUIRE(thingy1 == thingy2);
|
||||
// But we care, thankfully
|
||||
//REQUIRE(thingy1 == thingy3);
|
||||
REQUIRE(thingy2 == thingy3);
|
||||
REQUIRE((thingy2 == thingy3));
|
||||
}
|
||||
|
||||
TEST_CASE("state/require-safety", "make sure unrelated modules aren't harmed in using requires") {
|
||||
|
@ -299,6 +330,20 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
|
|||
static const char file_bad_runtime[] = "./temp.bad_runtime.lua";
|
||||
const static std::string good = "a = 21\nreturn a";
|
||||
static const char file_good[] = "./temp.good.lua";
|
||||
static std::once_flag flag_file_bs = {}, flag_file_br = {}, flag_file_g = {};
|
||||
static std::atomic<int> finished = 0;
|
||||
std::call_once(flag_file_bs, write_file_attempt_object(), file_bad_syntax, bad_syntax);
|
||||
std::call_once(flag_file_br, write_file_attempt_object(), file_bad_runtime, bad_runtime);
|
||||
std::call_once(flag_file_g, write_file_attempt_object(), file_good, good);
|
||||
|
||||
auto clean_files = []() {
|
||||
if (finished.fetch_add(1) != 11) {
|
||||
return;
|
||||
}
|
||||
std::remove(file_bad_syntax);
|
||||
std::remove(file_bad_runtime);
|
||||
std::remove(file_good);
|
||||
};
|
||||
|
||||
SECTION("script") {
|
||||
sol::state lua;
|
||||
|
@ -307,6 +352,16 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
|
|||
int a = lua["a"];
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
clean_files();
|
||||
}
|
||||
SECTION("unsafe_script") {
|
||||
sol::state lua;
|
||||
sol::stack_guard sg(lua);
|
||||
int ar = lua.unsafe_script(good);
|
||||
int a = lua["a"];
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
clean_files();
|
||||
}
|
||||
SECTION("script-handler") {
|
||||
sol::state lua;
|
||||
|
@ -323,6 +378,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
|
|||
REQUIRE(result.valid());
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
clean_files();
|
||||
}
|
||||
SECTION("do_string") {
|
||||
sol::state lua;
|
||||
|
@ -339,6 +395,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
|
|||
REQUIRE(result.valid());
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
clean_files();
|
||||
}
|
||||
SECTION("load_string") {
|
||||
sol::state lua;
|
||||
|
@ -361,14 +418,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
|
|||
REQUIRE(result.valid());
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
}
|
||||
{
|
||||
std::ofstream fbs(file_bad_syntax, std::ios::out);
|
||||
fbs << bad_syntax;
|
||||
std::ofstream fbr(file_bad_runtime, std::ios::out);
|
||||
fbr << bad_runtime;
|
||||
std::ofstream fg(file_good, std::ios::out);
|
||||
fg << good;
|
||||
clean_files();
|
||||
}
|
||||
SECTION("script_file") {
|
||||
sol::state lua;
|
||||
|
@ -377,6 +427,16 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
|
|||
int a = lua["a"];
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
clean_files();
|
||||
}
|
||||
SECTION("unsafe_script_file") {
|
||||
sol::state lua;
|
||||
sol::stack_guard sg(lua);
|
||||
int ar = lua.unsafe_script_file(file_good);
|
||||
int a = lua["a"];
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
clean_files();
|
||||
}
|
||||
SECTION("script_file-handler") {
|
||||
sol::state lua;
|
||||
|
@ -393,6 +453,24 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
|
|||
REQUIRE(result.valid());
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
clean_files();
|
||||
}
|
||||
SECTION("safe_script_file-handler") {
|
||||
sol::state lua;
|
||||
sol::stack_guard sg(lua);
|
||||
auto errbs = lua.safe_script_file(file_bad_syntax, sol::script_pass_on_error);
|
||||
REQUIRE(!errbs.valid());
|
||||
|
||||
auto errbr = lua.safe_script_file(file_bad_runtime, sol::script_pass_on_error);
|
||||
REQUIRE(!errbr.valid());
|
||||
|
||||
auto result = lua.safe_script_file(file_good, sol::script_pass_on_error);
|
||||
int a = lua["a"];
|
||||
int ar = result;
|
||||
REQUIRE(result.valid());
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
clean_files();
|
||||
}
|
||||
SECTION("do_file") {
|
||||
sol::state lua;
|
||||
|
@ -409,6 +487,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
|
|||
REQUIRE(result.valid());
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
clean_files();
|
||||
}
|
||||
SECTION("load_file") {
|
||||
sol::state lua;
|
||||
|
@ -431,6 +510,7 @@ TEST_CASE("state/script, do, and load", "test success and failure cases for load
|
|||
REQUIRE(result.valid());
|
||||
REQUIRE(a == 21);
|
||||
REQUIRE(ar == 21);
|
||||
clean_files();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -133,7 +133,8 @@ TEST_CASE("tables/new_enum", "Making sure enums can be put in and gotten out as
|
|||
|
||||
direction d = lua["direction"]["left"];
|
||||
REQUIRE(d == direction::left);
|
||||
REQUIRE_THROWS(lua.script("direction.left = 50"));
|
||||
auto result = lua.safe_script("direction.left = 50", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
d = lua["direction"]["left"];
|
||||
REQUIRE(d == direction::left);
|
||||
}
|
||||
|
|
|
@ -722,7 +722,8 @@ TEST_CASE("usertype/overloading", "Check if overloading works properly for usert
|
|||
REQUIRE((lua["a"] == 1));
|
||||
REQUIRE((lua["b"] == 3.5));
|
||||
REQUIRE((lua["c"] == bark_58));
|
||||
REQUIRE_THROWS(lua.script("r:func(1,2,'meow')"));
|
||||
auto result = lua.safe_script("r:func(1,2,'meow')", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
|
||||
TEST_CASE("usertype/overloading_values", "ensure overloads handle properly") {
|
||||
|
@ -799,8 +800,14 @@ TEST_CASE("usertype/reference-and-constness", "Make sure constness compiles prop
|
|||
REQUIRE(v == 25);
|
||||
REQUIRE(val);
|
||||
|
||||
REQUIRE_THROWS(lua.script("f(n, 50)"));
|
||||
REQUIRE_THROWS(lua.script("o.n = 25"));
|
||||
{
|
||||
auto result = lua.safe_script("f(n, 50)", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
{
|
||||
auto result = lua.safe_script("o.n = 25", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("usertype/readonly-and-static-functions", "Check if static functions can be called on userdata and from their originating (meta)tables") {
|
||||
|
@ -883,7 +890,8 @@ lw2 = bark.something2(2, 3)
|
|||
REQUIRE(lz == lz2);
|
||||
REQUIRE(lw == lw2);
|
||||
|
||||
REQUIRE_THROWS(lua.script("b.var2 = 2"));
|
||||
auto result = lua.safe_script("b.var2 = 2", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
|
||||
TEST_CASE("usertype/properties", "Check if member properties/variables work") {
|
||||
|
@ -931,11 +939,26 @@ TEST_CASE("usertype/properties", "Check if member properties/variables work") {
|
|||
REQUIRE(var2_1 == 59);
|
||||
REQUIRE(var2_2 == 1568);
|
||||
|
||||
REQUIRE_THROWS(lua.script("b.var2 = 24"));
|
||||
REQUIRE_THROWS(lua.script("r = b.d"));
|
||||
REQUIRE_THROWS(lua.script("r = b.d"));
|
||||
REQUIRE_THROWS(lua.script("b.b = 25"));
|
||||
REQUIRE_THROWS(lua.script("b.c = 11"));
|
||||
{
|
||||
auto result = lua.safe_script("b.var2 = 24", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
{
|
||||
auto result = lua.safe_script("r = b.d", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
{
|
||||
auto result = lua.safe_script("r = b.d", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
{
|
||||
auto result = lua.safe_script("b.b = 25", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
{
|
||||
auto result = lua.safe_script("b.c = 11", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("usertype/safety", "crash with an exception -- not a segfault -- on bad userdata calls") {
|
||||
|
@ -951,7 +974,8 @@ TEST_CASE("usertype/safety", "crash with an exception -- not a segfault -- on ba
|
|||
t:sayHello() --Works fine
|
||||
t.sayHello() --Uh oh.
|
||||
)";
|
||||
REQUIRE_THROWS(lua.script(code));
|
||||
auto result = lua.safe_script(code, sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
|
||||
TEST_CASE("usertype/call_constructor", "make sure lua types can be constructed with function call constructors") {
|
||||
|
@ -1028,16 +1052,17 @@ y = class02(x)
|
|||
REQUIRE(y.x == 57);
|
||||
}
|
||||
|
||||
TEST_CASE("usertype/blank_constructor", "make sure lua types cannot be constructed if a blank / empty constructor is provided") {
|
||||
TEST_CASE("usertype/blank_constructor", "make sure lua types cannot be constructed with arguments if a blank / empty constructor is provided") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_usertype<thing>("thing",
|
||||
"v", &thing::v
|
||||
, sol::call_constructor, sol::constructors<>()
|
||||
);
|
||||
);
|
||||
|
||||
REQUIRE_THROWS(lua.script("t = thing(256)"));
|
||||
auto result = lua.safe_script("t = thing(256)", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
|
||||
|
||||
|
@ -1050,7 +1075,8 @@ TEST_CASE("usertype/no_constructor", "make sure lua types cannot be constructed
|
|||
"v", &thing::v,
|
||||
sol::call_constructor, sol::no_constructor
|
||||
);
|
||||
REQUIRE_THROWS(lua.script("t = thing()"));
|
||||
auto result = lua.safe_script("t = thing()", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
|
||||
SECTION("order2") {
|
||||
|
@ -1061,7 +1087,8 @@ TEST_CASE("usertype/no_constructor", "make sure lua types cannot be constructed
|
|||
sol::call_constructor, sol::no_constructor,
|
||||
"v", &thing::v
|
||||
);
|
||||
REQUIRE_THROWS(lua.script("t = thing.new()"));
|
||||
auto result = lua.safe_script("t = thing.new()", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
|
||||
SECTION("new no_constructor") {
|
||||
|
@ -1071,7 +1098,8 @@ TEST_CASE("usertype/no_constructor", "make sure lua types cannot be constructed
|
|||
lua.new_usertype<thing>("thing",
|
||||
sol::meta_function::construct, sol::no_constructor
|
||||
);
|
||||
REQUIRE_THROWS(lua.script("a = thing.new()"));
|
||||
auto result = lua.safe_script("t = thing.new()", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
|
||||
SECTION("call no_constructor") {
|
||||
|
@ -1081,7 +1109,8 @@ TEST_CASE("usertype/no_constructor", "make sure lua types cannot be constructed
|
|||
lua.new_usertype<thing>("thing",
|
||||
sol::call_constructor, sol::no_constructor
|
||||
);
|
||||
REQUIRE_THROWS(lua.script("a = thing()"));
|
||||
auto result = lua.safe_script("t = thing()", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1180,14 +1209,21 @@ print(e.bark)
|
|||
REQUIRE(z == 500);
|
||||
|
||||
INFO("REQUIRE(z) successful");
|
||||
|
||||
REQUIRE_THROWS(lua.script("e.readonlybark = 24"));
|
||||
INFO("REQUIRE_THROWS 1 successful");
|
||||
REQUIRE_THROWS(lua.script("e.readonlypropbark = 500"));
|
||||
INFO("REQUIRE_THROWS 2 successful");
|
||||
REQUIRE_THROWS(lua.script("y = e.writeonlypropbark"));
|
||||
INFO("REQUIRE_THROWS 3 successful");
|
||||
|
||||
{
|
||||
auto result = lua.safe_script("e.readonlybark = 24", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
INFO("REQUIRE_FALSE 1 successful");
|
||||
}
|
||||
{
|
||||
auto result = lua.safe_script("e.readonlypropbark = 500", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
INFO("REQUIRE_FALSE 2 successful");
|
||||
}
|
||||
{
|
||||
auto result = lua.safe_script("y = e.writeonlypropbark", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
INFO("REQUIRE_FALSE 3 successful");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("usertype/copyability", "make sure user can write to a class variable even if the class itself isn't copy-safe") {
|
||||
|
@ -1429,14 +1465,15 @@ print(t.prop)
|
|||
test& t = lua["t"];
|
||||
REQUIRE(t.value == 50);
|
||||
|
||||
|
||||
REQUIRE_THROWS(
|
||||
lua.script(R"(
|
||||
lua.script(R"(
|
||||
t = test.new()
|
||||
print(t.global)
|
||||
t.global = 20
|
||||
print(t.global)
|
||||
)"));
|
||||
)");
|
||||
{
|
||||
auto result = lua.safe_script("t.global = 20", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
lua.script("print(t.global)");
|
||||
}
|
||||
|
||||
TEST_CASE("usertype/unique_usertype-check", "make sure unique usertypes don't get pushed as references with function calls and the like") {
|
||||
|
@ -1590,21 +1627,23 @@ TEST_CASE("usertype/runtime-extensibility", "Check if usertypes are runtime exte
|
|||
t = thing.new()
|
||||
)");
|
||||
|
||||
REQUIRE_THROWS([&lua]() {
|
||||
lua.script(R"(
|
||||
{
|
||||
auto result = lua.safe_script(R"(
|
||||
t.runtime_func = function (a)
|
||||
return a + 50
|
||||
end
|
||||
)");
|
||||
}());
|
||||
)", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
};
|
||||
|
||||
REQUIRE_THROWS([&lua]() {
|
||||
lua.script(R"(
|
||||
{
|
||||
auto result = lua.safe_script(R"(
|
||||
function t:runtime_func(a)
|
||||
return a + 52
|
||||
end
|
||||
)");
|
||||
}());
|
||||
)", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
};
|
||||
|
||||
lua.script("val = t:func(2)");
|
||||
val = lua["val"];
|
||||
|
@ -1635,21 +1674,23 @@ end
|
|||
t = thing.new()
|
||||
)");
|
||||
|
||||
REQUIRE_THROWS([&lua]() {
|
||||
lua.script(R"(
|
||||
{
|
||||
auto result = lua.safe_script(R"(
|
||||
t.runtime_func = function (a)
|
||||
return a + 50
|
||||
end
|
||||
)");
|
||||
}());
|
||||
)", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
};
|
||||
|
||||
REQUIRE_THROWS([&lua]() {
|
||||
lua.script(R"(
|
||||
{
|
||||
auto result = lua.safe_script(R"(
|
||||
function t:runtime_func(a)
|
||||
return a + 52
|
||||
end
|
||||
)");
|
||||
}());
|
||||
)", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
};
|
||||
|
||||
lua.script("val = t:func(2)");
|
||||
val = lua["val"];
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <catch.hpp>
|
||||
#include <sol.hpp>
|
||||
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#ifdef SOL_CXX17_FEATURES
|
||||
|
@ -10,19 +11,27 @@
|
|||
#include <variant>
|
||||
#endif
|
||||
|
||||
std::mutex basic_init_require_mutex;
|
||||
|
||||
void basic_initialization_and_lib_open() {
|
||||
|
||||
sol::state lua;
|
||||
try {
|
||||
lua.open_libraries();
|
||||
lua["a"] = 24;
|
||||
int a = lua["a"];
|
||||
REQUIRE(a == 24);
|
||||
{
|
||||
std::lock_guard<std::mutex> lg(basic_init_require_mutex);
|
||||
REQUIRE(a == 24);
|
||||
}
|
||||
}
|
||||
catch (const sol::error& e) {
|
||||
std::lock_guard<std::mutex> lg(basic_init_require_mutex);
|
||||
INFO(e.what());
|
||||
REQUIRE(false);
|
||||
}
|
||||
catch (...) {
|
||||
std::lock_guard<std::mutex> lg(basic_init_require_mutex);
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
|
@ -59,10 +68,14 @@ TEST_CASE("utility/variant", "test that variant can be round-tripped") {
|
|||
return v == 2;
|
||||
});
|
||||
lua["v"] = std::variant<float, int, std::string>(std::string("bark"));
|
||||
REQUIRE_THROWS([&]() {
|
||||
lua.script("assert(f(v))");
|
||||
lua.script("assert(g(v))");
|
||||
}());
|
||||
{
|
||||
auto result = lua.safe_script("assert(f(v))", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
};
|
||||
{
|
||||
auto result = lua.safe_script("assert(g(v))", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
};
|
||||
}
|
||||
#else
|
||||
REQUIRE(true);
|
||||
|
|
|
@ -48,9 +48,8 @@ TEST_CASE("variadics/required with variadic_args", "Check if a certain number of
|
|||
);
|
||||
REQUIRE_NOTHROW(lua.script("v(20, 25, 30)"));
|
||||
REQUIRE_NOTHROW(lua.script("v(20, 25)"));
|
||||
#ifndef SOL_LUAJIT
|
||||
REQUIRE_THROWS(lua.script("v(20)"));
|
||||
#endif // LuaJIT has problems with exceptions, as fucking usual
|
||||
auto result = lua.safe_script("v(20)", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
|
||||
TEST_CASE("variadics/variadic_args get type", "Make sure we can inspect types proper from variadic_args") {
|
||||
|
|
|
@ -189,7 +189,8 @@ TEST_CASE("simple/if", "check if if statements work through lua") {
|
|||
TEST_CASE("negative/basic errors", "Check if error handling works correctly") {
|
||||
sol::state lua;
|
||||
|
||||
REQUIRE_THROWS(lua.script("nil[5]"));
|
||||
auto result = lua.safe_script("nil[5]", sol::script_pass_on_error);
|
||||
REQUIRE_FALSE(result.valid());
|
||||
}
|
||||
|
||||
TEST_CASE("libraries", "Check if we can open libraries") {
|
||||
|
|
1
tmp_thingy_user.lua
Normal file
1
tmp_thingy_user.lua
Normal file
|
@ -0,0 +1 @@
|
|||
return { modfunc = function () return foo.new(221) end }
|
Loading…
Reference in New Issue
Block a user