mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
C++17 additions: std::variant, string_views of all types, checker for if we have the right version
added variadic_results, to return a variable number of arguments to Lua added variadic_results and as_results added improved function examples (for multiple results and split overloading out) added tests for variadics added tests for C++17 utilities added a forwarding header added a specific `unsafe_function` header added and improved documetation pages
This commit is contained in:
parent
077448bfc8
commit
e69e7c79fa
|
@ -35,7 +35,9 @@ Browse the various function and classes :doc:`Sol<../index>` utilizes to make yo
|
|||
thread
|
||||
optional
|
||||
variadic_args
|
||||
variadic_results
|
||||
as_args
|
||||
as_returns
|
||||
overload
|
||||
property
|
||||
var
|
||||
|
|
|
@ -6,7 +6,7 @@ turn an iterable argument into multiple arguments
|
|||
.. code-block:: cpp
|
||||
|
||||
template <typename T>
|
||||
as_args_t { ... };
|
||||
struct as_args_t { ... };
|
||||
|
||||
template <typename T>
|
||||
as_args_t<T> as_args( T&& );
|
||||
|
@ -15,6 +15,7 @@ turn an iterable argument into multiple arguments
|
|||
``sol::as_args`` is a function that that takes an iterable and turns it into multiple arguments to a function call. It forwards its arguments, and is meant to be used as shown below:
|
||||
|
||||
.. code-block:: cpp
|
||||
:linenos:
|
||||
:caption: as_args.c++
|
||||
|
||||
#define SOL_CHECK_ARGUMENTS
|
||||
|
|
50
docs/source/api/as_returns.rst
Normal file
50
docs/source/api/as_returns.rst
Normal file
|
@ -0,0 +1,50 @@
|
|||
as_returns
|
||||
==========
|
||||
turn an iterable argument into a multiple-return type
|
||||
-----------------------------------------------------
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
template <typename T>
|
||||
struct as_returns_t { ... };
|
||||
|
||||
template <typename T>
|
||||
as_returns_t<T> as_returns( T&& );
|
||||
|
||||
|
||||
This allows you to wrap up a source that has ``begin`` and ``end`` iterator-returning functions on it and return it as multiple results into Lua. To have more control over the returns, use :doc:`sol::variadic_results<variadic_results>`
|
||||
|
||||
|
||||
.. code-block:: cpp
|
||||
:linenos:
|
||||
:caption: as_returns.c++
|
||||
|
||||
#define SOL_CHECK_ARGUMENTS
|
||||
#include <sol.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
int main () {
|
||||
sol::state lua;
|
||||
|
||||
lua.set_function("f", []() {
|
||||
std::set<std::string> results{ "arf", "bark", "woof" };
|
||||
return sol::as_returns(std::move(results));
|
||||
});
|
||||
|
||||
lua.script(R"(
|
||||
v1, v2, v3 = f()
|
||||
)");
|
||||
}());
|
||||
|
||||
std::string v1 = lua["v1"];
|
||||
std::string v2 = lua["v2"];
|
||||
std::string v3 = lua["v3"];
|
||||
|
||||
assert(v1 == "arf");
|
||||
assert(v2 == "bark");
|
||||
assert(v3 == "woof");
|
||||
|
||||
return 0;
|
||||
}
|
11
docs/source/api/variadic_results.rst
Normal file
11
docs/source/api/variadic_results.rst
Normal file
|
@ -0,0 +1,11 @@
|
|||
variadic_results
|
||||
================
|
||||
push multiple disparate arguments into lua
|
||||
------------------------------------------
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
struct variadic_results : std::vector<object> { ... };
|
||||
|
||||
template <typename T>
|
||||
as_args_t<T> as_args( T&& );
|
|
@ -50,6 +50,10 @@ Clang 3.4, 3.5 and 3.6 have many bugs we have run into when developing sol2 and
|
|||
We encourage all users to upgrade immediately. If you need old code for some reason, use `sol2 release v2.18.0`_: otherwise, always grab sol2's latest.
|
||||
|
||||
|
||||
feature support
|
||||
---------------
|
||||
|
||||
track future compiler and feature support in `this issue here`_.
|
||||
|
||||
supported Lua version
|
||||
---------------------
|
||||
|
@ -106,3 +110,4 @@ Hopefully, as things progress, we move things forward.
|
|||
.. _sol2 release v2.18.0: https://github.com/ThePhD/sol2/releases/tag/v2.17.5
|
||||
.. _OrfeasZ in this issue: https://github.com/ThePhD/sol2/issues/329#issuecomment-276824983
|
||||
.. _issue describing preliminary steps can be found here: https://github.com/ThePhD/sol2/issues/436#issuecomment-312021508
|
||||
.. _this issue here: https://github.com/ThePhD/sol2/issues/426
|
||||
|
|
|
@ -9,11 +9,13 @@ There are a number of examples dealing with functions and how they can be bound
|
|||
* For a quicker walkthrough that demonstrates almost everything, see `the examples`_ and the :doc:`the quick and dirty tutorial<tutorial/all-the-things>`
|
||||
* For a full explanation, :doc:`read the tutorial<tutorial/functions>` and consult the subjects below
|
||||
* If you have bindings and set-ups that want to leverage the C API without sol2's interference, you can push a raw function, which has certain implications (noted :ref:`below<raw-function-note>`)
|
||||
* You return multiple values by returning a `std::tuple`
|
||||
* You can work with **transparent arguments** that provide you with special information, such as
|
||||
- :doc:`sol::variadic_args<api/variadic_args>`, for handling variable number of arguments at runtime
|
||||
- :doc:`sol::this_state<api/this_state>`, for getting the current Lua state
|
||||
- :doc:`sol::this_environment<api/this_environment>`, for potentially retrieving the current Lua environment
|
||||
* :doc:`Overload function calls on a single name<api/overload>`, discriminating by argument number and type (first-come, first-serve overloading)
|
||||
- Note: because of this feature, automatic number to string conversion from Lua is not permitted
|
||||
* Control serialization of arguments and return types with :doc:`sol::nested<api/nested>`, :doc:`sol::as_table<api/nested>`, :doc:`sol::as_args<api/as_args>` and :doc:`sol::as_function<api/as_function>`
|
||||
* Set environments for Lua functions and scrips with :doc:`sol::environment<api/environment>`
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ config
|
|||
Note that you can obtain safety with regards to functions you bind by using the :doc:`protect<api/protect>` wrapper around function/variable bindings you set into Lua. Additionally, you can have basic boolean checks when using the API by just converting to a :doc:`sol::optional\<T><api/optional>` when necessary for getting things out of Lua and for function arguments.
|
||||
|
||||
``SOL_SAFE_USERTYPE`` triggers the following change:
|
||||
* If the userdata to a usertype function is nil, will trigger an error instead of letting things go through and letting the system segfault/crash.
|
||||
* If the userdata to a usertype function is nil, will trigger an error instead of letting things go through and letting the system segfault/crash
|
||||
* Turned on by default with clang++, g++ and VC++ if a basic check for building in debug mode is detected
|
||||
|
||||
``SOL_SAFE_FUNCTION`` triggers the following change:
|
||||
|
@ -19,8 +19,9 @@ Note that you can obtain safety with regards to functions you bind by using the
|
|||
* Not turned on by default under any detectible compiler settings: you must turn this one on manually
|
||||
|
||||
``SOL_CHECK_ARGUMENTS`` triggers the following changes:
|
||||
* ``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.
|
||||
* ``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
|
||||
* ``lua_tolstring`` conversions are not permitted on numbers: through the API: only actual strings are allowed. This is necessary to allow :doc:`sol::overload<api/overload>` to work properly
|
||||
* ``sol::stack::call`` and its variants will, if no templated boolean is specified, check all of the arguments for a function call
|
||||
* If ``SOL_SAFE_USERTYPE`` is not defined, it gets defined to turn being on and the effects described above kick in
|
||||
|
||||
Tests are compiled with this on to ensure everything is going as expected. Remember that if you want these features, you must explicitly turn them on all of them to be sure you are getting them.
|
||||
|
|
|
@ -18,10 +18,6 @@ struct multiplier {
|
|||
}
|
||||
};
|
||||
|
||||
inline std::string make_string( std::string input ) {
|
||||
return "string: " + input;
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::cout << "=== functions example ===" << std::endl;
|
||||
|
||||
|
@ -67,6 +63,7 @@ inc()
|
|||
// Do something based on this information
|
||||
std::cout << "Yahoo! x is " << x << std::endl;
|
||||
}
|
||||
|
||||
// retrieval of a function is done similarly
|
||||
// to other variables, using sol::function
|
||||
sol::function add = lua["my_add"];
|
||||
|
@ -79,34 +76,7 @@ inc()
|
|||
std::cout << "Woo, value is 21!" << std::endl;
|
||||
}
|
||||
|
||||
// multi-return functions are supported using
|
||||
// std::tuple as the interface.
|
||||
lua.set_function("multi", [] { return std::make_tuple(10, "goodbye"); });
|
||||
lua.script("x, y = multi()");
|
||||
lua.script("assert(x == 10 and y == 'goodbye')");
|
||||
|
||||
auto multi = lua.get<sol::function>("multi");
|
||||
int first;
|
||||
std::string second;
|
||||
sol::tie(first, second) = multi();
|
||||
|
||||
// use the values
|
||||
assert(first == 10);
|
||||
assert(second == "goodbye");
|
||||
|
||||
// you can even overload functions
|
||||
// just pass in the different functions
|
||||
// you want to pack into a single name:
|
||||
// make SURE they take different types!
|
||||
|
||||
lua.set_function("func", sol::overload([](int x) { return x; }, make_string, my_add));
|
||||
|
||||
// All these functions are now overloaded through "func"
|
||||
lua.script(R"(
|
||||
print(func(1))
|
||||
print(func("bark"))
|
||||
print(func(1,2))
|
||||
)");
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
81
examples/multi_results.cpp
Normal file
81
examples/multi_results.cpp
Normal file
|
@ -0,0 +1,81 @@
|
|||
#define SOL_CHECK_ARGUMENTS
|
||||
#include <sol.hpp>
|
||||
|
||||
#include <tuple>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
std::cout << "=== multi results example ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
// multi-return functions are supported using
|
||||
// std::tuple as the transfer type,
|
||||
// sol::as_returns for containers,
|
||||
// and sol::variadic_results for more special things
|
||||
lua.set_function("multi_tuple", [] {
|
||||
return std::make_tuple(10, "goodbye");
|
||||
});
|
||||
lua.script("print('calling multi_tuple')");
|
||||
lua.script("print(multi_tuple())");
|
||||
lua.script("x, y = multi_tuple()");
|
||||
lua.script("assert(x == 10 and y == 'goodbye')");
|
||||
|
||||
auto multi = lua.get<sol::function>("multi");
|
||||
int first;
|
||||
std::string second;
|
||||
// tie the values
|
||||
sol::tie(first, second) = multi();
|
||||
|
||||
// use the values
|
||||
assert(first == 10);
|
||||
assert(second == "goodbye");
|
||||
|
||||
// sol::as_returns
|
||||
// works with any iterable,
|
||||
// but we show off std::vector here
|
||||
lua.set_function("multi_containers", [] (bool add_extra) {
|
||||
std::vector<int> values{55, 66};
|
||||
if (add_extra) {
|
||||
values.push_back(77);
|
||||
}
|
||||
return sol::as_returns(std::move(values));
|
||||
});
|
||||
lua.script("print('calling multi_containers')");
|
||||
lua.script("print(multi_containers(false))");
|
||||
lua.script("a, b, c = multi_containers(true)");
|
||||
int a = lua["a"];
|
||||
int b = lua["b"];
|
||||
int c = lua["c"];
|
||||
|
||||
assert(a == 55);
|
||||
assert(b == 66);
|
||||
assert(c == 77);
|
||||
|
||||
// sol::variadic_results
|
||||
// you can push objects of different types
|
||||
// note that sol::this_state is a transparent
|
||||
// argument: you don't need to pass
|
||||
// that state through Lua
|
||||
lua.set_function("multi_vars", [](int a, bool b, sol::this_state L) {
|
||||
sol::variadic_results values;
|
||||
values.push_back({ L, sol::in_place_type<int>, a });
|
||||
values.push_back({ L, sol::in_place_type<bool>, b });
|
||||
values.push_back({ L, sol::in_place_type<const char*>, "awoo" });
|
||||
return values;
|
||||
});
|
||||
lua.script("print('calling multi_vars')");
|
||||
lua.script("print(multi_vars(2, false))");
|
||||
lua.script("t, u, v = multi_vars(42, true)");
|
||||
int t = lua["t"];
|
||||
bool u = lua["u"];
|
||||
std::string v = lua["v"];
|
||||
|
||||
assert(t == 42);
|
||||
assert(u);
|
||||
assert(v == "awoo");
|
||||
|
||||
return 0;
|
||||
}
|
42
examples/overloading.cpp
Normal file
42
examples/overloading.cpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
#define SOL_CHECK_ARGUMENTS
|
||||
#include <sol.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
inline int my_add(int x, int y) {
|
||||
return x + y;
|
||||
}
|
||||
|
||||
inline std::string make_string(std::string input) {
|
||||
return "string: " + input;
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::cout << "=== overloading example ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
// you can overload functions
|
||||
// just pass in the different functions
|
||||
// you want to pack into a single name:
|
||||
// make SURE they take different types!
|
||||
|
||||
lua.set_function("func", sol::overload(
|
||||
[](int x) { return x; },
|
||||
make_string,
|
||||
my_add
|
||||
));
|
||||
|
||||
// All these functions are now overloaded through "func"
|
||||
lua.script(R"(
|
||||
print(func(1))
|
||||
print(func("bark"))
|
||||
print(func(1,2))
|
||||
)");
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
4
sol.hpp
4
sol.hpp
|
@ -43,8 +43,11 @@
|
|||
#elif defined _MSC_VER
|
||||
#pragma warning( push )
|
||||
#pragma warning( disable : 4324 ) // structure was padded due to alignment specifier
|
||||
#pragma warning( disable : 4503 ) // decorated name horse shit
|
||||
#pragma warning( disable : 4702 ) // unreachable code
|
||||
#endif // g++
|
||||
|
||||
#include "sol/forward.hpp"
|
||||
#include "sol/state.hpp"
|
||||
#include "sol/object.hpp"
|
||||
#include "sol/function.hpp"
|
||||
|
@ -52,6 +55,7 @@
|
|||
#include "sol/state.hpp"
|
||||
#include "sol/coroutine.hpp"
|
||||
#include "sol/variadic_args.hpp"
|
||||
#include "sol/variadic_results.hpp"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
|
|
|
@ -19,26 +19,26 @@
|
|||
// 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_TO_ARGS_HPP
|
||||
#define SOL_TO_ARGS_HPP
|
||||
#ifndef SOL_AS_ARGS_HPP
|
||||
#define SOL_AS_ARGS_HPP
|
||||
|
||||
#include "stack.hpp"
|
||||
|
||||
namespace sol {
|
||||
template <typename T>
|
||||
struct to_args_t {
|
||||
struct as_args_t {
|
||||
T src;
|
||||
};
|
||||
|
||||
template <typename Source>
|
||||
auto as_args(Source&& source) {
|
||||
return to_args_t<Source>{ std::forward<Source>(source) };
|
||||
return as_args_t<Source>{ std::forward<Source>(source) };
|
||||
}
|
||||
|
||||
namespace stack {
|
||||
template <typename T>
|
||||
struct pusher<to_args_t<T>> {
|
||||
int push(lua_State* L, const to_args_t<T>& e) {
|
||||
struct pusher<as_args_t<T>> {
|
||||
int push(lua_State* L, const as_args_t<T>& e) {
|
||||
int p = 0;
|
||||
for (const auto& i : e.src) {
|
||||
p += stack::push(L, i);
|
||||
|
@ -46,7 +46,7 @@ namespace sol {
|
|||
return p;
|
||||
}
|
||||
};
|
||||
}
|
||||
} // stack
|
||||
} // sol
|
||||
|
||||
#endif // SOL_TO_ARGS_HPP
|
||||
#endif // SOL_AS_ARGS_HPP
|
||||
|
|
54
sol/as_returns.hpp
Normal file
54
sol/as_returns.hpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2017 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef SOL_AS_RETURNS_HPP
|
||||
#define SOL_AS_RETURNS_HPP
|
||||
|
||||
#include "traits.hpp"
|
||||
#include "stack.hpp"
|
||||
|
||||
namespace sol {
|
||||
template <typename T>
|
||||
struct as_returns_t {
|
||||
T src;
|
||||
};
|
||||
|
||||
template <typename Source>
|
||||
auto as_returns(Source&& source) {
|
||||
return as_returns_t<std::decay_t<Source>>{ std::forward<Source>(source) };
|
||||
}
|
||||
|
||||
namespace stack {
|
||||
template <typename T>
|
||||
struct pusher<as_returns_t<T>> {
|
||||
int push(lua_State* L, const as_returns_t<T>& e) {
|
||||
auto& src = detail::unwrap(e.src);
|
||||
int p = 0;
|
||||
for (const auto& i : src) {
|
||||
p += stack::push(L, i);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
};
|
||||
} // stack
|
||||
} // sol
|
||||
|
||||
#endif // SOL_AS_RETURNS_HPP
|
|
@ -22,11 +22,523 @@
|
|||
#ifndef SOL_CONTAINER_TRAITS_HPP
|
||||
#define SOL_CONTAINER_TRAITS_HPP
|
||||
|
||||
#include "traits.hpp"
|
||||
#include "stack.hpp"
|
||||
#include <unordered_map>
|
||||
|
||||
namespace sol {
|
||||
|
||||
namespace container_detail {
|
||||
template <typename T>
|
||||
struct has_find {
|
||||
private:
|
||||
typedef std::array<char, 1> one;
|
||||
typedef std::array<char, 2> two;
|
||||
|
||||
template <typename C> static one test(decltype(std::declval<C>().find(std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);
|
||||
template <typename C> static two test(...);
|
||||
|
||||
public:
|
||||
static const bool value = sizeof(test<T>(0)) == sizeof(char);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct has_push_back {
|
||||
private:
|
||||
typedef std::array<char, 1> one;
|
||||
typedef std::array<char, 2> two;
|
||||
|
||||
template <typename C> static one test(decltype(std::declval<C>().push_back(std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);
|
||||
template <typename C> static two test(...);
|
||||
|
||||
public:
|
||||
static const bool value = sizeof(test<T>(0)) == sizeof(char);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct has_clear {
|
||||
private:
|
||||
typedef std::array<char, 1> one;
|
||||
typedef std::array<char, 2> two;
|
||||
|
||||
template <typename C> static one test(decltype(&C::clear));
|
||||
template <typename C> static two test(...);
|
||||
|
||||
public:
|
||||
static const bool value = sizeof(test<T>(0)) == sizeof(char);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct has_insert {
|
||||
private:
|
||||
typedef std::array<char, 1> one;
|
||||
typedef std::array<char, 2> two;
|
||||
|
||||
template <typename C> static one test(decltype(std::declval<C>().insert(std::declval<std::add_rvalue_reference_t<typename C::const_iterator>>(), std::declval<std::add_rvalue_reference_t<typename C::value_type>>()))*);
|
||||
template <typename C> static two test(...);
|
||||
|
||||
public:
|
||||
static const bool value = sizeof(test<T>(0)) == sizeof(char);
|
||||
};
|
||||
|
||||
template <typename X, typename = void>
|
||||
struct container_traits_default {
|
||||
private:
|
||||
typedef std::remove_pointer_t<meta::unwrap_unqualified_t<X>> T;
|
||||
public:
|
||||
typedef std::false_type is_container;
|
||||
typedef std::false_type is_associative;
|
||||
typedef lua_nil_t iterator;
|
||||
typedef lua_nil_t value_type;
|
||||
|
||||
static lua_nil_t get(lua_State* L, T* self, stack_object key) {
|
||||
(void)self;
|
||||
(void)key;
|
||||
luaL_error(L, "sol: cannot call 'get(key)' on type '%s' because it is not recognized as a container", detail::demangle<X>().c_str());
|
||||
return lua_nil;
|
||||
}
|
||||
|
||||
static lua_nil_t index_get(lua_State* L, T* self, stack_object key) {
|
||||
(void)self;
|
||||
(void)key;
|
||||
luaL_error(L, "sol: cannot call 'container[key]' on type '%s' because it is not recognized as a container", detail::demangle<X>().c_str());
|
||||
return lua_nil;
|
||||
}
|
||||
|
||||
static lua_nil_t index_set(lua_State* L, T* self, stack_object key, stack_object value) {
|
||||
(void)self;
|
||||
(void)key;
|
||||
(void)value;
|
||||
luaL_error(L, "sol: cannot call 'container[key] = value' on type '%s' because it is not recognized as a container", detail::demangle<X>().c_str());
|
||||
return lua_nil;
|
||||
}
|
||||
|
||||
static lua_nil_t add(lua_State* L, T* self, stack_object key, stack_object value) {
|
||||
(void)self;
|
||||
(void)key;
|
||||
(void)value;
|
||||
luaL_error(L, "sol: cannot call '%s' on type '%s' because it is not recognized as a container", value.valid() ? "add(key, value)" : "add(value)", detail::demangle<X>().c_str());
|
||||
return lua_nil;
|
||||
}
|
||||
|
||||
static lua_nil_t insert(lua_State* L, T* self, stack_object where, stack_object value) {
|
||||
(void)self;
|
||||
(void)where;
|
||||
(void)value;
|
||||
luaL_error(L, "sol: cannot call 'container[key] = value' on type '%s' because it is not recognized as a container", detail::demangle<X>().c_str());
|
||||
return lua_nil;
|
||||
}
|
||||
|
||||
static lua_nil_t find(lua_State* L, T* self, stack_object key) {
|
||||
(void)self;
|
||||
(void)key;
|
||||
luaL_error(L, "sol: cannot call 'container[key] = value' on type '%s' because it is not recognized as a container", detail::demangle<X>().c_str());
|
||||
return lua_nil;
|
||||
}
|
||||
|
||||
static lua_nil_t begin(lua_State* L, T* self) {
|
||||
(void)self;
|
||||
luaL_error(L, "sol: cannot call 'begin' on type '%s' because it is not recognized as a container", detail::demangle<X>().c_str());
|
||||
return lua_nil;
|
||||
}
|
||||
|
||||
static lua_nil_t end(lua_State* L, T* self) {
|
||||
(void)self;
|
||||
luaL_error(L, "sol: cannot call 'end' on type '%s' because it is not recognized as a container", detail::demangle<X>().c_str());
|
||||
return lua_nil;
|
||||
}
|
||||
|
||||
static lua_nil_t size(lua_State* L, T* self) {
|
||||
(void)self;
|
||||
luaL_error(L, "sol: cannot call 'end' on type '%s' because it is not recognized as a container", detail::demangle<X>().c_str());
|
||||
return lua_nil;
|
||||
}
|
||||
|
||||
static lua_nil_t clear(lua_State* L, T* self) {
|
||||
(void)self;
|
||||
luaL_error(L, "sol: cannot call 'clear' on type '%s' because it is not recognized as a container", detail::demangle<X>().c_str());
|
||||
return lua_nil;
|
||||
}
|
||||
|
||||
static lua_nil_t erase(lua_State* L, T* self, stack_object key) {
|
||||
(void)self;
|
||||
(void)key;
|
||||
luaL_error(L, "sol: cannot call 'erase' on type '%s' because it is not recognized as a container", detail::demangle<X>().c_str());
|
||||
return lua_nil;
|
||||
}
|
||||
};
|
||||
template <typename X>
|
||||
struct container_traits_default<T, std::enable_if_t<
|
||||
meta::all<is_container<meta::unqualified<X>>, meta::has_value_type<meta::unqualified<X>>, meta::has_iterator<meta::unqualified<X>>>::value
|
||||
>> {
|
||||
private:
|
||||
typedef std::remove_pointer_t<meta::unwrap_unqualified_t<X>> T;
|
||||
typedef typename T::iterator iterator;
|
||||
typedef std::conditional_t<is_associative::value, typename T::value_type, std::pair<std::size_t, typename T::value_type>> KV;
|
||||
typedef typename KV::first_type K;
|
||||
typedef typename KV::second_type V;
|
||||
typedef std::remove_reference_t<decltype(*std::declval<I&>())> iterator_return;
|
||||
typedef typename meta::iterator_tag<I>::type iterator_category;
|
||||
typedef std::conditional_t<std::is_same<tag_t, std::input_iterator_tag>::value,
|
||||
V,
|
||||
std::conditional_t<is_associative::value,
|
||||
V,
|
||||
decltype(*std::declval<I&>())
|
||||
>
|
||||
> push_type;
|
||||
|
||||
static auto& get_src(lua_State* L) {
|
||||
#ifdef SOL_SAFE_USERTYPE
|
||||
auto p = stack::check_get<T*>(L, 1);
|
||||
if (!p || p.value() == nullptr) {
|
||||
luaL_error(L, "sol: 'self' argument is not the proper type (pass 'self' as first argument with ':' or call on proper type)");
|
||||
}
|
||||
return *p.value();
|
||||
#else
|
||||
return stack::get<T>(L, 1);
|
||||
#endif // Safe getting with error
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
static int delegate_call(lua_State* L) {
|
||||
static std::unordered_map<std::string, lua_CFunction> calls{
|
||||
{ "add", &real_add_call },
|
||||
{ "insert", &real_insert_call },
|
||||
{ "clear", &real_clear_call },
|
||||
{ "find", &real_find_call },
|
||||
{ "get", &real_get_call }
|
||||
};
|
||||
auto maybename = stack::check_get<std::string>(L, 2);
|
||||
if (maybename) {
|
||||
auto& name = *maybename;
|
||||
auto it = calls.find(name);
|
||||
if (it != calls.cend()) {
|
||||
return stack::push(L, it->second);
|
||||
}
|
||||
}
|
||||
return stack::push(L, lua_nil);
|
||||
}
|
||||
|
||||
static int real_index_call_associative(std::true_type, lua_State* L) {
|
||||
auto k = stack::check_get<K>(L, 2);
|
||||
if (k) {
|
||||
auto& src = get_src(L);
|
||||
using std::end;
|
||||
auto it = detail::find(src, *k);
|
||||
if (it != end(src)) {
|
||||
auto& v = *it;
|
||||
return stack::stack_detail::push_reference<push_type>(L, v.second);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return delegate_call(L);
|
||||
}
|
||||
return stack::push(L, lua_nil);
|
||||
}
|
||||
|
||||
static int real_index_call_associative(std::false_type, lua_State* L) {
|
||||
auto& src = get_src(L);
|
||||
auto maybek = stack::check_get<K>(L, 2);
|
||||
if (maybek) {
|
||||
using std::begin;
|
||||
auto it = begin(src);
|
||||
K k = *maybek;
|
||||
if (k > src.size() || k < 1) {
|
||||
return stack::push(L, lua_nil);
|
||||
}
|
||||
--k;
|
||||
std::advance(it, k);
|
||||
return stack::stack_detail::push_reference<push_type>(L, *it);
|
||||
}
|
||||
else {
|
||||
return delegate_call(L);
|
||||
}
|
||||
|
||||
return stack::push(L, lua_nil);
|
||||
}
|
||||
|
||||
static int real_index_call(lua_State* L) {
|
||||
return real_index_call_associative(is_associative(), L);
|
||||
}
|
||||
|
||||
static int real_get_call(lua_State* L) {
|
||||
return real_index_call_associative(is_associative(), L);
|
||||
}
|
||||
|
||||
static int real_new_index_call_const(std::false_type, std::false_type, lua_State* L) {
|
||||
return luaL_error(L, "sol: cannot write to a const value type or an immutable iterator (e.g., std::set)");
|
||||
}
|
||||
|
||||
static int real_new_index_call_const(std::false_type, std::true_type, lua_State* L) {
|
||||
return luaL_error(L, "sol: cannot write to a const value type or an immutable iterator (e.g., std::set)");
|
||||
}
|
||||
|
||||
static int real_new_index_call_fixed(std::true_type, lua_State* L) {
|
||||
auto& src = get_src(L);
|
||||
#ifdef SOL_CHECK_ARGUMENTS
|
||||
auto maybek = stack::check_get<K>(L, 2);
|
||||
if (!maybek) {
|
||||
return luaL_error(L, "sol: improper key of type %s for %s", lua_typename(L, static_cast<int>(type_of(L, 2))), detail::demangle<T>().c_str());
|
||||
}
|
||||
K& k = *maybek;
|
||||
#else
|
||||
K k = stack::get<K>(L, 2);
|
||||
#endif
|
||||
using std::end;
|
||||
auto it = detail::find(src, k);
|
||||
if (it != end(src)) {
|
||||
auto& v = *it;
|
||||
v.second = stack::get<V>(L, 3);
|
||||
}
|
||||
else {
|
||||
src.insert(it, { std::move(k), stack::get<V>(L, 3) });
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int real_new_index_call_fixed(std::false_type, lua_State* L) {
|
||||
auto& src = get_src(L);
|
||||
#ifdef SOL_CHECK_ARGUMENTS
|
||||
auto maybek = stack::check_get<K>(L, 2);
|
||||
if (!maybek) {
|
||||
return luaL_error(L, "sol: improper key of type %s for %s", lua_typename(L, static_cast<int>(type_of(L, 2))), detail::demangle<T>().c_str());
|
||||
}
|
||||
K& k = *maybek;
|
||||
#else
|
||||
K k = stack::get<K>(L, 2);
|
||||
#endif
|
||||
using std::end;
|
||||
auto it = detail::find(src, k);
|
||||
if (it != end(src)) {
|
||||
auto& v = *it;
|
||||
v.second = stack::get<V>(L, 3);
|
||||
}
|
||||
else {
|
||||
return luaL_error(L, "sol: cannot insert key of type %s to into %s", lua_typename(L, static_cast<int>(type_of(L, 2))), detail::demangle<T>().c_str());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int real_new_index_call_const(std::true_type, std::true_type, lua_State* L) {
|
||||
return real_new_index_call_fixed(std::integral_constant<bool, detail::has_insert<T>::value>(), L);
|
||||
}
|
||||
|
||||
static int real_new_index_call_const(std::true_type, std::false_type, lua_State* L) {
|
||||
auto& src = get_src(L);
|
||||
#ifdef SOL_CHECK_ARGUMENTS
|
||||
auto maybek = stack::check_get<K>(L, 2);
|
||||
if (!maybek) {
|
||||
return luaL_error(L, "sol: improper index of type %s to a %s", lua_typename(L, static_cast<int>(type_of(L, 2))), detail::demangle<T>().c_str());
|
||||
}
|
||||
K& k = *maybek;
|
||||
#else
|
||||
K k = stack::get<K>(L, 2);
|
||||
#endif
|
||||
using std::begin;
|
||||
auto it = begin(src);
|
||||
#ifdef SOL_CHECK_ARGUMENTS
|
||||
if (k < 1) {
|
||||
return luaL_error(L, "sol: out of bounds index to a %s", detail::demangle<T>().c_str());
|
||||
}
|
||||
#endif
|
||||
--k;
|
||||
if (k == src.size()) {
|
||||
real_add_call_push(std::integral_constant<bool, detail::has_push_back<T>::value && std::is_copy_constructible<V>::value>(), L, src, 1);
|
||||
return 0;
|
||||
}
|
||||
#ifdef SOL_CHECK_ARGUMENTS
|
||||
if (k > src.size()) {
|
||||
return luaL_error(L, "sol: out of bounds index to a %s", detail::demangle<T>().c_str());
|
||||
}
|
||||
#endif
|
||||
std::advance(it, k);
|
||||
*it = stack::get<V>(L, 3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int real_new_index_call(lua_State* L) {
|
||||
return real_new_index_call_const(meta::neg<meta::any<std::is_const<V>, std::is_const<IR>, meta::neg<std::is_copy_assignable<V>>>>(), meta::all<is_associative, detail::has_insert<T>>(), L);
|
||||
}
|
||||
|
||||
static int real_pairs_next_call_assoc(std::true_type, lua_State* L) {
|
||||
using std::end;
|
||||
iter& i = stack::get<user<iter>>(L, 1);
|
||||
auto& source = i.source;
|
||||
auto& it = i.it;
|
||||
if (it == end(source)) {
|
||||
return 0;
|
||||
}
|
||||
int p;
|
||||
p = stack::push_reference(L, it->first);
|
||||
p += stack::stack_detail::push_reference<push_type>(L, it->second);
|
||||
std::advance(it, 1);
|
||||
return p;
|
||||
}
|
||||
|
||||
static int real_pairs_call_assoc(std::true_type, lua_State* L) {
|
||||
auto& src = get_src(L);
|
||||
using std::begin;
|
||||
stack::push(L, pairs_next_call);
|
||||
stack::push<user<iter>>(L, src, begin(src));
|
||||
stack::push(L, 1);
|
||||
return 3;
|
||||
}
|
||||
|
||||
static int real_pairs_next_call_assoc(std::false_type, lua_State* L) {
|
||||
using std::end;
|
||||
iter& i = stack::get<user<iter>>(L, 1);
|
||||
auto& source = i.source;
|
||||
auto& it = i.it;
|
||||
K k = stack::get<K>(L, 2);
|
||||
if (it == end(source)) {
|
||||
return 0;
|
||||
}
|
||||
int p;
|
||||
p = stack::push_reference(L, k + 1);
|
||||
p += stack::stack_detail::push_reference<push_type>(L, *it);
|
||||
std::advance(it, 1);
|
||||
return p;
|
||||
}
|
||||
|
||||
static int real_pairs_call_assoc(std::false_type, lua_State* L) {
|
||||
auto& src = get_src(L);
|
||||
using std::begin;
|
||||
stack::push(L, pairs_next_call);
|
||||
stack::push<user<iter>>(L, src, begin(src));
|
||||
stack::push(L, 0);
|
||||
return 3;
|
||||
}
|
||||
|
||||
static int real_pairs_next_call(lua_State* L) {
|
||||
return real_pairs_next_call_assoc(is_associative(), L);
|
||||
}
|
||||
|
||||
static int real_pairs_call(lua_State* L) {
|
||||
return real_pairs_call_assoc(is_associative(), L);
|
||||
}
|
||||
|
||||
static int real_length_call(lua_State*L) {
|
||||
auto& src = get_src(L);
|
||||
return stack::push(L, src.size());
|
||||
}
|
||||
|
||||
static int real_add_call_insert(std::true_type, lua_State*L, T& src, int boost = 0) {
|
||||
using std::end;
|
||||
src.insert(end(src), stack::get<V>(L, 2 + boost));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int real_add_call_insert(std::false_type, lua_State*L, T&, int = 0) {
|
||||
static const std::string& s = detail::demangle<T>();
|
||||
return luaL_error(L, "sol: cannot call insert on type %s", s.c_str());
|
||||
}
|
||||
|
||||
static int real_add_call_push(std::true_type, lua_State*L, T& src, int boost = 0) {
|
||||
src.push_back(stack::get<V>(L, 2 + boost));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int real_add_call_push(std::false_type, lua_State*L, T& src, int boost = 0) {
|
||||
return real_add_call_insert(std::integral_constant<bool, detail::has_insert<T>::value && std::is_copy_constructible<V>::value>(), L, src, boost);
|
||||
}
|
||||
|
||||
static int real_add_call_associative(std::true_type, lua_State* L) {
|
||||
return real_insert_call(L);
|
||||
}
|
||||
|
||||
static int real_add_call_associative(std::false_type, lua_State* L) {
|
||||
auto& src = get_src(L);
|
||||
return real_add_call_push(std::integral_constant<bool, detail::has_push_back<T>::value && std::is_copy_constructible<V>::value>(), L, src);
|
||||
}
|
||||
|
||||
static int real_add_call_capable(std::true_type, lua_State* L) {
|
||||
return real_add_call_associative(is_associative(), L);
|
||||
}
|
||||
|
||||
static int real_add_call_capable(std::false_type, lua_State* L) {
|
||||
static const std::string& s = detail::demangle<T>();
|
||||
return luaL_error(L, "sol: cannot call add on type %s", s.c_str());
|
||||
}
|
||||
|
||||
static int real_add_call(lua_State* L) {
|
||||
return real_add_call_capable(std::integral_constant<bool, (detail::has_push_back<T>::value || detail::has_insert<T>::value) && std::is_copy_constructible<V>::value>(), L);
|
||||
}
|
||||
|
||||
static int real_insert_call_capable(std::false_type, std::false_type, lua_State*L) {
|
||||
static const std::string& s = detail::demangle<T>();
|
||||
return luaL_error(L, "sol: cannot call insert on type %s", s.c_str());
|
||||
}
|
||||
|
||||
static int real_insert_call_capable(std::false_type, std::true_type, lua_State*L) {
|
||||
return real_insert_call_capable(std::false_type(), std::false_type(), L);
|
||||
}
|
||||
|
||||
static int real_insert_call_capable(std::true_type, std::false_type, lua_State* L) {
|
||||
using std::begin;
|
||||
auto& src = get_src(L);
|
||||
src.insert(std::next(begin(src), stack::get<K>(L, 2)), stack::get<V>(L, 3));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int real_insert_call_capable(std::true_type, std::true_type, lua_State* L) {
|
||||
return real_new_index_call(L);
|
||||
}
|
||||
|
||||
static int real_insert_call(lua_State*L) {
|
||||
return real_insert_call_capable(std::integral_constant<bool, detail::has_insert<T>::value && std::is_copy_assignable<V>::value>(), is_associative(), L);
|
||||
}
|
||||
|
||||
static int real_clear_call_capable(std::false_type, lua_State* L) {
|
||||
static const std::string& s = detail::demangle<T>();
|
||||
return luaL_error(L, "sol: cannot call clear on type %s", s.c_str());
|
||||
}
|
||||
|
||||
static int real_clear_call_capable(std::true_type, lua_State* L) {
|
||||
auto& src = get_src(L);
|
||||
src.clear();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int real_clear_call(lua_State*L) {
|
||||
return real_clear_call_capable(std::integral_constant<bool, detail::has_clear<T>::value>(), L);
|
||||
}
|
||||
|
||||
static int real_find_call_capable(std::false_type, std::false_type, lua_State*L) {
|
||||
static const std::string& s = detail::demangle<T>();
|
||||
return luaL_error(L, "sol: cannot call find on type %s", s.c_str());
|
||||
}
|
||||
|
||||
static int real_find_call_capable(std::false_type, std::true_type, lua_State*L) {
|
||||
return real_index_call(L);
|
||||
}
|
||||
|
||||
static int real_find_call_capable(std::true_type, std::false_type, lua_State* L) {
|
||||
auto k = stack::check_get<V>(L, 2);
|
||||
if (k) {
|
||||
auto& src = get_src(L);
|
||||
auto it = src.find(*k);
|
||||
if (it != src.end()) {
|
||||
auto& v = *it;
|
||||
return stack::stack_detail::push_reference<push_type>(L, v);
|
||||
}
|
||||
}
|
||||
return stack::push(L, lua_nil);
|
||||
}
|
||||
|
||||
static int real_find_call_capable(std::true_type, std::true_type, lua_State* L) {
|
||||
return real_index_call(L);
|
||||
}
|
||||
|
||||
static int real_find_call(lua_State*L) {
|
||||
return real_find_call_capable(std::integral_constant<bool, detail::has_find<T>::value>(), is_associative(), L);
|
||||
}
|
||||
};
|
||||
} // container_detail
|
||||
|
||||
template <typename T>
|
||||
struct container_traits : container_detail::container_traits_default<T> {};
|
||||
|
||||
} // sol
|
||||
|
||||
#endif // SOL_CONTAINER_TRAITS_HPP
|
||||
|
|
|
@ -174,11 +174,8 @@ namespace sol {
|
|||
return stack::stack_detail::push_reference<push_type>(L, v.second);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return delegate_call(L);
|
||||
}
|
||||
return stack::push(L, lua_nil);
|
||||
}
|
||||
|
||||
static int real_index_call_associative(std::false_type, lua_State* L) {
|
||||
auto& src = get_src(L);
|
||||
|
@ -194,13 +191,9 @@ namespace sol {
|
|||
std::advance(it, k);
|
||||
return stack::stack_detail::push_reference<push_type>(L, *it);
|
||||
}
|
||||
else {
|
||||
return delegate_call(L);
|
||||
}
|
||||
|
||||
return stack::push(L, lua_nil);
|
||||
}
|
||||
|
||||
static int real_index_call(lua_State* L) {
|
||||
return real_index_call_associative(is_associative(), L);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,12 @@
|
|||
#ifndef SOL_FEATURE_TEST_HPP
|
||||
#define SOL_FEATURE_TEST_HPP
|
||||
|
||||
#if (defined(__cplusplus) && __cplusplus == 201703L) || (defined(_MSC_VER) && _MSC_VER > 1900 && (defined(_HAS_CXX17) && _HAS_CXX17 == 1) || (_MSVC_LANG > 201402))
|
||||
#ifndef SOL_CXX17_FEATURES
|
||||
#define SOL_CXX17_FEATURES 1
|
||||
#endif // C++17 features macro
|
||||
#endif // C++17 features check
|
||||
|
||||
#if defined(__cpp_noexcept_function_type)
|
||||
#ifndef SOL_NOEXCEPT_FUNCTION_TYPE
|
||||
#define SOL_NOEXCEPT_FUNCTION_TYPE 1
|
||||
|
|
98
sol/forward.hpp
Normal file
98
sol/forward.hpp
Normal file
|
@ -0,0 +1,98 @@
|
|||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2017 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef SOL_FORWARD_HPP
|
||||
#define SOL_FORWARD_HPP
|
||||
|
||||
#include "feature_test.hpp"
|
||||
|
||||
namespace sol {
|
||||
|
||||
class reference;
|
||||
class stack_reference;
|
||||
template <typename Table, typename Key>
|
||||
struct proxy;
|
||||
template<typename T>
|
||||
class usertype;
|
||||
template<typename T>
|
||||
class simple_usertype;
|
||||
template <bool, typename T>
|
||||
class basic_table_core;
|
||||
template <bool b>
|
||||
using table_core = basic_table_core<b, reference>;
|
||||
template <bool b>
|
||||
using stack_table_core = basic_table_core<b, stack_reference>;
|
||||
template <typename T>
|
||||
using basic_table = basic_table_core<false, T>;
|
||||
typedef table_core<false> table;
|
||||
typedef table_core<true> global_table;
|
||||
typedef stack_table_core<false> stack_table;
|
||||
typedef stack_table_core<true> stack_global_table;
|
||||
template <typename base_t>
|
||||
struct basic_environment;
|
||||
using environment = basic_environment<reference>;
|
||||
using stack_environment = basic_environment<stack_reference>;
|
||||
template <typename T>
|
||||
class basic_function;
|
||||
template <typename T>
|
||||
class basic_protected_function;
|
||||
using protected_function = basic_protected_function<reference>;
|
||||
using stack_protected_function = basic_protected_function<stack_reference>;
|
||||
using unsafe_function = basic_function<reference>;
|
||||
using safe_function = basic_protected_function<reference>;
|
||||
using stack_unsafe_function = basic_function<stack_reference>;
|
||||
using stack_safe_function = basic_protected_function<stack_reference>;
|
||||
#ifdef SOL_SAFE_FUNCTIONS
|
||||
using function = protected_function;
|
||||
using stack_function = stack_protected_function;
|
||||
#else
|
||||
using function = unsafe_function;
|
||||
using stack_function = stack_unsafe_function;
|
||||
#endif
|
||||
template <typename base_t>
|
||||
class basic_object;
|
||||
template <typename base_t>
|
||||
class basic_userdata;
|
||||
template <typename base_t>
|
||||
class basic_lightuserdata;
|
||||
struct variadic_args;
|
||||
using object = basic_object<reference>;
|
||||
using stack_object = basic_object<stack_reference>;
|
||||
using userdata = basic_userdata<reference>;
|
||||
using stack_userdata = basic_userdata<stack_reference>;
|
||||
using lightuserdata = basic_lightuserdata<reference>;
|
||||
using stack_lightuserdata = basic_lightuserdata<stack_reference>;
|
||||
class coroutine;
|
||||
class thread;
|
||||
struct variadic_args;
|
||||
struct variadic_results;
|
||||
struct this_state;
|
||||
struct this_environment;
|
||||
template <typename T>
|
||||
struct light;
|
||||
template <typename T>
|
||||
struct user;
|
||||
template <typename T>
|
||||
struct as_args_t;
|
||||
|
||||
} // sol
|
||||
|
||||
#endif SOL_FORWARD_HPP
|
|
@ -22,96 +22,12 @@
|
|||
#ifndef SOL_FUNCTION_HPP
|
||||
#define SOL_FUNCTION_HPP
|
||||
|
||||
#include "reference.hpp"
|
||||
#include "unsafe_function.hpp"
|
||||
#include "protected_function.hpp"
|
||||
#include "stack.hpp"
|
||||
#include "function_result.hpp"
|
||||
#include "function_types.hpp"
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace sol {
|
||||
template <typename base_t>
|
||||
class basic_function : public base_t {
|
||||
private:
|
||||
void luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount) const {
|
||||
lua_callk(base_t::lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount), 0, nullptr);
|
||||
}
|
||||
|
||||
template<std::size_t... I, typename... Ret>
|
||||
auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n) const {
|
||||
luacall(n, lua_size<std::tuple<Ret...>>::value);
|
||||
return stack::pop<std::tuple<Ret...>>(base_t::lua_state());
|
||||
}
|
||||
|
||||
template<std::size_t I, typename Ret>
|
||||
Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n) const {
|
||||
luacall(n, lua_size<Ret>::value);
|
||||
return stack::pop<Ret>(base_t::lua_state());
|
||||
}
|
||||
|
||||
template <std::size_t I>
|
||||
void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n) const {
|
||||
luacall(n, 0);
|
||||
}
|
||||
|
||||
function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) const {
|
||||
int stacksize = lua_gettop(base_t::lua_state());
|
||||
int firstreturn = (std::max)(1, stacksize - static_cast<int>(n));
|
||||
luacall(n, LUA_MULTRET);
|
||||
int poststacksize = lua_gettop(base_t::lua_state());
|
||||
int returncount = poststacksize - (firstreturn - 1);
|
||||
return function_result(base_t::lua_state(), firstreturn, returncount);
|
||||
}
|
||||
|
||||
public:
|
||||
basic_function() = default;
|
||||
template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_function>>, meta::neg<std::is_same<base_t, stack_reference>>, std::is_base_of<base_t, meta::unqualified_t<T>>> = meta::enabler>
|
||||
basic_function(T&& r) noexcept : base_t(std::forward<T>(r)) {
|
||||
#ifdef SOL_CHECK_ARGUMENTS
|
||||
if (!is_function<meta::unqualified_t<T>>::value) {
|
||||
auto pp = stack::push_pop(*this);
|
||||
stack::check<basic_function>(base_t::lua_state(), -1, type_panic);
|
||||
}
|
||||
#endif // Safety
|
||||
}
|
||||
basic_function(const basic_function&) = default;
|
||||
basic_function& operator=(const basic_function&) = default;
|
||||
basic_function(basic_function&&) = default;
|
||||
basic_function& operator=(basic_function&&) = default;
|
||||
basic_function(const stack_reference& r) : basic_function(r.lua_state(), r.stack_index()) {}
|
||||
basic_function(stack_reference&& r) : basic_function(r.lua_state(), r.stack_index()) {}
|
||||
template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<std::is_same<T, ref_index>>> = meta::enabler>
|
||||
basic_function(lua_State* L, T&& r) : basic_function(L, sol::ref_index(r.registry_index())) {}
|
||||
basic_function(lua_State* L, int index = -1) : base_t(L, index) {
|
||||
#ifdef SOL_CHECK_ARGUMENTS
|
||||
stack::check<basic_function>(L, index, type_panic);
|
||||
#endif // Safety
|
||||
}
|
||||
basic_function(lua_State* L, ref_index index) : base_t(L, index) {
|
||||
#ifdef SOL_CHECK_ARGUMENTS
|
||||
auto pp = stack::push_pop(*this);
|
||||
stack::check<basic_function>(L, -1, type_panic);
|
||||
#endif // Safety
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
function_result operator()(Args&&... args) const {
|
||||
return call<>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Ret, typename... Args>
|
||||
decltype(auto) operator()(types<Ret...>, Args&&... args) const {
|
||||
return call<Ret...>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Ret, typename... Args>
|
||||
decltype(auto) call(Args&&... args) const {
|
||||
base_t::push();
|
||||
int pushcount = stack::multi_push_reference(base_t::lua_state(), std::forward<Args>(args)...);
|
||||
return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount);
|
||||
}
|
||||
};
|
||||
|
||||
namespace stack {
|
||||
template<typename Signature>
|
||||
|
@ -154,6 +70,7 @@ namespace sol {
|
|||
}
|
||||
};
|
||||
} // stack
|
||||
|
||||
} // sol
|
||||
|
||||
#endif // SOL_FUNCTION_HPP
|
||||
|
|
|
@ -22,8 +22,23 @@
|
|||
#ifndef SOL_IN_PLACE_HPP
|
||||
#define SOL_IN_PLACE_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
namespace sol {
|
||||
|
||||
#ifdef SOL_CXX17_FEATURES
|
||||
using in_place_t = std::in_place_t;
|
||||
constexpr std::in_place_t in_place{};
|
||||
|
||||
template <typename T> using in_place_type_t = std::in_place_type_t<T>;
|
||||
template <typename T>
|
||||
constexpr std::in_place_type_t<T> in_place_type{};
|
||||
|
||||
template <size_t I> using in_place_index_t = std::in_place_index_t<I>;
|
||||
template <size_t I>
|
||||
constexpr in_place_index_t<I> in_place_index{};
|
||||
#else
|
||||
namespace detail {
|
||||
struct in_place_of {};
|
||||
template <std::size_t I>
|
||||
|
@ -32,18 +47,25 @@ namespace sol {
|
|||
struct in_place_of_t {};
|
||||
} // detail
|
||||
|
||||
struct in_place_tag { struct init {}; constexpr in_place_tag(init) {} in_place_tag() = delete; };
|
||||
constexpr inline in_place_tag in_place(detail::in_place_of) { return in_place_tag(in_place_tag::init()); }
|
||||
struct in_place_tag { constexpr in_place_tag() = default; };
|
||||
|
||||
constexpr inline in_place_tag in_place (detail::in_place_of) { return in_place_tag(); }
|
||||
template <typename T>
|
||||
constexpr inline in_place_tag in_place(detail::in_place_of_t<T>) { return in_place_tag(in_place_tag::init()); }
|
||||
constexpr inline in_place_tag in_place (detail::in_place_of_t<T>) { return in_place_tag(); }
|
||||
template <std::size_t I>
|
||||
constexpr inline in_place_tag in_place(detail::in_place_of_i<I>) { return in_place_tag(in_place_tag::init()); }
|
||||
constexpr inline in_place_tag in_place (detail::in_place_of_i<I>) { return in_place_tag(); }
|
||||
|
||||
template <typename T>
|
||||
constexpr inline in_place_tag in_place_type (detail::in_place_of_t<T>) { return in_place_tag(); }
|
||||
template <std::size_t I>
|
||||
constexpr inline in_place_tag in_place_index (detail::in_place_of_i<I>) { return in_place_tag(); }
|
||||
|
||||
using in_place_t = in_place_tag(&)(detail::in_place_of);
|
||||
template <typename T>
|
||||
using in_place_type_t = in_place_tag(&)(detail::in_place_of_t<T>);
|
||||
template <std::size_t I>
|
||||
using in_place_index_t = in_place_tag(&)(detail::in_place_of_i<I>);
|
||||
#endif
|
||||
|
||||
} // sol
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ namespace sol {
|
|||
template <typename T, typename... Args>
|
||||
basic_object(lua_State* L, in_place_type_t<T>, Args&&... args) noexcept : basic_object(std::integral_constant<bool, !std::is_base_of<stack_reference, base_t>::value>(), L, -stack::push<T>(L, std::forward<Args>(args)...)) {}
|
||||
template <typename T, typename... Args>
|
||||
basic_object(lua_State* L, in_place_t, T&& arg, Args&&... args) noexcept : basic_object(L, in_place<T>, std::forward<T>(arg), std::forward<Args>(args)...) {}
|
||||
basic_object(lua_State* L, in_place_t, T&& arg, Args&&... args) noexcept : basic_object(L, in_place_type<T>, std::forward<T>(arg), std::forward<Args>(args)...) {}
|
||||
basic_object& operator=(const basic_object&) = default;
|
||||
basic_object& operator=(basic_object&&) = default;
|
||||
basic_object& operator=(const base_type& b) { base_t::operator=(b); return *this; }
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
# ifndef SOL_OPTIONAL_IMPLEMENTATION_HPP
|
||||
# define SOL_OPTIONAL_IMPLEMENTATION_HPP
|
||||
|
||||
#include "in_place.hpp"
|
||||
|
||||
# include <utility>
|
||||
# include <type_traits>
|
||||
# include <initializer_list>
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#ifndef SOL_OVERLOAD_HPP
|
||||
#define SOL_OVERLOAD_HPP
|
||||
|
||||
#include "traits.hpp"
|
||||
#include <utility>
|
||||
|
||||
namespace sol {
|
||||
|
|
|
@ -22,6 +22,10 @@
|
|||
#ifndef SOL_PROPERTY_HPP
|
||||
#define SOL_PROPERTY_HPP
|
||||
|
||||
#include "types.hpp"
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace sol {
|
||||
|
||||
struct no_prop { };
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "reference.hpp"
|
||||
#include "stack.hpp"
|
||||
#include "protected_function_result.hpp"
|
||||
#include "unsafe_function.hpp"
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#define SOL_PROXY_HPP
|
||||
|
||||
#include "traits.hpp"
|
||||
#include "object.hpp"
|
||||
#include "function.hpp"
|
||||
#include "protected_function.hpp"
|
||||
#include "proxy_base.hpp"
|
||||
|
@ -119,6 +118,17 @@ namespace sol {
|
|||
lua_pop(tbl.lua_state(), p.levels);
|
||||
return p;
|
||||
}
|
||||
|
||||
type get_type() const {
|
||||
type t = type::none;
|
||||
auto pp = stack::push_pop(tbl);
|
||||
auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(tbl.lua_state(), key, lua_gettop(tbl.lua_state()));
|
||||
if (p) {
|
||||
t = type_of(tbl.lua_state(), -1);
|
||||
}
|
||||
lua_pop(tbl.lua_state(), p.levels);
|
||||
return t;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Table, typename Key, typename T>
|
||||
|
|
|
@ -66,7 +66,7 @@ namespace sol {
|
|||
}
|
||||
}
|
||||
string_detail::string_shim accessor = stack::get<string_detail::string_shim>(L, keyidx);
|
||||
std::string accessorkey = accessor.c_str();
|
||||
std::string accessorkey = accessor.data();
|
||||
auto vit = variables.find(accessorkey);
|
||||
if (vit != variables.cend()) {
|
||||
auto& varwrap = *(vit->second);
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
#include <memory>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#ifdef SOL_CXX17_FEATURES
|
||||
#include <variant>
|
||||
#endif // C++17
|
||||
|
||||
namespace sol {
|
||||
namespace stack {
|
||||
|
@ -485,6 +488,40 @@ namespace sol {
|
|||
return stack::check<T>(L, index, no_panic, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef SOL_CXX17_FEATURES
|
||||
template<typename... Tn, typename C>
|
||||
struct checker<std::variant<Tn...>, type::poly, C> {
|
||||
typedef std::variant<Tn...> V;
|
||||
typedef std::variant_size<V> V_size;
|
||||
typedef std::integral_constant<bool, V_size::value == 0> V_is_empty;
|
||||
|
||||
template <typename Handler>
|
||||
static bool is_one(std::integral_constant<std::size_t, 0>, lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
if (V_is_empty::value && lua_isnone(L, index)) {
|
||||
return true;
|
||||
}
|
||||
tracking.use(1);
|
||||
handler(L, index, type::poly, type_of(L, index));
|
||||
return false;
|
||||
}
|
||||
|
||||
template <std::size_t I, typename Handler>
|
||||
static bool is_one(std::integral_constant<std::size_t, I>, lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
typedef std::variant_alternative_t<I - 1, V> T;
|
||||
if (stack::check<T>(L, index, no_panic, tracking)) {
|
||||
return true;
|
||||
}
|
||||
return is_one(std::integral_constant<std::size_t, I - 1>(), L, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
return is_one(std::integral_constant<std::size_t, V_size::value>(), L, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
};
|
||||
#endif // C++17
|
||||
|
||||
} // stack
|
||||
} // sol
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "stack_get.hpp"
|
||||
#include "stack_check.hpp"
|
||||
#include "optional.hpp"
|
||||
#include <cstdlib>
|
||||
|
||||
namespace sol {
|
||||
namespace stack {
|
||||
|
@ -108,6 +109,48 @@ namespace sol {
|
|||
return check_get<T>(L, index, no_panic, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef SOL_CXX17_FEATURES
|
||||
template <typename... Tn>
|
||||
struct check_getter<std::variant<Tn...>> {
|
||||
typedef std::variant<Tn...> V;
|
||||
typedef std::variant_size<V> V_size;
|
||||
typedef std::integral_constant<bool, V_size::value == 0> V_is_empty;
|
||||
|
||||
template <typename Handler>
|
||||
static optional<V> get_empty(std::true_type, lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
static optional<V> get_empty(std::false_type, lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
typedef std::variant_alternative_t<0, V> T;
|
||||
// This should never be reached...
|
||||
// please check your code and understand what you did to bring yourself here
|
||||
handler(L, index, type::poly, type_of(L, index));
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
static optional<V> get_one(std::integral_constant<std::size_t, 0>, lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
return get_empty(V_is_empty(), L, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
|
||||
template <std::size_t I, typename Handler>
|
||||
static optional<V> get_one(std::integral_constant<std::size_t, I>, lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
typedef std::variant_alternative_t<I - 1, V> T;
|
||||
if (stack::check<T>(L, index, no_panic, tracking)) {
|
||||
return V(std::in_place_index<I - 1>, stack::get<T>(L, index));
|
||||
}
|
||||
return get_one(std::integral_constant<std::size_t, I - 1>(), L, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
static optional<V> get(lua_State* L, int index, Handler&& handler, record& tracking) {
|
||||
return get_one(std::integral_constant<std::size_t, V_size::value>(), L, index, std::forward<Handler>(handler), tracking);
|
||||
}
|
||||
};
|
||||
#endif // C++17
|
||||
} // stack
|
||||
} // sol
|
||||
|
||||
|
|
|
@ -30,10 +30,15 @@
|
|||
#include <memory>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include <cstdlib>
|
||||
#ifdef SOL_CODECVT_SUPPORT
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
#endif
|
||||
#endif // codecvt header support
|
||||
#ifdef SOL_CXX17_FEATURES
|
||||
#include <string_view>
|
||||
#include <variant>
|
||||
#endif // C++17
|
||||
|
||||
namespace sol {
|
||||
namespace stack {
|
||||
|
@ -268,17 +273,7 @@ namespace sol {
|
|||
tracking.use(1);
|
||||
std::size_t len;
|
||||
auto str = lua_tolstring(L, index, &len);
|
||||
return std::string( str, len );
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct getter<string_detail::string_shim> {
|
||||
string_detail::string_shim get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
size_t len;
|
||||
const char* p = lua_tolstring(L, index, &len);
|
||||
return string_detail::string_shim(p, len);
|
||||
return std::string(str, len);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -286,7 +281,8 @@ namespace sol {
|
|||
struct getter<const char*> {
|
||||
static const char* get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
return lua_tostring(L, index);
|
||||
size_t sz;
|
||||
return lua_tolstring(L, index, &sz);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -573,25 +569,25 @@ namespace sol {
|
|||
}
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
struct getter<std::tuple<Args...>> {
|
||||
typedef std::tuple<decltype(stack::get<Args>(nullptr, 0))...> R;
|
||||
template<typename... Tn>
|
||||
struct getter<std::tuple<Tn...>> {
|
||||
typedef std::tuple<decltype(stack::get<Tn>(nullptr, 0))...> R;
|
||||
|
||||
template <typename... TArgs>
|
||||
static R apply(std::index_sequence<>, lua_State*, int, record&, TArgs&&... args) {
|
||||
template <typename... Args>
|
||||
static R apply(std::index_sequence<>, lua_State*, int, record&, Args&&... args) {
|
||||
// Fuck you too, VC++
|
||||
return R{std::forward<TArgs>(args)...};
|
||||
return R{ std::forward<Args>(args)... };
|
||||
}
|
||||
|
||||
template <std::size_t I, std::size_t... Ix, typename... TArgs>
|
||||
static R apply(std::index_sequence<I, Ix...>, lua_State* L, int index, record& tracking, TArgs&&... args) {
|
||||
template <std::size_t I, std::size_t... Ix, typename... Args>
|
||||
static R apply(std::index_sequence<I, Ix...>, lua_State* L, int index, record& tracking, Args&&... args) {
|
||||
// Fuck you too, VC++
|
||||
typedef std::tuple_element_t<I, std::tuple<Args...>> T;
|
||||
return apply(std::index_sequence<Ix...>(), L, index, tracking, std::forward<TArgs>(args)..., stack::get<T>(L, index + tracking.used, tracking));
|
||||
typedef std::tuple_element_t<I, std::tuple<Tn...>> T;
|
||||
return apply(std::index_sequence<Ix...>(), L, index, tracking, std::forward<Args>(args)..., stack::get<T>(L, index + tracking.used, tracking));
|
||||
}
|
||||
|
||||
static R get(lua_State* L, int index, record& tracking) {
|
||||
return apply(std::make_index_sequence<sizeof...(Args)>(), L, index, tracking);
|
||||
return apply(std::make_index_sequence<sizeof...(Tn)>(), L, index, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -601,6 +597,65 @@ namespace sol {
|
|||
return std::pair<decltype(stack::get<A>(L, index)), decltype(stack::get<B>(L, index))>{stack::get<A>(L, index, tracking), stack::get<B>(L, index + tracking.used, tracking)};
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef SOL_CXX17_FEATURES
|
||||
template<>
|
||||
struct getter<std::string_view> {
|
||||
static std::string_view get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
size_t sz;
|
||||
const char* str = lua_tolstring(L, index, &sz);
|
||||
return std::string_view(str, sz);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... Tn>
|
||||
struct getter<std::variant<Tn...>> {
|
||||
typedef std::variant<Tn...> V;
|
||||
typedef std::variant_size<V> V_size;
|
||||
typedef std::integral_constant<bool, V_size::value == 0> V_is_empty;
|
||||
|
||||
static V get_empty(std::true_type, lua_State* L, int index, record& tracking) {
|
||||
return V();
|
||||
}
|
||||
|
||||
static V get_empty(std::false_type, lua_State* L, int index, record& tracking) {
|
||||
typedef std::variant_alternative_t<0, V> T;
|
||||
// This should never be reached...
|
||||
// please check your code and understand what you did to bring yourself here
|
||||
std::abort();
|
||||
return V(std::in_place_index<0>, stack::get<T>(L, index));
|
||||
}
|
||||
|
||||
static V get_one(std::integral_constant<std::size_t, 0>, lua_State* L, int index, record& tracking) {
|
||||
return get_empty(V_is_empty(), L, index, tracking);
|
||||
}
|
||||
|
||||
template <std::size_t I>
|
||||
static V get_one(std::integral_constant<std::size_t, I>, lua_State* L, int index, record& tracking) {
|
||||
typedef std::variant_alternative_t<I - 1, V> T;
|
||||
if (stack::check<T>(L, index, no_panic, tracking)) {
|
||||
return V(std::in_place_index<I - 1>, stack::get<T>(L, index));
|
||||
}
|
||||
return get_one(std::integral_constant<std::size_t, I - 1>(), L, index, tracking);
|
||||
}
|
||||
|
||||
static V get(lua_State* L, int index, record& tracking) {
|
||||
return get_one(std::integral_constant<std::size_t, V_size::value>(), L, index, tracking);
|
||||
}
|
||||
};
|
||||
#else
|
||||
template <>
|
||||
struct getter<string_detail::string_shim> {
|
||||
string_detail::string_shim get(lua_State* L, int index, record& tracking) {
|
||||
tracking.use(1);
|
||||
size_t len;
|
||||
const char* p = lua_tolstring(L, index, &len);
|
||||
return string_detail::string_shim(p, len);
|
||||
}
|
||||
};
|
||||
#endif // C++17-wave
|
||||
|
||||
} // stack
|
||||
} // sol
|
||||
|
||||
|
|
|
@ -42,6 +42,10 @@ namespace sol {
|
|||
return stack::get<T>(L, stack_index());
|
||||
}
|
||||
|
||||
type get_type() const noexcept {
|
||||
return type_of(lua_state(), stack_index());
|
||||
}
|
||||
|
||||
int push() const {
|
||||
return push(L);
|
||||
}
|
||||
|
|
|
@ -25,12 +25,17 @@
|
|||
#include "stack_core.hpp"
|
||||
#include "raii.hpp"
|
||||
#include "optional.hpp"
|
||||
#include "usertype_traits.hpp"
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#ifdef SOL_CODECVT_SUPPORT
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
#endif
|
||||
#ifdef SOL_CXX17_FEATURES
|
||||
#include <string_view>
|
||||
#include <variant>
|
||||
#endif // C++17
|
||||
|
||||
namespace sol {
|
||||
namespace stack {
|
||||
|
@ -736,6 +741,63 @@ namespace sol {
|
|||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef SOL_CXX17_FEATURES
|
||||
template <>
|
||||
struct pusher<std::string_view> {
|
||||
static int push(lua_State* L, const std::string_view& sv) {
|
||||
return stack::push(L, sv.data(), sv.length());
|
||||
}
|
||||
};
|
||||
#ifdef SOL_CODECVT_SUPPORT
|
||||
template <>
|
||||
struct pusher<std::wstring_view> {
|
||||
static int push(lua_State* L, const std::wstring_view& sv) {
|
||||
return stack::push(L, sv.data(), sv.length());
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct pusher<std::u16string_view> {
|
||||
static int push(lua_State* L, const std::u16string_view& sv) {
|
||||
return stack::push(L, sv.data(), sv.length());
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct pusher<std::u32string_view> {
|
||||
static int push(lua_State* L, const std::u32string_view& sv) {
|
||||
return stack::push(L, sv.data(), sv.length());
|
||||
}
|
||||
};
|
||||
#endif // codecvt header support
|
||||
|
||||
namespace stack_detail {
|
||||
|
||||
struct push_function {
|
||||
lua_State* L;
|
||||
|
||||
push_function(lua_State* L) : L(L) {}
|
||||
|
||||
template <typename T>
|
||||
int operator()(T&& value) const {
|
||||
return stack::push<T>(L, std::forward<T>(value));
|
||||
}
|
||||
};
|
||||
|
||||
} // stack_detail
|
||||
|
||||
template <typename... Tn>
|
||||
struct pusher<std::variant<Tn...>> {
|
||||
static int push(lua_State* L, const std::variant<Tn...>& v) {
|
||||
return std::visit(stack_detail::push_function(L), v);
|
||||
}
|
||||
|
||||
static int push(lua_State* L, std::variant<Tn...>&& v) {
|
||||
return std::visit(stack_detail::push_function(L), std::move(v));
|
||||
}
|
||||
};
|
||||
#endif
|
||||
} // stack
|
||||
} // sol
|
||||
|
||||
|
|
|
@ -47,13 +47,13 @@ namespace sol {
|
|||
optional<string_detail::string_shim> maybetopmsg = stack::check_get<string_detail::string_shim>(L, 1);
|
||||
if (maybetopmsg) {
|
||||
const string_detail::string_shim& topmsg = maybetopmsg.value();
|
||||
msg.assign(topmsg.c_str(), topmsg.size());
|
||||
msg.assign(topmsg.data(), topmsg.size());
|
||||
}
|
||||
luaL_traceback(L, L, msg.c_str(), 1);
|
||||
optional<string_detail::string_shim> maybetraceback = stack::check_get<string_detail::string_shim>(L, -1);
|
||||
if (maybetraceback) {
|
||||
const string_detail::string_shim& traceback = maybetraceback.value();
|
||||
msg.assign(traceback.c_str(), traceback.size());
|
||||
msg.assign(traceback.data(), traceback.size());
|
||||
}
|
||||
return stack::push(L, msg);
|
||||
}
|
||||
|
|
|
@ -22,11 +22,18 @@
|
|||
#ifndef SOL_STRING_SHIM_HPP
|
||||
#define SOL_STRING_SHIM_HPP
|
||||
|
||||
#include "feature_test.hpp"
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#ifdef SOL_CXX17_FEATURES
|
||||
#include <string_view>
|
||||
#endif // C++17 features
|
||||
|
||||
namespace sol {
|
||||
namespace string_detail {
|
||||
#ifdef SOL_CXX17_FEATURES
|
||||
typedef std::string_view string_shim;
|
||||
#else
|
||||
struct string_shim {
|
||||
std::size_t s;
|
||||
const char* p;
|
||||
|
@ -82,6 +89,7 @@ namespace sol {
|
|||
return !(*this == r);
|
||||
}
|
||||
};
|
||||
#endif // C++17
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include "function_types.hpp"
|
||||
#include "usertype.hpp"
|
||||
#include "table_iterator.hpp"
|
||||
#include "types.hpp"
|
||||
#include "object_base.hpp"
|
||||
|
||||
namespace sol {
|
||||
namespace detail {
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
#include <memory>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#ifdef SOL_CXX17_FEATURES
|
||||
#include <string_view>
|
||||
#endif
|
||||
|
||||
namespace sol {
|
||||
template<std::size_t I>
|
||||
|
@ -294,6 +297,24 @@ namespace sol {
|
|||
static std::false_type test(...);
|
||||
};
|
||||
|
||||
struct has_value_type_impl {
|
||||
template<typename T, typename U = unqualified_t<T>,
|
||||
typename V = typename U::value_type>
|
||||
static std::true_type test(int);
|
||||
|
||||
template<typename...>
|
||||
static std::false_type test(...);
|
||||
};
|
||||
|
||||
struct has_iterator_impl {
|
||||
template<typename T, typename U = unqualified_t<T>,
|
||||
typename V = typename U::iterator>
|
||||
static std::true_type test(int);
|
||||
|
||||
template<typename...>
|
||||
static std::false_type test(...);
|
||||
};
|
||||
|
||||
struct has_key_value_pair_impl {
|
||||
template<typename T, typename U = unqualified_t<T>,
|
||||
typename V = typename U::value_type,
|
||||
|
@ -339,11 +360,25 @@ namespace sol {
|
|||
template<typename T>
|
||||
struct has_mapped_type : decltype(meta_detail::has_mapped_type_impl::test<T>(0)) {};
|
||||
|
||||
template<typename T>
|
||||
struct has_iterator : decltype(meta_detail::has_iterator_impl::test<T>(0)) {};
|
||||
|
||||
template<typename T>
|
||||
struct has_value_type : decltype(meta_detail::has_value_type_impl::test<T>(0)) {};
|
||||
|
||||
template <typename T>
|
||||
struct is_associative : meta::all<has_key_value_pair<T>, has_mapped_type<T>> {};
|
||||
|
||||
template <typename T>
|
||||
using is_string_constructible = any<std::is_same<unqualified_t<T>, const char*>, std::is_same<unqualified_t<T>, char>, std::is_same<unqualified_t<T>, std::string>, std::is_same<unqualified_t<T>, std::initializer_list<char>>>;
|
||||
using is_string_constructible = any<
|
||||
std::is_same<unqualified_t<T>, const char*>
|
||||
, std::is_same<unqualified_t<T>, char>
|
||||
, std::is_same<unqualified_t<T>, std::string>
|
||||
, std::is_same<unqualified_t<T>, std::initializer_list<char>>
|
||||
#ifdef SOL_CXX17_FEATURES
|
||||
, std::is_same<unqualified_t<T>, std::string_view>
|
||||
#endif
|
||||
>;
|
||||
|
||||
template <typename T>
|
||||
struct is_pair : std::false_type {};
|
||||
|
|
108
sol/types.hpp
108
sol/types.hpp
|
@ -22,12 +22,18 @@
|
|||
#ifndef SOL_TYPES_HPP
|
||||
#define SOL_TYPES_HPP
|
||||
|
||||
#include "error.hpp"
|
||||
#include "optional.hpp"
|
||||
#include "compatibility.hpp"
|
||||
#include "forward.hpp"
|
||||
#include "traits.hpp"
|
||||
#include "string_shim.hpp"
|
||||
#include <array>
|
||||
#include <string>
|
||||
#ifdef SOL_CXX17_FEATURES
|
||||
#include <string_view>
|
||||
#include <variant>
|
||||
#endif // C++17
|
||||
|
||||
namespace sol {
|
||||
namespace detail {
|
||||
|
@ -650,64 +656,6 @@ namespace sol {
|
|||
return lua_typename(L, static_cast<int>(t));
|
||||
}
|
||||
|
||||
class reference;
|
||||
class stack_reference;
|
||||
template <typename Table, typename Key>
|
||||
struct proxy;
|
||||
template<typename T>
|
||||
class usertype;
|
||||
template <bool, typename T>
|
||||
class basic_table_core;
|
||||
template <bool b>
|
||||
using table_core = basic_table_core<b, reference>;
|
||||
template <bool b>
|
||||
using stack_table_core = basic_table_core<b, stack_reference>;
|
||||
template <typename T>
|
||||
using basic_table = basic_table_core<false, T>;
|
||||
typedef table_core<false> table;
|
||||
typedef table_core<true> global_table;
|
||||
typedef stack_table_core<false> stack_table;
|
||||
typedef stack_table_core<true> stack_global_table;
|
||||
template <typename base_t>
|
||||
struct basic_environment;
|
||||
using environment = basic_environment<reference>;
|
||||
using stack_environment = basic_environment<stack_reference>;
|
||||
template <typename T>
|
||||
class basic_function;
|
||||
template <typename T>
|
||||
class basic_protected_function;
|
||||
using protected_function = basic_protected_function<reference>;
|
||||
using stack_protected_function = basic_protected_function<stack_reference>;
|
||||
using unsafe_function = basic_function<reference>;
|
||||
using safe_function = basic_protected_function<reference>;
|
||||
using stack_unsafe_function = basic_function<stack_reference>;
|
||||
using stack_safe_function = basic_protected_function<stack_reference>;
|
||||
#ifdef SOL_SAFE_FUNCTIONS
|
||||
using function = protected_function;
|
||||
using stack_function = stack_protected_function;
|
||||
#else
|
||||
using function = unsafe_function;
|
||||
using stack_function = stack_unsafe_function;
|
||||
#endif
|
||||
template <typename base_t>
|
||||
class basic_object;
|
||||
template <typename base_t>
|
||||
class basic_userdata;
|
||||
template <typename base_t>
|
||||
class basic_lightuserdata;
|
||||
struct variadic_args;
|
||||
using object = basic_object<reference>;
|
||||
using stack_object = basic_object<stack_reference>;
|
||||
using userdata = basic_userdata<reference>;
|
||||
using stack_userdata = basic_userdata<stack_reference>;
|
||||
using lightuserdata = basic_lightuserdata<reference>;
|
||||
using stack_lightuserdata = basic_lightuserdata<stack_reference>;
|
||||
class coroutine;
|
||||
class thread;
|
||||
struct variadic_args;
|
||||
struct this_state;
|
||||
struct this_environment;
|
||||
|
||||
namespace detail {
|
||||
template <typename T, typename = void>
|
||||
struct lua_type_of : std::integral_constant<type, type::userdata> {};
|
||||
|
@ -757,9 +705,6 @@ namespace sol {
|
|||
template <>
|
||||
struct lua_type_of<const char32_t*> : std::integral_constant<type, type::string> {};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<string_detail::string_shim> : std::integral_constant<type, type::string> {};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<bool> : std::integral_constant<type, type::boolean> {};
|
||||
|
||||
|
@ -874,6 +819,29 @@ namespace sol {
|
|||
template <typename T>
|
||||
struct lua_type_of<T, std::enable_if_t<std::is_enum<T>::value>> : std::integral_constant<type, type::number> {};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<meta_function> : std::integral_constant<type, type::string> {};
|
||||
|
||||
#ifdef SOL_CXX17_FEATURES
|
||||
template <>
|
||||
struct lua_type_of<std::string_view> : std::integral_constant<type, type::string> {};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<std::wstring_view> : std::integral_constant<type, type::string> {};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<std::u16string_view> : std::integral_constant<type, type::string> {};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<std::u32string_view> : std::integral_constant<type, type::string> {};
|
||||
|
||||
template <typename... Tn>
|
||||
struct lua_type_of<std::variant<Tn...>> : std::integral_constant<type, type::poly> {};
|
||||
#else
|
||||
template <>
|
||||
struct lua_type_of<string_detail::string_shim> : std::integral_constant<type, type::string> {};
|
||||
#endif // C++ 17 (or not) features
|
||||
|
||||
template <typename T, typename C = void>
|
||||
struct is_container : std::false_type {};
|
||||
|
||||
|
@ -889,11 +857,23 @@ namespace sol {
|
|||
template <>
|
||||
struct is_container<std::u32string> : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_container<T, std::enable_if_t<meta::has_begin_end<meta::unqualified_t<T>>::value>> : std::true_type {};
|
||||
#ifdef SOL_CXX17_FEATURES
|
||||
template <>
|
||||
struct is_container<std::string_view> : std::false_type {};
|
||||
|
||||
template <>
|
||||
struct lua_type_of<meta_function> : std::integral_constant<type, type::string> {};
|
||||
struct is_container<std::wstring_view> : std::false_type {};
|
||||
|
||||
template <>
|
||||
struct is_container<std::u16string_view> : std::false_type {};
|
||||
|
||||
template <>
|
||||
struct is_container<std::u32string_view> : std::false_type {};
|
||||
|
||||
#endif // C++ 17
|
||||
|
||||
template <typename T>
|
||||
struct is_container<T, std::enable_if_t<meta::has_begin_end<meta::unqualified_t<T>>::value>> : std::true_type {};
|
||||
|
||||
template <typename C, C v, template <typename...> class V, typename... Args>
|
||||
struct accumulate : std::integral_constant<C, v> {};
|
||||
|
|
115
sol/unsafe_function.hpp
Normal file
115
sol/unsafe_function.hpp
Normal file
|
@ -0,0 +1,115 @@
|
|||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2017 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef SOL_UNSAFE_FUNCTION_HPP
|
||||
#define SOL_UNSAFE_FUNCTION_HPP
|
||||
|
||||
#include "reference.hpp"
|
||||
#include "stack.hpp"
|
||||
#include "function_result.hpp"
|
||||
#include "function_types.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
namespace sol {
|
||||
template <typename base_t>
|
||||
class basic_function : public base_t {
|
||||
private:
|
||||
void luacall(std::ptrdiff_t argcount, std::ptrdiff_t resultcount) const {
|
||||
lua_callk(base_t::lua_state(), static_cast<int>(argcount), static_cast<int>(resultcount), 0, nullptr);
|
||||
}
|
||||
|
||||
template<std::size_t... I, typename... Ret>
|
||||
auto invoke(types<Ret...>, std::index_sequence<I...>, std::ptrdiff_t n) const {
|
||||
luacall(n, lua_size<std::tuple<Ret...>>::value);
|
||||
return stack::pop<std::tuple<Ret...>>(base_t::lua_state());
|
||||
}
|
||||
|
||||
template<std::size_t I, typename Ret>
|
||||
Ret invoke(types<Ret>, std::index_sequence<I>, std::ptrdiff_t n) const {
|
||||
luacall(n, lua_size<Ret>::value);
|
||||
return stack::pop<Ret>(base_t::lua_state());
|
||||
}
|
||||
|
||||
template <std::size_t I>
|
||||
void invoke(types<void>, std::index_sequence<I>, std::ptrdiff_t n) const {
|
||||
luacall(n, 0);
|
||||
}
|
||||
|
||||
function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) const {
|
||||
int stacksize = lua_gettop(base_t::lua_state());
|
||||
int firstreturn = (std::max)(1, stacksize - static_cast<int>(n));
|
||||
luacall(n, LUA_MULTRET);
|
||||
int poststacksize = lua_gettop(base_t::lua_state());
|
||||
int returncount = poststacksize - (firstreturn - 1);
|
||||
return function_result(base_t::lua_state(), firstreturn, returncount);
|
||||
}
|
||||
|
||||
public:
|
||||
basic_function() = default;
|
||||
template <typename T, meta::enable<meta::neg<std::is_same<meta::unqualified_t<T>, basic_function>>, meta::neg<std::is_same<base_t, stack_reference>>, std::is_base_of<base_t, meta::unqualified_t<T>>> = meta::enabler>
|
||||
basic_function(T&& r) noexcept : base_t(std::forward<T>(r)) {
|
||||
#ifdef SOL_CHECK_ARGUMENTS
|
||||
if (!is_function<meta::unqualified_t<T>>::value) {
|
||||
auto pp = stack::push_pop(*this);
|
||||
stack::check<basic_function>(base_t::lua_state(), -1, type_panic);
|
||||
}
|
||||
#endif // Safety
|
||||
}
|
||||
basic_function(const basic_function&) = default;
|
||||
basic_function& operator=(const basic_function&) = default;
|
||||
basic_function(basic_function&&) = default;
|
||||
basic_function& operator=(basic_function&&) = default;
|
||||
basic_function(const stack_reference& r) : basic_function(r.lua_state(), r.stack_index()) {}
|
||||
basic_function(stack_reference&& r) : basic_function(r.lua_state(), r.stack_index()) {}
|
||||
template <typename T, meta::enable<meta::neg<std::is_integral<meta::unqualified_t<T>>>, meta::neg<std::is_same<T, ref_index>>> = meta::enabler>
|
||||
basic_function(lua_State* L, T&& r) : basic_function(L, sol::ref_index(r.registry_index())) {}
|
||||
basic_function(lua_State* L, int index = -1) : base_t(L, index) {
|
||||
#ifdef SOL_CHECK_ARGUMENTS
|
||||
stack::check<basic_function>(L, index, type_panic);
|
||||
#endif // Safety
|
||||
}
|
||||
basic_function(lua_State* L, ref_index index) : base_t(L, index) {
|
||||
#ifdef SOL_CHECK_ARGUMENTS
|
||||
auto pp = stack::push_pop(*this);
|
||||
stack::check<basic_function>(L, -1, type_panic);
|
||||
#endif // Safety
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
function_result operator()(Args&&... args) const {
|
||||
return call<>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Ret, typename... Args>
|
||||
decltype(auto) operator()(types<Ret...>, Args&&... args) const {
|
||||
return call<Ret...>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Ret, typename... Args>
|
||||
decltype(auto) call(Args&&... args) const {
|
||||
base_t::push();
|
||||
int pushcount = stack::multi_push_reference(base_t::lua_state(), std::forward<Args>(args)...);
|
||||
return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount);
|
||||
}
|
||||
};
|
||||
} // sol
|
||||
|
||||
#endif // SOL_UNSAFE_FUNCTION_HPP
|
|
@ -82,7 +82,7 @@ namespace sol {
|
|||
template <typename N, typename F>
|
||||
void set(N&& n, F&& f) {
|
||||
auto meta = static_cast<simple_usertype_metatable<T>*>(base_t::registrar_data());
|
||||
meta->add(state, n, f);
|
||||
meta->add(state, std::forward<N>(n), std::forward<F>(f));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "inheritance.hpp"
|
||||
#include "raii.hpp"
|
||||
#include "deprecate.hpp"
|
||||
#include "object.hpp"
|
||||
#include <unordered_map>
|
||||
#include <cstdio>
|
||||
|
||||
|
@ -250,7 +251,7 @@ namespace sol {
|
|||
#if 0//def SOL_SAFE_USERTYPE
|
||||
auto maybeaccessor = stack::get<optional<string_detail::string_shim>>(L, is_index ? -1 : -2);
|
||||
string_detail::string_shim accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)"));
|
||||
return luaL_error(L, "sol: attempt to index (get) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.c_str());
|
||||
return luaL_error(L, "sol: attempt to index (get) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.data());
|
||||
#else
|
||||
if (is_toplevel(L)) {
|
||||
if (lua_getmetatable(L, 1) == 1) {
|
||||
|
@ -266,7 +267,7 @@ namespace sol {
|
|||
else {
|
||||
auto maybeaccessor = stack::get<optional<string_detail::string_shim>>(L, is_index ? -1 : -2);
|
||||
string_detail::string_shim accessor = maybeaccessor.value_or(string_detail::string_shim("(unknown)"));
|
||||
return luaL_error(L, "sol: attempt to index (set) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.c_str());
|
||||
return luaL_error(L, "sol: attempt to index (set) nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.data());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,17 +42,27 @@ namespace sol {
|
|||
stack_proxy sp;
|
||||
|
||||
va_iterator() : L(nullptr), index((std::numeric_limits<int>::max)()), stacktop((std::numeric_limits<int>::max)()) {}
|
||||
va_iterator(const va_iterator<true>& r) : L(r.L), index(r.index), stacktop(r.stacktop) {}
|
||||
va_iterator(lua_State* luastate, int idx, int topidx) : L(luastate), index(idx), stacktop(topidx), sp(luastate, idx) {}
|
||||
|
||||
reference operator*() {
|
||||
return stack_proxy(L, index);
|
||||
}
|
||||
|
||||
reference operator*() const {
|
||||
return stack_proxy(L, index);
|
||||
}
|
||||
|
||||
pointer operator->() {
|
||||
sp = stack_proxy(L, index);
|
||||
return &sp;
|
||||
}
|
||||
|
||||
pointer operator->() const {
|
||||
const_cast<stack_proxy&>(sp) = stack_proxy(L, index);
|
||||
return &sp;
|
||||
}
|
||||
|
||||
va_iterator& operator++ () {
|
||||
++index;
|
||||
return *this;
|
||||
|
@ -95,7 +105,7 @@ namespace sol {
|
|||
return r;
|
||||
}
|
||||
|
||||
reference operator[](difference_type idx) {
|
||||
reference operator[](difference_type idx) const {
|
||||
return stack_proxy(L, index + static_cast<int>(idx));
|
||||
}
|
||||
|
||||
|
@ -213,6 +223,10 @@ namespace sol {
|
|||
return stack::get<T>(L, index + static_cast<int>(start));
|
||||
}
|
||||
|
||||
type get_type(difference_type start = 0) const noexcept {
|
||||
return type_of(L, index + static_cast<int>(start));
|
||||
}
|
||||
|
||||
stack_proxy operator[](difference_type start) const {
|
||||
return stack_proxy(L, index + static_cast<int>(start));
|
||||
}
|
||||
|
@ -220,6 +234,7 @@ namespace sol {
|
|||
lua_State* lua_state() const { return L; };
|
||||
int stack_index() const { return index; };
|
||||
int leftover_count() const { return stacktop - (index - 1); }
|
||||
std::size_t size() const { return static_cast<std::size_t>(leftover_count()); }
|
||||
int top() const { return stacktop; }
|
||||
};
|
||||
|
||||
|
|
51
sol/variadic_results.hpp
Normal file
51
sol/variadic_results.hpp
Normal file
|
@ -0,0 +1,51 @@
|
|||
// The MIT License (MIT)
|
||||
|
||||
// Copyright (c) 2013-2017 Rapptz, ThePhD and contributors
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef SOL_VARIADIC_RESULTS_HPP
|
||||
#define SOL_VARIADIC_RESULTS_HPP
|
||||
|
||||
#include "stack.hpp"
|
||||
#include "object.hpp"
|
||||
#include "as_returns.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace sol {
|
||||
|
||||
struct variadic_results : public std::vector<object> {
|
||||
using std::vector<object>::vector;
|
||||
};
|
||||
|
||||
namespace stack {
|
||||
template <>
|
||||
struct pusher<variadic_results> {
|
||||
int push(lua_State* L, const variadic_results& e) {
|
||||
int p = 0;
|
||||
for (const auto& i : e) {
|
||||
p += stack::push(L, i);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
};
|
||||
} // stack
|
||||
|
||||
} // sol
|
||||
|
||||
#endif SOL_VARIADIC_RESULTS_HPP
|
|
@ -47,7 +47,7 @@ TEST_CASE("containers/returns", "make sure that even references to vectors are b
|
|||
REQUIRE(matching);
|
||||
}
|
||||
|
||||
TEST_CASE("containers/vector_roundtrip", "make sure vectors can be round-tripped") {
|
||||
TEST_CASE("containers/vector roundtrip", "make sure vectors can be round-tripped") {
|
||||
sol::state lua;
|
||||
std::vector<int> v{ 1, 2, 3 };
|
||||
lua.set_function("f", [&]() -> std::vector<int>& {
|
||||
|
@ -59,7 +59,7 @@ TEST_CASE("containers/vector_roundtrip", "make sure vectors can be round-tripped
|
|||
REQUIRE(areequal);
|
||||
}
|
||||
|
||||
TEST_CASE("containers/list_roundtrip", "make sure lists can be round-tripped") {
|
||||
TEST_CASE("containers/list roundtrip", "make sure lists can be round-tripped") {
|
||||
sol::state lua;
|
||||
std::list<int> v{ 1, 2, 3 };
|
||||
lua.set_function("f", [&]() -> std::list<int>& {
|
||||
|
@ -71,7 +71,7 @@ TEST_CASE("containers/list_roundtrip", "make sure lists can be round-tripped") {
|
|||
REQUIRE(areequal);
|
||||
}
|
||||
|
||||
TEST_CASE("containers/map_roundtrip", "make sure maps can be round-tripped") {
|
||||
TEST_CASE("containers/map roundtrip", "make sure maps can be round-tripped") {
|
||||
sol::state lua;
|
||||
std::map<std::string, int> v{ { "a", 1 },{ "b", 2 },{ "c", 3 } };
|
||||
lua.set_function("f", [&]() -> std::map<std::string, int>& {
|
||||
|
@ -83,7 +83,7 @@ TEST_CASE("containers/map_roundtrip", "make sure maps can be round-tripped") {
|
|||
REQUIRE(areequal);
|
||||
}
|
||||
|
||||
TEST_CASE("containers/unordered_map_roundtrip", "make sure unordered_maps can be round-tripped") {
|
||||
TEST_CASE("containers/unordered_map roundtrip", "make sure unordered_maps can be round-tripped") {
|
||||
sol::state lua;
|
||||
std::unordered_map<std::string, int> v{ { "a", 1 },{ "b", 2 },{ "c", 3 } };
|
||||
lua.set_function("f", [&]() -> std::unordered_map<std::string, int>& {
|
||||
|
@ -95,7 +95,7 @@ TEST_CASE("containers/unordered_map_roundtrip", "make sure unordered_maps can be
|
|||
REQUIRE(areequal);
|
||||
}
|
||||
|
||||
TEST_CASE("containers/unordered_set_roundtrip", "make sure unordered_sets can be round-tripped") {
|
||||
TEST_CASE("containers/unordered_set roundtrip", "make sure unordered_sets can be round-tripped") {
|
||||
sol::state lua;
|
||||
std::unordered_set<int> v{ 1, 2, 3 };
|
||||
lua.set_function("f", [&]() -> std::unordered_set<int>& {
|
||||
|
@ -107,7 +107,7 @@ TEST_CASE("containers/unordered_set_roundtrip", "make sure unordered_sets can be
|
|||
REQUIRE(areequal);
|
||||
}
|
||||
|
||||
TEST_CASE("containers/set_roundtrip", "make sure sets can be round-tripped") {
|
||||
TEST_CASE("containers/set roundtrip", "make sure sets can be round-tripped") {
|
||||
sol::state lua;
|
||||
std::set<int> v{ 1, 2, 3 };
|
||||
lua.set_function("f", [&]() -> std::set<int>& {
|
||||
|
@ -119,7 +119,7 @@ TEST_CASE("containers/set_roundtrip", "make sure sets can be round-tripped") {
|
|||
REQUIRE(areequal);
|
||||
}
|
||||
|
||||
TEST_CASE("containers/custom-usertype", "make sure container usertype metatables can be overridden") {
|
||||
TEST_CASE("containers/custom usertype", "make sure container usertype metatables can be overridden") {
|
||||
typedef std::unordered_map<int, int> bark;
|
||||
|
||||
sol::state lua;
|
||||
|
@ -141,7 +141,7 @@ TEST_CASE("containers/custom-usertype", "make sure container usertype metatables
|
|||
REQUIRE_NOTHROW(lua.script("a:something()"));
|
||||
}
|
||||
|
||||
TEST_CASE("containers/const-serialization-kvp", "make sure const keys / values are respected") {
|
||||
TEST_CASE("containers/const serialization kvp", "make sure const keys / values are respected") {
|
||||
typedef std::map<int, const int> bark;
|
||||
|
||||
sol::state lua;
|
||||
|
@ -153,7 +153,7 @@ TEST_CASE("containers/const-serialization-kvp", "make sure const keys / values a
|
|||
REQUIRE_NOTHROW(lua.script("assert(a[24] == 50)"));
|
||||
}
|
||||
|
||||
TEST_CASE("containers/basic-serialization", "make sure containers are turned into proper userdata and have basic hooks established") {
|
||||
TEST_CASE("containers/basic serialization", "make sure containers are turned into proper userdata and have basic hooks established") {
|
||||
typedef std::vector<int> woof;
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
@ -189,7 +189,7 @@ TEST_CASE("containers/const-serialization", "make sure containers are turned int
|
|||
}
|
||||
#endif // Fuck you, glibc
|
||||
|
||||
TEST_CASE("containers/table-serialization", "ensure types can be serialized as tables still") {
|
||||
TEST_CASE("containers/table serialization", "ensure types can be serialized as tables still") {
|
||||
typedef std::vector<int> woof;
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
@ -212,7 +212,7 @@ TEST_CASE("containers/table-serialization", "ensure types can be serialized as t
|
|||
);
|
||||
}
|
||||
|
||||
TEST_CASE("containers/const-correctness", "usertype metatable names should reasonably ignore const attributes") {
|
||||
TEST_CASE("containers/const correctness", "usertype metatable names should reasonably ignore const attributes") {
|
||||
struct Vec {
|
||||
int x, y, z;
|
||||
};
|
||||
|
@ -247,7 +247,7 @@ end
|
|||
}());
|
||||
}
|
||||
|
||||
TEST_CASE("containers/arbitrary-creation", "userdata and tables should be usable from standard containers") {
|
||||
TEST_CASE("containers/arbitrary creation", "userdata and tables should be usable from standard containers") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
lua.set_function("test_one", test_table_return_one);
|
||||
|
@ -286,7 +286,7 @@ TEST_CASE("containers/arbitrary-creation", "userdata and tables should be usable
|
|||
REQUIRE(d.get<int>("four") == 4);
|
||||
}
|
||||
|
||||
TEST_CASE("containers/extra-functions", "make sure the manipulation functions are present and usable and working across various container types") {
|
||||
TEST_CASE("containers/extra functions", "make sure the manipulation functions are present and usable and working across various container types") {
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
||||
|
@ -386,7 +386,7 @@ c_arr[-1] = 7
|
|||
}
|
||||
}
|
||||
|
||||
TEST_CASE("containers/usertype-transparency", "Make sure containers pass their arguments through transparently and push the results as references, not new values") {
|
||||
TEST_CASE("containers/usertype transparency", "Make sure containers pass their arguments through transparently and push the results as references, not new values") {
|
||||
class A {
|
||||
public:
|
||||
int a;
|
||||
|
@ -458,7 +458,7 @@ namespace sol {
|
|||
struct is_container<options> : std::false_type {};
|
||||
}
|
||||
|
||||
TEST_CASE("containers/is-container", "make sure the is_container trait behaves properly") {
|
||||
TEST_CASE("containers/is container", "make sure the is_container trait behaves properly") {
|
||||
sol::state lua;
|
||||
lua.open_libraries();
|
||||
|
||||
|
@ -553,7 +553,7 @@ TEST_CASE("containers/to_args", "Test that the to_args abstractions works") {
|
|||
|
||||
}
|
||||
|
||||
TEST_CASE("containers/ipairs-test", "ensure that abstractions roundtrip properly") {
|
||||
TEST_CASE("containers/ipairs test", "ensure that abstractions roundtrip properly") {
|
||||
struct thing {
|
||||
int x = 20;
|
||||
};
|
||||
|
@ -585,7 +585,7 @@ end
|
|||
}
|
||||
}
|
||||
|
||||
TEST_CASE("containers/append-idiom", "ensure the append-idiom works as intended") {
|
||||
TEST_CASE("containers/append idiom", "ensure the append-idiom works as intended") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
lua.script(
|
||||
|
|
|
@ -32,7 +32,7 @@ end
|
|||
REQUIRE(counter == 30);
|
||||
}
|
||||
|
||||
TEST_CASE("threading/new-thread-coroutines", "ensure calling a coroutine works when the work is put on a different thread") {
|
||||
TEST_CASE("threading/new thread coroutines", "ensure calling a coroutine works when the work is put on a different thread") {
|
||||
const auto& script = R"(counter = 20
|
||||
|
||||
function loop()
|
||||
|
|
|
@ -18,6 +18,10 @@ namespace sol {
|
|||
template <>
|
||||
struct lua_size<two_things> : std::integral_constant<int, 2> {};
|
||||
|
||||
// Then, the expected type
|
||||
template <>
|
||||
struct lua_type_of<two_things> : std::integral_constant<sol::type, sol::type::poly> {};
|
||||
|
||||
// Now, specialize various stack structures
|
||||
namespace stack {
|
||||
|
||||
|
@ -60,7 +64,7 @@ namespace sol {
|
|||
}
|
||||
}
|
||||
|
||||
TEST_CASE("customization/split-struct", "using the newly documented customization points to handle different kinds of classes") {
|
||||
TEST_CASE("customization/split struct", "using the newly documented customization points to handle different kinds of classes") {
|
||||
sol::state lua;
|
||||
|
||||
// Create a pass-through style of function
|
||||
|
|
|
@ -103,7 +103,7 @@ static int raw_noexcept_function(lua_State* L) noexcept {
|
|||
return sol::stack::push(L, 0x63);
|
||||
}
|
||||
|
||||
TEST_CASE("functions/tuple-returns", "Make sure tuple returns are ordered properly") {
|
||||
TEST_CASE("functions/tuple returns", "Make sure tuple returns are ordered properly") {
|
||||
sol::state lua;
|
||||
lua.script("function f() return '3', 4 end");
|
||||
|
||||
|
@ -114,7 +114,7 @@ TEST_CASE("functions/tuple-returns", "Make sure tuple returns are ordered proper
|
|||
REQUIRE(v == 4);
|
||||
}
|
||||
|
||||
TEST_CASE("functions/overload-resolution", "Check if overloaded function resolution templates compile/work") {
|
||||
TEST_CASE("functions/overload resolution", "Check if overloaded function resolution templates compile/work") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
|
@ -143,7 +143,7 @@ TEST_CASE("functions/overload-resolution", "Check if overloaded function resolut
|
|||
REQUIRE_NOTHROW(lua.script("print(overloaded(1, 2, 3))"));
|
||||
}
|
||||
|
||||
TEST_CASE("functions/return-order-and-multi-get", "Check if return order is in the same reading order specified in Lua") {
|
||||
TEST_CASE("functions/return order and multi get", "Check if return order is in the same reading order specified in Lua") {
|
||||
const static std::tuple<int, int, int> triple = std::make_tuple(10, 11, 12);
|
||||
const static std::tuple<int, float> paired = std::make_tuple(10, 10.f);
|
||||
sol::state lua;
|
||||
|
@ -165,7 +165,7 @@ TEST_CASE("functions/return-order-and-multi-get", "Check if return order is in t
|
|||
REQUIRE(tcpp2 == paired);
|
||||
}
|
||||
|
||||
TEST_CASE("functions/deducing-return-order-and-multi-get", "Check if return order is in the same reading order specified in Lua, with regular deducing calls") {
|
||||
TEST_CASE("functions/deducing return order and multi get", "Check if return order is in the same reading order specified in Lua, with regular deducing calls") {
|
||||
const static std::tuple<int, int, int> triple = std::make_tuple(10, 11, 12);
|
||||
sol::state lua;
|
||||
lua.set_function("f_string", []() { return "this is a string!"; });
|
||||
|
@ -192,7 +192,7 @@ TEST_CASE("functions/deducing-return-order-and-multi-get", "Check if return orde
|
|||
REQUIRE(tluaget == triple);
|
||||
}
|
||||
|
||||
TEST_CASE("functions/optional-values", "check if optionals can be passed in to be nil or otherwise") {
|
||||
TEST_CASE("functions/optional values", "check if optionals can be passed in to be nil or otherwise") {
|
||||
struct thing {
|
||||
int v;
|
||||
};
|
||||
|
@ -213,7 +213,7 @@ end )");
|
|||
REQUIRE(v->v == 29);
|
||||
}
|
||||
|
||||
TEST_CASE("functions/pair-and-tuple-and-proxy-tests", "Check if sol::reference and sol::proxy can be passed to functions as arguments") {
|
||||
TEST_CASE("functions/pair and tuple and proxy tests", "Check if sol::reference and sol::proxy can be passed to functions as arguments") {
|
||||
sol::state lua;
|
||||
lua.new_usertype<A>("A",
|
||||
"bark", &A::bark);
|
||||
|
@ -253,7 +253,7 @@ nested = { variables = { no = { problem = 10 } } } )");
|
|||
REQUIRE(abc == abcdesired);
|
||||
}
|
||||
|
||||
TEST_CASE("functions/sol::function-to-std::function", "check if conversion to std::function works properly and calls with correct arguments") {
|
||||
TEST_CASE("functions/sol::function to std::function", "check if conversion to std::function works properly and calls with correct arguments") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
|
@ -272,7 +272,7 @@ TEST_CASE("functions/sol::function-to-std::function", "check if conversion to st
|
|||
));
|
||||
}
|
||||
|
||||
TEST_CASE("functions/returning-functions-from-C++-and-gettin-in-lua", "check to see if returning a functor and getting a functor from lua is possible") {
|
||||
TEST_CASE("functions/returning functions from C++", "check to see if returning a functor and getting a functor from lua is possible") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
|
@ -283,7 +283,7 @@ TEST_CASE("functions/returning-functions-from-C++-and-gettin-in-lua", "check to
|
|||
"takefn(afx)\n");
|
||||
}
|
||||
|
||||
TEST_CASE("functions/function_result-protected_function_result", "Function result should be the beefy return type for sol::function that allows for error checking and error handlers") {
|
||||
TEST_CASE("functions/function_result and protected_function_result", "Function result should be the beefy return type for sol::function that allows for error checking and error handlers") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base, sol::lib::debug);
|
||||
static const char unhandlederrormessage[] = "true error message";
|
||||
|
@ -392,7 +392,7 @@ TEST_CASE("functions/function_result-protected_function_result", "Function resul
|
|||
}
|
||||
}
|
||||
|
||||
TEST_CASE("functions/destructor-tests", "Show that proper copies / destruction happens") {
|
||||
TEST_CASE("functions/destructor tests", "Show that proper copies / destruction happens") {
|
||||
static int created = 0;
|
||||
static int destroyed = 0;
|
||||
static void* last_call = nullptr;
|
||||
|
@ -471,7 +471,7 @@ TEST_CASE("functions/destructor-tests", "Show that proper copies / destruction h
|
|||
}
|
||||
|
||||
|
||||
TEST_CASE("functions/all-kinds", "Register all kinds of functions, make sure they all compile and work") {
|
||||
TEST_CASE("functions/all kinds", "Register all kinds of functions, make sure they all compile and work") {
|
||||
sol::state lua;
|
||||
|
||||
struct test_1 {
|
||||
|
@ -661,7 +661,7 @@ N = n(1, 2, 3)
|
|||
REQUIRE_THROWS(lua.script("v(nested, inner)"));
|
||||
}
|
||||
|
||||
TEST_CASE("simple/call-with-parameters", "Lua function is called with a few parameters from C++") {
|
||||
TEST_CASE("simple/call with parameters", "Lua function is called with a few parameters from C++") {
|
||||
sol::state lua;
|
||||
|
||||
REQUIRE_NOTHROW(lua.script("function my_add(i, j, k) return i + j + k end"));
|
||||
|
@ -675,7 +675,7 @@ TEST_CASE("simple/call-with-parameters", "Lua function is called with a few para
|
|||
REQUIRE_THROWS(a = f(1, 2, "arf"));
|
||||
}
|
||||
|
||||
TEST_CASE("simple/call-c++-function", "C++ function is called from lua") {
|
||||
TEST_CASE("simple/call c++ function", "C++ function is called from lua") {
|
||||
sol::state lua;
|
||||
|
||||
lua.set_function("plop_xyz", sep::plop_xyz);
|
||||
|
@ -684,7 +684,7 @@ TEST_CASE("simple/call-c++-function", "C++ function is called from lua") {
|
|||
REQUIRE(lua.get<int>("x") == 11);
|
||||
}
|
||||
|
||||
TEST_CASE("simple/call-lambda", "A C++ lambda is exposed to lua and called") {
|
||||
TEST_CASE("simple/call lambda", "A C++ lambda is exposed to lua and called") {
|
||||
sol::state lua;
|
||||
|
||||
int a = 0;
|
||||
|
@ -696,7 +696,7 @@ TEST_CASE("simple/call-lambda", "A C++ lambda is exposed to lua and called") {
|
|||
REQUIRE(a == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("advanced/get-and-call", "Checks for lambdas returning values after a get operation") {
|
||||
TEST_CASE("advanced/get and call", "Checks for lambdas returning values after a get operation") {
|
||||
const static std::string lol = "lol", str = "str";
|
||||
const static std::tuple<int, float, double, std::string> heh_tuple = std::make_tuple(1, 6.28f, 3.14, std::string("heh"));
|
||||
sol::state lua;
|
||||
|
@ -731,7 +731,7 @@ TEST_CASE("advanced/get-and-call", "Checks for lambdas returning values after a
|
|||
REQUIRE((lua.get<sol::function>("j").call<int, float, double, std::string>() == heh_tuple));
|
||||
}
|
||||
|
||||
TEST_CASE("advanced/operator[]-call", "Checks for lambdas returning values using operator[]") {
|
||||
TEST_CASE("advanced/operator[] call", "Checks for lambdas returning values using operator[]") {
|
||||
const static std::string lol = "lol", str = "str";
|
||||
const static std::tuple<int, float, double, std::string> heh_tuple = std::make_tuple(1, 6.28f, 3.14, std::string("heh"));
|
||||
sol::state lua;
|
||||
|
@ -766,7 +766,7 @@ TEST_CASE("advanced/operator[]-call", "Checks for lambdas returning values using
|
|||
REQUIRE((lua["j"].call<int, float, double, std::string>() == heh_tuple));
|
||||
}
|
||||
|
||||
TEST_CASE("advanced/call-lambdas", "A C++ lambda is exposed to lua and called") {
|
||||
TEST_CASE("advanced/call lambdas", "A C++ lambda is exposed to lua and called") {
|
||||
sol::state lua;
|
||||
|
||||
int x = 0;
|
||||
|
@ -779,7 +779,7 @@ TEST_CASE("advanced/call-lambdas", "A C++ lambda is exposed to lua and called")
|
|||
REQUIRE(x == 9);
|
||||
}
|
||||
|
||||
TEST_CASE("advanced/call-referenced_obj", "A C++ object is passed by pointer/reference_wrapper to lua and invoked") {
|
||||
TEST_CASE("advanced/call referenced obj", "A C++ object is passed by pointer/reference_wrapper to lua and invoked") {
|
||||
sol::state lua;
|
||||
|
||||
int x = 0;
|
||||
|
@ -817,51 +817,6 @@ end)");
|
|||
REQUIRE(c == 3);
|
||||
}
|
||||
|
||||
TEST_CASE("functions/variadic_args", "Check to see we can receive multiple arguments through a variadic") {
|
||||
struct structure {
|
||||
int x;
|
||||
bool b;
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
lua.set_function("v", [](sol::this_state, sol::variadic_args va) -> structure {
|
||||
int r = 0;
|
||||
for (auto v : va) {
|
||||
int value = v;
|
||||
r += value;
|
||||
}
|
||||
return{ r, r > 200 };
|
||||
});
|
||||
|
||||
lua.script("x = v(25, 25)");
|
||||
lua.script("x2 = v(25, 25, 100, 50, 250, 150)");
|
||||
lua.script("x3 = v(1, 2, 3, 4, 5, 6)");
|
||||
|
||||
structure& lx = lua["x"];
|
||||
structure& lx2 = lua["x2"];
|
||||
structure& lx3 = lua["x3"];
|
||||
REQUIRE(lx.x == 50);
|
||||
REQUIRE(lx2.x == 600);
|
||||
REQUIRE(lx3.x == 21);
|
||||
REQUIRE_FALSE(lx.b);
|
||||
REQUIRE(lx2.b);
|
||||
REQUIRE_FALSE(lx3.b);
|
||||
}
|
||||
|
||||
TEST_CASE("functions/required_and_variadic_args", "Check if a certain number of arguments can still be required even when using variadic_args") {
|
||||
sol::state lua;
|
||||
lua.set_function("v",
|
||||
[](sol::this_state, sol::variadic_args, int, int) {
|
||||
}
|
||||
);
|
||||
REQUIRE_NOTHROW(lua.script("v(20, 25, 30)"));
|
||||
REQUIRE_NOTHROW(lua.script("v(20, 25)"));
|
||||
#ifndef SOL_LUAJIT
|
||||
REQUIRE_THROWS(lua.script("v(20)"));
|
||||
#endif // LuaJIT has problems with exceptions, as fucking usual
|
||||
}
|
||||
|
||||
TEST_CASE("functions/overloading", "Check if overloading works properly for regular set function syntax") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include <catch.hpp>
|
||||
#include <sol.hpp>
|
||||
|
||||
TEST_CASE("storage/registry=construction", "ensure entries from the registry can be retrieved") {
|
||||
TEST_CASE("storage/registry construction", "ensure entries from the registry can be retrieved") {
|
||||
const auto& script = R"(
|
||||
function f()
|
||||
return 2
|
||||
|
@ -23,7 +23,7 @@ end
|
|||
REQUIRE(isequal);
|
||||
}
|
||||
|
||||
TEST_CASE("storage/main-thread", "ensure round-tripping and pulling out thread data even on 5.1 with a backup works") {
|
||||
TEST_CASE("storage/main thread", "ensure round-tripping and pulling out thread data even on 5.1 with a backup works") {
|
||||
sol::state lua;
|
||||
{
|
||||
sol::stack_guard g(lua);
|
||||
|
|
69
test_utility.cpp
Normal file
69
test_utility.cpp
Normal file
|
@ -0,0 +1,69 @@
|
|||
#define SOL_CHECK_ARGUMENTS
|
||||
|
||||
#include <catch.hpp>
|
||||
#include <sol.hpp>
|
||||
|
||||
#ifdef SOL_CXX17_FEATURES
|
||||
#include <string_view>
|
||||
#include <variant>
|
||||
#endif
|
||||
|
||||
|
||||
TEST_CASE("utility/variant", "test that variant can be round-tripped") {
|
||||
#ifdef SOL_CXX17_FEATURES
|
||||
SECTION("okay") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.set_function("f", [](int v) {
|
||||
return v == 2;
|
||||
});
|
||||
lua.set_function("g", [](std::variant<float, int, std::string> vv) {
|
||||
int v = std::get<int>(vv);
|
||||
return v == 2;
|
||||
});
|
||||
lua["v"] = std::variant<float, int, std::string>(2);
|
||||
REQUIRE_NOTHROW([&]() {
|
||||
lua.script("assert(f(v))");
|
||||
lua.script("assert(g(v))");
|
||||
}());
|
||||
}
|
||||
SECTION("throws") {
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.set_function("f", [](int v) {
|
||||
return v == 2;
|
||||
});
|
||||
lua.set_function("g", [](std::variant<float, int, std::string> vv) {
|
||||
int v = std::get<int>(vv);
|
||||
return v == 2;
|
||||
});
|
||||
lua["v"] = std::variant<float, int, std::string>(std::string("bark"));
|
||||
REQUIRE_THROWS([&]() {
|
||||
lua.script("assert(f(v))");
|
||||
lua.script("assert(g(v))");
|
||||
}());
|
||||
}
|
||||
#else
|
||||
REQUIRE(true);
|
||||
#endif // C++17
|
||||
}
|
||||
|
||||
TEST_CASE("utility/string_view", "test that string_view can be taken as an argument") {
|
||||
#ifdef SOL_CXX17_FEATURES
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.set_function("f", [](std::string_view v) {
|
||||
return v == "bark!";
|
||||
});
|
||||
lua["v"] = "bark!";
|
||||
|
||||
REQUIRE_NOTHROW([&]() {
|
||||
lua.script("assert(f(v))");
|
||||
}());
|
||||
#else
|
||||
REQUIRE(true);
|
||||
#endif // C++17
|
||||
}
|
182
test_variadics.cpp
Normal file
182
test_variadics.cpp
Normal file
|
@ -0,0 +1,182 @@
|
|||
#define SOL_CHECK_ARGUMENTS
|
||||
|
||||
#include <catch.hpp>
|
||||
#include <sol.hpp>
|
||||
|
||||
#include <deque>
|
||||
#include <set>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
TEST_CASE("variadics/variadic_args", "Check to see we can receive multiple arguments through a variadic") {
|
||||
struct structure {
|
||||
int x;
|
||||
bool b;
|
||||
};
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
lua.set_function("v", [](sol::this_state, sol::variadic_args va) -> structure {
|
||||
int r = 0;
|
||||
for (auto v : va) {
|
||||
int value = v;
|
||||
r += value;
|
||||
}
|
||||
return{ r, r > 200 };
|
||||
});
|
||||
|
||||
lua.script("x = v(25, 25)");
|
||||
lua.script("x2 = v(25, 25, 100, 50, 250, 150)");
|
||||
lua.script("x3 = v(1, 2, 3, 4, 5, 6)");
|
||||
|
||||
structure& lx = lua["x"];
|
||||
structure& lx2 = lua["x2"];
|
||||
structure& lx3 = lua["x3"];
|
||||
REQUIRE(lx.x == 50);
|
||||
REQUIRE(lx2.x == 600);
|
||||
REQUIRE(lx3.x == 21);
|
||||
REQUIRE_FALSE(lx.b);
|
||||
REQUIRE(lx2.b);
|
||||
REQUIRE_FALSE(lx3.b);
|
||||
}
|
||||
|
||||
TEST_CASE("variadics/required with variadic_args", "Check if a certain number of arguments can still be required even when using variadic_args") {
|
||||
sol::state lua;
|
||||
lua.set_function("v",
|
||||
[](sol::this_state, sol::variadic_args, int, int) {
|
||||
}
|
||||
);
|
||||
REQUIRE_NOTHROW(lua.script("v(20, 25, 30)"));
|
||||
REQUIRE_NOTHROW(lua.script("v(20, 25)"));
|
||||
#ifndef SOL_LUAJIT
|
||||
REQUIRE_THROWS(lua.script("v(20)"));
|
||||
#endif // LuaJIT has problems with exceptions, as fucking usual
|
||||
}
|
||||
|
||||
TEST_CASE("variadics/variadic_args get type", "Make sure we can inspect types proper from variadic_args") {
|
||||
sol::state lua;
|
||||
|
||||
lua.set_function("f", [](sol::variadic_args va) {
|
||||
sol::type types[] = {
|
||||
sol::type::number,
|
||||
sol::type::string,
|
||||
sol::type::boolean
|
||||
};
|
||||
bool working = true;
|
||||
auto b = va.begin();
|
||||
for (std::size_t i = 0; i < va.size(); ++i, ++b) {
|
||||
sol::type t1 = va.get_type(i);
|
||||
sol::type t2 = b->get_type();
|
||||
working &= types[i] == t1;
|
||||
working &= types[i] == t2;
|
||||
}
|
||||
REQUIRE(working);
|
||||
});
|
||||
|
||||
lua.script("f(1, 'bark', true)");
|
||||
lua.script("f(2, 'wuf', false)");
|
||||
}
|
||||
|
||||
TEST_CASE("variadics/variadic_results", "returning a variable amount of arguments from C++") {
|
||||
SECTION("as_returns - containers") {
|
||||
sol::state lua;
|
||||
|
||||
lua.set_function("f", []() {
|
||||
std::set<std::string> results{ "arf", "bark", "woof" };
|
||||
return sol::as_returns(std::move(results));
|
||||
});
|
||||
lua.set_function("g", []() {
|
||||
static const std::deque<int> results{ 25, 82 };
|
||||
return sol::as_returns(std::ref(results));
|
||||
});
|
||||
|
||||
REQUIRE_NOTHROW([&]() {
|
||||
lua.script(R"(
|
||||
v1, v2, v3 = f()
|
||||
v4, v5 = g()
|
||||
)");
|
||||
}());
|
||||
|
||||
std::string v1 = lua["v1"];
|
||||
std::string v2 = lua["v2"];
|
||||
std::string v3 = lua["v3"];
|
||||
int v4 = lua["v4"];
|
||||
int v5 = lua["v5"];
|
||||
|
||||
REQUIRE(v1 == "arf");
|
||||
REQUIRE(v2 == "bark");
|
||||
REQUIRE(v3 == "woof");
|
||||
REQUIRE(v4 == 25);
|
||||
REQUIRE(v5 == 82);
|
||||
}
|
||||
SECTION("variadic_results - variadic_args") {
|
||||
sol::state lua;
|
||||
|
||||
lua.set_function("f", [](sol::variadic_args args) {
|
||||
return sol::variadic_results(args.cbegin(), args.cend());
|
||||
});
|
||||
|
||||
REQUIRE_NOTHROW([&]() {
|
||||
lua.script(R"(
|
||||
v1, v2, v3 = f(1, 'bark', true)
|
||||
v4, v5 = f(25, 82)
|
||||
)");
|
||||
}());
|
||||
|
||||
int v1 = lua["v1"];
|
||||
std::string v2 = lua["v2"];
|
||||
bool v3 = lua["v3"];
|
||||
int v4 = lua["v4"];
|
||||
int v5 = lua["v5"];
|
||||
|
||||
REQUIRE(v1 == 1);
|
||||
REQUIRE(v2 == "bark");
|
||||
REQUIRE(v3);
|
||||
REQUIRE(v4 == 25);
|
||||
REQUIRE(v5 == 82);
|
||||
}
|
||||
SECTION("variadic_results") {
|
||||
sol::state lua;
|
||||
|
||||
lua.set_function("f", [](sol::this_state ts, bool maybe) {
|
||||
if (maybe) {
|
||||
sol::variadic_results vr;
|
||||
vr.emplace_back(ts, sol::in_place<int>, 1);
|
||||
vr.push_back({ ts, sol::in_place, 2 });
|
||||
vr.insert(vr.cend(), { ts, sol::in_place, 3 });
|
||||
return vr;
|
||||
}
|
||||
else {
|
||||
sol::variadic_results vr;
|
||||
vr.emplace_back(ts, sol::in_place<const char*>, "bark");
|
||||
vr.push_back({ ts, sol::in_place<const char*>, "woof" });
|
||||
vr.insert(vr.cend(), { ts, sol::in_place<const char*>, "arf" });
|
||||
vr.emplace_back(ts, sol::in_place<const char*>, "borf");
|
||||
return vr;
|
||||
}
|
||||
});
|
||||
|
||||
REQUIRE_NOTHROW([&]() {
|
||||
lua.script(R"(
|
||||
v1, v2, v3 = f(true)
|
||||
v4, v5, v6, v7 = f(false)
|
||||
)");
|
||||
}());
|
||||
|
||||
int v1 = lua["v1"];
|
||||
int v2 = lua["v2"];
|
||||
int v3 = lua["v3"];
|
||||
std::string v4 = lua["v4"];
|
||||
std::string v5 = lua["v5"];
|
||||
std::string v6 = lua["v6"];
|
||||
std::string v7 = lua["v7"];
|
||||
|
||||
REQUIRE(v1 == 1);
|
||||
REQUIRE(v2 == 2);
|
||||
REQUIRE(v3 == 3);
|
||||
REQUIRE(v4 == "bark");
|
||||
REQUIRE(v5 == "woof");
|
||||
REQUIRE(v6 == "arf");
|
||||
REQUIRE(v7 == "borf");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user