mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
full-on optional support. so much support it's coming through my eyeballs. Goodness.
Support for c_call wrapper to be a thing.
This commit is contained in:
parent
cd1e085224
commit
5acb33e2bc
2
Optional
2
Optional
|
@ -1 +1 @@
|
|||
Subproject commit dfd239237279fe3e1793daf23fffbe92209c8ae2
|
||||
Subproject commit 9dd28f70f01b4c5417da2f7794fc1ea978bdfd00
|
|
@ -1,4 +1,6 @@
|
|||
optional
|
||||
========
|
||||
optional<T>
|
||||
===========
|
||||
|
||||
This is an implemention of `optional from the standard library`. If it detects that a proper optional exists, it will attempt to use it. This is mostly an implementation detail, used in the :ref:`stack::check_get<stack-check-get>` and :ref:`stack::get\<optional\<T>><stack-get>` and ``optional<T> maybe_value = table["arf"];`` impementations for additional safety reasons.
|
||||
This is an implemention of `optional from the standard library`_. If it detects that a proper optional exists, it will attempt to use it. This is mostly an implementation detail, used in the :ref:`sol::stack::check_get<stack-check-get>` and :ref:`sol::stack::get\<optional\<T>><stack-get>` and ``optional<T> maybe_value = table["arf"];`` implementations for additional safety reasons.
|
||||
|
||||
.. _optional from the standard library: http://en.cppreference.com/w/cpp/utility/optional
|
|
@ -122,7 +122,7 @@ Gets the value associated with the keys the proxy was generated and convers it t
|
|||
|
||||
bool valid () const;
|
||||
|
||||
Returns whether this proxy actually refers to a valid object.
|
||||
Returns whether this proxy actually refers to a valid object. It uses :ref:`sol::stack::probe_get_field<stack-probe-get-field>` to determine whether or not its valid.
|
||||
|
||||
.. code-block:: c++
|
||||
:caption: functions: [overloaded] implicit set
|
||||
|
|
|
@ -23,15 +23,17 @@ You can disambiguate them using ``resolve``:
|
|||
.. code-block:: cpp
|
||||
:linenos:
|
||||
|
||||
auto single = resolve<int(int)>( overloaded );
|
||||
auto one_argument_func = resolve<int(int)>( overloaded );
|
||||
auto two_argument_func = resolve<int(int, int)>( overloaded );
|
||||
auto three_argument_func = resolve<int(int, int, int)>( overloaded );
|
||||
|
||||
Note that this resolution is also built into ``set_function`` on :doc:`table<table>` and :doc:`state<state>`:
|
||||
This resolution becomes useful when setting functions on a :doc:`table<table>` or :doc:`state_view<state>`:
|
||||
|
||||
.. code-block:: cpp
|
||||
:linenos:
|
||||
|
||||
sol::state lua;
|
||||
|
||||
lua.set_function<int(int)>("overloaded", overloaded);
|
||||
lua.set_function<int(int, int)>("overloaded", overloaded);
|
||||
lua.set_function<int(int, int, int)>("overloaded", overloaded);
|
||||
lua.set_function("a", resolve<int(int)>( overloaded ) );
|
||||
lua.set_function("b", resolve<int(int, int)>( overloaded ));
|
||||
lua.set_function("c", resolve<int(int, int, int)>( overloaded ));
|
||||
|
|
|
@ -11,8 +11,8 @@ If you find that the higher level abstractions are not meeting your needs, you m
|
|||
|
||||
There are, however, a few :ref:`template customization points<extension_points>` that you may use for your purposes and a handful of potentially handy functions. These may help if you're trying to slim down the code you have to write, or if you want to make your types behave differently throughout the Sol stack. Note that overriding the defaults **can** throw out many of the safety guarantees Sol provides: therefore, modify the :ref:`extension points<extension_points>` at your own discretion.
|
||||
|
||||
functions
|
||||
---------
|
||||
members
|
||||
-------
|
||||
|
||||
.. code-block:: cpp
|
||||
:caption: function: get
|
||||
|
@ -87,6 +87,31 @@ Gets the field referenced by the key ``k``, by pushing the key onto the stack, a
|
|||
|
||||
This function leaves the retrieved value on the stack.
|
||||
|
||||
.. code-block:: cpp
|
||||
:caption: function: probe_get_field
|
||||
:name: stack-probe-get-field
|
||||
|
||||
template <bool global = false, typename Key>
|
||||
probe probe_get_field( lua_State* L, Key&& k [, int objectindex] );
|
||||
|
||||
Gets the field referenced by the key ``k``, by pushing the key onto the stack, and then doing the equivalent of ``lua_getfield``. Performs optimizations and calls faster verions of the function if the type of ``Key`` is considered a c-style string and/or if its also marked by the templated ``global`` argument to be a global. Furthermore, it does this safely by only going in as many levels deep as is possible: if the returned value is not something that can be indexed into, then traversal queries with ``std::tuple``/``std::pair`` will stop early and return probing information with the :ref:`probe struct<stack-probe-struct>`.
|
||||
|
||||
This function leaves the retrieved value on the stack.
|
||||
|
||||
.. code-block:: cpp
|
||||
:caption: struct: probe
|
||||
:name: stack-probe-struct
|
||||
|
||||
struct probe {
|
||||
bool success;
|
||||
int levels;
|
||||
|
||||
probe(bool s, int l);
|
||||
operator bool() const;
|
||||
};
|
||||
|
||||
This struct is used for showing whether or not a :ref:`probing get_field<stack-probe-get-field>` was successful or not.
|
||||
|
||||
.. _extension_points:
|
||||
|
||||
objects (extension points)
|
||||
|
|
|
@ -105,7 +105,7 @@ Generates a :doc:`proxy<proxy>` that is templated on the table type and the key
|
|||
template<typename Key, typename Fx>
|
||||
state_view& set_function(Key&& key, Fx&& fx, [...]);
|
||||
|
||||
Sets the desired function to the specified key value. Note that it also allows for passing a member function plus a member object: however, using a lambda is almost always better when you want to bind a member function + class instance to a single function call in Lua.
|
||||
Sets the desired function to the specified key value. Note that it also allows for passing a member function plus a member object or just a single member function: however, using a lambda is almost always better when you want to bind a member function + class instance to a single function call in Lua.
|
||||
|
||||
.. code-block:: cpp
|
||||
:caption: function: create a table with defaults
|
||||
|
@ -125,14 +125,12 @@ Creates a table, optionally with the specified values pre-set into the table. If
|
|||
:caption: function: create a table with compile-time defaults assumed
|
||||
:name: table-create-with
|
||||
|
||||
table create(int narr = 0, int nrec = 0);
|
||||
template <typename Key, typename Value, typename... Args>
|
||||
table create(int narr, int nrec, Key&& key, Value&& value, Args&&... args);
|
||||
template <typename... Args>
|
||||
table create_with(Args&&... args);
|
||||
template <typename... Args>
|
||||
static table create_with(lua_State* L, Args&&... args);
|
||||
|
||||
static table create(lua_State* L, int narr = 0, int nrec = 0);
|
||||
template <typename Key, typename Value, typename... Args>
|
||||
static table create(lua_State* L, int narr, int nrec, Key&& key, Value&& value, Args&&... args);
|
||||
|
||||
Creates a table, optionally with the specified values pre-set into the table. If ``narr`` or ``nrec`` are 0, then compile-time shenanigans are used to guess the amount of array entries (e.g., integer keys) and the amount of hashable entries (e.g., all other entries).
|
||||
Creates a table, optionally with the specified values pre-set into the table. It checks every 2nd argument (the keys) and generates hints for how many array or map-style entries will be placed into the table.
|
||||
|
||||
.. _input iterators: http://en.cppreference.com/w/cpp/concept/InputIterator
|
|
@ -1,10 +1,10 @@
|
|||
safety
|
||||
======
|
||||
|
||||
Sol was designed to be correct and fast, and in the pursuit of both uses the regular ``lua_to{x}`` functions of Lua rather than the checking versions (``lua_check{X}``) functions. The API defaults to safe alternatives if you have a ``#define SOL_CHECK_ARGUMENTS`` before you include Sol, or if you pass the ``SOL_CHECK_ARGUMENTS`` define on the build command for your build system. By default, it is off and remains off unless you define this, even in debug mode.
|
||||
Sol was designed to be correct and fast, and in the pursuit of both uses the regular ``lua_to{x}`` functions of Lua rather than the checking versions (``lua_check{X}``) functions. The API defaults to paranoidly-safe alternatives if you have a ``#define SOL_CHECK_ARGUMENTS`` before you include Sol, or if you pass the ``SOL_CHECK_ARGUMENTS`` define on the build command for your build system. By default, it is off and remains off unless you define this, even in debug mode.
|
||||
|
||||
``SOL_CHECK_ARGUMENTS`` triggers the following changes:
|
||||
* ``stack::get`` (used everywhere) defaults to using ``stack::check_get`` and dereferencing the argument. It uses ``type_panic`` as the handler if something goes wrong.
|
||||
* ``stack::call`` will, if no template boolean is specified, check all of the arguments for a function call.
|
||||
* ``sol::stack::get`` (used everywhere) defaults to using ``sol::stack::check_get`` and dereferencing the argument. It uses ``sol::type_panic`` as the handler if something goes wrong.
|
||||
* ``sol::stack::call`` and its variants will, if no templated boolean is specified, check all of the arguments for a function call.
|
||||
|
||||
Remember that if you want these features, you must explicitly turn them on. Additionally, you can have basic boolean checks when using the API by just converting to a :ref:`sol::optional\<T><optional>` when necessary.
|
||||
Remember that if you want these features, you must explicitly turn them on. Additionally, you can have basic boolean checks when using the API by just converting to a :doc:`sol::optional\<T><api/optional>` when necessary. Tests are compiled with this on to ensure everythign is going as expected.
|
18
docs/source/tutorial/existing.rst
Normal file
18
docs/source/tutorial/existing.rst
Normal file
|
@ -0,0 +1,18 @@
|
|||
integrating into existing code
|
||||
==============================
|
||||
|
||||
If you're already using lua and you just want to use ``sol`` in some places, you can use ``state_view``:
|
||||
|
||||
.. code-block:: cpp
|
||||
:linenos:
|
||||
:caption: using state_view
|
||||
:name: state-view-snippet
|
||||
|
||||
void something_in_my_system (lua_State* L) {
|
||||
// start using Sol with a pre-existing system
|
||||
sol::state_view lua(L); // non-owning
|
||||
|
||||
lua.script("print('bark bark bark!')")
|
||||
}
|
||||
|
||||
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.
|
32
docs/source/tutorial/getting-started.rst
Normal file
32
docs/source/tutorial/getting-started.rst
Normal file
|
@ -0,0 +1,32 @@
|
|||
getting started
|
||||
===============
|
||||
|
||||
Let's get you going with Sol! To start, you'll need to use a lua distribution of some sort. Sol doesn't provide that: it only wraps the API that comes with it, so you can pick whatever distribution you like for your application. There are lots, but the two popular ones are `vanilla Lua`_ and speedy `LuaJIT`_ . We recommend vanilla Lua if you're getting started, LuaJIT if you need speed and can handle some caveats: the interface for Sol doesn't change no matter what Lua version you're using.
|
||||
|
||||
When you're ready: try compiling this short snippet:
|
||||
|
||||
.. code-block:: cpp
|
||||
:linenos:
|
||||
:caption: the first snippet
|
||||
:name: the-first-snippet
|
||||
|
||||
#include "sol.hpp" // or #include <sol.hpp>, whichever suits your needs
|
||||
|
||||
int main (int argc, char* argv[]) {
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries( sol::lib::base );
|
||||
|
||||
lua.script( "print('bark bark bark!')" );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
If this works, you're ready to start! The first line creates the ``lua_State`` and will hold onto it for the duration of the scope its declared in (e.g., from the opening ``{`` to the closing ``}``). It will automatically close / cleanup that lua state when it gets destructed. The second line opens a single lua-provided library, "base". There are several other libraries that come with lua that you can open by default, and those are included in the :ref:`sol::lib::base<lib-enum>` enumeration.
|
||||
|
||||
Next, let's start :doc:`reading/writing some variables<variables>` from Lua into C++, and vice-versa!
|
||||
|
||||
|
||||
.. _vanilla Lua: https://www.lua.org/
|
||||
|
||||
.. _LuaJIT: http://luajit.org/
|
89
docs/source/tutorial/variables.rst
Normal file
89
docs/source/tutorial/variables.rst
Normal file
|
@ -0,0 +1,89 @@
|
|||
variables
|
||||
=========
|
||||
|
||||
Working with variables is easy with Sol, and behaves pretty much like any associative array / map structure you've dealt with previously. Given this lua file that gets loaded into Sol:
|
||||
|
||||
reading
|
||||
-------
|
||||
|
||||
.. code-block:: lua
|
||||
:caption: variables.lua
|
||||
|
||||
config = {
|
||||
fullscreen = false,
|
||||
resolution = { x = 1024, y = 768 }
|
||||
}
|
||||
|
||||
.. code-block:: cpp
|
||||
:caption: main.cpp
|
||||
|
||||
int main () {
|
||||
|
||||
sol::state lua;
|
||||
lua.script_file( variables.lua );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
You can interact with the variables like this:
|
||||
|
||||
.. code-block:: cpp
|
||||
:caption: main.cpp extended
|
||||
|
||||
#include <utility> // for std::pair
|
||||
|
||||
int main () {
|
||||
|
||||
sol::state lua;
|
||||
lua.script_file( variables.lua );
|
||||
|
||||
// the type "state" behaves exactly like a table!
|
||||
bool isfullscreen = lua["config"]["fullscreen"]; // can get nested variables
|
||||
sol::table config = lua["config"];
|
||||
|
||||
// can also get it using the "get" member function
|
||||
// auto replaces the unqualified type name
|
||||
auto resolution = config.get<sol::table>( "config" );
|
||||
|
||||
// table and state can have multiple things pulled out of it too
|
||||
std::pair<int, int> xyresolution = resolution.get<int, int>( "x", "y" );
|
||||
// As an example, you can also pull out a tuple as well
|
||||
// std::tuple<int, int> xyresolution = resolution.get<int, int>( "x", "y" );
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
From this example, you can see that there's many ways to pull out the varaibles you want. Some can be more safe than others. For example, to determine if a nested variable exists or not, you can use ``auto`` to capture the value of a ``table[key]`` lookup, and then use the ``.valid()`` method:
|
||||
|
||||
.. code-block:: cpp
|
||||
:caption: safe lookup
|
||||
|
||||
auto bark = lua["config"]["bark"];
|
||||
if (bark.valid()) {
|
||||
// branch not taken: config / bark is not a variable
|
||||
}
|
||||
else {
|
||||
// Branch taken: config is a not a variable
|
||||
}
|
||||
|
||||
This comes in handy when you want to check if a nested variable exists. You can also check if a toplevel variable is present or not by using ``sol::optional``, which also checks if the type you're trying to get is of a specific type:
|
||||
|
||||
.. code-block:: cpp
|
||||
:caption: optional lookup
|
||||
|
||||
sol::optional<int> not_an_integer = lua["config"]["fullscreen"];
|
||||
if (not_an_integer) {
|
||||
// Branch not taken: value is not an integer
|
||||
}
|
||||
|
||||
sol::optoinal<bool> is_a_boolean = lua["config"]["fullscreen"];
|
||||
if (is_a_boolean) {
|
||||
// Branch taken: the value is a boolean
|
||||
}
|
||||
|
||||
sol::optional<double> does_not_exist = lua["not_a_variable"];
|
||||
if (does_not_exist) {
|
||||
// Branch not taken: that variable is not present
|
||||
}
|
||||
|
183
sol/function.hpp
183
sol/function.hpp
|
@ -32,18 +32,6 @@
|
|||
#include <memory>
|
||||
|
||||
namespace sol {
|
||||
template <typename Sig, typename... Functions>
|
||||
struct function_packer {
|
||||
std::tuple<Functions...> set;
|
||||
template <typename... Args>
|
||||
function_packer(Args&&... args) : set(std::forward<Args>(args)...) {}
|
||||
};
|
||||
|
||||
template <typename Sig, typename... Args>
|
||||
function_packer<Sig, Args...> function_pack( Args&&... args ) {
|
||||
return function_packer<Sig, Args...>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
class function : public reference {
|
||||
private:
|
||||
void luacall( std::ptrdiff_t argcount, std::ptrdiff_t resultcount ) const {
|
||||
|
@ -98,178 +86,9 @@ public:
|
|||
};
|
||||
|
||||
namespace stack {
|
||||
template<typename... Sigs>
|
||||
struct pusher<function_sig<Sigs...>> {
|
||||
|
||||
template<typename R, typename... Args, typename Fx, typename = std::result_of_t<Fx(Args...)>>
|
||||
static void set_memfx(types<R(Args...)> t, lua_State* L, Fx&& fx) {
|
||||
typedef std::decay_t<meta::Unwrapped<meta::Unqualified<Fx>>> raw_fx_t;
|
||||
typedef R(* fx_ptr_t)(Args...);
|
||||
typedef std::is_convertible<raw_fx_t, fx_ptr_t> is_convertible;
|
||||
set_isconvertible_fx(is_convertible(), t, L, std::forward<Fx>(fx));
|
||||
}
|
||||
|
||||
template<typename Fx>
|
||||
static void set_memfx(types<>, lua_State* L, Fx&& fx) {
|
||||
typedef meta::Unwrapped<meta::Unqualified<Fx>> fx_t;
|
||||
set(L, &fx_t::operator(), std::forward<Fx>(fx));
|
||||
}
|
||||
|
||||
template<typename... Args, typename R>
|
||||
static void set(lua_State* L, R fxptr(Args...)){
|
||||
set_fx(std::false_type(), L, fxptr);
|
||||
}
|
||||
|
||||
template<typename Sig>
|
||||
static void set(lua_State* L, Sig* fxptr){
|
||||
set_fx(std::false_type(), L, fxptr);
|
||||
}
|
||||
|
||||
template<typename... Args, typename R, typename C>
|
||||
static void set(lua_State* L, R (C::*memfxptr)(Args...)) {
|
||||
// Layout:
|
||||
// idx 1...n: verbatim data of member function pointer
|
||||
lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, R(C::*)(Args...)>::call;
|
||||
int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr);
|
||||
stack::push(L, freefunc, upvalues);
|
||||
}
|
||||
|
||||
template<typename Sig, typename C>
|
||||
static void set(lua_State* L, Sig C::* memfxptr) {
|
||||
// Layout:
|
||||
// idx 1...n: verbatim data of member function pointer
|
||||
lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, Sig C::*>::call;
|
||||
int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr);
|
||||
stack::push(L, freefunc, upvalues);
|
||||
}
|
||||
|
||||
template<typename... Args, typename R, typename C, typename T>
|
||||
static void set(lua_State* L, R (C::*memfxptr)(Args...), T&& obj) {
|
||||
typedef meta::Bool<meta::is_specialization_of<meta::Unqualified<T>, std::reference_wrapper>::value || std::is_pointer<T>::value> is_reference;
|
||||
set_reference_fx(is_reference(), L, memfxptr, std::forward<T>(obj));
|
||||
}
|
||||
|
||||
template<typename Sig, typename C, typename T>
|
||||
static void set(lua_State* L, Sig C::* memfxptr, T&& obj) {
|
||||
typedef meta::Bool<meta::is_specialization_of<meta::Unqualified<T>, std::reference_wrapper>::value || std::is_pointer<T>::value> is_reference;
|
||||
set_reference_fx(is_reference(), L, memfxptr, std::forward<T>(obj));
|
||||
}
|
||||
|
||||
template<typename... Sig, typename Fx>
|
||||
static void set(lua_State* L, Fx&& fx) {
|
||||
set_memfx(types<Sig...>(), L, std::forward<Fx>(fx));
|
||||
}
|
||||
|
||||
template<typename Fx, typename R, typename... Args>
|
||||
static void set_isconvertible_fx(std::true_type, types<R(Args...)>, lua_State* L, Fx&& fx) {
|
||||
using fx_ptr_t = R(*)(Args...);
|
||||
fx_ptr_t fxptr = detail::unwrap(std::forward<Fx>(fx));
|
||||
set(L, fxptr);
|
||||
}
|
||||
|
||||
template<typename Fx, typename R, typename... Args>
|
||||
static void set_isconvertible_fx(std::false_type, types<R(Args...)>, lua_State* L, Fx&& fx) {
|
||||
typedef meta::Unwrapped<std::decay_t<Fx>> fx_t;
|
||||
std::unique_ptr<function_detail::base_function> sptr = std::make_unique<function_detail::functor_function<fx_t>>(std::forward<Fx>(fx));
|
||||
set_fx(L, std::move(sptr));
|
||||
}
|
||||
|
||||
template<typename Fx, typename T>
|
||||
static void set_reference_fx(std::true_type, lua_State* L, Fx&& fx, T&& obj) {
|
||||
set_fx(std::true_type(), L, std::forward<Fx>(fx), std::forward<T>(obj));
|
||||
}
|
||||
|
||||
template<typename Fx, typename T>
|
||||
static void set_reference_fx(std::false_type, lua_State* L, Fx&& fx, T&& obj) {
|
||||
typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx;
|
||||
std::unique_ptr<function_detail::base_function> sptr = std::make_unique<function_detail::member_function<clean_fx, meta::Unqualified<T>>>(std::forward<T>(obj), std::forward<Fx>(fx));
|
||||
return set_fx(L, std::move(sptr));
|
||||
}
|
||||
|
||||
template<typename Fx, typename T>
|
||||
static void set_fx(std::true_type, lua_State* L, Fx&& fx, T&& obj) {
|
||||
// Layout:
|
||||
// idx 1...n: verbatim data of member function pointer
|
||||
// idx n + 1: is the object's void pointer
|
||||
// We don't need to store the size, because the other side is templated
|
||||
// with the same member function pointer type
|
||||
typedef std::decay_t<Fx> dFx;
|
||||
typedef meta::Unqualified<Fx> uFx;
|
||||
dFx memfxptr(std::forward<Fx>(fx));
|
||||
auto userptr = detail::ptr(obj);
|
||||
void* userobjdata = static_cast<void*>(userptr);
|
||||
lua_CFunction freefunc = &function_detail::upvalue_member_function<std::decay_t<decltype(*userptr)>, uFx>::call;
|
||||
|
||||
int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr);
|
||||
upvalues += stack::push(L, userobjdata);
|
||||
|
||||
stack::push(L, freefunc, upvalues);
|
||||
}
|
||||
|
||||
template<typename Fx>
|
||||
static void set_fx(std::false_type, lua_State* L, Fx&& fx) {
|
||||
std::decay_t<Fx> target(std::forward<Fx>(fx));
|
||||
lua_CFunction freefunc = &function_detail::upvalue_free_function<Fx>::call;
|
||||
|
||||
int upvalues = stack::stack_detail::push_as_upvalues(L, target);
|
||||
stack::push(L, freefunc, upvalues);
|
||||
}
|
||||
|
||||
static void set_fx(lua_State* L, std::unique_ptr<function_detail::base_function> luafunc) {
|
||||
function_detail::base_function* target = luafunc.release();
|
||||
void* targetdata = static_cast<void*>(target);
|
||||
lua_CFunction freefunc = function_detail::call;
|
||||
|
||||
stack::push(L, userdata_value(targetdata));
|
||||
function_detail::free_function_cleanup(L);
|
||||
lua_setmetatable(L, -2);
|
||||
stack::push(L, freefunc, 1);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
static int push(lua_State* L, Args&&... args) {
|
||||
// Set will always place one thing (function) on the stack
|
||||
set<Sigs...>(L, std::forward<Args>(args)...);
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename... Args>
|
||||
struct pusher<function_packer<T, Args...>> {
|
||||
template <std::size_t... I, typename FP>
|
||||
static int push_func(std::index_sequence<I...>, lua_State* L, FP&& fp) {
|
||||
return stack::push<T>(L, detail::forward_get<I>(fp.set)...);
|
||||
}
|
||||
|
||||
template <typename FP>
|
||||
static int push(lua_State* L, FP&& fp) {
|
||||
return push_func(std::index_sequence_for<Args...>(), L, std::forward<FP>(fp));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Signature>
|
||||
struct pusher<std::function<Signature>> {
|
||||
static int push(lua_State* L, std::function<Signature> fx) {
|
||||
return pusher<function_sig<>>{}.push(L, std::move(fx));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Functions>
|
||||
struct pusher<overload_set<Functions...>> {
|
||||
static int push(lua_State* L, overload_set<Functions...>&& set) {
|
||||
pusher<function_sig<>>{}.set_fx(L, std::make_unique<function_detail::overloaded_function<Functions...>>(std::move(set.set)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int push(lua_State* L, const overload_set<Functions...>& set) {
|
||||
pusher<function_sig<>>{}.set_fx(L, std::make_unique<function_detail::overloaded_function<Functions...>>(set.set));
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Signature>
|
||||
struct getter<std::function<Signature>> {
|
||||
typedef meta::function_traits<Signature> fx_t;
|
||||
typedef meta::bind_traits<Signature> fx_t;
|
||||
typedef typename fx_t::args_type args_types;
|
||||
typedef meta::tuple_types<typename fx_t::return_type> return_types;
|
||||
|
||||
|
|
|
@ -23,11 +23,212 @@
|
|||
#define SOL_FUNCTION_TYPES_HPP
|
||||
|
||||
#include "function_types_core.hpp"
|
||||
#include "function_types_static.hpp"
|
||||
#include "function_types_templated.hpp"
|
||||
#include "function_types_basic.hpp"
|
||||
#include "function_types_allocator.hpp"
|
||||
#include "function_types_member.hpp"
|
||||
#include "function_types_usertype.hpp"
|
||||
#include "function_types_overload.hpp"
|
||||
#include "function_types_allocator.hpp"
|
||||
#include "resolve.hpp"
|
||||
|
||||
namespace sol {
|
||||
|
||||
template <typename Sig, typename... Ps>
|
||||
struct function_arguments {
|
||||
std::tuple<Ps...> params;
|
||||
template <typename... Args>
|
||||
function_arguments(Args&&... args) : params(std::forward<Args>(args)...) {}
|
||||
};
|
||||
|
||||
template <typename Sig = function_sig<>, typename... Args>
|
||||
function_arguments<Sig, Args...> function_args( Args&&... args ) {
|
||||
return function_arguments<Sig, Args...>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
namespace stack {
|
||||
template<typename... Sigs>
|
||||
struct pusher<function_sig<Sigs...>> {
|
||||
template <typename... Sig, typename Fx, typename... Args>
|
||||
static void select_convertible(std::false_type, types<Sig...>, lua_State* L, Fx&& fx, Args&&... args) {
|
||||
typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx;
|
||||
std::unique_ptr<function_detail::base_function> sptr = std::make_unique<function_detail::functor_function<clean_fx>>(std::forward<Fx>(fx), std::forward<Args>(args)...);
|
||||
set_fx(L, std::move(sptr));
|
||||
}
|
||||
|
||||
template <typename R, typename... A, typename Fx, typename... Args>
|
||||
static void select_convertible(std::true_type, types<R(A...)>, lua_State* L, Fx&& fx, Args&&... args) {
|
||||
using fx_ptr_t = R(*)(A...);
|
||||
fx_ptr_t fxptr = detail::unwrap(std::forward<Fx>(fx));
|
||||
select_function(std::true_type(), L, fxptr, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename R, typename... A, typename Fx, typename... Args>
|
||||
static void select_convertible(types<R(A...)> t, lua_State* L, Fx&& fx, Args&&... args) {
|
||||
typedef std::decay_t<meta::Unwrapped<meta::Unqualified<Fx>>> raw_fx_t;
|
||||
typedef R(* fx_ptr_t)(A...);
|
||||
typedef std::is_convertible<raw_fx_t, fx_ptr_t> is_convertible;
|
||||
select_convertible(is_convertible(), t, L, std::forward<Fx>(fx), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename Fx, typename... Args>
|
||||
static void select_convertible(types<>, lua_State* L, Fx&& fx, Args&&... args) {
|
||||
typedef meta::function_signature_t<meta::Unwrapped<meta::Unqualified<Fx>>> Sig;
|
||||
select_convertible(types<Sig>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename Fx, typename T, typename... Args>
|
||||
static void select_reference_member_variable(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
|
||||
typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx;
|
||||
std::unique_ptr<function_detail::base_function> sptr = std::make_unique<function_detail::member_variable<meta::Unqualified<T>, clean_fx>>(std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)... );
|
||||
set_fx(L, std::move(sptr));
|
||||
}
|
||||
|
||||
template <typename Fx, typename T, typename... Args>
|
||||
static void select_reference_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
|
||||
typedef std::decay_t<Fx> dFx;
|
||||
dFx memfxptr(std::forward<Fx>(fx));
|
||||
auto userptr = detail::ptr(std::forward<T>(obj));
|
||||
lua_CFunction freefunc = &function_detail::upvalue_member_variable<std::decay_t<decltype(*userptr)>, meta::Unqualified<Fx>>::call;
|
||||
|
||||
int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr);
|
||||
upvalues += stack::push(L, light_userdata_value(static_cast<void*>(userptr)));
|
||||
stack::push(L, c_closure(freefunc, upvalues));
|
||||
}
|
||||
|
||||
template <typename Fx, typename... Args>
|
||||
static void select_member_variable(std::false_type, lua_State* L, Fx&& fx, Args&&... args) {
|
||||
select_convertible(types<Sigs...>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename Fx, typename T, typename... Args>
|
||||
static void select_member_variable(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
|
||||
typedef meta::Bool<meta::is_specialization_of<meta::Unqualified<T>, std::reference_wrapper>::value || std::is_pointer<T>::value> is_reference;
|
||||
select_reference_member_variable(is_reference(), L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename Fx, typename... Args>
|
||||
static void select_member_variable(std::true_type, lua_State* L, Fx&& fx) {
|
||||
typedef typename meta::bind_traits<meta::Unqualified<Fx>>::object_type C;
|
||||
lua_CFunction freefunc = &function_detail::upvalue_this_member_variable<C, Fx>::call;
|
||||
int upvalues = stack::stack_detail::push_as_upvalues(L, fx);
|
||||
stack::push(L, c_closure(freefunc, upvalues));
|
||||
}
|
||||
|
||||
template <typename Fx, typename T, typename... Args>
|
||||
static void select_reference_member_function(std::false_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
|
||||
typedef std::remove_pointer_t<std::decay_t<Fx>> clean_fx;
|
||||
std::unique_ptr<function_detail::base_function> sptr = std::make_unique<function_detail::member_function<meta::Unwrapped<meta::Unqualified<T>>, clean_fx>>(std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)... );
|
||||
set_fx(L, std::move(sptr));
|
||||
}
|
||||
|
||||
template <typename Fx, typename T, typename... Args>
|
||||
static void select_reference_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
|
||||
typedef std::decay_t<Fx> dFx;
|
||||
dFx memfxptr(std::forward<Fx>(fx));
|
||||
auto userptr = detail::ptr(std::forward<T>(obj));
|
||||
lua_CFunction freefunc = &function_detail::upvalue_member_function<std::decay_t<decltype(*userptr)>, meta::Unqualified<Fx>>::call;
|
||||
|
||||
int upvalues = stack::stack_detail::push_as_upvalues(L, memfxptr);
|
||||
upvalues += stack::push(L, light_userdata_value(static_cast<void*>(userptr)));
|
||||
stack::push(L, c_closure(freefunc, upvalues));
|
||||
}
|
||||
|
||||
template <typename Fx, typename... Args>
|
||||
static void select_member_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) {
|
||||
select_member_variable(std::is_member_object_pointer<meta::Unqualified<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename Fx, typename T, typename... Args>
|
||||
static void select_member_function(std::true_type, lua_State* L, Fx&& fx, T&& obj, Args&&... args) {
|
||||
typedef meta::Bool<meta::is_specialization_of<meta::Unqualified<T>, std::reference_wrapper>::value || std::is_pointer<T>::value> is_reference;
|
||||
select_reference_member_function(is_reference(), L, std::forward<Fx>(fx), std::forward<T>(obj), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename Fx, typename... Args>
|
||||
static void select_member_function(std::true_type, lua_State* L, Fx&& fx) {
|
||||
typedef typename meta::bind_traits<meta::Unqualified<Fx>>::object_type C;
|
||||
lua_CFunction freefunc = &function_detail::upvalue_this_member_function<C, Fx>::call;
|
||||
int upvalues = stack::stack_detail::push_as_upvalues(L, fx);
|
||||
stack::push(L, c_closure(freefunc, upvalues));
|
||||
}
|
||||
|
||||
template <typename Fx, typename... Args>
|
||||
static void select_function(std::false_type, lua_State* L, Fx&& fx, Args&&... args) {
|
||||
select_member_function(std::is_member_function_pointer<meta::Unqualified<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename Fx, typename... Args>
|
||||
static void select_function(std::true_type, lua_State* L, Fx&& fx, Args&&... args) {
|
||||
std::decay_t<Fx> target(std::forward<Fx>(fx), std::forward<Args>(args)...);
|
||||
lua_CFunction freefunc = &function_detail::upvalue_free_function<Fx>::call;
|
||||
|
||||
int upvalues = stack::stack_detail::push_as_upvalues(L, target);
|
||||
stack::push(L, freefunc, upvalues);
|
||||
}
|
||||
|
||||
static void select_function(std::true_type, lua_State* L, lua_CFunction f) {
|
||||
stack::push(L, f);
|
||||
}
|
||||
|
||||
template <typename Fx, typename... Args>
|
||||
static void select(lua_State* L, Fx&& fx, Args&&... args) {
|
||||
select_function(std::is_function<meta::Unqualified<Fx>>(), L, std::forward<Fx>(fx), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
static void set_fx(lua_State* L, std::unique_ptr<function_detail::base_function> luafunc) {
|
||||
function_detail::base_function* target = luafunc.release();
|
||||
void* targetdata = static_cast<void*>(target);
|
||||
lua_CFunction freefunc = function_detail::call;
|
||||
|
||||
stack::push(L, userdata_value(targetdata));
|
||||
function_detail::free_function_cleanup(L);
|
||||
lua_setmetatable(L, -2);
|
||||
stack::push(L, freefunc, 1);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
static int push(lua_State* L, Args&&... args) {
|
||||
// Set will always place one thing (function) on the stack
|
||||
select(L, std::forward<Args>(args)...);
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename... Args>
|
||||
struct pusher<function_arguments<T, Args...>> {
|
||||
template <std::size_t... I, typename FP>
|
||||
static int push_func(std::index_sequence<I...>, lua_State* L, FP&& fp) {
|
||||
return stack::push<T>(L, detail::forward_get<I>(fp.params)...);
|
||||
}
|
||||
|
||||
template <typename FP>
|
||||
static int push(lua_State* L, FP&& fp) {
|
||||
return push_func(std::index_sequence_for<Args...>(), L, std::forward<FP>(fp));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Signature>
|
||||
struct pusher<std::function<Signature>> {
|
||||
static int push(lua_State* L, std::function<Signature> fx) {
|
||||
return pusher<function_sig<>>{}.push(L, std::move(fx));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Functions>
|
||||
struct pusher<overload_set<Functions...>> {
|
||||
static int push(lua_State* L, overload_set<Functions...>&& set) {
|
||||
pusher<function_sig<>>{}.set_fx(L, std::make_unique<function_detail::overloaded_function<Functions...>>(std::move(set.set)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int push(lua_State* L, const overload_set<Functions...>& set) {
|
||||
pusher<function_sig<>>{}.set_fx(L, std::make_unique<function_detail::overloaded_function<Functions...>>(set.set));
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
} // stack
|
||||
} // sol
|
||||
|
||||
#endif // SOL_FUNCTION_TYPES_HPP
|
||||
|
|
|
@ -45,7 +45,7 @@ struct constructor_match {
|
|||
template <typename Fx, std::size_t I, typename... R, typename... Args>
|
||||
int operator()(types<Fx>, Index<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) const {
|
||||
default_construct func{};
|
||||
return stack::call_into_lua<false>(r, a, func, L, start, obj);
|
||||
return stack::call_into_lua<0, false>(r, a, func, L, start, obj);
|
||||
}
|
||||
};
|
||||
} // detail
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef SOL_FUNCTION_TYPES_STATIC_HPP
|
||||
#define SOL_FUNCTION_TYPES_STATIC_HPP
|
||||
#ifndef SOL_FUNCTION_TYPES_BASIC_HPP
|
||||
#define SOL_FUNCTION_TYPES_BASIC_HPP
|
||||
|
||||
#include "stack.hpp"
|
||||
|
||||
|
@ -29,7 +29,7 @@ namespace function_detail {
|
|||
template<typename Function>
|
||||
struct upvalue_free_function {
|
||||
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
||||
typedef meta::function_traits<function_type> traits_type;
|
||||
typedef meta::bind_traits<function_type> traits_type;
|
||||
|
||||
static int real_call(lua_State* L) {
|
||||
auto udata = stack::stack_detail::get_as_upvalues<function_type*>(L);
|
||||
|
@ -50,13 +50,18 @@ struct upvalue_free_function {
|
|||
template<typename T, typename Function>
|
||||
struct upvalue_member_function {
|
||||
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
||||
typedef meta::function_traits<function_type> traits_type;
|
||||
typedef meta::bind_traits<function_type> traits_type;
|
||||
|
||||
static int real_call(lua_State* L) {
|
||||
// Layout:
|
||||
// idx 1...n: verbatim data of member function pointer
|
||||
// idx n + 1: is the object's void pointer
|
||||
// We don't need to store the size, because the other side is templated
|
||||
// with the same member function pointer type
|
||||
auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1);
|
||||
auto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second);
|
||||
function_type& memfx = memberdata.first;
|
||||
T& item = *objdata.first;
|
||||
auto& item = *objdata.first;
|
||||
auto fx = [&item, &memfx](auto&&... args) -> typename traits_type::return_type {
|
||||
return (item.*memfx)(std::forward<decltype(args)>(args)...);
|
||||
};
|
||||
|
@ -73,18 +78,92 @@ struct upvalue_member_function {
|
|||
};
|
||||
|
||||
template<typename T, typename Function>
|
||||
struct upvalue_this_member_function {
|
||||
struct upvalue_member_variable {
|
||||
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
||||
typedef meta::function_traits<function_type> traits_type;
|
||||
typedef meta::bind_traits<function_type> traits_type;
|
||||
|
||||
static int real_call(lua_State* L) {
|
||||
// Layout:
|
||||
// idx 1...n: verbatim data of member variable pointer
|
||||
// idx n + 1: is the object's void pointer
|
||||
// We don't need to store the size, because the other side is templated
|
||||
// with the same member function pointer type
|
||||
auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1);
|
||||
auto objdata = stack::stack_detail::get_as_upvalues<T*>(L, memberdata.second);
|
||||
auto& mem = *objdata.first;
|
||||
function_type& var = memberdata.first;
|
||||
switch (lua_gettop(L)) {
|
||||
case 0:
|
||||
stack::push(L, (mem.*var));
|
||||
return 1;
|
||||
case 1:
|
||||
(mem.*var) = stack::get<typename traits_type::return_type>(L, 1);
|
||||
lua_pop(L, 1);
|
||||
return 0;
|
||||
default:
|
||||
return luaL_error(L, "sol: incorrect number of arguments to member variable function");
|
||||
}
|
||||
}
|
||||
|
||||
static int call (lua_State* L) {
|
||||
return detail::static_trampoline<(&real_call)>(L);
|
||||
}
|
||||
|
||||
int operator()(lua_State* L) {
|
||||
return call(L);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename Function>
|
||||
struct upvalue_this_member_function {
|
||||
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
||||
typedef meta::bind_traits<function_type> traits_type;
|
||||
|
||||
static int real_call(lua_State* L) {
|
||||
// Layout:
|
||||
// idx 1...n: verbatim data of member variable pointer
|
||||
auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1);
|
||||
function_type& memfx = memberdata.first;
|
||||
auto fx = [&memfx](lua_State* L, auto&&... args) -> typename traits_type::return_type {
|
||||
T& item = stack::get<T>(L, 1);
|
||||
auto& item = stack::get<T>(L, 1);
|
||||
return (item.*memfx)(std::forward<decltype(args)>(args)...);
|
||||
};
|
||||
return stack::call_into_lua(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_type(), fx, L, 2, L);
|
||||
int n = stack::call_into_lua<1>(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_type(), fx, L, 2, L);
|
||||
return n;
|
||||
}
|
||||
|
||||
static int call (lua_State* L) {
|
||||
return detail::static_trampoline<(&real_call)>(L);
|
||||
}
|
||||
|
||||
int operator()(lua_State* L) {
|
||||
return call(L);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename Function>
|
||||
struct upvalue_this_member_variable {
|
||||
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
||||
typedef meta::bind_traits<function_type> traits_type;
|
||||
|
||||
static int real_call(lua_State* L) {
|
||||
// Layout:
|
||||
// idx 1...n: verbatim data of member variable pointer
|
||||
auto memberdata = stack::stack_detail::get_as_upvalues<function_type>(L, 1);
|
||||
auto& mem = stack::get<T>(L, 1);
|
||||
function_type& var = memberdata.first;
|
||||
switch (lua_gettop(L)) {
|
||||
case 1:
|
||||
lua_pop(L, 1);
|
||||
stack::push(L, (mem.*var));
|
||||
return 1;
|
||||
case 2:
|
||||
(mem.*var) = stack::get<typename traits_type::return_type>(L, 2);
|
||||
lua_pop(L, 2);
|
||||
return 0;
|
||||
default:
|
||||
return luaL_error(L, "sol: incorrect number of arguments to member variable function");
|
||||
}
|
||||
}
|
||||
|
||||
static int call (lua_State* L) {
|
||||
|
@ -98,4 +177,4 @@ struct upvalue_this_member_function {
|
|||
} // function_detail
|
||||
} // sol
|
||||
|
||||
#endif // SOL_FUNCTION_TYPES_STATIC_HPP
|
||||
#endif // SOL_FUNCTION_TYPES_BASIC_HPP
|
|
@ -47,7 +47,7 @@ inline decltype(auto) cleanup_key() {
|
|||
|
||||
template<typename T, typename Func, typename = void>
|
||||
struct functor {
|
||||
typedef meta::callable_traits<Func> traits_type;
|
||||
typedef meta::bind_traits<Func> traits_type;
|
||||
typedef typename traits_type::args_type args_type;
|
||||
typedef typename traits_type::return_type return_type;
|
||||
static const std::size_t arity = traits_type::arity;
|
||||
|
@ -82,7 +82,7 @@ struct functor {
|
|||
|
||||
template<typename T, typename Func>
|
||||
struct functor<T, Func, std::enable_if_t<std::is_member_object_pointer<Func>::value>> {
|
||||
typedef meta::callable_traits<Func> traits_type;
|
||||
typedef meta::bind_traits<Func> traits_type;
|
||||
typedef typename traits_type::args_type args_type;
|
||||
typedef typename traits_type::return_type return_type;
|
||||
static const std::size_t arity = traits_type::arity;
|
||||
|
@ -115,7 +115,7 @@ struct functor<T, Func, std::enable_if_t<std::is_member_object_pointer<Func>::va
|
|||
|
||||
template<typename T, typename Func>
|
||||
struct functor<T, Func, std::enable_if_t<std::is_function<Func>::value || std::is_class<Func>::value>> {
|
||||
typedef meta::callable_traits<Func> traits_type;
|
||||
typedef meta::bind_traits<Func> traits_type;
|
||||
typedef meta::pop_front_type_t<typename traits_type::args_type> args_type;
|
||||
typedef typename traits_type::return_type return_type;
|
||||
static const std::size_t arity = traits_type::arity;
|
||||
|
|
|
@ -26,8 +26,9 @@
|
|||
|
||||
namespace sol {
|
||||
namespace function_detail {
|
||||
template<typename Function>
|
||||
template<typename Func>
|
||||
struct functor_function : public base_function {
|
||||
typedef meta::Unwrapped<meta::Unqualified<Func>> Function;
|
||||
typedef decltype(&Function::operator()) function_type;
|
||||
typedef meta::function_return_t<function_type> return_type;
|
||||
typedef meta::function_args_t<function_type> args_types;
|
||||
|
@ -46,48 +47,17 @@ struct functor_function : public base_function {
|
|||
}
|
||||
};
|
||||
|
||||
template<typename Function, typename T>
|
||||
struct this_member_function : public base_function {
|
||||
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
||||
typedef meta::function_return_t<function_type> return_type;
|
||||
typedef meta::function_args_t<function_type> args_types;
|
||||
struct functor {
|
||||
function_type invocation;
|
||||
|
||||
template<typename... Args>
|
||||
functor(Args&&... args): invocation(std::forward<Args>(args)...) {}
|
||||
|
||||
template<typename... Args>
|
||||
return_type operator()(lua_State* L, Args&&... args) {
|
||||
auto& mem = detail::unwrap(stack::get<T&>(L, 1));
|
||||
return (mem.*invocation)(std::forward<Args>(args)...);
|
||||
}
|
||||
} fx;
|
||||
|
||||
template<typename... Args>
|
||||
this_member_function(Args&&... args): fx(std::forward<Args>(args)...) {}
|
||||
|
||||
int call(lua_State* L) {
|
||||
return stack::call_into_lua(meta::tuple_types<return_type>(), args_types(), fx, L, 2, L);
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L) override {
|
||||
auto f = [&](lua_State* L) -> int { return this->call(L);};
|
||||
return detail::trampoline(L, f);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Function, typename T>
|
||||
template<typename T, typename Function>
|
||||
struct member_function : public base_function {
|
||||
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
||||
typedef meta::function_return_t<function_type> return_type;
|
||||
typedef meta::function_args_t<function_type> args_types;
|
||||
struct functor {
|
||||
T member;
|
||||
function_type invocation;
|
||||
|
||||
template<typename Tm, typename... Args>
|
||||
functor(Tm&& m, Args&&... args): member(std::forward<Tm>(m)), invocation(std::forward<Args>(args)...) {}
|
||||
T member;
|
||||
|
||||
template<typename F, typename... Args>
|
||||
functor(F&& f, Args&&... args): invocation(std::forward<F>(f)), member(std::forward<Args>(args)...) {}
|
||||
|
||||
template<typename... Args>
|
||||
return_type operator()(Args&&... args) {
|
||||
|
@ -96,8 +66,8 @@ struct member_function : public base_function {
|
|||
}
|
||||
} fx;
|
||||
|
||||
template<typename Tm, typename... Args>
|
||||
member_function(Tm&& m, Args&&... args): fx(std::forward<Tm>(m), std::forward<Args>(args)...) {}
|
||||
template<typename F, typename... Args>
|
||||
member_function(F&& f, Args&&... args) : fx(std::forward<F>(f), std::forward<Args>(args)...) {}
|
||||
|
||||
int call(lua_State* L) {
|
||||
return stack::call_into_lua(meta::tuple_types<return_type>(), args_types(), fx, L, 1);
|
||||
|
@ -108,6 +78,39 @@ struct member_function : public base_function {
|
|||
return detail::trampoline(L, f);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename Function>
|
||||
struct member_variable : public base_function {
|
||||
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
|
||||
typedef typename meta::bind_traits<function_type>::return_type return_type;
|
||||
typedef typename meta::bind_traits<function_type>::args_type args_types;
|
||||
function_type var;
|
||||
T member;
|
||||
|
||||
template<typename Fx, typename... Args>
|
||||
member_variable(Fx&& fx, Args&&... args): var(std::forward<Fx>(fx)), member(std::forward<Args>(args)...) {}
|
||||
|
||||
int call(lua_State* L) {
|
||||
auto& mem = detail::unwrap(detail::deref(member));
|
||||
switch (lua_gettop(L)) {
|
||||
case 0: {
|
||||
stack::push(L, (mem.*var));
|
||||
return 1;
|
||||
}
|
||||
case 1:
|
||||
(mem.*var) = stack::get<return_type>(L, 1);
|
||||
lua_pop(L, 1);
|
||||
return 0;
|
||||
default:
|
||||
return luaL_error(L, "sol: incorrect number of arguments to member variable function");
|
||||
}
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L) override {
|
||||
auto f = [&](lua_State* L) -> int { return this->call(L);};
|
||||
return detail::trampoline(L, f);
|
||||
}
|
||||
};
|
||||
} // function_detail
|
||||
} // sol
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace sol {
|
|||
namespace function_detail {
|
||||
namespace internals {
|
||||
template <typename T>
|
||||
struct overload_traits : meta::function_traits<T> {};
|
||||
struct overload_traits : meta::bind_traits<T> {};
|
||||
|
||||
template <typename T, typename Func, typename X>
|
||||
struct overload_traits<functor<T, Func, X>> {
|
||||
|
@ -92,7 +92,7 @@ struct overloaded_function : base_function {
|
|||
template <typename Fx, std::size_t I, typename... R, typename... Args>
|
||||
int call(types<Fx>, Index<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) {
|
||||
auto& func = std::get<I>(overloads);
|
||||
return stack::call_into_lua<false>(r, a, func, L, start);
|
||||
return stack::call_into_lua<0, false>(r, a, func, L, start);
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L) override {
|
||||
|
@ -113,7 +113,7 @@ struct usertype_overloaded_function : base_function {
|
|||
int call(types<Fx>, Index<I>, types<R...> r, types<Args...> a, lua_State* L, int, int start) {
|
||||
auto& func = std::get<I>(overloads);
|
||||
func.item = detail::ptr(stack::get<T>(L, 1));
|
||||
return stack::call_into_lua<false>(r, a, func, L, start);
|
||||
return stack::call_into_lua<0, false>(r, a, func, L, start);
|
||||
}
|
||||
|
||||
virtual int operator()(lua_State* L) override {
|
||||
|
|
89
sol/function_types_templated.hpp
Normal file
89
sol/function_types_templated.hpp
Normal file
|
@ -0,0 +1,89 @@
|
|||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef SOL_FUNCTION_TYPES_TEMPLATED_HPP
|
||||
#define SOL_FUNCTION_TYPES_TEMPLATED_HPP
|
||||
|
||||
#include "stack.hpp"
|
||||
|
||||
namespace sol {
|
||||
namespace function_detail {
|
||||
template <typename F, F fx>
|
||||
inline int call_wrapper_variable(std::false_type, lua_State* L) {
|
||||
typedef meta::bind_traits<meta::Unqualified<F>> traits_type;
|
||||
typedef typename traits_type::args_type args_type;
|
||||
typedef meta::tuple_types<typename traits_type::return_type> return_type;
|
||||
return stack::call_into_lua(return_type(), args_type(), fx, L, 1);
|
||||
}
|
||||
|
||||
template <typename V, V variable>
|
||||
inline int call_wrapper_variable(std::true_type, lua_State* L) {
|
||||
typedef meta::bind_traits<meta::Unqualified<V>> traits_type;
|
||||
typedef typename traits_type::object_type T;
|
||||
typedef typename traits_type::return_type R;
|
||||
auto& mem = stack::get<T>(L, 1);
|
||||
switch (lua_gettop(L)) {
|
||||
case 1:
|
||||
lua_pop(L, 1);
|
||||
stack::push(L, (mem.*variable));
|
||||
return 1;
|
||||
case 2:
|
||||
(mem.*variable) = stack::get<R>(L, 2);
|
||||
lua_pop(L, 2);
|
||||
return 0;
|
||||
default:
|
||||
return luaL_error(L, "incorrect number of arguments to member variable function call");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename F, F fx>
|
||||
inline int call_wrapper_function(std::false_type, lua_State* L) {
|
||||
return call_wrapper_variable<F, fx>(std::is_member_object_pointer<F>(), L);
|
||||
}
|
||||
|
||||
template <typename F, F fx>
|
||||
inline int call_wrapper_function(std::true_type, lua_State* L) {
|
||||
typedef meta::bind_traits<meta::Unqualified<F>> traits_type;
|
||||
typedef typename traits_type::object_type T;
|
||||
typedef typename traits_type::args_type args_type;
|
||||
typedef typename traits_type::return_type return_type;
|
||||
typedef meta::tuple_types<return_type> return_type_list;
|
||||
auto mfx = [&](auto&&... args) -> typename traits_type::return_type {
|
||||
auto& member = stack::get<T>(L, 1);
|
||||
return (member.*fx)(std::forward<decltype(args)>(args)...);
|
||||
};
|
||||
int n = stack::call_into_lua<1>(return_type_list(), args_type(), mfx, L, 2);
|
||||
return n;
|
||||
}
|
||||
|
||||
template <typename F, F fx>
|
||||
inline int call_wrapper_entry(lua_State* L) {
|
||||
return call_wrapper_function<F, fx>(std::is_member_function_pointer<meta::Unqualified<F>>(), L);
|
||||
}
|
||||
} // function_detail
|
||||
|
||||
template <typename F, F fx>
|
||||
inline int c_call(lua_State* L) {
|
||||
return detail::static_trampoline<function_detail::call_wrapper_entry<F, fx>>(L);
|
||||
}
|
||||
} // sol
|
||||
|
||||
#endif // SOL_FUNCTION_TYPES_TEMPLATED_HPP
|
|
@ -96,8 +96,8 @@ public:
|
|||
|
||||
bool valid () const {
|
||||
auto p = stack::probe_get_field<std::is_same<meta::Unqualified<Table>, global_table>::value>(tbl.lua_state(), key);
|
||||
lua_pop(tbl.lua_state(), p.levels);
|
||||
return p;
|
||||
lua_pop(tbl.lua_state(), p.levels);
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -145,8 +145,8 @@ namespace stack {
|
|||
template <typename Table, typename Key>
|
||||
struct pusher<proxy<Table, Key>> {
|
||||
static int push (lua_State*, const proxy<Table, Key>& p) {
|
||||
sol::reference r = p;
|
||||
r.push();
|
||||
sol::reference r = p;
|
||||
r.push();
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -132,18 +132,18 @@ inline void call_from_top(types<void> tr, types<Args...> ta, lua_State* L, Fx&&
|
|||
call<check_args>(tr, ta, L, static_cast<int>(lua_gettop(L) - sizeof...(Args)), std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
|
||||
}
|
||||
|
||||
template<bool check_args = stack_detail::default_check_arguments, typename... Args, typename Fx, typename... FxArgs>
|
||||
template<int additionalpop = 0, bool check_args = stack_detail::default_check_arguments, typename... Args, typename Fx, typename... FxArgs>
|
||||
inline int call_into_lua(types<void> tr, types<Args...> ta, Fx&& fx, lua_State* L, int start, FxArgs&&... fxargs) {
|
||||
call<check_args>(tr, ta, L, start, fx, std::forward<FxArgs>(fxargs)...);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
int nargs = static_cast<int>(sizeof...(Args)) + additionalpop;
|
||||
lua_pop(L, nargs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<bool check_args = stack_detail::default_check_arguments, typename Ret0, typename... Ret, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<meta::Not<std::is_void<Ret0>>::value>>
|
||||
template<int additionalpop = 0, bool check_args = stack_detail::default_check_arguments, typename Ret0, typename... Ret, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<meta::Not<std::is_void<Ret0>>::value>>
|
||||
inline int call_into_lua(types<Ret0, Ret...>, types<Args...> ta, Fx&& fx, lua_State* L, int start, FxArgs&&... fxargs) {
|
||||
decltype(auto) r = call<check_args>(types<meta::return_type_t<Ret0, Ret...>>(), ta, L, start, fx, std::forward<FxArgs>(fxargs)...);
|
||||
int nargs = static_cast<int>(sizeof...(Args));
|
||||
int nargs = static_cast<int>(sizeof...(Args)) + additionalpop;
|
||||
lua_pop(L, nargs);
|
||||
return push(L, std::forward<decltype(r)>(r));
|
||||
}
|
||||
|
|
|
@ -136,7 +136,7 @@ struct checker<T, type::lightuserdata, C> {
|
|||
template <typename Handler>
|
||||
static bool check (lua_State* L, int index, Handler&& handler) {
|
||||
type t = type_of(L, index);
|
||||
bool success = t == type::userdata || t == type::lightuserdata;
|
||||
bool success = t == type::userdata || t == type::lightuserdata;
|
||||
if (!success) {
|
||||
// expected type, actual type
|
||||
handler(L, index, type::lightuserdata, t);
|
||||
|
@ -181,12 +181,12 @@ struct checker<T, type::userdata, C> {
|
|||
if (lua_getmetatable(L, index) == 0) {
|
||||
handler(L, index, type::userdata, indextype);
|
||||
return false;
|
||||
}
|
||||
if (stack_detail::check_metatable<U>(L))
|
||||
}
|
||||
if (stack_detail::check_metatable<U>(L))
|
||||
return true;
|
||||
if (stack_detail::check_metatable<U*>(L))
|
||||
if (stack_detail::check_metatable<U*>(L))
|
||||
return true;
|
||||
if (stack_detail::check_metatable<unique_usertype<U>>(L))
|
||||
if (stack_detail::check_metatable<unique_usertype<U>>(L))
|
||||
return true;
|
||||
#ifndef SOL_NO_EXCEPTIONS
|
||||
lua_getfield(L, -1, &detail::base_class_check_key()[0]);
|
||||
|
|
|
@ -53,10 +53,10 @@ namespace stack {
|
|||
|
||||
template<typename T, bool global = false, typename = void>
|
||||
struct field_getter;
|
||||
template<typename T, bool global = false, typename = void>
|
||||
struct field_setter;
|
||||
template <typename T, bool global = false, typename = void>
|
||||
struct probe_field_getter;
|
||||
template<typename T, bool global = false, typename = void>
|
||||
struct field_setter;
|
||||
template<typename T, typename = void>
|
||||
struct getter;
|
||||
template<typename T, typename = void>
|
||||
|
|
|
@ -41,8 +41,9 @@ struct field_getter {
|
|||
template <typename... Args, bool b, typename C>
|
||||
struct field_getter<std::tuple<Args...>, b, C> {
|
||||
template <std::size_t... I, typename Keys>
|
||||
void apply(std::index_sequence<I...>, lua_State* L, Keys&& keys, int tableindex) {
|
||||
void(detail::swallow{ (get_field<I < 1 && b>(L, detail::forward_get<I>(keys), tableindex), 0)... });
|
||||
void apply(std::index_sequence<0, I...>, lua_State* L, Keys&& keys, int tableindex) {
|
||||
get_field<b>(L, detail::forward_get<0>(keys), tableindex);
|
||||
void(detail::swallow{ (get_field<false>(L, detail::forward_get<I>(keys), -1), 0)... });
|
||||
reference saved(L, -1);
|
||||
lua_pop(L, static_cast<int>(sizeof...(I)));
|
||||
saved.push();
|
||||
|
@ -50,7 +51,6 @@ struct field_getter<std::tuple<Args...>, b, C> {
|
|||
|
||||
template <typename Keys>
|
||||
void get(lua_State* L, Keys&& keys, int tableindex = -2) {
|
||||
tableindex = lua_absindex(L, tableindex);
|
||||
apply(std::index_sequence_for<Args...>(), L, std::forward<Keys>(keys), tableindex);
|
||||
}
|
||||
};
|
||||
|
@ -132,7 +132,35 @@ struct field_setter<T, false, std::enable_if_t<std::is_integral<T>::value>> {
|
|||
}
|
||||
};
|
||||
#endif // Lua 5.3.x
|
||||
|
||||
template <typename... Args, bool b, typename C>
|
||||
struct field_setter<std::tuple<Args...>, b, C> {
|
||||
template <bool g, std::size_t I, typename Key, typename Value>
|
||||
void apply(std::index_sequence<I>, lua_State* L, Key&& keys, Value&& value, int tableindex) {
|
||||
set_field<g>(L, detail::forward_get<I>(keys), std::forward<Value>(value), I > 0 ? -1 : tableindex);
|
||||
}
|
||||
|
||||
template <bool g, std::size_t I0, std::size_t I1, std::size_t... I, typename Keys, typename Value>
|
||||
void apply(std::index_sequence<I0, I1, I...>, lua_State* L, Keys&& keys, Value&& value, int tableindex) {
|
||||
get_field<g>(L, detail::forward_get<I0>(keys), tableindex);
|
||||
apply<false>(std::index_sequence<I1, I...>(), L, std::forward<Keys>(keys), std::forward<Value>(value), -1);
|
||||
}
|
||||
|
||||
template <typename Keys, typename Value>
|
||||
void set(lua_State* L, Keys&& keys, Value&& value, int tableindex = -3) {
|
||||
apply<b>(std::make_index_sequence<sizeof...(Args)>(), L, std::forward<Keys>(keys), std::forward<Value>(value), tableindex);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename A, typename B, bool b, typename C>
|
||||
struct field_setter<std::pair<A, B>, b, C> {
|
||||
template <typename Keys, typename Value>
|
||||
void set(lua_State* L, Keys&& keys, Value&& value, int tableindex = -1) {
|
||||
get_field<b>(L, detail::forward_get<0>(keys), tableindex);
|
||||
set_field<false>(L, detail::forward_get<1>(keys), std::forward<Value>(value));
|
||||
}
|
||||
};
|
||||
} // stack
|
||||
} // sol
|
||||
|
||||
#endif // SOL_STACK_FIELD_HPP
|
||||
#endif // SOL_STACK_FIELD_HPP
|
||||
|
|
|
@ -32,8 +32,27 @@ template <typename T, bool b, typename>
|
|||
struct probe_field_getter {
|
||||
template <typename Key>
|
||||
probe get(lua_State* L, Key&& key, int tableindex = -2) {
|
||||
if (!b && !maybe_indexable(L, tableindex)) {
|
||||
return probe(false, 0);
|
||||
}
|
||||
get_field<b>(L, std::forward<Key>(key), tableindex);
|
||||
return probe(!check<nil_t>(L), 1);
|
||||
return probe(!check<nil_t>(L), 1);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename A, typename B, bool b, typename C>
|
||||
struct probe_field_getter<std::pair<A, B>, b, C> {
|
||||
template <typename Keys>
|
||||
probe get(lua_State* L, Keys&& keys, int tableindex = -2) {
|
||||
if (!b && !maybe_indexable(L, tableindex)) {
|
||||
return probe(false, 0);
|
||||
}
|
||||
get_field<b>(L, std::get<0>(keys), tableindex);
|
||||
if (!maybe_indexable(L)) {
|
||||
return probe(false, 1);
|
||||
}
|
||||
get_field<false>(L, std::get<1>(keys), tableindex);
|
||||
return probe(!check<nil_t>(L), 2);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -51,11 +70,14 @@ struct probe_field_getter<std::tuple<Args...>, b, C> {
|
|||
if (!maybe_indexable(L)) {
|
||||
return probe(false, sofar);
|
||||
}
|
||||
return apply(std::index_sequence<I1, In...>(), sofar + 1, L, std::forward<Keys>(keys), tableindex);
|
||||
return apply(std::index_sequence<I1, In...>(), sofar + 1, L, std::forward<Keys>(keys), -1);
|
||||
}
|
||||
|
||||
template <typename Keys>
|
||||
probe get(lua_State* L, Keys&& keys, int tableindex = -2) {
|
||||
if (!b && !maybe_indexable(L, tableindex)) {
|
||||
return probe(false, 0);
|
||||
}
|
||||
return apply(std::index_sequence_for<Args...>(), 1, L, std::forward<Keys>(keys), tableindex);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -71,7 +71,7 @@ struct pusher<unique_usertype<T, Real>> {
|
|||
Real* mem = static_cast<Real*>(static_cast<void*>(fx + 1));
|
||||
*fx = detail::special_destruct<T, Real>;
|
||||
detail::default_construct::construct(mem, std::forward<Args>(args)...);
|
||||
*pref = std::addressof(detail::deref(*mem));
|
||||
*pref = std::addressof(detail::deref(*mem));
|
||||
if (luaL_newmetatable(L, &usertype_traits<unique_usertype<T>>::metatable[0]) == 1) {
|
||||
set_field(L, "__gc", detail::unique_destruct<T>);
|
||||
}
|
||||
|
|
|
@ -243,45 +243,15 @@ public:
|
|||
return global[std::forward<T>(key)];
|
||||
}
|
||||
|
||||
template<typename... Args, typename R, typename Key>
|
||||
state_view& set_function(Key&& key, R fun_ptr(Args...)){
|
||||
global.set_function(std::forward<Key>(key), fun_ptr);
|
||||
template<typename Sig, typename... Args, typename Key>
|
||||
state_view& set_function(Key&& key, Args&&... args) {
|
||||
global.set_function<Sig>(std::forward<Key>(key), std::forward<Args>(args)...);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Sig, typename Key>
|
||||
state_view& set_function(Key&& key, Sig* fun_ptr){
|
||||
global.set_function(std::forward<Key>(key), fun_ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename... Args, typename R, typename C, typename Key>
|
||||
state_view& set_function(Key&& key, R (C::*mem_ptr)(Args...)) {
|
||||
global.set_function(std::forward<Key>(key), mem_ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Sig, typename C, typename Key>
|
||||
state_view& set_function(Key&& key, Sig C::* mem_ptr) {
|
||||
global.set_function(std::forward<Key>(key), mem_ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename... Args, typename R, typename C, typename T, typename Key>
|
||||
state_view& set_function(Key&& key, R (C::*mem_ptr)(Args...), T&& obj) {
|
||||
global.set_function(std::forward<Key>(key), mem_ptr, std::forward<T>(obj));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Sig, typename C, typename T, typename Key>
|
||||
state_view& set_function(Key&& key, Sig C::* mem_ptr, T&& obj) {
|
||||
global.set_function(std::forward<Key>(key), mem_ptr, std::forward<T>(obj));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename... Sig, typename Fx, typename Key>
|
||||
state_view& set_function(Key&& key, Fx&& fx) {
|
||||
global.set_function<Sig...>(std::forward<Key>(key), std::forward<Fx>(fx));
|
||||
template<typename... Args, typename Key>
|
||||
state_view& set_function(Key&& key, Args&&... args) {
|
||||
global.set_function(std::forward<Key>(key), std::forward<Args>(args)...);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -295,6 +265,13 @@ public:
|
|||
return global.create(std::forward<Name>(name), narr, nrec, std::forward<Key>(key), std::forward<Value>(value), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename Name, typename... Args>
|
||||
table create_named_table(Name&& name, Args&&... args) {
|
||||
table x = global.create_with(std::forward<Args>(args)...);
|
||||
global.set(std::forward<Name>(name), x);
|
||||
return x;
|
||||
}
|
||||
|
||||
table create_table(int narr = 0, int nrec = 0) {
|
||||
return create_table(lua_state(), narr, nrec);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,11 @@
|
|||
#include "table_iterator.hpp"
|
||||
|
||||
namespace sol {
|
||||
namespace detail {
|
||||
template <std::size_t n>
|
||||
struct clean { lua_State* L; clean(lua_State* L) : L(L) {} ~clean() { lua_pop(L, static_cast<int>(n)); } };
|
||||
struct ref_clean { lua_State* L; int& n; ref_clean(lua_State* L, int& n) : L(L), n(n) {} ~ref_clean() { lua_pop(L, static_cast<int>(n)); } };
|
||||
}
|
||||
template <bool top_level>
|
||||
class table_core : public reference {
|
||||
friend class state;
|
||||
|
@ -63,26 +68,26 @@ class table_core : public reference {
|
|||
}
|
||||
|
||||
template<typename Ret0, typename Ret1, typename... Ret, std::size_t... I, typename Keys>
|
||||
auto tuple_get( types<Ret0, Ret1, Ret...>, std::index_sequence<I...>, Keys&& keys ) const
|
||||
auto tuple_get( types<Ret0, Ret1, Ret...>, std::index_sequence<0, 1, I...>, Keys&& keys ) const
|
||||
-> decltype(stack::pop<std::tuple<Ret0, Ret1, Ret...>>(nullptr)){
|
||||
auto pp = stack::push_pop<is_global<meta::tuple_element_t<I, Keys>...>::value>(*this);
|
||||
int tableindex = lua_gettop(lua_state());
|
||||
void(detail::swallow{ ( stack::get_field<top_level>(lua_state(), detail::forward_get<I>(keys), tableindex), 0)... });
|
||||
return stack::pop<std::tuple<Ret0, Ret1, Ret...>>( lua_state() );
|
||||
typedef decltype(stack::pop<std::tuple<Ret0, Ret1, Ret...>>(nullptr)) Tup;
|
||||
return Tup(
|
||||
traverse_get_optional<top_level, Ret0>(meta::is_specialization_of<meta::Unqualified<Ret0>, sol::optional>(), detail::forward_get<0>(keys)),
|
||||
traverse_get_optional<top_level, Ret1>(meta::is_specialization_of<meta::Unqualified<Ret1>, sol::optional>(), detail::forward_get<1>(keys)),
|
||||
traverse_get_optional<top_level, Ret>(meta::is_specialization_of<meta::Unqualified<Ret>, sol::optional>(), detail::forward_get<I>(keys))...
|
||||
);
|
||||
}
|
||||
|
||||
template<typename Ret, std::size_t I, typename Keys>
|
||||
decltype(auto) tuple_get( types<Ret>, std::index_sequence<I>, Keys&& keys ) const {
|
||||
auto pp = stack::push_pop<is_global<meta::tuple_element_t<I, Keys>>::value>(*this);
|
||||
stack::get_field<top_level>( lua_state( ), detail::forward_get<I>(keys));
|
||||
return stack::pop<Ret>( lua_state( ) );
|
||||
return traverse_get_optional<top_level, Ret>( meta::is_specialization_of<meta::Unqualified<Ret>, sol::optional>(), detail::forward_get<I>(keys) );
|
||||
}
|
||||
|
||||
template<typename Pairs, std::size_t... I>
|
||||
void tuple_set( std::index_sequence<I...>, Pairs&& pairs ) {
|
||||
auto pp = stack::push_pop<is_global<decltype(detail::forward_get<I>(pairs))...>::value>(*this);
|
||||
auto pp = stack::push_pop<top_level && (is_global<decltype(detail::forward_get<I * 2>(pairs))...>::value)>(*this);
|
||||
void(detail::swallow{ (stack::set_field<top_level>(lua_state(),
|
||||
detail::forward_get<I * 2>(pairs),
|
||||
detail::forward_get<I * 2>(pairs),
|
||||
detail::forward_get<I * 2 + 1>(pairs)
|
||||
), 0)... });
|
||||
}
|
||||
|
@ -99,6 +104,37 @@ class table_core : public reference {
|
|||
return traverse_get_deep<false, T>(std::forward<Keys>(keys)...);
|
||||
}
|
||||
|
||||
template <bool global, typename T, std::size_t I, typename Key>
|
||||
decltype(auto) traverse_get_deep_optional( int& popcount, Key&& key ) const {
|
||||
auto p = stack::probe_get_field<global>(lua_state(), std::forward<Key>(key), -1);
|
||||
popcount += p.levels;
|
||||
if (!p.success)
|
||||
return T(nullopt);
|
||||
return stack::get<T>( lua_state( ) );
|
||||
}
|
||||
|
||||
template <bool global, typename T, std::size_t I, typename Key, typename... Keys>
|
||||
decltype(auto) traverse_get_deep_optional( int& popcount, Key&& key, Keys&&... keys ) const {
|
||||
auto p = I > 0 ? stack::probe_get_field<global>(lua_state(), std::forward<Key>(key), - 1) : stack::probe_get_field<global>( lua_state( ), std::forward<Key>( key ) );
|
||||
popcount += p.levels;
|
||||
if (!p.success)
|
||||
return T(nullopt);
|
||||
return traverse_get_deep_optional<false, T, I + 1>(popcount, std::forward<Keys>(keys)...);
|
||||
}
|
||||
|
||||
template <bool global, typename T, typename... Keys>
|
||||
decltype(auto) traverse_get_optional( std::false_type, Keys&&... keys ) const {
|
||||
detail::clean<sizeof...(Keys)> c(lua_state());
|
||||
return traverse_get_deep<top_level, T>(std::forward<Keys>(keys)...);
|
||||
}
|
||||
|
||||
template <bool global, typename T, typename... Keys>
|
||||
decltype(auto) traverse_get_optional( std::true_type, Keys&&... keys ) const {
|
||||
int popcount = 0;
|
||||
detail::ref_clean c(lua_state(), popcount);
|
||||
return traverse_get_deep_optional<top_level, T, 0>(popcount, std::forward<Keys>(keys)...);
|
||||
}
|
||||
|
||||
template <bool global, typename Key, typename Value>
|
||||
void traverse_set_deep( Key&& key, Value&& value ) const {
|
||||
stack::set_field<global>( lua_state( ), std::forward<Key>( key ), std::forward<Value>(value) );
|
||||
|
@ -137,14 +173,15 @@ public:
|
|||
|
||||
template<typename... Ret, typename... Keys>
|
||||
decltype(auto) get( Keys&&... keys ) const {
|
||||
return tuple_get( types<Ret...>( ), std::index_sequence_for<Ret...>( ), std::forward_as_tuple(std::forward<Keys>(keys)...));
|
||||
static_assert(sizeof...(Keys) == sizeof...(Ret), "number of keys and number of return types do not match");
|
||||
auto pp = stack::push_pop<is_global<Keys...>::value>(*this);
|
||||
return tuple_get( types<Ret...>( ), std::index_sequence_for<Ret...>( ), std::forward_as_tuple(std::forward<Keys>(keys)...));
|
||||
}
|
||||
|
||||
template <typename T, typename... Keys>
|
||||
decltype(auto) traverse_get( Keys&&... keys ) const {
|
||||
auto pp = stack::push_pop<is_global<Keys...>::value>(*this);
|
||||
struct clean { lua_State* L; clean(lua_State* L) : L(L) {} ~clean() { lua_pop(L, static_cast<int>(sizeof...(Keys))); } } c(lua_state());
|
||||
return traverse_get_deep<top_level, T>(std::forward<Keys>(keys)...);
|
||||
return traverse_get_optional<top_level, T>(meta::is_specialization_of<meta::Unqualified<T>, sol::optional>(), std::forward<Keys>(keys)...);
|
||||
}
|
||||
|
||||
template <typename... Keys>
|
||||
|
@ -202,6 +239,10 @@ public:
|
|||
return lua_rawlen(lua_state(), -1);
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return cbegin() == cend();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
proxy<table_core&, T> operator[]( T&& key ) & {
|
||||
return proxy<table_core&, T>( *this, std::forward<T>( key ) );
|
||||
|
@ -217,45 +258,15 @@ public:
|
|||
return proxy<table_core, T>( *this, std::forward<T>( key ) );
|
||||
}
|
||||
|
||||
template<typename... Args, typename R, typename Key>
|
||||
table_core& set_function( Key&& key, R fun_ptr( Args... ) ) {
|
||||
set_resolved_function( std::forward<Key>( key ), fun_ptr );
|
||||
template<typename Sig, typename Key, typename... Args>
|
||||
table_core& set_function( Key&& key, Args&&... args ) {
|
||||
set_fx( types<Sig>( ), std::forward<Key>( key ), std::forward<Args>( args )... );
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Sig, typename Key>
|
||||
table_core& set_function( Key&& key, Sig* fun_ptr ) {
|
||||
set_resolved_function( std::forward<Key>( key ), fun_ptr );
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename... Args, typename R, typename C, typename T, typename Key>
|
||||
table_core& set_function( Key&& key, R( C::*mem_ptr )( Args... ), T&& obj ) {
|
||||
set_resolved_function( std::forward<Key>( key ), mem_ptr, std::forward<T>( obj ) );
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Sig, typename C, typename T, typename Key>
|
||||
table_core& set_function( Key&& key, Sig C::* mem_ptr, T&& obj ) {
|
||||
set_resolved_function( std::forward<Key>( key ), mem_ptr, std::forward<T>( obj ) );
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename... Args, typename R, typename C, typename Key>
|
||||
table_core& set_function( Key&& key, R( C::*mem_ptr )( Args... ) ) {
|
||||
set_resolved_function( std::forward<Key>( key ), mem_ptr );
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Sig, typename C, typename Key>
|
||||
table_core& set_function( Key&& key, Sig C::* mem_ptr ) {
|
||||
set_resolved_function( std::forward<Key>( key ), mem_ptr );
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename... Sig, typename Fx, typename Key>
|
||||
table_core& set_function( Key&& key, Fx&& fx ) {
|
||||
set_fx( types<Sig...>( ), std::forward<Key>( key ), std::forward<Fx>( fx ) );
|
||||
template<typename Key, typename... Args>
|
||||
table_core& set_function( Key&& key, Args&&... args ) {
|
||||
set_fx( types<>( ), std::forward<Key>( key ), std::forward<Args>( args )... );
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -270,16 +281,14 @@ private:
|
|||
set(std::forward<Key>(key), std::forward<Fx>(fx));
|
||||
}
|
||||
|
||||
template<typename Fx, typename Key, meta::DisableIf<meta::is_specialization_of<meta::Unqualified<Fx>, overload_set>> = 0>
|
||||
void set_fx( types<>, Key&& key, Fx&& fx ) {
|
||||
typedef meta::Unwrapped<meta::Unqualified<Fx>> fx_t;
|
||||
typedef decltype( &fx_t::operator() ) Sig;
|
||||
set_fx( types<meta::function_signature_t<Sig>>( ), std::forward<Key>( key ), std::forward<Fx>( fx ) );
|
||||
template<typename Fx, typename Key, typename... Args, meta::DisableIf<meta::is_specialization_of<meta::Unqualified<Fx>, overload_set>> = 0>
|
||||
void set_fx( types<>, Key&& key, Fx&& fx, Args&&... args ) {
|
||||
set(std::forward<Key>(key), function_args(std::forward<Fx>(fx), std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template<typename... Sig, typename... Args, typename Key>
|
||||
void set_resolved_function( Key&& key, Args&&... args ) {
|
||||
set(std::forward<Key>(key), function_pack<function_sig<Sig...>>(std::forward<Args>(args)...));
|
||||
set(std::forward<Key>(key), function_args<function_sig<Sig...>>(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -331,7 +340,13 @@ public:
|
|||
template <typename... Args>
|
||||
table create_with(Args&&... args) {
|
||||
return create_with(lua_state(), std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Name, typename... Args>
|
||||
table create_named(Name&& name, Args&&... args) {
|
||||
static const int narr = static_cast<int>(meta::count_if_2_pack<std::is_integral, Args...>::value);
|
||||
return create(lua_state(), narr, sizeof...(Args) / 2 - narr, std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
} // sol
|
||||
|
||||
|
|
|
@ -58,7 +58,10 @@ public:
|
|||
tableidx = lua_gettop(ref.lua_state());
|
||||
stack::push(ref.lua_state(), nil);
|
||||
this->operator++();
|
||||
--idx;
|
||||
if (idx == -1) {
|
||||
return;
|
||||
}
|
||||
--idx;
|
||||
}
|
||||
|
||||
table_iterator& operator++() {
|
||||
|
|
|
@ -140,14 +140,14 @@ struct at_in_pack<I, Arg, Args...> : std::conditional<I == 0, Arg, at_in_pack_t<
|
|||
|
||||
namespace meta_detail {
|
||||
template<std::size_t I, template<typename...> class Pred, typename... Ts>
|
||||
struct count_if_pack {};
|
||||
struct count_if_pack : std::integral_constant<std::size_t, 0> {};
|
||||
template<std::size_t I, template<typename...> class Pred, typename T, typename... Ts>
|
||||
struct count_if_pack<I, Pred, T, Ts...> : std::conditional_t<sizeof...(Ts) == 0,
|
||||
std::integral_constant<std::size_t, I + static_cast<std::size_t>(Pred<T>::value)>,
|
||||
count_if_pack<I + static_cast<std::size_t>(Pred<T>::value), Pred, Ts...>
|
||||
> { };
|
||||
template<std::size_t I, template<typename...> class Pred, typename... Ts>
|
||||
struct count_if_2_pack {};
|
||||
struct count_if_2_pack : std::integral_constant<std::size_t, 0> {};
|
||||
template<std::size_t I, template<typename...> class Pred, typename T, typename U, typename... Ts>
|
||||
struct count_if_2_pack<I, Pred, T, U, Ts...> : std::conditional_t<sizeof...(Ts) == 0,
|
||||
std::integral_constant<std::size_t, I + static_cast<std::size_t>(Pred<T>::value)>,
|
||||
|
@ -236,6 +236,7 @@ template<typename T>
|
|||
struct Function : Bool<meta_detail::is_function_impl<T>::value> {};
|
||||
|
||||
namespace meta_detail {
|
||||
|
||||
template<typename Signature, bool b = has_deducible_signature<Signature>::value>
|
||||
struct fx_traits;
|
||||
|
||||
|
@ -248,6 +249,7 @@ template<typename T, typename R, typename... Args>
|
|||
struct fx_traits<R(T::*)(Args...), false> {
|
||||
static const std::size_t arity = sizeof...(Args);
|
||||
static const bool is_member_function = true;
|
||||
typedef T object_type;
|
||||
typedef std::tuple<Args...> args_tuple_type;
|
||||
typedef types<Args...> args_type;
|
||||
typedef R(T::* function_pointer_type)(Args...);
|
||||
|
@ -263,6 +265,7 @@ template<typename T, typename R, typename... Args>
|
|||
struct fx_traits<R(T::*)(Args...) const, false> {
|
||||
static const std::size_t arity = sizeof...(Args);
|
||||
static const bool is_member_function = true;
|
||||
typedef T object_type;
|
||||
typedef std::tuple<Args...> args_tuple_type;
|
||||
typedef types<Args...> args_type;
|
||||
typedef R(T::* function_pointer_type)(Args...);
|
||||
|
@ -304,31 +307,16 @@ struct fx_traits<R(*)(Args...), false> {
|
|||
using arg = meta::tuple_element_t<i, args_tuple_type>;
|
||||
};
|
||||
|
||||
} // meta_detail
|
||||
|
||||
template<typename Signature>
|
||||
struct function_traits : meta_detail::fx_traits<std::decay_t<Signature>> {};
|
||||
|
||||
template<typename Signature>
|
||||
using function_args_t = typename function_traits<Signature>::args_type;
|
||||
|
||||
template<typename Signature>
|
||||
using function_signature_t = typename function_traits<Signature>::signature_type;
|
||||
|
||||
template<typename Signature>
|
||||
using function_return_t = typename function_traits<Signature>::return_type;
|
||||
|
||||
namespace meta_detail {
|
||||
template<typename Signature, bool b = std::is_member_object_pointer<Signature>::value>
|
||||
struct callable_traits : function_traits<Signature> {
|
||||
struct callable_traits : fx_traits<std::decay_t<Signature>> {
|
||||
|
||||
};
|
||||
|
||||
template<typename Signature>
|
||||
struct callable_traits<Signature, true> {
|
||||
typedef typename remove_member_pointer<Signature>::type Arg;
|
||||
typedef typename remove_member_pointer<Signature>::type R;
|
||||
typedef Signature signature_type;
|
||||
template<typename R, typename T>
|
||||
struct callable_traits<R(T::*), true> {
|
||||
typedef R Arg;
|
||||
typedef T object_type;
|
||||
using signature_type = R(T::*);
|
||||
static const bool is_member_function = false;
|
||||
static const std::size_t arity = 1;
|
||||
typedef std::tuple<Arg> args_tuple_type;
|
||||
|
@ -343,9 +331,16 @@ struct callable_traits<Signature, true> {
|
|||
} // meta_detail
|
||||
|
||||
template<typename Signature>
|
||||
struct callable_traits : meta_detail::callable_traits<std::remove_volatile_t<Signature>> {
|
||||
struct bind_traits : meta_detail::callable_traits<std::remove_volatile_t<Signature>> {};
|
||||
|
||||
};
|
||||
template<typename Signature>
|
||||
using function_args_t = typename bind_traits<Signature>::args_type;
|
||||
|
||||
template<typename Signature>
|
||||
using function_signature_t = typename bind_traits<Signature>::signature_type;
|
||||
|
||||
template<typename Signature>
|
||||
using function_return_t = typename bind_traits<Signature>::return_type;
|
||||
|
||||
struct has_begin_end_impl {
|
||||
template<typename T, typename U = Unqualified<T>,
|
||||
|
@ -378,7 +373,11 @@ template <typename T>
|
|||
using is_string_constructible = Or<std::is_same<Unqualified<T>, const char*>, std::is_same<Unqualified<T>, char>, std::is_same<Unqualified<T>, std::string>, std::is_same<Unqualified<T>, std::initializer_list<char>>>;
|
||||
|
||||
template <typename T>
|
||||
using is_c_str = Or<std::is_same<std::decay_t<Unqualified<T>>, char*>, std::is_same<Unqualified<T>, std::string>>;
|
||||
using is_c_str = Or<
|
||||
std::is_same<std::decay_t<Unqualified<T>>, const char*>,
|
||||
std::is_same<std::decay_t<Unqualified<T>>, char*>,
|
||||
std::is_same<Unqualified<T>, std::string>
|
||||
>;
|
||||
|
||||
namespace meta_detail {
|
||||
template <typename T, meta::DisableIf<meta::is_specialization_of<meta::Unqualified<T>, std::tuple>> = 0>
|
||||
|
|
|
@ -88,6 +88,8 @@ const nil_t nil {};
|
|||
inline bool operator==(nil_t, nil_t) { return true; }
|
||||
inline bool operator!=(nil_t, nil_t) { return false; }
|
||||
|
||||
typedef std::add_lvalue_reference_t<std::remove_pointer_t<lua_CFunction>> lua_r_CFunction;
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct unique_usertype {};
|
||||
|
||||
|
|
|
@ -275,7 +275,7 @@ private:
|
|||
template<typename Fx>
|
||||
std::unique_ptr<function_detail::base_function> make_function(const std::string&, Fx&& func) {
|
||||
typedef meta::Unqualified<Fx> Fxu;
|
||||
typedef meta::tuple_element_t<0, typename meta::function_traits<Fxu>::args_tuple_type> Arg0;
|
||||
typedef meta::tuple_element_t<0, typename meta::bind_traits<Fxu>::args_tuple_type> Arg0;
|
||||
typedef meta::Unqualified<std::remove_pointer_t<Arg0>> Argu;
|
||||
static_assert(std::is_base_of<Argu, T>::value, "Any non-member-function must have a first argument which is covariant with the desired usertype.");
|
||||
typedef std::decay_t<Fxu> function_type;
|
||||
|
@ -292,6 +292,41 @@ private:
|
|||
metafunctiontable.push_back({ name.c_str(), constructfunc });
|
||||
}
|
||||
|
||||
template<std::size_t N, typename... Args>
|
||||
void build_function(std::string funcname, lua_CFunction direct) {
|
||||
functionnames.push_back(std::move(funcname));
|
||||
std::string& name = functionnames.back();
|
||||
|
||||
// Insert bubble to keep with compile-time argument count (simpler and cheaper to do)
|
||||
functions.push_back(nullptr);
|
||||
|
||||
auto metamethodfind = std::find(meta_function_names.begin(), meta_function_names.end(), name);
|
||||
if (metamethodfind != meta_function_names.end()) {
|
||||
metafunctiontable.push_back({ name.c_str(), function_detail::usertype_call<N> });
|
||||
meta_function metafunction = static_cast<meta_function>(metamethodfind - meta_function_names.begin());
|
||||
switch (metafunction) {
|
||||
case meta_function::garbage_collect:
|
||||
destructfuncname = name.c_str();
|
||||
destructfunc = function_detail::usertype_call<N>;
|
||||
return;
|
||||
case meta_function::index:
|
||||
indexfunc = functions.back().get();
|
||||
needsindexfunction = true;
|
||||
break;
|
||||
case meta_function::new_index:
|
||||
newindexfunc = functions.back().get();
|
||||
break;
|
||||
case meta_function::construct:
|
||||
constructfunc = function_detail::usertype_call<N>;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
functiontable.push_back({ name.c_str(), direct });
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
void build_function(std::string funcname, destructor_wrapper<void>) {
|
||||
auto metamethodfind = std::find(meta_function_names.begin(), meta_function_names.end(), funcname);
|
||||
|
|
|
@ -17,7 +17,7 @@ void takefn(std::function<int()> purr) {
|
|||
}
|
||||
|
||||
struct A {
|
||||
int a = 0xA; int bark() { return 1; }
|
||||
int a = 0xA; int bark() { return 1; }
|
||||
};
|
||||
|
||||
std::tuple<int, int> bark(int num_value, A* a) {
|
||||
|
@ -73,13 +73,13 @@ TEST_CASE("functions/overload-resolution", "Check if overloaded function resolut
|
|||
lua.set_function<int, int, int>("overloaded", overloaded);
|
||||
REQUIRE_NOTHROW(lua.script("print(overloaded(1, 2, 3))"));
|
||||
*/
|
||||
lua.set_function<int(int)>("overloaded", overloaded);
|
||||
lua.set_function("overloaded", sol::resolve<int(int)>(overloaded));
|
||||
REQUIRE_NOTHROW(lua.script("print(overloaded(1))"));
|
||||
|
||||
lua.set_function<int(int, int)>("overloaded", overloaded);
|
||||
lua.set_function("overloaded", sol::resolve<int(int, int)>(overloaded));
|
||||
REQUIRE_NOTHROW(lua.script("print(overloaded(1, 2))"));
|
||||
|
||||
lua.set_function<int(int, int, int)>("overloaded", overloaded);
|
||||
lua.set_function("overloaded", sol::resolve<int(int, int, int)>(overloaded));
|
||||
REQUIRE_NOTHROW(lua.script("print(overloaded(1, 2, 3))"));
|
||||
}
|
||||
|
||||
|
@ -326,4 +326,121 @@ TEST_CASE("functions/destructor-tests", "Show that proper copies / destruction h
|
|||
REQUIRE(created == 1);
|
||||
REQUIRE(destroyed == 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("functions/all-kinds", "Register all kinds of functions, make sure they all compile and work") {
|
||||
sol::state lua;
|
||||
|
||||
struct test_1 {
|
||||
int a = 0xA;
|
||||
virtual int bark() {
|
||||
return a;
|
||||
}
|
||||
|
||||
int bark_mem() {
|
||||
return a;
|
||||
}
|
||||
|
||||
static std::tuple<int, int> x_bark(int num_value, test_1* a) {
|
||||
return std::tuple<int, int>(num_value * 2, a->a);
|
||||
}
|
||||
};
|
||||
|
||||
struct test_2 {
|
||||
int a = 0xC;
|
||||
int bark() {
|
||||
return 20;
|
||||
}
|
||||
};
|
||||
|
||||
auto a = []() { return 500; };
|
||||
auto b = [&]() { return 501; };
|
||||
auto c = [&]() { return 502; };
|
||||
auto d = []() { return 503; };
|
||||
|
||||
lua.new_usertype<test_1>("test_1",
|
||||
"bark", sol::c_call<decltype(&test_1::bark_mem), &test_1::bark_mem>
|
||||
);
|
||||
lua.new_usertype<test_2>("test_2",
|
||||
"bark", sol::c_call<decltype(&test_2::bark), &test_2::bark>
|
||||
);
|
||||
test_2 t2;
|
||||
|
||||
lua.set_function("a", a);
|
||||
lua.set_function("b", b);
|
||||
lua.set_function("c", std::ref(c));
|
||||
lua.set_function("d", std::ref(d));
|
||||
lua.set_function("f", &test_1::bark);
|
||||
lua.set_function("g", test_1::x_bark);
|
||||
lua.set_function("h", sol::c_call<decltype(&test_1::bark_mem), &test_1::bark_mem>);
|
||||
lua.set_function("i", &test_2::bark, test_2());
|
||||
lua.set_function("j", &test_2::a, test_2());
|
||||
lua.set_function("k", &test_2::a);
|
||||
lua.set_function("l", sol::c_call<decltype(&test_1::a), &test_1::a>);
|
||||
lua.set_function("m", &test_2::a, &t2);
|
||||
|
||||
lua.script(R"(
|
||||
o1 = test_1.new()
|
||||
o2 = test_2.new()
|
||||
|
||||
ob = o1:bark()
|
||||
|
||||
A = a()
|
||||
B = b()
|
||||
C = c()
|
||||
D = d()
|
||||
F = f(o1)
|
||||
G0, G1 = g(2, o1)
|
||||
H = h(o1)
|
||||
I = i(o1)
|
||||
I = i(o1)
|
||||
|
||||
J0 = j()
|
||||
j(24)
|
||||
J1 = j()
|
||||
|
||||
K0 = k(o2)
|
||||
k(o2, 1024)
|
||||
K1 = k(o2)
|
||||
|
||||
L0 = l(o1)
|
||||
l(o1, 678)
|
||||
L1 = l(o1)
|
||||
|
||||
|
||||
M0 = m()
|
||||
m(256)
|
||||
M1 = m()
|
||||
)");
|
||||
int ob, A, B, C, D, F, G0, G1, H, I, J0, J1, K0, K1, L0, L1, M0, M1;
|
||||
std::tie( ob, A, B, C, D, F, G0, G1, H, I, J0, J1, K0, K1, L0, L1, M0, M1 )
|
||||
= lua.get<int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int>(
|
||||
"ob", "A", "B", "C", "D", "F", "G0", "G1", "H", "I", "J0", "J1", "K0", "K1", "L0", "L1", "M0", "M1"
|
||||
);
|
||||
|
||||
REQUIRE(ob == 0xA);
|
||||
|
||||
REQUIRE( A == 500 );
|
||||
REQUIRE( B == 501 );
|
||||
REQUIRE( C == 502 );
|
||||
REQUIRE( D == 503 );
|
||||
|
||||
REQUIRE( F == 0xA );
|
||||
REQUIRE( G0 == 4 );
|
||||
REQUIRE( G1 == 0xA );
|
||||
REQUIRE( H == 0xA );
|
||||
REQUIRE( I == 20 );
|
||||
|
||||
REQUIRE( J0 == 0xC );
|
||||
REQUIRE( J1 == 24 );
|
||||
|
||||
REQUIRE( K0 == 0xC );
|
||||
REQUIRE( K1 == 1024 );
|
||||
|
||||
REQUIRE( L0 == 0xA );
|
||||
REQUIRE( L1 == 678 );
|
||||
|
||||
REQUIRE( M0 == 0xC );
|
||||
REQUIRE( M1 == 256 );
|
||||
}
|
||||
|
|
83
tests.cpp
83
tests.cpp
|
@ -685,6 +685,32 @@ TEST_CASE("tables/operator[]-optional", "Test if proxies on tables can lazily ev
|
|||
present = (bool)test2;
|
||||
REQUIRE(present);
|
||||
REQUIRE(test2.value() == 262);
|
||||
|
||||
sol::optional<int> nope = lua["nope"]["kek"]["hah"];
|
||||
auto nope2 = lua.get<sol::optional<int>>(std::make_tuple("nope", "kek", "hah"));
|
||||
present = (bool)nope;
|
||||
REQUIRE_FALSE(present);
|
||||
present = (bool)nope2;
|
||||
REQUIRE_FALSE(present);
|
||||
lua.create_named_table("nope", "kek", lua.create_table_with("hah", 1));
|
||||
sol::optional<int> non_nope = lua["nope"]["kek"]["hah"].get<sol::optional<int>>();
|
||||
sol::optional<int> non_nope2 = lua.get<sol::optional<int>>(std::make_tuple("nope", "kek", "hah"));
|
||||
present = (bool)non_nope;
|
||||
REQUIRE(present);
|
||||
present = (bool)non_nope2;
|
||||
REQUIRE(present);
|
||||
REQUIRE(non_nope.value() == 1);
|
||||
REQUIRE(non_nope2.value() == 1);
|
||||
|
||||
lua.set(std::make_tuple("nope", "kek", "hah"), 35);
|
||||
sol::optional<int> non_nope3 = lua["nope"]["kek"]["hah"].get<sol::optional<int>>();
|
||||
sol::optional<int> non_nope4 = lua.get<sol::optional<int>>(std::make_tuple("nope", "kek", "hah"));
|
||||
present = (bool)non_nope3;
|
||||
REQUIRE(present);
|
||||
present = (bool)non_nope4;
|
||||
REQUIRE(present);
|
||||
REQUIRE(non_nope3.value() == 1);
|
||||
REQUIRE(non_nope4.value() == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("tables/usertype", "Show that we can create classes from usertype and use them") {
|
||||
|
@ -912,6 +938,63 @@ TEST_CASE("tables/for-each", "Testing the use of for_each to get values from a l
|
|||
REQUIRE(iterations == tablesize);
|
||||
}
|
||||
|
||||
TEST_CASE("tables/for-each-empty", "empty tables should not crash") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.script("arr = {}");
|
||||
sol::table tbl = lua[ "arr" ];
|
||||
REQUIRE(tbl.empty());
|
||||
std::size_t tablesize = 0;
|
||||
std::size_t iterations = 0;
|
||||
auto fx = [&iterations](sol::object key, sol::object value) {
|
||||
++iterations;
|
||||
sol::type keytype = key.get_type();
|
||||
switch (keytype) {
|
||||
case sol::type::number:
|
||||
switch (key.as<int>()) {
|
||||
case 0:
|
||||
REQUIRE((value.as<std::string>() == "Hi"));
|
||||
break;
|
||||
case 1:
|
||||
REQUIRE((value.as<double>() == 123.45));
|
||||
break;
|
||||
case 2:
|
||||
REQUIRE((value.as<std::string>() == "String value"));
|
||||
break;
|
||||
case 3:
|
||||
REQUIRE((value.is<sol::nil_t>()));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case sol::type::string:
|
||||
if (key.as<std::string>() == "WOOF") {
|
||||
REQUIRE((value.as<double>() == 123));
|
||||
}
|
||||
break;
|
||||
case sol::type::nil:
|
||||
REQUIRE((value.as<double>() == 3));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
auto fxpair = [&fx](std::pair<sol::object, sol::object> kvp) { fx(kvp.first, kvp.second); };
|
||||
tbl.for_each( fx );
|
||||
REQUIRE(iterations == tablesize);
|
||||
|
||||
iterations = 0;
|
||||
tbl.for_each( fxpair );
|
||||
REQUIRE(iterations == tablesize);
|
||||
|
||||
iterations = 0;
|
||||
for (const auto& kvp : tbl) {
|
||||
fxpair(kvp);
|
||||
++iterations;
|
||||
}
|
||||
REQUIRE(iterations == tablesize);
|
||||
}
|
||||
|
||||
TEST_CASE("tables/iterators", "Testing the use of iteratrs to get values from a lua table") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
|
Loading…
Reference in New Issue
Block a user