fix destructor semantics of tests (fixes old iterator debug level problems)

Closes #361
add defines for #543
This commit is contained in:
ThePhD 2017-12-07 08:24:50 -05:00
parent e17c0a1a80
commit 7193115e24
24 changed files with 1086 additions and 592 deletions

View File

@ -5,6 +5,8 @@ because this is surprisingly hard using standard C++
Individuals using Visual Studio 2015, or on Windows with the VC++ and MinGW compilers (possibly Clang++ on Windows as well) have ``<codecvt>`` headers, and thusly Sol will attempt to include it. Individuals on GCC 4.9.x, Clang 3.5.x, Clang 3.6.x do not seem to have ``<codecvt>`` shipped with the standard library that comes with installation of these compilers. If you want ``std::wstring``, ``std::u16string``, ``std::u32string`` automatic handling then you need to make sure you have those headers and then define ``SOL_CODECVT_SUPPORT`` on unsupported compilers.
ThePhD did not want this to have to be a thing, but slow implementations and such force their hand. When GCC 7.x comes out, ThePhD will consider removing the effect of defining this macro and leaving <codecvt> support in at all times.
.. _codecvt-deprecation:
GCC 7.x is now out, and its codecvt support seems to work in it as well. We will be deprecating the conditional SOL_CODECVT support and deprecating support for GCC 4.x.x, Clang 3.5.x, and Clang 3.6.x in releases past sol2 v2.17.5
.. note::
Visual C++, in Visual Studio versions 15.5+ (``_MSC_VER >= 1912``), introduced deprecation macros when you are in ``/std:c++latest``. In order to get rid of codecvt issues, you need to define the silencing macros they ask for. It must be defined because despite the committee deprecating it, there is no useful standard alternative to perform these conversions (without, saying, including ``<Windows.h>`` on Windows machines, which is unacceptable).

View File

@ -8,7 +8,7 @@ supported compilers
GCC 7.x is now out alongside Visual Studio 2017. This means that `sol2 release v2.18.3`_ is the current version of the code targeted at the older compilers not listed below. Newer code will be targeted at working with the following compilers and leveraging their features, possibly taking advantage of whatever C++17 features are made available by the compilers and standard libraries bundled by-default with them.
``v2.18.2`` supports:
``v2.18.3`` supports:
* VC++
- Visual Studio 2017

View File

@ -21,7 +21,8 @@ A myriad of compiler errors can occur when something goes wrong. Here is some ba
* If you have a move-only type, that type may need to be made ``readonly`` if it is bound as a member variable on a usertype or bound using ``state_view::set_function``. See :doc:`sol::readonly<api/readonly>` for more details.
* Assigning a ``std::string`` or a ``std::pair<T1, T2>`` using ``operator=`` after it's been constructed can result in compiler errors when working with ``sol::function`` and its results. See `this issue for fixes to this behavior`_.
* Sometimes, using ``__stdcall`` in a 32-bit (x86) environment on VC++ can cause problems binding functions because of a compiler bug. We have a prelimanry fix in, but if it doesn't work and there are still problems: put the function in a ``std::function`` to make the compiler errors and other problems go away. Also see `this __stdcall issue report`_ for more details.
* If you are using ``/std:c++latest`` on VC++ and get a number of deprecation errors for ``<codecvt>`` and others, please see :ref:`this note here<codecvt-deprecation>`.
* If you are using ``/std:c++latest`` on VC++ and get a number of errors for ``noexcept`` specifiers on functions, you may need to file an issue or wait for the next release of the VC++ compiler.
Mac OSX Crashes
---------------

View File

@ -66,15 +66,15 @@ Note that you can obtain safety with regards to functions you bind by using the
* Turns on ``SOL_EXCEPTIONS_SAFE_PROPAGATION`` automatically for you
* Only use this if you know you've built your LuaJIT with the C++-specific invocations of your compiler (LuaJIT by default builds as C code)
``SOL_EXCEPTIONS_ALWAYS_UNSAFE`` triggers the following changes:
* If any of the ``SOL_USING_CXX_*`` defines are in play, it **does NOT** automatically turn on ``SOL_EXCEPTIONS_SAFE_PROPAGATION`` automatically
* This standardizes some behavior, since throwing exceptions through the C API's interface can still lead to undefined behavior that Lua cannot handle properly
``SOL_EXCEPTIONS_SAFE_PROPAGATION`` triggers the following changes:
* try/catch will not be used around C-function trampolines when going from Lua to C++
* try/catch will not be used in ``safe_``/``protected_function`` internals
* Should only be used in accordance with compiling vanilla PUC-RIO Lua as C++, using :ref:`LuaJIT under the proper conditions<exception-interop>`, or in accordance with your Lua distribution's documentation
``SOL_EXCEPTIONS_ALWAYS_UNSAFE`` triggers the following changes:
* If any of the ``SOL_USING_CXX_*`` defines are in play, it does not automatically turn on ``SOL_EXCEPTIONS_SAFE_PROPAGATION`` automatically
* This standardizes some behavior, since throwing exceptions through the C API's interface can still lead to undefined behavior that Lua cannot handle properly
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.
memory

View File

@ -3,11 +3,11 @@ threading
Lua has no thread safety. sol does not force thread safety bottlenecks anywhere. Tr(eat access and object handling like you were dealing with a raw ``int`` reference (``int&``) (no safety or order guarantees whatsoever).
Assume any access or any call on Lua affects the whole global state (because it does, in a fair bit of cases). Therefore, every call to a state should be blocked off in C++ with some kind of access control (when you're working with multiple C++ threads). When you start hitting the same state from multiple threads, race conditions (data or instruction) can happen.
Assume any access or any call on Lua affects the whole ``sol::state``/``lua_State*`` (because it does, in a fair bit of cases). Therefore, every call to a state should be blocked off in C++ with some kind of access control (when you're working with multiple C++ threads). When you start hitting the same state from multiple threads, race conditions (data or instruction) can happen.
Individual Lua coroutines might be able to run on separate C++-created threads without tanking the state utterly, since each Lua coroutine has the capability to run on an independent Lua execution stack (Lua confusingly calls it a ``thread`` in the C API, but it really just means a seperate execution stack) as well as some other associated bits and pieces that won't quite interfere with the global state.
To handle multithreaded environments, it is encouraged to either spawn a Lua state for each thread you are working with and keep inter-state communication to synchronized serialization points. This means that 3 C++ threads should each have their own Lua state, and access between them should be controlled using some kind of synchronied C++ mechanism (actual transfer between states must be done by serializing the value into C++ and then re-pushing it into the other state).
To handle multithreaded environments, it is encouraged to either spawn a Lua state (``sol::state``) for each thread you are working with and keep inter-state communication to synchronized serialization points. This means that 3 C++ threads should each have their own Lua state, and access between them should be controlled using some kind of synchronied C++ mechanism (actual transfer between states must be done by serializing the value into C++ and then re-pushing it into the other state).
Using coroutines and Lua's threads might also buy you some concurrency and parallelism (**unconfirmed and likely untrue, do not gamble on this**), but remember that Lua's 'threading' technique is ultimately cooperative and requires explicit yielding and resuming (simplified as function calls for :doc:`sol::coroutine<api/coroutine>`).

View File

@ -20,8 +20,8 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script.
// Generated 2017-12-01 23:47:06.820012 UTC
// This header was generated with sol v2.18.7 (revision a8b2c25)
// Generated 2017-12-07 13:23:41.409999 UTC
// This header was generated with sol v2.18.7 (revision e17c0a1)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_HPP
@ -64,13 +64,13 @@
// beginning of sol/feature_test.hpp
#if (defined(__cplusplus) && __cplusplus == 201703L) || (defined(_MSC_VER) && _MSC_VER > 1900 && ((defined(_HAS_CXX17) && _HAS_CXX17 == 1) || (defined(_MSVC_LANG) && _MSVC_LANG > 201402)))
#if (defined(__cplusplus) && __cplusplus == 201703L) || (defined(_MSC_VER) && _MSC_VER > 1900 && ((defined(_HAS_CXX17) && _HAS_CXX17 == 1) || (defined(_MSVC_LANG) && _MSVC_LANG > 201402L)))
#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)
#if defined(__cpp_noexcept_function_type) || ((defined(_MSC_VER) && _MSC_VER > 1911) && ((defined(_HAS_CXX17) && _HAS_CXX17 == 1) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)))
#ifndef SOL_NOEXCEPT_FUNCTION_TYPE
#define SOL_NOEXCEPT_FUNCTION_TYPE 1
#endif // noexcept is part of a function's type
@ -90,15 +90,17 @@
#endif // Windows/VC++ vs. g++ vs Others
#ifdef _MSC_VER
#ifdef _DEBUG
#ifndef NDEBUG
#ifndef SOL_CHECK_ARGUMENTS
#endif // Check Arguments
#ifndef SOL_SAFE_USERTYPE
#if defined(_DEBUG) && !defined(NDEBUG)
#if !defined(SOL_SAFE_REFERENCES)
#define SOL_SAFE_REFERENCES 1
#endif
#if !defined(SOL_SAFE_USERTYPE)
#define SOL_SAFE_USERTYPE 1
#endif // Safe Usertypes
#endif // NDEBUG
#endif // Debug
#endif
#endif // VC++ Debug macros
#ifndef _CPPUNWIND
#ifndef SOL_NO_EXCEPTIONS
@ -113,15 +115,17 @@
#endif // Automatic RTTI
#elif defined(__GNUC__) || defined(__clang__)
#ifndef NDEBUG
#ifndef __OPTIMIZE__
#ifndef SOL_CHECK_ARGUMENTS
#endif // Check Arguments
#ifndef SOL_SAFE_USERTYPE
#if !defined(NDEBUG) && !defined(__OPTIMIZE__)
#if !defined(SOL_SAFE_REFERENCES)
#define SOL_SAFE_REFERENCES 1
#endif
#if !defined(SOL_SAFE_USERTYPE)
#define SOL_SAFE_USERTYPE 1
#endif // Safe Usertypes
#endif // g++ optimizer flag
#endif // Not Debug
#endif
#endif // Not Debug && g++ optimizer flag
#ifndef __EXCEPTIONS
#ifndef SOL_NO_EXCEPTIONS
@ -137,11 +141,29 @@
#endif // vc++ || clang++/g++
#ifndef SOL_SAFE_USERTYPE
#ifdef SOL_CHECK_ARGUMENTS
#if defined(SOL_CHECK_ARGUMENTS)
#if !defined(SOL_SAFE_GETTER)
#define SOL_SAFE_GETTER 1
#endif
#if !defined(SOL_SAFE_USERTYPE)
#define SOL_SAFE_USERTYPE 1
#endif // Turn on Safety for all
#endif // Safe Usertypes
#endif
#if !defined(SOL_SAFE_REFERENCES)
#define SOL_SAFE_REFERENCES 1
#endif
#if !defined(SOL_SAFE_FUNCTION_CALLS)
#define SOL_SAFE_FUNCTION_CALLS 1
#endif
#if !defined(SOL_SAFE_PROXIES)
#define SOL_SAFE_PROXIES 1
#endif
#endif // Turn on Safety for all if top-level macro is defined
#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) || defined(__OBJC__) || defined(nil)
#ifndef SOL_NO_NIL
@ -1579,7 +1601,7 @@ namespace sol {
#ifdef SOL_USING_CXX_LUAJIT
#include <luajit.h>
#endif // C++ LuaJIT ... whatever that means
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) && !defined(SOL_EXCEPTIONS_UNSAFE_ALWAYS)
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) && !defined(SOL_EXCEPTIONS_ALWAYS_UNSAFE)
#define SOL_EXCEPTIONS_SAFE_PROPAGATION
#endif // Exceptions can be propagated safely using C++-compiled Lua
#else
@ -4193,8 +4215,9 @@ namespace sol {
struct default_construct {
template <typename T, typename... Args>
static void construct(T&& obj, Args&&... args) {
std::allocator<meta::unqualified_t<T>> alloc{};
alloc.construct(obj, std::forward<Args>(args)...);
typedef meta::unqualified_t<T> Tu;
std::allocator<Tu> alloc{};
std::allocator_traits<std::allocator<Tu>>::construct(alloc, obj, std::forward<Args>(args)...);
}
template <typename T, typename... Args>
@ -6889,7 +6912,7 @@ namespace sol {
T** pdata = static_cast<T**>(memory);
T* data = *pdata;
std::allocator<T> alloc{};
alloc.destroy(data);
std::allocator_traits<std::allocator<T>>::destroy(alloc, data);
return 0;
}
@ -6909,7 +6932,7 @@ namespace sol {
memory = align_user<T>(memory);
T* data = static_cast<T*>(memory);
std::allocator<T> alloc;
alloc.destroy(data);
std::allocator_traits<std::allocator<T>>::destroy(alloc, data);
return 0;
}
@ -6918,7 +6941,7 @@ namespace sol {
memory = align_usertype_unique<Real, true>(memory);
Real* target = static_cast<Real*>(memory);
std::allocator<Real> alloc;
alloc.destroy(target);
std::allocator_traits<std::allocator<Real>>::destroy(alloc, target);
}
template <typename T>
@ -9017,7 +9040,7 @@ namespace stack {
// just the sizeof(T*), and nothing else.
T* obj = detail::usertype_allocate<T>(L);
std::allocator<T> alloc{};
alloc.construct(obj, std::forward<Args>(args)...);
std::allocator_traits<std::allocator<T>>::construct(alloc, obj, std::forward<Args>(args)...);
f();
return 1;
}
@ -9398,8 +9421,8 @@ namespace stack {
static int push_with(lua_State* L, Key&& name, Args&&... args) {
// A dumb pusher
T* data = detail::user_allocate<T>(L);
std::allocator<T> alloc;
alloc.construct(data, std::forward<Args>(args)...);
std::allocator<T> alloc{};
std::allocator_traits<std::allocator<T>>::construct(alloc, data, std::forward<Args>(args)...);
if (with_meta) {
// Make sure we have a plain GC set for this data
if (luaL_newmetatable(L, name) != 0) {
@ -10551,13 +10574,12 @@ namespace sol {
namespace sol {
template <typename proxy_t, bool is_const>
struct stack_iterator : std::iterator<std::random_access_iterator_tag, std::conditional_t<is_const, const proxy_t, proxy_t>, std::ptrdiff_t, std::conditional_t<is_const, const proxy_t*, proxy_t*>, std::conditional_t<is_const, const proxy_t, proxy_t>> {
typedef std::iterator<std::random_access_iterator_tag, std::conditional_t<is_const, const proxy_t, proxy_t>, std::ptrdiff_t, std::conditional_t<is_const, const proxy_t*, proxy_t*>, std::conditional_t<is_const, const proxy_t, proxy_t>> base_t;
typedef typename base_t::reference reference;
typedef typename base_t::pointer pointer;
typedef typename base_t::value_type value_type;
typedef typename base_t::difference_type difference_type;
typedef typename base_t::iterator_category iterator_category;
struct stack_iterator {
typedef std::conditional_t<is_const, const proxy_t, proxy_t> reference;
typedef std::conditional_t<is_const, const proxy_t*, proxy_t*> pointer;
typedef proxy_t value_type;
typedef std::ptrdiff_t difference_type;
typedef std::random_access_iterator_tag iterator_category;
lua_State* L;
int index;
int stacktop;
@ -14053,14 +14075,16 @@ namespace sol {
template <bool b>
template <typename Super>
basic_reference<b>& basic_reference<b>::operator=(proxy_base<Super>&& r) {
this->operator=(r.operator basic_reference<b>());
basic_reference<b> v = r;
this->operator=(std::move(v));
return *this;
}
template <bool b>
template <typename Super>
basic_reference<b>& basic_reference<b>::operator=(const proxy_base<Super>& r) {
this->operator=(r.operator basic_reference<b>());
basic_reference<b> v = r;
this->operator=(std::move(v));
return *this;
}
@ -14967,6 +14991,28 @@ namespace sol {
return t.second;
}
struct error_result {
int results;
const char* fmt;
std::array<const char*, 4> args;
error_result() : results(0), fmt(nullptr), args({}) {
}
error_result(int results) : results(results), fmt(nullptr), args({}) {
}
error_result(const char* fmt, const char* msg) : results(0), fmt(fmt), args({ msg, nullptr, nullptr, nullptr }) {
}
};
inline int handle_errors(lua_State* L, const error_result& er) {
if (er.fmt == nullptr) {
return er.results;
}
return luaL_error(L, er.fmt, er.args[0], er.args[1], er.args[2], er.args[3]);
}
template <typename X, typename = void>
struct container_traits_default {
private:
@ -15096,21 +15142,21 @@ namespace sol {
#endif // Safe getting with error
}
static int get_associative(std::true_type, lua_State* L, iterator& it) {
static error_result get_associative(std::true_type, lua_State* L, iterator& it) {
auto& v = *it;
return stack::stack_detail::push_reference<push_type>(L, detail::deref(v.second));
}
static int get_associative(std::false_type, lua_State* L, iterator& it) {
static error_result get_associative(std::false_type, lua_State* L, iterator& it) {
return stack::stack_detail::push_reference<push_type>(L, detail::deref(*it));
}
static int get_category(std::input_iterator_tag, lua_State* L, T& self, K& key) {
static error_result get_category(std::input_iterator_tag, lua_State* L, T& self, K& key) {
if (key < 1) {
return stack::push(L, lua_nil);
}
auto it = begin(L, self);
auto e = end(L, self);
auto it = deferred_traits::begin(L, self);
auto e = deferred_traits::end(L, self);
if (it == e) {
return stack::push(L, lua_nil);
}
@ -15124,187 +15170,183 @@ namespace sol {
return get_associative(is_associative(), L, it);
}
static int get_category(std::random_access_iterator_tag, lua_State* L, T& self, K& key) {
static error_result get_category(std::random_access_iterator_tag, lua_State* L, T& self, K& key) {
std::ptrdiff_t len = static_cast<std::ptrdiff_t>(size_start(L, self));
if (key < 1 || key > len) {
return stack::push(L, lua_nil);
}
--key;
auto it = std::next(begin(L, self), key);
auto it = std::next(deferred_traits::begin(L, self), key);
return get_associative(is_associative(), L, it);
}
static int get_it(std::true_type, lua_State* L, T& self, K& key) {
static error_result get_it(std::true_type, lua_State* L, T& self, K& key) {
return get_category(iterator_category(), L, self, key);
}
static int get_comparative(std::true_type, lua_State* L, T& self, K& key) {
static error_result get_comparative(std::true_type, lua_State* L, T& self, K& key) {
auto fx = [&](const value_type& r) -> bool {
return key == get_key(is_associative(), r);
};
auto e = end(L, self);
auto it = std::find_if(begin(L, self), e, std::ref(fx));
auto e = deferred_traits::end(L, self);
auto it = std::find_if(deferred_traits::begin(L, self), e, std::ref(fx));
if (it == e) {
return stack::push(L, lua_nil);
}
return get_associative(is_associative(), L, it);
}
static int get_comparative(std::false_type, lua_State* L, T&, K&) {
return luaL_error(L, "cannot get this key on '%s': no suitable way to increment iterator and compare to key value '%s'", detail::demangle<T>().data(), detail::demangle<K>().data());
static error_result get_comparative(std::false_type, lua_State*, T&, K&) {
return error_result("cannot get this key on '%s': no suitable way to increment iterator and compare to key value '%s'", detail::demangle<T>().data(), detail::demangle<K>().data());
}
static int get_it(std::false_type, lua_State* L, T& self, K& key) {
static error_result get_it(std::false_type, lua_State* L, T& self, K& key) {
return get_comparative(meta::supports_op_equal<K, key_type>(), L, self, key);
}
static void set_associative(std::true_type, iterator& it, stack_object value) {
static error_result set_associative(std::true_type, iterator& it, stack_object value) {
auto& v = *it;
v.second = value.as<V>();
return {};
}
static void set_associative(std::false_type, iterator& it, stack_object value) {
static error_result set_associative(std::false_type, iterator& it, stack_object value) {
auto& v = *it;
v = value.as<V>();
return {};
}
static void set_writable(std::true_type, lua_State*, T&, iterator& it, stack_object value) {
set_associative(is_associative(), it, std::move(value));
static error_result set_writable(std::true_type, lua_State*, T&, iterator& it, stack_object value) {
return set_associative(is_associative(), it, std::move(value));
}
static void set_writable(std::false_type, lua_State* L, T&, iterator&, stack_object) {
luaL_error(L, "cannot perform a 'set': '%s's iterator reference is not writable (non-copy-assignable or const)", detail::demangle<T>().data());
static error_result set_writable(std::false_type, lua_State*, T&, iterator&, stack_object) {
return error_result("cannot perform a 'set': '%s's iterator reference is not writable (non-copy-assignable or const)", detail::demangle<T>().data());
}
static void set_category(std::input_iterator_tag, lua_State* L, T& self, stack_object okey, stack_object value) {
static error_result set_category(std::input_iterator_tag, lua_State* L, T& self, stack_object okey, stack_object value) {
decltype(auto) key = okey.as<K>();
auto e = end(L, self);
auto it = begin(L, self);
auto e = deferred_traits::end(L, self);
auto it = deferred_traits::begin(L, self);
auto backit = it;
for (; key > 1 && it != e; --key, ++it) {
backit = it;
}
if (it == e) {
if (key == 1) {
add_copyable(is_copyable(), L, self, std::move(value), meta::has_insert_after<T>::value ? backit : it);
return;
return add_copyable(is_copyable(), L, self, std::move(value), meta::has_insert_after<T>::value ? backit : it);
}
luaL_error(L, "out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str());
return;
return error_result("out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str());
}
set_writable(is_writable(), L, self, it, std::move(value));
return set_writable(is_writable(), L, self, it, std::move(value));
}
static void set_category(std::random_access_iterator_tag, lua_State* L, T& self, stack_object okey, stack_object value) {
static error_result set_category(std::random_access_iterator_tag, lua_State* L, T& self, stack_object okey, stack_object value) {
decltype(auto) key = okey.as<K>();
if (key < 1) {
luaL_error(L, "sol: out of bounds (too small) for set on '%s'", detail::demangle<T>().c_str());
return;
return error_result("sol: out of bounds (too small) for set on '%s'", detail::demangle<T>().c_str());
}
--key;
std::ptrdiff_t len = static_cast<std::ptrdiff_t>(size_start(L, self));
if (key == len) {
add_copyable(is_copyable(), L, self, std::move(value));
return;
return add_copyable(is_copyable(), L, self, std::move(value));
}
else if (key > len) {
luaL_error(L, "sol: out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str());
return;
return error_result("sol: out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str());
}
auto it = std::next(begin(L, self), key);
set_writable(is_writable(), L, self, it, std::move(value));
auto it = std::next(deferred_traits::begin(L, self), key);
return set_writable(is_writable(), L, self, it, std::move(value));
}
static void set_comparative(std::true_type, lua_State* L, T& self, stack_object okey, stack_object value) {
decltype(auto) key = okey.as<K>();
if (!is_writable::value) {
luaL_error(L, "cannot perform a 'set': '%s's iterator reference is not writable (non-copy-assignable or const)", detail::demangle<T>().data());
;
return;
return error_result("cannot perform a 'set': '%s's iterator reference is not writable (non-copy-assignable or const)", detail::demangle<T>().data());
}
auto fx = [&](const value_type& r) -> bool {
return key == get_key(is_associative(), r);
};
auto e = end(L, self);
auto it = std::find_if(begin(L, self), e, std::ref(fx));
auto e = deferred_traits::end(L, self);
auto it = std::find_if(deferred_traits::begin(L, self), e, std::ref(fx));
if (it == e) {
return;
return {};
}
set_writable(is_writable(), L, self, it, std::move(value));
return set_writable(is_writable(), L, self, it, std::move(value));
}
static void set_comparative(std::false_type, lua_State* L, T&, stack_object, stack_object) {
luaL_error(L, "cannot set this value on '%s': no suitable way to increment iterator or compare to '%s' key", detail::demangle<T>().data(), detail::demangle<K>().data());
static error_result set_comparative(std::false_type, lua_State*, T&, stack_object, stack_object) {
return error_result("cannot set this value on '%s': no suitable way to increment iterator or compare to '%s' key", detail::demangle<T>().data(), detail::demangle<K>().data());
}
static void set_associative_insert(std::true_type, lua_State*, T& self, iterator& it, K& key, stack_object value) {
static error_result set_associative_insert(std::true_type, lua_State*, T& self, iterator& it, K& key, stack_object value) {
self.insert(it, value_type(key, value.as<V>()));
return {};
}
static void set_associative_insert(std::false_type, lua_State*, T& self, iterator& it, K& key, stack_object) {
static error_result set_associative_insert(std::false_type, lua_State*, T& self, iterator& it, K& key, stack_object) {
self.insert(it, key);
return {};
}
static void set_associative_find(std::true_type, lua_State* L, T& self, stack_object okey, stack_object value) {
static error_result set_associative_find(std::true_type, lua_State* L, T& self, stack_object okey, stack_object value) {
decltype(auto) key = okey.as<K>();
auto it = self.find(key);
if (it == end(L, self)) {
set_associative_insert(is_associative(), L, self, it, key, std::move(value));
return;
if (it == deferred_traits::end(L, self)) {
return set_associative_insert(is_associative(), L, self, it, key, std::move(value));
}
set_writable(is_writable(), L, self, it, std::move(value));
return set_writable(is_writable(), L, self, it, std::move(value));
}
static void set_associative_find(std::false_type, lua_State* L, T& self, stack_object key, stack_object value) {
set_comparative(meta::supports_op_equal<K, key_type>(), L, self, std::move(key), std::move(value));
static error_result set_associative_find(std::false_type, lua_State* L, T& self, stack_object key, stack_object value) {
return set_comparative(meta::supports_op_equal<K, key_type>(), L, self, std::move(key), std::move(value));
}
static void set_it(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) {
set_category(iterator_category(), L, self, std::move(key), std::move(value));
static error_result set_it(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) {
return set_category(iterator_category(), L, self, std::move(key), std::move(value));
}
static void set_it(std::false_type, lua_State* L, T& self, stack_object key, stack_object value) {
set_associative_find(meta::all<has_find<T>, meta::any<is_associative, is_lookup>>(), L, self, std::move(key), std::move(value));
static error_result set_it(std::false_type, lua_State* L, T& self, stack_object key, stack_object value) {
return set_associative_find(meta::all<has_find<T>, meta::any<is_associative, is_lookup>>(), L, self, std::move(key), std::move(value));
}
static int find_has_associative_lookup(std::true_type, lua_State* L, T& self) {
static error_result find_has_associative_lookup(std::true_type, lua_State* L, T& self) {
decltype(auto) key = stack::get<K>(L, 2);
auto it = self.find(key);
if (it == end(L, self)) {
if (it == deferred_traits::end(L, self)) {
return stack::push(L, lua_nil);
}
return get_associative(is_associative(), L, it);
}
static int find_has_associative_lookup(std::false_type, lua_State* L, T& self) {
static error_result find_has_associative_lookup(std::false_type, lua_State* L, T& self) {
decltype(auto) value = stack::get<V>(L, 2);
auto it = self.find(value);
if (it == end(L, self)) {
if (it == deferred_traits::end(L, self)) {
return stack::push(L, lua_nil);
}
return get_associative(is_associative(), L, it);
}
static int find_has(std::true_type, lua_State* L, T& self) {
static error_result find_has(std::true_type, lua_State* L, T& self) {
return find_has_associative_lookup(meta::any<is_lookup, is_associative>(), L, self);
}
static int find_associative_lookup(std::true_type, lua_State* L, iterator& it, std::size_t) {
static error_result find_associative_lookup(std::true_type, lua_State* L, iterator& it, std::size_t) {
return get_associative(is_associative(), L, it);
}
static int find_associative_lookup(std::false_type, lua_State* L, iterator&, std::size_t index) {
static error_result find_associative_lookup(std::false_type, lua_State* L, iterator&, std::size_t index) {
return stack::push(L, index);
}
static int find_comparative(std::false_type, lua_State* L, T&) {
return luaL_error(L, "cannot call 'find' on '%s': there is no 'find' function and the value_type is not equality comparable", detail::demangle<T>().c_str());
static error_result find_comparative(std::false_type, lua_State*, T&) {
return error_result("cannot call 'find' on '%s': there is no 'find' function and the value_type is not equality comparable", detail::demangle<T>().c_str());
}
static int find_comparative(std::true_type, lua_State* L, T& self) {
static error_result find_comparative(std::true_type, lua_State* L, T& self) {
decltype(auto) value = stack::get<V>(L, 2);
auto it = begin(L, self);
auto e = end(L, self);
auto it = deferred_traits::begin(L, self);
auto e = deferred_traits::end(L, self);
std::size_t index = 1;
for (;; ++it, ++index) {
if (it == e) {
@ -15317,199 +15359,210 @@ namespace sol {
return find_associative_lookup(meta::any<is_lookup, is_associative>(), L, it, index);
}
static int find_has(std::false_type, lua_State* L, T& self) {
static error_result find_has(std::false_type, lua_State* L, T& self) {
return find_comparative(meta::supports_op_equal<V>(), L, self);
}
static void add_insert_after(std::false_type, lua_State* L, T& self, stack_object value, iterator&) {
add_insert_after(std::false_type(), L, self, value);
static error_result add_insert_after(std::false_type, lua_State* L, T& self, stack_object value, iterator&) {
return add_insert_after(std::false_type(), L, self, value);
}
static void add_insert_after(std::false_type, lua_State* L, T&, stack_object) {
luaL_error(L, "cannot call 'add' on type '%s': no suitable insert/push_back C++ functions", detail::demangle<T>().data());
static error_result add_insert_after(std::false_type, lua_State*, T&, stack_object) {
return error_result("cannot call 'add' on type '%s': no suitable insert/push_back C++ functions", detail::demangle<T>().data());
}
static void add_insert_after(std::true_type, lua_State*, T& self, stack_object value, iterator& at) {
static error_result add_insert_after(std::true_type, lua_State*, T& self, stack_object value, iterator& at) {
self.insert_after(at, value.as<V>());
return {};
}
static void add_insert_after(std::true_type, lua_State* L, T& self, stack_object value) {
static error_result add_insert_after(std::true_type, lua_State* L, T& self, stack_object value) {
auto backit = self.before_begin();
{
auto e = end(L, self);
for (auto it = begin(L, self); it != e; ++backit, ++it) {
auto e = deferred_traits::end(L, self);
for (auto it = deferred_traits::begin(L, self); it != e; ++backit, ++it) {
}
}
return add_insert_after(std::true_type(), L, self, value, backit);
}
static void add_insert(std::true_type, lua_State*, T& self, stack_object value, iterator& at) {
static error_result add_insert(std::true_type, lua_State*, T& self, stack_object value, iterator& at) {
self.insert(at, value.as<V>());
return {};
}
static void add_insert(std::true_type, lua_State* L, T& self, stack_object value) {
auto at = end(L, self);
add_insert(std::true_type(), L, self, value, at);
static error_result add_insert(std::true_type, lua_State* L, T& self, stack_object value) {
auto at = deferred_traits::end(L, self);
return add_insert(std::true_type(), L, self, value, at);
}
static void add_insert(std::false_type, lua_State* L, T& self, stack_object value, iterator& at) {
static error_result add_insert(std::false_type, lua_State* L, T& self, stack_object value, iterator& at) {
return add_insert_after(meta::has_insert_after<T>(), L, self, std::move(value), at);
}
static void add_insert(std::false_type, lua_State* L, T& self, stack_object value) {
static error_result add_insert(std::false_type, lua_State* L, T& self, stack_object value) {
return add_insert_after(meta::has_insert_after<T>(), L, self, std::move(value));
}
static void add_push_back(std::true_type, lua_State*, T& self, stack_object value, iterator&) {
static error_result add_push_back(std::true_type, lua_State*, T& self, stack_object value, iterator&) {
self.push_back(value.as<V>());
return {};
}
static void add_push_back(std::true_type, lua_State*, T& self, stack_object value) {
static error_result add_push_back(std::true_type, lua_State*, T& self, stack_object value) {
self.push_back(value.as<V>());
return {};
}
static void add_push_back(std::false_type, lua_State* L, T& self, stack_object value, iterator& at) {
add_insert(meta::has_insert<T>(), L, self, value, at);
static error_result add_push_back(std::false_type, lua_State* L, T& self, stack_object value, iterator& at) {
return add_insert(meta::has_insert<T>(), L, self, value, at);
}
static void add_push_back(std::false_type, lua_State* L, T& self, stack_object value) {
add_insert(meta::has_insert<T>(), L, self, value);
static error_result add_push_back(std::false_type, lua_State* L, T& self, stack_object value) {
return add_insert(meta::has_insert<T>(), L, self, value);
}
static void add_associative(std::true_type, lua_State* L, T& self, stack_object key, iterator& at) {
static error_result add_associative(std::true_type, lua_State* L, T& self, stack_object key, iterator& at) {
self.insert(at, value_type(key.as<K>(), stack::get<V>(L, 3)));
return {};
}
static void add_associative(std::true_type, lua_State* L, T& self, stack_object key) {
auto at = end(L, self);
add_associative(std::true_type(), L, self, std::move(key), at);
static error_result add_associative(std::true_type, lua_State* L, T& self, stack_object key) {
auto at = deferred_traits::end(L, self);
return add_associative(std::true_type(), L, self, std::move(key), at);
}
static void add_associative(std::false_type, lua_State* L, T& self, stack_object value, iterator& at) {
add_push_back(meta::has_push_back<T>(), L, self, value, at);
static error_result add_associative(std::false_type, lua_State* L, T& self, stack_object value, iterator& at) {
return add_push_back(meta::has_push_back<T>(), L, self, value, at);
}
static void add_associative(std::false_type, lua_State* L, T& self, stack_object value) {
add_push_back(meta::has_push_back<T>(), L, self, value);
static error_result add_associative(std::false_type, lua_State* L, T& self, stack_object value) {
return add_push_back(meta::has_push_back<T>(), L, self, value);
}
static void add_copyable(std::true_type, lua_State* L, T& self, stack_object value, iterator& at) {
add_associative(is_associative(), L, self, std::move(value), at);
static error_result add_copyable(std::true_type, lua_State* L, T& self, stack_object value, iterator& at) {
return add_associative(is_associative(), L, self, std::move(value), at);
}
static void add_copyable(std::true_type, lua_State* L, T& self, stack_object value) {
add_associative(is_associative(), L, self, value);
static error_result add_copyable(std::true_type, lua_State* L, T& self, stack_object value) {
return add_associative(is_associative(), L, self, value);
}
static void add_copyable(std::false_type, lua_State* L, T& self, stack_object value, iterator&) {
add_copyable(std::false_type(), L, self, std::move(value));
static error_result add_copyable(std::false_type, lua_State* L, T& self, stack_object value, iterator&) {
return add_copyable(std::false_type(), L, self, std::move(value));
}
static void add_copyable(std::false_type, lua_State* L, T&, stack_object) {
luaL_error(L, "cannot call 'add' on '%s': value_type is non-copyable", detail::demangle<T>().data());
static error_result add_copyable(std::false_type, lua_State*, T&, stack_object) {
return error_result("cannot call 'add' on '%s': value_type is non-copyable", detail::demangle<T>().data());
}
static void insert_lookup(std::true_type, lua_State* L, T& self, stack_object, stack_object value) {
static error_result insert_lookup(std::true_type, lua_State* L, T& self, stack_object, stack_object value) {
// TODO: should we warn or error about someone calling insert on an ordered / lookup container with no associativity?
add_copyable(std::true_type(), L, self, std::move(value));
return add_copyable(std::true_type(), L, self, std::move(value));
}
static void insert_lookup(std::false_type, lua_State* L, T& self, stack_object where, stack_object value) {
auto it = begin(L, self);
static error_result insert_lookup(std::false_type, lua_State* L, T& self, stack_object where, stack_object value) {
auto it = deferred_traits::begin(L, self);
auto key = where.as<K>();
--key;
std::advance(it, key);
self.insert(it, value.as<V>());
return {};
}
static void insert_after_has(std::true_type, lua_State* L, T& self, stack_object where, stack_object value) {
static error_result insert_after_has(std::true_type, lua_State* L, T& self, stack_object where, stack_object value) {
auto key = where.as<K>();
auto backit = self.before_begin();
{
--key;
auto e = end(L, self);
for (auto it = begin(L, self); key > 0; ++backit, ++it, --key) {
auto e = deferred_traits::end(L, self);
for (auto it = deferred_traits::begin(L, self); key > 0; ++backit, ++it, --key) {
if (backit == e) {
luaL_error(L, "sol: out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str());
return;
return error_result("sol: out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str());
}
}
}
self.insert_after(backit, value.as<V>());
return {};
}
static void insert_after_has(std::false_type, lua_State* L, T&, stack_object, stack_object) {
luaL_error(L, "cannot call 'insert' on '%s': no suitable or similar functionality detected on this container", detail::demangle<T>().data());
static error_result insert_after_has(std::false_type, lua_State*, T&, stack_object, stack_object) {
return error_result("cannot call 'insert' on '%s': no suitable or similar functionality detected on this container", detail::demangle<T>().data());
}
static void insert_has(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) {
insert_lookup(meta::all<is_associative, is_lookup>(), L, self, std::move(key), std::move(value));
static error_result insert_has(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) {
return insert_lookup(meta::all<is_associative, is_lookup>(), L, self, std::move(key), std::move(value));
}
static void insert_has(std::false_type, lua_State* L, T& self, stack_object where, stack_object value) {
insert_after_has(meta::has_insert_after<T>(), L, self, where, value);
static error_result insert_has(std::false_type, lua_State* L, T& self, stack_object where, stack_object value) {
return insert_after_has(meta::has_insert_after<T>(), L, self, where, value);
}
static void insert_copyable(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) {
insert_has(meta::has_insert<T>(), L, self, std::move(key), std::move(value));
static error_result insert_copyable(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) {
return insert_has(meta::has_insert<T>(), L, self, std::move(key), std::move(value));
}
static void insert_copyable(std::false_type, lua_State* L, T&, stack_object, stack_object) {
luaL_error(L, "cannot call 'insert' on '%s': value_type is non-copyable", detail::demangle<T>().data());
static error_result insert_copyable(std::false_type, lua_State*, T&, stack_object, stack_object) {
return error_result("cannot call 'insert' on '%s': value_type is non-copyable", detail::demangle<T>().data());
}
static void erase_integral(std::true_type, lua_State* L, T& self, K& key) {
auto it = begin(L, self);
static error_result erase_integral(std::true_type, lua_State* L, T& self, K& key) {
auto it = deferred_traits::begin(L, self);
--key;
std::advance(it, key);
self.erase(it);
return {};
}
static void erase_integral(std::false_type, lua_State* L, T& self, const K& key) {
static error_result erase_integral(std::false_type, lua_State* L, T& self, const K& key) {
auto fx = [&](const value_type& r) -> bool {
return key == r;
};
auto e = end(L, self);
auto it = std::find_if(begin(L, self), e, std::ref(fx));
auto e = deferred_traits::end(L, self);
auto it = std::find_if(deferred_traits::begin(L, self), e, std::ref(fx));
if (it == e) {
return;
return {};
}
self.erase(it);
return {};
}
static void erase_associative_lookup(std::true_type, lua_State*, T& self, const K& key) {
static error_result erase_associative_lookup(std::true_type, lua_State*, T& self, const K& key) {
self.erase(key);
return {};
}
static void erase_associative_lookup(std::false_type, lua_State* L, T& self, K& key) {
erase_integral(std::is_integral<K>(), L, self, key);
static error_result erase_associative_lookup(std::false_type, lua_State* L, T& self, K& key) {
return erase_integral(std::is_integral<K>(), L, self, key);
}
static void erase_after_has(std::true_type, lua_State* L, T& self, K& key) {
static error_result erase_after_has(std::true_type, lua_State* L, T& self, K& key) {
auto backit = self.before_begin();
{
--key;
auto e = end(L, self);
for (auto it = begin(L, self); key > 0; ++backit, ++it, --key) {
auto e = deferred_traits::end(L, self);
for (auto it = deferred_traits::begin(L, self); key > 0; ++backit, ++it, --key) {
if (backit == e) {
luaL_error(L, "sol: out of bounds for erase on '%s'", detail::demangle<T>().c_str());
return;
return error_result("sol: out of bounds for erase on '%s'", detail::demangle<T>().c_str());
}
}
}
self.erase_after(backit);
return {};
}
static void erase_after_has(std::false_type, lua_State* L, T&, const K&) {
luaL_error(L, "sol: cannot call erase on '%s'", detail::demangle<T>().c_str());
static error_result erase_after_has(std::false_type, lua_State*, T&, const K&) {
return error_result("sol: cannot call erase on '%s'", detail::demangle<T>().c_str());
}
static void erase_has(std::true_type, lua_State* L, T& self, K& key) {
erase_associative_lookup(meta::any<is_associative, is_lookup>(), L, self, key);
static error_result erase_has(std::true_type, lua_State* L, T& self, K& key) {
return erase_associative_lookup(meta::any<is_associative, is_lookup>(), L, self, key);
}
static void erase_has(std::false_type, lua_State* L, T& self, K& key) {
erase_after_has(has_erase_after<T>(), L, self, key);
static error_result erase_has(std::false_type, lua_State* L, T& self, K& key) {
return erase_after_has(has_erase_after<T>(), L, self, key);
}
static auto size_has(std::false_type, lua_State* L, T& self) {
@ -15536,12 +15589,12 @@ namespace sol {
return deferred_traits::begin(L, self) == deferred_traits::end(L, self);
}
static int get_start(lua_State* L, T& self, K& key) {
static error_result get_start(lua_State* L, T& self, K& key) {
return get_it(is_linear_integral(), L, self, key);
}
static void set_start(lua_State* L, T& self, stack_object key, stack_object value) {
set_it(is_linear_integral(), L, self, std::move(key), std::move(value));
static error_result set_start(lua_State* L, T& self, stack_object key, stack_object value) {
return set_it(is_linear_integral(), L, self, std::move(key), std::move(value));
}
static std::size_t size_start(lua_State* L, T& self) {
@ -15555,9 +15608,9 @@ namespace sol {
static bool empty_start(lua_State* L, T& self) {
return empty_has(has_empty<T>(), L, self);
}
static void erase_start(lua_State* L, T& self, K& key) {
erase_has(has_erase<T>(), L, self, key);
static error_result erase_start(lua_State* L, T& self, K& key) {
return erase_has(has_erase<T>(), L, self, key);
}
template <bool ip>
@ -15623,8 +15676,12 @@ namespace sol {
public:
static int get(lua_State* L) {
auto& self = get_src(L);
decltype(auto) key = stack::get<K>(L);
return get_start(L, self, key);
error_result er;
{
decltype(auto) key = stack::get<K>(L);
er = get_start(L, self, key);
}
return handle_errors(L, er);
}
static int index_get(lua_State* L) {
@ -15637,8 +15694,8 @@ namespace sol {
return erase(L);
}
auto& self = get_src(L);
set_start(L, self, stack_object(L, raw_index(2)), std::move(value));
return 0;
error_result er = set_start(L, self, stack_object(L, raw_index(2)), std::move(value));
return handle_errors(L, er);
}
static int index_set(lua_State* L) {
@ -15647,19 +15704,20 @@ namespace sol {
static int add(lua_State* L) {
auto& self = get_src(L);
add_copyable(is_copyable(), L, self, stack_object(L, raw_index(2)));
return 0;
error_result er = add_copyable(is_copyable(), L, self, stack_object(L, raw_index(2)));
return handle_errors(L, er);
}
static int insert(lua_State* L) {
auto& self = get_src(L);
insert_copyable(is_copyable(), L, self, stack_object(L, raw_index(2)), stack_object(L, raw_index(3)));
return 0;
error_result er = insert_copyable(is_copyable(), L, self, stack_object(L, raw_index(2)), stack_object(L, raw_index(3)));
return handle_errors(L, er);
}
static int find(lua_State* L) {
auto& self = get_src(L);
return find_has(has_find<T>(), L, self);
error_result er = find_has(has_find<T>(), L, self);
return handle_errors(L, er);
}
static iterator begin(lua_State*, T& self) {
@ -15686,9 +15744,12 @@ namespace sol {
static int erase(lua_State* L) {
auto& self = get_src(L);
decltype(auto) key = stack::get<K>(L, 2);
erase_start(L, self, key);
return 0;
error_result er;
{
decltype(auto) key = stack::get<K>(L, 2);
er = erase_start(L, self, key);
}
return handle_errors(L, er);
}
static int empty(lua_State* L) {
@ -17909,17 +17970,14 @@ namespace sol {
template <typename reference_type>
class basic_table_iterator : public std::iterator<std::input_iterator_tag, std::pair<object, object>> {
private:
typedef std::iterator<std::input_iterator_tag, std::pair<object, object>> base_t;
public:
typedef object key_type;
typedef object mapped_type;
typedef base_t::value_type value_type;
typedef base_t::iterator_category iterator_category;
typedef base_t::difference_type difference_type;
typedef base_t::pointer pointer;
typedef base_t::reference reference;
typedef std::pair<object, object> value_type;
typedef std::input_iterator_tag iterator_category;
typedef std::ptrdiff_t difference_type;
typedef value_type* pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
private:
@ -19884,8 +19942,7 @@ namespace sol {
}
protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) {
int stacksize = lua_gettop(lua_state());
int firstreturn = (std::max)(1, stacksize - static_cast<int>(n));
int firstreturn = 1;
luacall(n, LUA_MULTRET);
int poststacksize = lua_gettop(lua_state());
int returncount = poststacksize - (firstreturn - 1);
@ -19975,7 +20032,6 @@ namespace sol {
// and try to use it with sol::coroutine without ever calling the first resume in Lua
// this makes the stack incompatible with other kinds of stacks: protect against this
// make sure coroutines don't screw us over
stack::coroutine_create_guard(lua_state());
base_t::push();
int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...);
return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount);

View File

@ -31,7 +31,7 @@
#ifdef SOL_USING_CXX_LUAJIT
#include <luajit.h>
#endif // C++ LuaJIT ... whatever that means
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) && !defined(SOL_EXCEPTIONS_UNSAFE_ALWAYS)
#if !defined(SOL_EXCEPTIONS_SAFE_PROPAGATION) && !defined(SOL_EXCEPTIONS_ALWAYS_UNSAFE)
#define SOL_EXCEPTIONS_SAFE_PROPAGATION
#endif // Exceptions can be propagated safely using C++-compiled Lua
#else

View File

@ -401,6 +401,28 @@ namespace sol {
return t.second;
}
struct error_result {
int results;
const char* fmt;
std::array<const char*, 4> args;
error_result() : results(0), fmt(nullptr), args({}) {
}
error_result(int results) : results(results), fmt(nullptr), args({}) {
}
error_result(const char* fmt, const char* msg) : results(0), fmt(fmt), args({ msg, nullptr, nullptr, nullptr }) {
}
};
inline int handle_errors(lua_State* L, const error_result& er) {
if (er.fmt == nullptr) {
return er.results;
}
return luaL_error(L, er.fmt, er.args[0], er.args[1], er.args[2], er.args[3]);
}
template <typename X, typename = void>
struct container_traits_default {
private:
@ -530,21 +552,21 @@ namespace sol {
#endif // Safe getting with error
}
static int get_associative(std::true_type, lua_State* L, iterator& it) {
static error_result get_associative(std::true_type, lua_State* L, iterator& it) {
auto& v = *it;
return stack::stack_detail::push_reference<push_type>(L, detail::deref(v.second));
}
static int get_associative(std::false_type, lua_State* L, iterator& it) {
static error_result get_associative(std::false_type, lua_State* L, iterator& it) {
return stack::stack_detail::push_reference<push_type>(L, detail::deref(*it));
}
static int get_category(std::input_iterator_tag, lua_State* L, T& self, K& key) {
static error_result get_category(std::input_iterator_tag, lua_State* L, T& self, K& key) {
if (key < 1) {
return stack::push(L, lua_nil);
}
auto it = begin(L, self);
auto e = end(L, self);
auto it = deferred_traits::begin(L, self);
auto e = deferred_traits::end(L, self);
if (it == e) {
return stack::push(L, lua_nil);
}
@ -558,187 +580,183 @@ namespace sol {
return get_associative(is_associative(), L, it);
}
static int get_category(std::random_access_iterator_tag, lua_State* L, T& self, K& key) {
static error_result get_category(std::random_access_iterator_tag, lua_State* L, T& self, K& key) {
std::ptrdiff_t len = static_cast<std::ptrdiff_t>(size_start(L, self));
if (key < 1 || key > len) {
return stack::push(L, lua_nil);
}
--key;
auto it = std::next(begin(L, self), key);
auto it = std::next(deferred_traits::begin(L, self), key);
return get_associative(is_associative(), L, it);
}
static int get_it(std::true_type, lua_State* L, T& self, K& key) {
static error_result get_it(std::true_type, lua_State* L, T& self, K& key) {
return get_category(iterator_category(), L, self, key);
}
static int get_comparative(std::true_type, lua_State* L, T& self, K& key) {
static error_result get_comparative(std::true_type, lua_State* L, T& self, K& key) {
auto fx = [&](const value_type& r) -> bool {
return key == get_key(is_associative(), r);
};
auto e = end(L, self);
auto it = std::find_if(begin(L, self), e, std::ref(fx));
auto e = deferred_traits::end(L, self);
auto it = std::find_if(deferred_traits::begin(L, self), e, std::ref(fx));
if (it == e) {
return stack::push(L, lua_nil);
}
return get_associative(is_associative(), L, it);
}
static int get_comparative(std::false_type, lua_State* L, T&, K&) {
return luaL_error(L, "cannot get this key on '%s': no suitable way to increment iterator and compare to key value '%s'", detail::demangle<T>().data(), detail::demangle<K>().data());
static error_result get_comparative(std::false_type, lua_State*, T&, K&) {
return error_result("cannot get this key on '%s': no suitable way to increment iterator and compare to key value '%s'", detail::demangle<T>().data(), detail::demangle<K>().data());
}
static int get_it(std::false_type, lua_State* L, T& self, K& key) {
static error_result get_it(std::false_type, lua_State* L, T& self, K& key) {
return get_comparative(meta::supports_op_equal<K, key_type>(), L, self, key);
}
static void set_associative(std::true_type, iterator& it, stack_object value) {
static error_result set_associative(std::true_type, iterator& it, stack_object value) {
auto& v = *it;
v.second = value.as<V>();
return {};
}
static void set_associative(std::false_type, iterator& it, stack_object value) {
static error_result set_associative(std::false_type, iterator& it, stack_object value) {
auto& v = *it;
v = value.as<V>();
return {};
}
static void set_writable(std::true_type, lua_State*, T&, iterator& it, stack_object value) {
set_associative(is_associative(), it, std::move(value));
static error_result set_writable(std::true_type, lua_State*, T&, iterator& it, stack_object value) {
return set_associative(is_associative(), it, std::move(value));
}
static void set_writable(std::false_type, lua_State* L, T&, iterator&, stack_object) {
luaL_error(L, "cannot perform a 'set': '%s's iterator reference is not writable (non-copy-assignable or const)", detail::demangle<T>().data());
static error_result set_writable(std::false_type, lua_State*, T&, iterator&, stack_object) {
return error_result("cannot perform a 'set': '%s's iterator reference is not writable (non-copy-assignable or const)", detail::demangle<T>().data());
}
static void set_category(std::input_iterator_tag, lua_State* L, T& self, stack_object okey, stack_object value) {
static error_result set_category(std::input_iterator_tag, lua_State* L, T& self, stack_object okey, stack_object value) {
decltype(auto) key = okey.as<K>();
auto e = end(L, self);
auto it = begin(L, self);
auto e = deferred_traits::end(L, self);
auto it = deferred_traits::begin(L, self);
auto backit = it;
for (; key > 1 && it != e; --key, ++it) {
backit = it;
}
if (it == e) {
if (key == 1) {
add_copyable(is_copyable(), L, self, std::move(value), meta::has_insert_after<T>::value ? backit : it);
return;
return add_copyable(is_copyable(), L, self, std::move(value), meta::has_insert_after<T>::value ? backit : it);
}
luaL_error(L, "out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str());
return;
return error_result("out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str());
}
set_writable(is_writable(), L, self, it, std::move(value));
return set_writable(is_writable(), L, self, it, std::move(value));
}
static void set_category(std::random_access_iterator_tag, lua_State* L, T& self, stack_object okey, stack_object value) {
static error_result set_category(std::random_access_iterator_tag, lua_State* L, T& self, stack_object okey, stack_object value) {
decltype(auto) key = okey.as<K>();
if (key < 1) {
luaL_error(L, "sol: out of bounds (too small) for set on '%s'", detail::demangle<T>().c_str());
return;
return error_result("sol: out of bounds (too small) for set on '%s'", detail::demangle<T>().c_str());
}
--key;
std::ptrdiff_t len = static_cast<std::ptrdiff_t>(size_start(L, self));
if (key == len) {
add_copyable(is_copyable(), L, self, std::move(value));
return;
return add_copyable(is_copyable(), L, self, std::move(value));
}
else if (key > len) {
luaL_error(L, "sol: out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str());
return;
return error_result("sol: out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str());
}
auto it = std::next(begin(L, self), key);
set_writable(is_writable(), L, self, it, std::move(value));
auto it = std::next(deferred_traits::begin(L, self), key);
return set_writable(is_writable(), L, self, it, std::move(value));
}
static void set_comparative(std::true_type, lua_State* L, T& self, stack_object okey, stack_object value) {
decltype(auto) key = okey.as<K>();
if (!is_writable::value) {
luaL_error(L, "cannot perform a 'set': '%s's iterator reference is not writable (non-copy-assignable or const)", detail::demangle<T>().data());
;
return;
return error_result("cannot perform a 'set': '%s's iterator reference is not writable (non-copy-assignable or const)", detail::demangle<T>().data());
}
auto fx = [&](const value_type& r) -> bool {
return key == get_key(is_associative(), r);
};
auto e = end(L, self);
auto it = std::find_if(begin(L, self), e, std::ref(fx));
auto e = deferred_traits::end(L, self);
auto it = std::find_if(deferred_traits::begin(L, self), e, std::ref(fx));
if (it == e) {
return;
return {};
}
set_writable(is_writable(), L, self, it, std::move(value));
return set_writable(is_writable(), L, self, it, std::move(value));
}
static void set_comparative(std::false_type, lua_State* L, T&, stack_object, stack_object) {
luaL_error(L, "cannot set this value on '%s': no suitable way to increment iterator or compare to '%s' key", detail::demangle<T>().data(), detail::demangle<K>().data());
static error_result set_comparative(std::false_type, lua_State*, T&, stack_object, stack_object) {
return error_result("cannot set this value on '%s': no suitable way to increment iterator or compare to '%s' key", detail::demangle<T>().data(), detail::demangle<K>().data());
}
static void set_associative_insert(std::true_type, lua_State*, T& self, iterator& it, K& key, stack_object value) {
static error_result set_associative_insert(std::true_type, lua_State*, T& self, iterator& it, K& key, stack_object value) {
self.insert(it, value_type(key, value.as<V>()));
return {};
}
static void set_associative_insert(std::false_type, lua_State*, T& self, iterator& it, K& key, stack_object) {
static error_result set_associative_insert(std::false_type, lua_State*, T& self, iterator& it, K& key, stack_object) {
self.insert(it, key);
return {};
}
static void set_associative_find(std::true_type, lua_State* L, T& self, stack_object okey, stack_object value) {
static error_result set_associative_find(std::true_type, lua_State* L, T& self, stack_object okey, stack_object value) {
decltype(auto) key = okey.as<K>();
auto it = self.find(key);
if (it == end(L, self)) {
set_associative_insert(is_associative(), L, self, it, key, std::move(value));
return;
if (it == deferred_traits::end(L, self)) {
return set_associative_insert(is_associative(), L, self, it, key, std::move(value));
}
set_writable(is_writable(), L, self, it, std::move(value));
return set_writable(is_writable(), L, self, it, std::move(value));
}
static void set_associative_find(std::false_type, lua_State* L, T& self, stack_object key, stack_object value) {
set_comparative(meta::supports_op_equal<K, key_type>(), L, self, std::move(key), std::move(value));
static error_result set_associative_find(std::false_type, lua_State* L, T& self, stack_object key, stack_object value) {
return set_comparative(meta::supports_op_equal<K, key_type>(), L, self, std::move(key), std::move(value));
}
static void set_it(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) {
set_category(iterator_category(), L, self, std::move(key), std::move(value));
static error_result set_it(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) {
return set_category(iterator_category(), L, self, std::move(key), std::move(value));
}
static void set_it(std::false_type, lua_State* L, T& self, stack_object key, stack_object value) {
set_associative_find(meta::all<has_find<T>, meta::any<is_associative, is_lookup>>(), L, self, std::move(key), std::move(value));
static error_result set_it(std::false_type, lua_State* L, T& self, stack_object key, stack_object value) {
return set_associative_find(meta::all<has_find<T>, meta::any<is_associative, is_lookup>>(), L, self, std::move(key), std::move(value));
}
static int find_has_associative_lookup(std::true_type, lua_State* L, T& self) {
static error_result find_has_associative_lookup(std::true_type, lua_State* L, T& self) {
decltype(auto) key = stack::get<K>(L, 2);
auto it = self.find(key);
if (it == end(L, self)) {
if (it == deferred_traits::end(L, self)) {
return stack::push(L, lua_nil);
}
return get_associative(is_associative(), L, it);
}
static int find_has_associative_lookup(std::false_type, lua_State* L, T& self) {
static error_result find_has_associative_lookup(std::false_type, lua_State* L, T& self) {
decltype(auto) value = stack::get<V>(L, 2);
auto it = self.find(value);
if (it == end(L, self)) {
if (it == deferred_traits::end(L, self)) {
return stack::push(L, lua_nil);
}
return get_associative(is_associative(), L, it);
}
static int find_has(std::true_type, lua_State* L, T& self) {
static error_result find_has(std::true_type, lua_State* L, T& self) {
return find_has_associative_lookup(meta::any<is_lookup, is_associative>(), L, self);
}
static int find_associative_lookup(std::true_type, lua_State* L, iterator& it, std::size_t) {
static error_result find_associative_lookup(std::true_type, lua_State* L, iterator& it, std::size_t) {
return get_associative(is_associative(), L, it);
}
static int find_associative_lookup(std::false_type, lua_State* L, iterator&, std::size_t index) {
static error_result find_associative_lookup(std::false_type, lua_State* L, iterator&, std::size_t index) {
return stack::push(L, index);
}
static int find_comparative(std::false_type, lua_State* L, T&) {
return luaL_error(L, "cannot call 'find' on '%s': there is no 'find' function and the value_type is not equality comparable", detail::demangle<T>().c_str());
static error_result find_comparative(std::false_type, lua_State*, T&) {
return error_result("cannot call 'find' on '%s': there is no 'find' function and the value_type is not equality comparable", detail::demangle<T>().c_str());
}
static int find_comparative(std::true_type, lua_State* L, T& self) {
static error_result find_comparative(std::true_type, lua_State* L, T& self) {
decltype(auto) value = stack::get<V>(L, 2);
auto it = begin(L, self);
auto e = end(L, self);
auto it = deferred_traits::begin(L, self);
auto e = deferred_traits::end(L, self);
std::size_t index = 1;
for (;; ++it, ++index) {
if (it == e) {
@ -751,199 +769,210 @@ namespace sol {
return find_associative_lookup(meta::any<is_lookup, is_associative>(), L, it, index);
}
static int find_has(std::false_type, lua_State* L, T& self) {
static error_result find_has(std::false_type, lua_State* L, T& self) {
return find_comparative(meta::supports_op_equal<V>(), L, self);
}
static void add_insert_after(std::false_type, lua_State* L, T& self, stack_object value, iterator&) {
add_insert_after(std::false_type(), L, self, value);
static error_result add_insert_after(std::false_type, lua_State* L, T& self, stack_object value, iterator&) {
return add_insert_after(std::false_type(), L, self, value);
}
static void add_insert_after(std::false_type, lua_State* L, T&, stack_object) {
luaL_error(L, "cannot call 'add' on type '%s': no suitable insert/push_back C++ functions", detail::demangle<T>().data());
static error_result add_insert_after(std::false_type, lua_State*, T&, stack_object) {
return error_result("cannot call 'add' on type '%s': no suitable insert/push_back C++ functions", detail::demangle<T>().data());
}
static void add_insert_after(std::true_type, lua_State*, T& self, stack_object value, iterator& at) {
static error_result add_insert_after(std::true_type, lua_State*, T& self, stack_object value, iterator& at) {
self.insert_after(at, value.as<V>());
return {};
}
static void add_insert_after(std::true_type, lua_State* L, T& self, stack_object value) {
static error_result add_insert_after(std::true_type, lua_State* L, T& self, stack_object value) {
auto backit = self.before_begin();
{
auto e = end(L, self);
for (auto it = begin(L, self); it != e; ++backit, ++it) {
auto e = deferred_traits::end(L, self);
for (auto it = deferred_traits::begin(L, self); it != e; ++backit, ++it) {
}
}
return add_insert_after(std::true_type(), L, self, value, backit);
}
static void add_insert(std::true_type, lua_State*, T& self, stack_object value, iterator& at) {
static error_result add_insert(std::true_type, lua_State*, T& self, stack_object value, iterator& at) {
self.insert(at, value.as<V>());
return {};
}
static void add_insert(std::true_type, lua_State* L, T& self, stack_object value) {
auto at = end(L, self);
add_insert(std::true_type(), L, self, value, at);
static error_result add_insert(std::true_type, lua_State* L, T& self, stack_object value) {
auto at = deferred_traits::end(L, self);
return add_insert(std::true_type(), L, self, value, at);
}
static void add_insert(std::false_type, lua_State* L, T& self, stack_object value, iterator& at) {
static error_result add_insert(std::false_type, lua_State* L, T& self, stack_object value, iterator& at) {
return add_insert_after(meta::has_insert_after<T>(), L, self, std::move(value), at);
}
static void add_insert(std::false_type, lua_State* L, T& self, stack_object value) {
static error_result add_insert(std::false_type, lua_State* L, T& self, stack_object value) {
return add_insert_after(meta::has_insert_after<T>(), L, self, std::move(value));
}
static void add_push_back(std::true_type, lua_State*, T& self, stack_object value, iterator&) {
static error_result add_push_back(std::true_type, lua_State*, T& self, stack_object value, iterator&) {
self.push_back(value.as<V>());
return {};
}
static void add_push_back(std::true_type, lua_State*, T& self, stack_object value) {
static error_result add_push_back(std::true_type, lua_State*, T& self, stack_object value) {
self.push_back(value.as<V>());
return {};
}
static void add_push_back(std::false_type, lua_State* L, T& self, stack_object value, iterator& at) {
add_insert(meta::has_insert<T>(), L, self, value, at);
static error_result add_push_back(std::false_type, lua_State* L, T& self, stack_object value, iterator& at) {
return add_insert(meta::has_insert<T>(), L, self, value, at);
}
static void add_push_back(std::false_type, lua_State* L, T& self, stack_object value) {
add_insert(meta::has_insert<T>(), L, self, value);
static error_result add_push_back(std::false_type, lua_State* L, T& self, stack_object value) {
return add_insert(meta::has_insert<T>(), L, self, value);
}
static void add_associative(std::true_type, lua_State* L, T& self, stack_object key, iterator& at) {
static error_result add_associative(std::true_type, lua_State* L, T& self, stack_object key, iterator& at) {
self.insert(at, value_type(key.as<K>(), stack::get<V>(L, 3)));
return {};
}
static void add_associative(std::true_type, lua_State* L, T& self, stack_object key) {
auto at = end(L, self);
add_associative(std::true_type(), L, self, std::move(key), at);
static error_result add_associative(std::true_type, lua_State* L, T& self, stack_object key) {
auto at = deferred_traits::end(L, self);
return add_associative(std::true_type(), L, self, std::move(key), at);
}
static void add_associative(std::false_type, lua_State* L, T& self, stack_object value, iterator& at) {
add_push_back(meta::has_push_back<T>(), L, self, value, at);
static error_result add_associative(std::false_type, lua_State* L, T& self, stack_object value, iterator& at) {
return add_push_back(meta::has_push_back<T>(), L, self, value, at);
}
static void add_associative(std::false_type, lua_State* L, T& self, stack_object value) {
add_push_back(meta::has_push_back<T>(), L, self, value);
static error_result add_associative(std::false_type, lua_State* L, T& self, stack_object value) {
return add_push_back(meta::has_push_back<T>(), L, self, value);
}
static void add_copyable(std::true_type, lua_State* L, T& self, stack_object value, iterator& at) {
add_associative(is_associative(), L, self, std::move(value), at);
static error_result add_copyable(std::true_type, lua_State* L, T& self, stack_object value, iterator& at) {
return add_associative(is_associative(), L, self, std::move(value), at);
}
static void add_copyable(std::true_type, lua_State* L, T& self, stack_object value) {
add_associative(is_associative(), L, self, value);
static error_result add_copyable(std::true_type, lua_State* L, T& self, stack_object value) {
return add_associative(is_associative(), L, self, value);
}
static void add_copyable(std::false_type, lua_State* L, T& self, stack_object value, iterator&) {
add_copyable(std::false_type(), L, self, std::move(value));
static error_result add_copyable(std::false_type, lua_State* L, T& self, stack_object value, iterator&) {
return add_copyable(std::false_type(), L, self, std::move(value));
}
static void add_copyable(std::false_type, lua_State* L, T&, stack_object) {
luaL_error(L, "cannot call 'add' on '%s': value_type is non-copyable", detail::demangle<T>().data());
static error_result add_copyable(std::false_type, lua_State*, T&, stack_object) {
return error_result("cannot call 'add' on '%s': value_type is non-copyable", detail::demangle<T>().data());
}
static void insert_lookup(std::true_type, lua_State* L, T& self, stack_object, stack_object value) {
static error_result insert_lookup(std::true_type, lua_State* L, T& self, stack_object, stack_object value) {
// TODO: should we warn or error about someone calling insert on an ordered / lookup container with no associativity?
add_copyable(std::true_type(), L, self, std::move(value));
return add_copyable(std::true_type(), L, self, std::move(value));
}
static void insert_lookup(std::false_type, lua_State* L, T& self, stack_object where, stack_object value) {
auto it = begin(L, self);
static error_result insert_lookup(std::false_type, lua_State* L, T& self, stack_object where, stack_object value) {
auto it = deferred_traits::begin(L, self);
auto key = where.as<K>();
--key;
std::advance(it, key);
self.insert(it, value.as<V>());
return {};
}
static void insert_after_has(std::true_type, lua_State* L, T& self, stack_object where, stack_object value) {
static error_result insert_after_has(std::true_type, lua_State* L, T& self, stack_object where, stack_object value) {
auto key = where.as<K>();
auto backit = self.before_begin();
{
--key;
auto e = end(L, self);
for (auto it = begin(L, self); key > 0; ++backit, ++it, --key) {
auto e = deferred_traits::end(L, self);
for (auto it = deferred_traits::begin(L, self); key > 0; ++backit, ++it, --key) {
if (backit == e) {
luaL_error(L, "sol: out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str());
return;
return error_result("sol: out of bounds (too big) for set on '%s'", detail::demangle<T>().c_str());
}
}
}
self.insert_after(backit, value.as<V>());
return {};
}
static void insert_after_has(std::false_type, lua_State* L, T&, stack_object, stack_object) {
luaL_error(L, "cannot call 'insert' on '%s': no suitable or similar functionality detected on this container", detail::demangle<T>().data());
static error_result insert_after_has(std::false_type, lua_State*, T&, stack_object, stack_object) {
return error_result("cannot call 'insert' on '%s': no suitable or similar functionality detected on this container", detail::demangle<T>().data());
}
static void insert_has(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) {
insert_lookup(meta::all<is_associative, is_lookup>(), L, self, std::move(key), std::move(value));
static error_result insert_has(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) {
return insert_lookup(meta::all<is_associative, is_lookup>(), L, self, std::move(key), std::move(value));
}
static void insert_has(std::false_type, lua_State* L, T& self, stack_object where, stack_object value) {
insert_after_has(meta::has_insert_after<T>(), L, self, where, value);
static error_result insert_has(std::false_type, lua_State* L, T& self, stack_object where, stack_object value) {
return insert_after_has(meta::has_insert_after<T>(), L, self, where, value);
}
static void insert_copyable(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) {
insert_has(meta::has_insert<T>(), L, self, std::move(key), std::move(value));
static error_result insert_copyable(std::true_type, lua_State* L, T& self, stack_object key, stack_object value) {
return insert_has(meta::has_insert<T>(), L, self, std::move(key), std::move(value));
}
static void insert_copyable(std::false_type, lua_State* L, T&, stack_object, stack_object) {
luaL_error(L, "cannot call 'insert' on '%s': value_type is non-copyable", detail::demangle<T>().data());
static error_result insert_copyable(std::false_type, lua_State*, T&, stack_object, stack_object) {
return error_result("cannot call 'insert' on '%s': value_type is non-copyable", detail::demangle<T>().data());
}
static void erase_integral(std::true_type, lua_State* L, T& self, K& key) {
auto it = begin(L, self);
static error_result erase_integral(std::true_type, lua_State* L, T& self, K& key) {
auto it = deferred_traits::begin(L, self);
--key;
std::advance(it, key);
self.erase(it);
return {};
}
static void erase_integral(std::false_type, lua_State* L, T& self, const K& key) {
static error_result erase_integral(std::false_type, lua_State* L, T& self, const K& key) {
auto fx = [&](const value_type& r) -> bool {
return key == r;
};
auto e = end(L, self);
auto it = std::find_if(begin(L, self), e, std::ref(fx));
auto e = deferred_traits::end(L, self);
auto it = std::find_if(deferred_traits::begin(L, self), e, std::ref(fx));
if (it == e) {
return;
return {};
}
self.erase(it);
return {};
}
static void erase_associative_lookup(std::true_type, lua_State*, T& self, const K& key) {
static error_result erase_associative_lookup(std::true_type, lua_State*, T& self, const K& key) {
self.erase(key);
return {};
}
static void erase_associative_lookup(std::false_type, lua_State* L, T& self, K& key) {
erase_integral(std::is_integral<K>(), L, self, key);
static error_result erase_associative_lookup(std::false_type, lua_State* L, T& self, K& key) {
return erase_integral(std::is_integral<K>(), L, self, key);
}
static void erase_after_has(std::true_type, lua_State* L, T& self, K& key) {
static error_result erase_after_has(std::true_type, lua_State* L, T& self, K& key) {
auto backit = self.before_begin();
{
--key;
auto e = end(L, self);
for (auto it = begin(L, self); key > 0; ++backit, ++it, --key) {
auto e = deferred_traits::end(L, self);
for (auto it = deferred_traits::begin(L, self); key > 0; ++backit, ++it, --key) {
if (backit == e) {
luaL_error(L, "sol: out of bounds for erase on '%s'", detail::demangle<T>().c_str());
return;
return error_result("sol: out of bounds for erase on '%s'", detail::demangle<T>().c_str());
}
}
}
self.erase_after(backit);
return {};
}
static void erase_after_has(std::false_type, lua_State* L, T&, const K&) {
luaL_error(L, "sol: cannot call erase on '%s'", detail::demangle<T>().c_str());
static error_result erase_after_has(std::false_type, lua_State*, T&, const K&) {
return error_result("sol: cannot call erase on '%s'", detail::demangle<T>().c_str());
}
static void erase_has(std::true_type, lua_State* L, T& self, K& key) {
erase_associative_lookup(meta::any<is_associative, is_lookup>(), L, self, key);
static error_result erase_has(std::true_type, lua_State* L, T& self, K& key) {
return erase_associative_lookup(meta::any<is_associative, is_lookup>(), L, self, key);
}
static void erase_has(std::false_type, lua_State* L, T& self, K& key) {
erase_after_has(has_erase_after<T>(), L, self, key);
static error_result erase_has(std::false_type, lua_State* L, T& self, K& key) {
return erase_after_has(has_erase_after<T>(), L, self, key);
}
static auto size_has(std::false_type, lua_State* L, T& self) {
@ -970,12 +999,12 @@ namespace sol {
return deferred_traits::begin(L, self) == deferred_traits::end(L, self);
}
static int get_start(lua_State* L, T& self, K& key) {
static error_result get_start(lua_State* L, T& self, K& key) {
return get_it(is_linear_integral(), L, self, key);
}
static void set_start(lua_State* L, T& self, stack_object key, stack_object value) {
set_it(is_linear_integral(), L, self, std::move(key), std::move(value));
static error_result set_start(lua_State* L, T& self, stack_object key, stack_object value) {
return set_it(is_linear_integral(), L, self, std::move(key), std::move(value));
}
static std::size_t size_start(lua_State* L, T& self) {
@ -989,9 +1018,9 @@ namespace sol {
static bool empty_start(lua_State* L, T& self) {
return empty_has(has_empty<T>(), L, self);
}
static void erase_start(lua_State* L, T& self, K& key) {
erase_has(has_erase<T>(), L, self, key);
static error_result erase_start(lua_State* L, T& self, K& key) {
return erase_has(has_erase<T>(), L, self, key);
}
template <bool ip>
@ -1057,8 +1086,12 @@ namespace sol {
public:
static int get(lua_State* L) {
auto& self = get_src(L);
decltype(auto) key = stack::get<K>(L);
return get_start(L, self, key);
error_result er;
{
decltype(auto) key = stack::get<K>(L);
er = get_start(L, self, key);
}
return handle_errors(L, er);
}
static int index_get(lua_State* L) {
@ -1071,8 +1104,8 @@ namespace sol {
return erase(L);
}
auto& self = get_src(L);
set_start(L, self, stack_object(L, raw_index(2)), std::move(value));
return 0;
error_result er = set_start(L, self, stack_object(L, raw_index(2)), std::move(value));
return handle_errors(L, er);
}
static int index_set(lua_State* L) {
@ -1081,19 +1114,20 @@ namespace sol {
static int add(lua_State* L) {
auto& self = get_src(L);
add_copyable(is_copyable(), L, self, stack_object(L, raw_index(2)));
return 0;
error_result er = add_copyable(is_copyable(), L, self, stack_object(L, raw_index(2)));
return handle_errors(L, er);
}
static int insert(lua_State* L) {
auto& self = get_src(L);
insert_copyable(is_copyable(), L, self, stack_object(L, raw_index(2)), stack_object(L, raw_index(3)));
return 0;
error_result er = insert_copyable(is_copyable(), L, self, stack_object(L, raw_index(2)), stack_object(L, raw_index(3)));
return handle_errors(L, er);
}
static int find(lua_State* L) {
auto& self = get_src(L);
return find_has(has_find<T>(), L, self);
error_result er = find_has(has_find<T>(), L, self);
return handle_errors(L, er);
}
static iterator begin(lua_State*, T& self) {
@ -1120,9 +1154,12 @@ namespace sol {
static int erase(lua_State* L) {
auto& self = get_src(L);
decltype(auto) key = stack::get<K>(L, 2);
erase_start(L, self, key);
return 0;
error_result er;
{
decltype(auto) key = stack::get<K>(L, 2);
er = erase_start(L, self, key);
}
return handle_errors(L, er);
}
static int empty(lua_State* L) {

View File

@ -55,8 +55,7 @@ namespace sol {
}
protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) {
int stacksize = lua_gettop(lua_state());
int firstreturn = (std::max)(1, stacksize - static_cast<int>(n));
int firstreturn = 1;
luacall(n, LUA_MULTRET);
int poststacksize = lua_gettop(lua_state());
int returncount = poststacksize - (firstreturn - 1);
@ -146,7 +145,6 @@ namespace sol {
// and try to use it with sol::coroutine without ever calling the first resume in Lua
// this makes the stack incompatible with other kinds of stacks: protect against this
// make sure coroutines don't screw us over
stack::coroutine_create_guard(lua_state());
base_t::push();
int pushcount = stack::multi_push_reference(lua_state(), std::forward<Args>(args)...);
return invoke(types<Ret...>(), std::make_index_sequence<sizeof...(Ret)>(), pushcount);

View File

@ -22,13 +22,13 @@
#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) || (defined(_MSVC_LANG) && _MSVC_LANG > 201402)))
#if (defined(__cplusplus) && __cplusplus == 201703L) || (defined(_MSC_VER) && _MSC_VER > 1900 && ((defined(_HAS_CXX17) && _HAS_CXX17 == 1) || (defined(_MSVC_LANG) && _MSVC_LANG > 201402L)))
#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)
#if defined(__cpp_noexcept_function_type) || ((defined(_MSC_VER) && _MSC_VER > 1911) && ((defined(_HAS_CXX17) && _HAS_CXX17 == 1) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)))
#ifndef SOL_NOEXCEPT_FUNCTION_TYPE
#define SOL_NOEXCEPT_FUNCTION_TYPE 1
#endif // noexcept is part of a function's type
@ -50,17 +50,19 @@
#endif // Windows/VC++ vs. g++ vs Others
#ifdef _MSC_VER
#ifdef _DEBUG
#ifndef NDEBUG
#ifndef SOL_CHECK_ARGUMENTS
// Do not define by default: let user turn it on
//#define SOL_CHECK_ARGUMENTS
#endif // Check Arguments
#ifndef SOL_SAFE_USERTYPE
#if defined(_DEBUG) && !defined(NDEBUG)
#if !defined(SOL_SAFE_REFERENCES)
// Ensure that references are forcefully type-checked upon construction
#define SOL_SAFE_REFERENCES 1
#endif
#if !defined(SOL_SAFE_USERTYPE)
// Usertypes should be safe no matter what
#define SOL_SAFE_USERTYPE 1
#endif // Safe Usertypes
#endif // NDEBUG
#endif // Debug
#endif
#endif // VC++ Debug macros
#ifndef _CPPUNWIND
#ifndef SOL_NO_EXCEPTIONS
@ -75,18 +77,19 @@
#endif // Automatic RTTI
#elif defined(__GNUC__) || defined(__clang__)
#ifndef NDEBUG
#ifndef __OPTIMIZE__
#ifndef SOL_CHECK_ARGUMENTS
// Do not define by default: let user choose
//#define SOL_CHECK_ARGUMENTS
// But do check userdata by default:
#endif // Check Arguments
#ifndef SOL_SAFE_USERTYPE
#if !defined(NDEBUG) && !defined(__OPTIMIZE__)
#if !defined(SOL_SAFE_REFERENCES)
// Ensure that references are forcefully type-checked upon construction
#define SOL_SAFE_REFERENCES 1
#endif
#if !defined(SOL_SAFE_USERTYPE)
// Usertypes should be safe no matter what
#define SOL_SAFE_USERTYPE 1
#endif // Safe Usertypes
#endif // g++ optimizer flag
#endif // Not Debug
#endif
#endif // Not Debug && g++ optimizer flag
#ifndef __EXCEPTIONS
#ifndef SOL_NO_EXCEPTIONS
@ -102,11 +105,47 @@
#endif // vc++ || clang++/g++
#ifndef SOL_SAFE_USERTYPE
#ifdef SOL_CHECK_ARGUMENTS
#if defined(SOL_CHECK_ARGUMENTS)
// turn things on automatically
// Checks low-level getter function
// (and thusly, affects nearly entire framework)
#if !defined(SOL_SAFE_GETTER)
#define SOL_SAFE_GETTER 1
#endif
// Checks access on usertype functions
// local my_obj = my_type.new()
// my_obj.my_member_function()
// -- bad syntax and crash
#if !defined(SOL_SAFE_USERTYPE)
#define SOL_SAFE_USERTYPE 1
#endif // Turn on Safety for all
#endif // Safe Usertypes
#endif
// Checks sol::reference derived boundaries
// sol::function ref(L, 1);
// sol::userdata sref(L, 2);
#if !defined(SOL_SAFE_REFERENCES)
#define SOL_SAFE_REFERENCES 1
#endif
// Checks function parameters and
// returns upon call into/from Lua
// local a = 1
// local b = "woof"
// my_c_function(a, b)
#if !defined(SOL_SAFE_FUNCTION_CALLS)
#define SOL_SAFE_FUNCTION_CALLS 1
#endif
// Checks conversions
// int v = lua["bark"];
// int v2 = my_sol_function();
#if !defined(SOL_SAFE_PROXIES)
#define SOL_SAFE_PROXIES 1
#endif
#endif // Turn on Safety for all if top-level macro is defined
#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) || defined(__OBJC__) || defined(nil)
#ifndef SOL_NO_NIL

View File

@ -202,14 +202,16 @@ namespace sol {
template <bool b>
template <typename Super>
basic_reference<b>& basic_reference<b>::operator=(proxy_base<Super>&& r) {
this->operator=(r.operator basic_reference<b>());
basic_reference<b> v = r;
this->operator=(std::move(v));
return *this;
}
template <bool b>
template <typename Super>
basic_reference<b>& basic_reference<b>::operator=(const proxy_base<Super>& r) {
this->operator=(r.operator basic_reference<b>());
basic_reference<b> v = r;
this->operator=(std::move(v));
return *this;
}

View File

@ -31,8 +31,9 @@ namespace sol {
struct default_construct {
template <typename T, typename... Args>
static void construct(T&& obj, Args&&... args) {
std::allocator<meta::unqualified_t<T>> alloc{};
alloc.construct(obj, std::forward<Args>(args)...);
typedef meta::unqualified_t<T> Tu;
std::allocator<Tu> alloc{};
std::allocator_traits<std::allocator<Tu>>::construct(alloc, obj, std::forward<Args>(args)...);
}
template <typename T, typename... Args>

View File

@ -389,7 +389,7 @@ namespace sol {
T** pdata = static_cast<T**>(memory);
T* data = *pdata;
std::allocator<T> alloc{};
alloc.destroy(data);
std::allocator_traits<std::allocator<T>>::destroy(alloc, data);
return 0;
}
@ -409,7 +409,7 @@ namespace sol {
memory = align_user<T>(memory);
T* data = static_cast<T*>(memory);
std::allocator<T> alloc;
alloc.destroy(data);
std::allocator_traits<std::allocator<T>>::destroy(alloc, data);
return 0;
}
@ -418,7 +418,7 @@ namespace sol {
memory = align_usertype_unique<Real, true>(memory);
Real* target = static_cast<Real*>(memory);
std::allocator<Real> alloc;
alloc.destroy(target);
std::allocator_traits<std::allocator<Real>>::destroy(alloc, target);
}
template <typename T>

View File

@ -28,13 +28,12 @@
namespace sol {
template <typename proxy_t, bool is_const>
struct stack_iterator : std::iterator<std::random_access_iterator_tag, std::conditional_t<is_const, const proxy_t, proxy_t>, std::ptrdiff_t, std::conditional_t<is_const, const proxy_t*, proxy_t*>, std::conditional_t<is_const, const proxy_t, proxy_t>> {
typedef std::iterator<std::random_access_iterator_tag, std::conditional_t<is_const, const proxy_t, proxy_t>, std::ptrdiff_t, std::conditional_t<is_const, const proxy_t*, proxy_t*>, std::conditional_t<is_const, const proxy_t, proxy_t>> base_t;
typedef typename base_t::reference reference;
typedef typename base_t::pointer pointer;
typedef typename base_t::value_type value_type;
typedef typename base_t::difference_type difference_type;
typedef typename base_t::iterator_category iterator_category;
struct stack_iterator {
typedef std::conditional_t<is_const, const proxy_t, proxy_t> reference;
typedef std::conditional_t<is_const, const proxy_t*, proxy_t*> pointer;
typedef proxy_t value_type;
typedef std::ptrdiff_t difference_type;
typedef std::random_access_iterator_tag iterator_category;
lua_State* L;
int index;
int stacktop;

View File

@ -75,7 +75,7 @@ namespace stack {
// just the sizeof(T*), and nothing else.
T* obj = detail::usertype_allocate<T>(L);
std::allocator<T> alloc{};
alloc.construct(obj, std::forward<Args>(args)...);
std::allocator_traits<std::allocator<T>>::construct(alloc, obj, std::forward<Args>(args)...);
f();
return 1;
}
@ -456,8 +456,8 @@ namespace stack {
static int push_with(lua_State* L, Key&& name, Args&&... args) {
// A dumb pusher
T* data = detail::user_allocate<T>(L);
std::allocator<T> alloc;
alloc.construct(data, std::forward<Args>(args)...);
std::allocator<T> alloc{};
std::allocator_traits<std::allocator<T>>::construct(alloc, data, std::forward<Args>(args)...);
if (with_meta) {
// Make sure we have a plain GC set for this data
if (luaL_newmetatable(L, name) != 0) {

View File

@ -29,17 +29,14 @@ namespace sol {
template <typename reference_type>
class basic_table_iterator : public std::iterator<std::input_iterator_tag, std::pair<object, object>> {
private:
typedef std::iterator<std::input_iterator_tag, std::pair<object, object>> base_t;
public:
typedef object key_type;
typedef object mapped_type;
typedef base_t::value_type value_type;
typedef base_t::iterator_category iterator_category;
typedef base_t::difference_type difference_type;
typedef base_t::pointer pointer;
typedef base_t::reference reference;
typedef std::pair<object, object> value_type;
typedef std::input_iterator_tag iterator_category;
typedef std::ptrdiff_t difference_type;
typedef value_type* pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
private:

View File

@ -326,11 +326,21 @@ TEST_CASE("containers/custom usertype", "make sure container usertype metatables
"size", &bark::size, "at", sol::resolve<const int&>(&bark::at), "clear", &bark::clear);
bark obj{ { 24, 50 } };
lua.set("a", &obj);
REQUIRE_NOTHROW(lua.safe_script("assert(a:at(24) == 50)"));
REQUIRE_NOTHROW(lua.safe_script("a:something()"));
{
auto result0 = lua.safe_script("assert(a:at(24) == 50)", sol::script_pass_on_error);
REQUIRE(result0.valid());
auto result1 = lua.safe_script("a:something()");
REQUIRE(result1.valid());
}
lua.set("a", obj);
REQUIRE_NOTHROW(lua.safe_script("assert(a:at(24) == 50)"));
REQUIRE_NOTHROW(lua.safe_script("a:something()"));
{
auto result = lua.safe_script("assert(a:at(24) == 50)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("a:something()", sol::script_pass_on_error);
REQUIRE(result.valid());
}
}
TEST_CASE("containers/const serialization kvp", "make sure const keys / values are respected") {
@ -338,12 +348,16 @@ TEST_CASE("containers/const serialization kvp", "make sure const keys / values a
sol::state lua;
lua.open_libraries();
bark obj{ { 24, 50 } };
lua.set("a", &obj);
REQUIRE_NOTHROW(lua.safe_script("assert(a[24] == 50)"));
auto result = lua.safe_script("a[24] = 51", sol::script_pass_on_error);
REQUIRE_FALSE(result.valid());
REQUIRE_NOTHROW(lua.safe_script("assert(a[24] == 50)"));
{
bark obj{ { 24, 50 } };
lua.set("a", std::ref(obj));
auto result0 = lua.safe_script("assert(a[24] == 50)", sol::script_pass_on_error);
REQUIRE(result0.valid());
auto result = lua.safe_script("a[24] = 51", sol::script_pass_on_error);
REQUIRE_FALSE(result.valid());
auto result2 = lua.safe_script("assert(a[24] == 50)", sol::script_pass_on_error);
REQUIRE(result2.valid());
}
}
TEST_CASE("containers/basic serialization", "make sure containers are turned into proper userdata and have basic hooks established") {
@ -351,18 +365,26 @@ TEST_CASE("containers/basic serialization", "make sure containers are turned int
sol::state lua;
lua.open_libraries();
lua.set("b", woof{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 });
REQUIRE_NOTHROW(
lua.safe_script("for k = 1, #b do assert(k == b[k]) end"));
{
auto result = lua.safe_script("for k = 1, #b do assert(k == b[k]) end", sol::script_pass_on_error);
REQUIRE(result.valid());
}
woof w{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 };
lua.set("b", w);
REQUIRE_NOTHROW(
lua.safe_script("for k = 1, #b do assert(k == b[k]) end"));
{
auto result = lua.safe_script("for k = 1, #b do assert(k == b[k]) end", sol::script_pass_on_error);
REQUIRE(result.valid());
}
lua.set("b", &w);
REQUIRE_NOTHROW(
lua.safe_script("for k = 1, #b do assert(k == b[k]) end"));
{
auto result = lua.safe_script("for k = 1, #b do assert(k == b[k]) end", sol::script_pass_on_error);
REQUIRE(result.valid());
}
lua.set("b", std::ref(w));
REQUIRE_NOTHROW(
lua.safe_script("for k = 1, #b do assert(k == b[k]) end"));
{
auto result = lua.safe_script("for k = 1, #b do assert(k == b[k]) end", sol::script_pass_on_error);
REQUIRE(result.valid());
}
}
#if 0 // LUL const int holders
@ -371,11 +393,14 @@ TEST_CASE("containers/const serialization", "make sure containers are turned int
sol::state lua;
lua.open_libraries();
lua.set("b", woof{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 });
REQUIRE_NOTHROW(
lua.safe_script("for k, v in pairs(b) do assert(k == v) end");
);
auto result = lua.safe_script("b[1] = 20", sol::script_pass_on_error);
REQUIRE_FALSE(result.valid());
{
auto result = lua.safe_script("for k, v in pairs(b) do assert(k == v) end", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("b[1] = 20", sol::script_pass_on_error);
REQUIRE_FALSE(result.valid());
}
}
#endif
@ -384,18 +409,26 @@ TEST_CASE("containers/table serialization", "ensure types can be serialized as t
sol::state lua;
lua.open_libraries();
lua.set("b", sol::as_table(woof{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 }));
REQUIRE_NOTHROW(
lua.safe_script("for k, v in ipairs(b) do assert(k == v) end"));
{
auto result = lua.safe_script("for k, v in ipairs(b) do assert(k == v) end", sol::script_pass_on_error);
REQUIRE(result.valid());
}
woof w{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 };
lua.set("b", sol::as_table(w));
REQUIRE_NOTHROW(
lua.safe_script("for k, v in ipairs(b) do assert(k == v) end"));
{
auto result = lua.safe_script("for k, v in ipairs(b) do assert(k == v) end", sol::script_pass_on_error);
REQUIRE(result.valid());
}
lua.set("b", sol::as_table(&w));
REQUIRE_NOTHROW(
lua.safe_script("for k, v in ipairs(b) do assert(k == v) end"));
{
auto result = lua.safe_script("for k, v in ipairs(b) do assert(k == v) end", sol::script_pass_on_error);
REQUIRE(result.valid());
}
lua.set("b", sol::as_table(std::ref(w)));
REQUIRE_NOTHROW(
lua.safe_script("for k, v in ipairs(b) do assert(k == v) end"));
{
auto result = lua.safe_script("for k, v in ipairs(b) do assert(k == v) end", sol::script_pass_on_error);
REQUIRE(result.valid());
}
}
TEST_CASE("containers/const correctness", "usertype metatable names should reasonably ignore const attributes") {
@ -441,20 +474,59 @@ TEST_CASE("containers/arbitrary creation", "userdata and tables should be usable
lua.set_function("test_three", test_table_return_three);
lua.set_function("test_four", test_table_return_four);
REQUIRE_NOTHROW(lua.safe_script("a = test_one()"));
REQUIRE_NOTHROW(lua.safe_script("b = test_two()"));
REQUIRE_NOTHROW(lua.safe_script("c = test_three()"));
REQUIRE_NOTHROW(lua.safe_script("d = test_four()"));
{
auto result = lua.safe_script("a = test_one()", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("b = test_two()", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("c = test_three()", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("d = test_four()", sol::script_pass_on_error);
REQUIRE(result.valid());
}
REQUIRE_NOTHROW(lua.safe_script("assert(#a == 10, 'error')"));
REQUIRE_NOTHROW(lua.safe_script("assert(a[3] == 3, 'error')"));
REQUIRE_NOTHROW(lua.safe_script("assert(b.one == 1, 'error')"));
REQUIRE_NOTHROW(lua.safe_script("assert(b.three == 3, 'error')"));
REQUIRE_NOTHROW(lua.safe_script("assert(c.name == 'Rapptz', 'error')"));
REQUIRE_NOTHROW(lua.safe_script("assert(c.project == 'sol', 'error')"));
REQUIRE_NOTHROW(lua.safe_script("assert(d.one == 1, 'error')"));
REQUIRE_NOTHROW(lua.safe_script("assert(d.three == 3, 'error')"));
REQUIRE_NOTHROW(lua.safe_script("assert(d.four == 4, 'error')"));
{
auto result = lua.safe_script("assert(#a == 10, 'error')", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("assert(a[3] == 3, 'error')", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("assert(b.one == 1, 'error')", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("assert(b.three == 3, 'error')", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("assert(c.name == 'Rapptz', 'error')", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("assert(c.project == 'sol', 'error')", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("assert(d.one == 1, 'error')", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("assert(d.three == 3, 'error')", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("assert(d.four == 4, 'error')", sol::script_pass_on_error);
REQUIRE(result.valid());
}
sol::table a = lua.get<sol::table>("a");
sol::table b = lua.get<sol::table>("b");
@ -765,8 +837,15 @@ TEST_CASE("containers/input iterators", "test shitty input iterators that are al
int x_ = -1;
};
class input_it : public std::iterator<std::input_iterator_tag, int_shim> {
class input_it {
public:
typedef std::input_iterator_tag iterator_category;
typedef int_shim value_type;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef value_type* pointer;
typedef std::ptrdiff_t difference_type;
input_it() = default;
input_it(int n, int m)

View File

@ -403,3 +403,77 @@ loop_th = coroutine.create(loop)
REQUIRE(v2 == 2);
REQUIRE(v3 == 3);
}
TEST_CASE("coroutines/stack-check", "check that resumed functions consume the entire execution stack") {
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::table, sol::lib::coroutine);
lua.script(
R"(
unpack = unpack or table.unpack
function loop()
local i = 0
while true do
print("pre-yield in loop")
coroutine.yield(i)
print("post-yield in loop")
i = i+1
end
end
loop_th = coroutine.create(loop)
loop_res = function(...)
returns = { coroutine.resume(loop_th, ...) }
return unpack(returns, 2)
end
)"
);
// Resume from lua via thread and coroutine
sol::thread runner_thread = lua["loop_th"];
sol::state_view runner_thread_state = runner_thread.state();
auto test_resume = [&runner_thread, &runner_thread_state]() {
sol::coroutine cr = runner_thread_state["loop"];
sol::stack::push(runner_thread_state, 50);
sol::stack::push(runner_thread_state, 25);
int r = cr();
return r;
};
lua.set_function("test_resume", std::ref(test_resume));
// Resume via getting a sol::function from the state
sol::function test_resume_lua = lua["loop_res"];
// Resume via passing a sol::function object
auto test_resume_func = [](sol::function f) {
int r = f();
return r;
};
lua.set_function("test_resume_func", std::ref(test_resume_func));
int v0 = test_resume();
int s0 = runner_thread_state.stack_top();
int v1 = test_resume();
int s1 = runner_thread_state.stack_top();
int v2 = lua.script("return test_resume()");
int s2 = runner_thread_state.stack_top();
int v3 = lua.script("return test_resume()");
int s3 = runner_thread_state.stack_top();
int v4 = test_resume_lua();
int s4 = runner_thread_state.stack_top();
int v5 = lua.script("return test_resume_func(loop_res)");
int s5 = runner_thread_state.stack_top();
REQUIRE(v0 == 0);
REQUIRE(v1 == 1);
REQUIRE(v2 == 2);
REQUIRE(v3 == 3);
REQUIRE(v4 == 4);
REQUIRE(v5 == 5);
REQUIRE(s0 == 0);
REQUIRE(s1 == 0);
REQUIRE(s2 == 0);
REQUIRE(s3 == 0);
REQUIRE(s4 == 0);
REQUIRE(s5 == 0);
}

View File

@ -128,28 +128,40 @@ TEST_CASE("functions/overload resolution", "Check if overloaded function resolut
lua.open_libraries(sol::lib::base);
lua.set_function("non_overloaded", non_overloaded);
REQUIRE_NOTHROW(lua.safe_script("x = non_overloaded(1, 2, 3)\nprint(x)"));
{
auto result = lua.safe_script("x = non_overloaded(1, 2, 3)\nprint(x)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
/*
// Cannot reasonably support: clang++ refuses to try enough
// deductions to make this work
lua.set_function<int>("overloaded", overloaded);
REQUIRE_NOTHROW(lua.safe_script("print(overloaded(1))"));
{ auto result = lua.safe_script("print(overloaded(1))", sol::script_pass_on_error); REQUIRE(result.valid()); }
lua.set_function<int, int>("overloaded", overloaded);
REQUIRE_NOTHROW(lua.safe_script("print(overloaded(1, 2))"));
{ auto result = lua.safe_script("print(overloaded(1, 2))", sol::script_pass_on_error); REQUIRE(result.valid()); }
lua.set_function<int, int, int>("overloaded", overloaded);
REQUIRE_NOTHROW(lua.safe_script("print(overloaded(1, 2, 3))"));
{ auto result = lua.safe_script("print(overloaded(1, 2, 3))", sol::script_pass_on_error); REQUIRE(result.valid()); }
*/
lua.set_function("overloaded", sol::resolve<int(int)>(overloaded));
REQUIRE_NOTHROW(lua.safe_script("print(overloaded(1))"));
{
auto result = lua.safe_script("print(overloaded(1))", sol::script_pass_on_error);
REQUIRE(result.valid());
}
lua.set_function("overloaded", sol::resolve<int(int, int)>(overloaded));
REQUIRE_NOTHROW(lua.safe_script("print(overloaded(1, 2))"));
{
auto result = lua.safe_script("print(overloaded(1, 2))", sol::script_pass_on_error);
REQUIRE(result.valid());
}
lua.set_function("overloaded", sol::resolve<int(int, int, int)>(overloaded));
REQUIRE_NOTHROW(lua.safe_script("print(overloaded(1, 2, 3))"));
{
auto result = lua.safe_script("print(overloaded(1, 2, 3))", sol::script_pass_on_error);
REQUIRE(result.valid());
}
}
TEST_CASE("functions/return order and multi get", "Check if return order is in the same reading order specified in Lua") {
@ -269,13 +281,16 @@ TEST_CASE("functions/sol::function to std::function", "check if conversion to st
lua.set_function("testFunc2", test_free_func2);
lua.safe_script(
"testFunc(function() print(\"hello std::function\") end)");
REQUIRE_NOTHROW(lua.safe_script(
"function m(a)\n"
" print(\"hello std::function with arg \", a)\n"
" return a\n"
"end\n"
"\n"
"testFunc2(m, 1)"));
{
auto result = lua.safe_script(
"function m(a)\n"
" print(\"hello std::function with arg \", a)\n"
" return a\n"
"end\n"
"\n"
"testFunc2(m, 1)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
}
TEST_CASE("functions/returning functions from C++", "check to see if returning a functor and getting a functor from lua is possible") {
@ -284,10 +299,13 @@ TEST_CASE("functions/returning functions from C++", "check to see if returning a
lua.set_function("makefn", makefn);
lua.set_function("takefn", takefn);
lua.safe_script(
"afx = makefn()\n"
"print(afx())\n"
"takefn(afx)\n");
{
auto result = lua.safe_script(
"afx = makefn()\n"
"print(afx())\n"
"takefn(afx)\n");
REQUIRE(result.valid());
}
}
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") {
@ -597,9 +615,15 @@ N = n(1, 2, 3)
TEST_CASE("simple/call with parameters", "Lua function is called with a few parameters from C++") {
sol::state lua;
REQUIRE_NOTHROW(lua.safe_script("function my_add(i, j, k) return i + j + k end"));
{
auto result = lua.safe_script("function my_add(i, j, k) return i + j + k end", sol::script_pass_on_error);
REQUIRE(result.valid());
}
auto f = lua.get<sol::function>("my_add");
REQUIRE_NOTHROW(lua.safe_script("function my_nothing(i, j, k) end"));
{
auto result = lua.safe_script("function my_nothing(i, j, k) end", sol::script_pass_on_error);
REQUIRE(result.valid());
}
auto fvoid = lua.get<sol::function>("my_nothing");
REQUIRE_NOTHROW([&]() {
fvoid(1, 2, 3);
@ -766,18 +790,23 @@ TEST_CASE("functions/overloading", "Check if overloading works properly for regu
const std::string string_bark = "string: bark";
REQUIRE_NOTHROW(lua.safe_script(
"a = func(1)\n"
"b = func('bark')\n"
"c = func(1,2)\n"
"func(1,2,3)\n"));
{
auto result = lua.safe_script(
"a = func(1)\n"
"b = func('bark')\n"
"c = func(1,2)\n"
"func(1,2,3)\n", sol::script_pass_on_error);
REQUIRE(result.valid());
}
REQUIRE((lua["a"] == 1));
REQUIRE((lua["b"] == string_bark));
REQUIRE((lua["c"] == 2));
auto result = lua.safe_script("func(1,2,'meow')", sol::script_pass_on_error);
REQUIRE_FALSE(result.valid());
{
auto result = lua.safe_script("func(1,2,'meow')", sol::script_pass_on_error);
REQUIRE_FALSE(result.valid());
}
}
TEST_CASE("overloading/c_call", "Make sure that overloading works with c_call functionality") {
@ -1016,17 +1045,44 @@ TEST_CASE("functions/set_function already wrapped", "setting a function returned
lua.set_function("test2", pfn);
lua.set_function("test3", sfn);
REQUIRE_NOTHROW(lua.safe_script("assert(type(test) == 'function')"));
REQUIRE_NOTHROW(lua.safe_script("assert(test() ~= nil)"));
REQUIRE_NOTHROW(lua.safe_script("assert(test() == 5)"));
{
auto result = lua.safe_script("assert(type(test) == 'function')", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("assert(test() ~= nil)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("assert(test() == 5)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
REQUIRE_NOTHROW(lua.safe_script("assert(type(test2) == 'function')"));
REQUIRE_NOTHROW(lua.safe_script("assert(test2() ~= nil)"));
REQUIRE_NOTHROW(lua.safe_script("assert(test2() == 5)"));
{
auto result = lua.safe_script("assert(type(test2) == 'function')", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("assert(test2() ~= nil)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("assert(test2() == 5)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
REQUIRE_NOTHROW(lua.safe_script("assert(type(test3) == 'function')"));
REQUIRE_NOTHROW(lua.safe_script("assert(test3() ~= nil)"));
REQUIRE_NOTHROW(lua.safe_script("assert(test3() == 5)"));
{
auto result = lua.safe_script("assert(type(test3) == 'function')", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("assert(test3() ~= nil)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("assert(test3() == 5)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
}
SECTION("getting the value from C++") {
@ -1045,9 +1101,18 @@ TEST_CASE("functions/set_function already wrapped", "setting a function returned
lua.set_function("test", fn);
REQUIRE_NOTHROW(lua.safe_script("assert(type(test) == 'function')"));
REQUIRE_NOTHROW(lua.safe_script("assert(test() ~= nil)"));
REQUIRE_NOTHROW(lua.safe_script("assert(test() == 5)"));
{
auto result = lua.safe_script("assert(type(test) == 'function')", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("assert(test() ~= nil)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("assert(test() == 5)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
}
SECTION("does the function actually get executed?") {
@ -1057,8 +1122,14 @@ TEST_CASE("functions/set_function already wrapped", "setting a function returned
sol::function fn2 = lua.safe_script("return function() print('this was executed') end");
lua.set_function("test", fn2);
REQUIRE_NOTHROW(lua.safe_script("assert(type(test) == 'function')"));
REQUIRE_NOTHROW(lua.safe_script("test()"));
{
auto result = lua.safe_script("assert(type(test) == 'function')", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("test()", sol::script_pass_on_error);
REQUIRE(result.valid());
}
}
SECTION("setting the function indirectly, with the return value cast explicitly") {
@ -1068,9 +1139,18 @@ TEST_CASE("functions/set_function already wrapped", "setting a function returned
lua.set_function("test", [&fn]() { return fn.call<int>(); });
REQUIRE_NOTHROW(lua.safe_script("assert(type(test) == 'function')"));
REQUIRE_NOTHROW(lua.safe_script("assert(test() ~= nil)"));
REQUIRE_NOTHROW(lua.safe_script("assert(test() == 5)"));
{
auto result = lua.safe_script("assert(type(test) == 'function')", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("assert(test() ~= nil)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("assert(test() == 5)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
}
}
@ -1293,18 +1373,46 @@ TEST_CASE("functions/unique_usertype overloading", "make sure overloading can wo
lua["v3"] = test(17);
lua["v4"] = ut.get();
REQUIRE_NOTHROW([&]() {
lua.safe_script("f(v1)");
lua.safe_script("g(v1)");
lua.safe_script("g(v2)");
lua.safe_script("g(v3)");
lua.safe_script("g(v4)");
lua.safe_script("h(v1)");
lua.safe_script("h(v2)");
lua.safe_script("h(v3)");
lua.safe_script("h(v4)");
lua.safe_script("i(20, v1)");
}());
{
auto result = lua.safe_script("f(v1)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("g(v1)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("g(v2)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("g(v3)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("g(v4)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("h(v1)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("h(v2)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("h(v3)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("h(v4)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("i(20, v1)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
};
// LuaJIT segfaults hard on some Linux machines
// and it breaks all the tests...

View File

@ -507,10 +507,16 @@ TEST_CASE("simple_usertype/call constructor", "ensure that all kinds of call-bas
lua.safe_script("things = {thing.new(), thing.new()}");
SECTION("new") {
REQUIRE_NOTHROW(lua.safe_script("a = v_test.new(things)"));
{
auto result = lua.safe_script("a = v_test.new(things)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
}
SECTION("call_constructor") {
REQUIRE_NOTHROW(lua.safe_script("b = v_test(things)"));
{
auto result = lua.safe_script("b = v_test(things)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
}
}
@ -545,7 +551,10 @@ TEST_CASE("simple_usertype/missing key", "make sure a missing key returns nil")
lua.open_libraries(sol::lib::base);
lua.new_simple_usertype<thing>("thing");
REQUIRE_NOTHROW(lua.safe_script("print(thing.missingKey)"));
{
auto result = lua.safe_script("print(thing.missingKey)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
}
TEST_CASE("simple_usertype/runtime extensibility", "Check if usertypes are runtime extensible") {

View File

@ -333,7 +333,10 @@ TEST_CASE("tables/variables", "Check if tables and variables work as intended")
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::os);
lua.get<sol::table>("os").set("name", "windows");
REQUIRE_NOTHROW(lua.safe_script("assert(os.name == \"windows\")"));
{
auto result = lua.safe_script("assert(os.name == \"windows\")", sol::script_pass_on_error);
REQUIRE(result.valid());
}
}
TEST_CASE("tables/create", "Check if creating a table is kosher") {
@ -453,7 +456,10 @@ TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works
// function setting
lua["test"] = plop_xyz;
REQUIRE_NOTHROW(lua.safe_script("assert(test(10, 11, \"hello\") == 11)"));
{
auto result = lua.safe_script("assert(test(10, 11, \"hello\") == 11)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
// function retrieval
sol::function test = lua["test"];
@ -464,7 +470,10 @@ TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works
return x * 2;
};
REQUIRE_NOTHROW(lua.safe_script("assert(lamb(220) == 440)"));
{
auto result = lua.safe_script("assert(lamb(220) == 440)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
// function retrieval of a lambda
sol::function lamb = lua["lamb"];

View File

@ -388,7 +388,10 @@ TEST_CASE("usertype/usertype-utility-derived", "usertype classes must play nice
lua.set_usertype(baseusertype);
lua.safe_script("base = Base.new(5)");
REQUIRE_NOTHROW(lua.safe_script("print(base:get_num())"));
{
auto result = lua.safe_script("print(base:get_num())", sol::script_pass_on_error);
REQUIRE(result.valid());
}
sol::constructors<sol::types<int>> derivedctor;
sol::usertype<Derived> derivedusertype(derivedctor,
@ -449,16 +452,46 @@ TEST_CASE("usertype/issue-number-twenty-five", "Using pointers and references fr
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_usertype<test>("test", "set", &test::set, "get", &test::get, "pointer_get", &test::pget, "fun", &test::fun, "create_get", &test::create_get);
REQUIRE_NOTHROW(lua.safe_script("x = test.new()"));
REQUIRE_NOTHROW(lua.safe_script("assert(x:set():get() == 10)"));
REQUIRE_NOTHROW(lua.safe_script("y = x:pointer_get()"));
REQUIRE_NOTHROW(lua.safe_script("y:set():get()"));
REQUIRE_NOTHROW(lua.safe_script("y:fun(10)"));
REQUIRE_NOTHROW(lua.safe_script("x:fun(10)"));
REQUIRE_NOTHROW(lua.safe_script("assert(y:fun(10) == x:fun(10), '...')"));
REQUIRE_NOTHROW(lua.safe_script("assert(y:fun(10) == 100, '...')"));
REQUIRE_NOTHROW(lua.safe_script("assert(y:set():get() == y:set():get(), '...')"));
REQUIRE_NOTHROW(lua.safe_script("assert(y:set():get() == 10, '...')"));
{
auto result = lua.safe_script("x = test.new()", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("assert(x:set():get() == 10)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("y = x:pointer_get()", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("y:set():get()", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("y:fun(10)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("x:fun(10)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("assert(y:fun(10) == x:fun(10), '...')", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("assert(y:fun(10) == 100, '...')", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("assert(y:set():get() == y:set():get(), '...')", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("assert(y:set():get() == 10, '...')", sol::script_pass_on_error);
REQUIRE(result.valid());
}
}
TEST_CASE("usertype/issue-number-thirty-five", "using value types created from lua-called C++ code, fixing user-defined types with constructors") {
@ -541,8 +574,14 @@ TEST_CASE("usertype/member-variables", "allow table-like accessors to behave as
"f", &breaks::f);
breaks& b = lua["b"];
REQUIRE_NOTHROW(lua.safe_script("b.f = function () print('BARK!') end"));
REQUIRE_NOTHROW(lua.safe_script("b.f()"));
{
auto result = lua.safe_script("b.f = function () print('BARK!') end", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("b.f()", sol::script_pass_on_error);
REQUIRE(result.valid());
}
REQUIRE_NOTHROW(b.f());
}
@ -559,12 +598,18 @@ TEST_CASE("usertype/nonmember-functions", "let users set non-member functions th
.get<sol::table>("giver")
.set_function("stuff", giver::stuff);
REQUIRE_NOTHROW(lua.safe_script("giver.stuff()"));
REQUIRE_NOTHROW(lua.safe_script(
"t = giver.new()\n"
"print(tostring(t))\n"
"t:gief()\n"
"t:gief_stuff(20)\n"));
{
auto result = lua.safe_script("giver.stuff()", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script(
"t = giver.new()\n"
"print(tostring(t))\n"
"t:gief()\n"
"t:gief_stuff(20)\n");
REQUIRE(result.valid());
}
giver& g = lua.get<giver>("t");
REQUIRE(g.a == 20);
}
@ -653,7 +698,10 @@ TEST_CASE("usertype/private-constructible", "Check to make sure special snowflak
std::unique_ptr<factory_test, factory_test::deleter> f = factory_test::make();
lua.set("true_a", factory_test::true_a, "f", f.get());
REQUIRE_NOTHROW(lua.safe_script("assert(f.a == true_a)"));
{
auto result = lua.safe_script("assert(f.a == true_a)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
REQUIRE_NOTHROW(lua.safe_script(
"local fresh_f = factory_test:new()\n"
@ -841,8 +889,14 @@ TEST_CASE("usertype/readonly-and-static-functions", "Check if static functions c
"oh_boy", sol::overload(sol::resolve<void()>(&bark::oh_boy), sol::resolve<int(std::string)>(&bark::oh_boy)),
sol::meta_function::call_function, &bark::operator());
REQUIRE_NOTHROW(lua.safe_script("assert(bark.oh_boy('woo') == 3)"));
REQUIRE_NOTHROW(lua.safe_script("bark.oh_boy()"));
{
auto result = lua.safe_script("assert(bark.oh_boy('woo') == 3)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("bark.oh_boy()", sol::script_pass_on_error);
REQUIRE(result.valid());
}
bark b;
lua.set("b", &b);
@ -1490,7 +1544,10 @@ TEST_CASE("usertype/missing-key", "make sure a missing key returns nil") {
lua.open_libraries(sol::lib::base);
lua.new_usertype<thing>("thing");
REQUIRE_NOTHROW(lua.safe_script("v = thing.missingKey\nprint(v)"));
{
auto result = lua.safe_script("v = thing.missingKey\nprint(v)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
sol::object o = lua["v"];
bool isnil = o.is<sol::lua_nil_t>();
REQUIRE(isnil);

View File

@ -47,10 +47,18 @@ TEST_CASE("variadics/required with variadic_args", "Check if a certain number of
lua.set_function("v",
[](sol::this_state, sol::variadic_args, int, int) {
});
REQUIRE_NOTHROW(lua.safe_script("v(20, 25, 30)"));
REQUIRE_NOTHROW(lua.safe_script("v(20, 25)"));
auto result = lua.safe_script("v(20)", sol::script_pass_on_error);
REQUIRE_FALSE(result.valid());
{
auto result = lua.safe_script("v(20, 25, 30)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("v(20, 25)", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("v(20)", sol::script_pass_on_error);
REQUIRE_FALSE(result.valid());
}
}
TEST_CASE("variadics/variadic_args get type", "Make sure we can inspect types proper from variadic_args") {

View File

@ -84,21 +84,33 @@ TEST_CASE("simple/set", "Check if the set works properly.") {
lua.set("a", 9);
}
REQUIRE(begintop == endtop);
REQUIRE_NOTHROW(lua.safe_script("if a ~= 9 then error('wrong value') end"));
{
auto result = lua.safe_script("if a ~= 9 then error('wrong value') end", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
test_stack_guard g(lua.lua_state(), begintop, endtop);
lua.set("d", "hello");
}
REQUIRE(begintop == endtop);
REQUIRE_NOTHROW(lua.safe_script("if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end"));
{
auto result = lua.safe_script("if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
test_stack_guard g(lua.lua_state(), begintop, endtop);
lua.set("e", std::string("hello"), "f", true);
}
REQUIRE(begintop == endtop);
REQUIRE_NOTHROW(lua.safe_script("if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end"));
REQUIRE_NOTHROW(lua.safe_script("if f ~= true then error('wrong value') end"));
{
auto result = lua.safe_script("if d ~= 'hello' then error('expected \\'hello\\', got '.. tostring(d)) end", sol::script_pass_on_error);
REQUIRE(result.valid());
}
{
auto result = lua.safe_script("if f ~= true then error('wrong value') end", sol::script_pass_on_error);
REQUIRE(result.valid());
}
}
TEST_CASE("simple/get", "Tests if the get function works properly.") {
@ -564,9 +576,9 @@ TEST_CASE("proxy/equality", "check to make sure equality tests work") {
lua["a"] = 2;
REQUIRE_FALSE((lua["a"] == sol::lua_nil)); //0
REQUIRE_FALSE((lua["a"] == nullptr)); //0
REQUIRE_FALSE((lua["a"] == 0)); //0
REQUIRE((lua["a"] == 2)); //1
REQUIRE_FALSE((lua["a"] == nullptr)); //0
REQUIRE_FALSE((lua["a"] == 0)); //0
REQUIRE((lua["a"] == 2)); //1
}
TEST_CASE("compilation/const regression", "make sure constness in tables is respected all the way down") {
@ -615,7 +627,10 @@ TEST_CASE("object/is", "test whether or not the is abstraction works properly fo
lua.open_libraries(sol::lib::base);
lua.set_function("is_thing", [](sol::stack_object obj) { return obj.is<thing>(); });
lua["a"] = thing{};
REQUIRE_NOTHROW(lua.safe_script("assert(is_thing(a))"));
{
auto result = lua.safe_script("assert(is_thing(a))", sol::script_pass_on_error);
REQUIRE(result.valid());
}
}
SECTION("object") {
@ -623,6 +638,9 @@ TEST_CASE("object/is", "test whether or not the is abstraction works properly fo
lua.open_libraries(sol::lib::base);
lua.set_function("is_thing", [](sol::object obj) { return obj.is<thing>(); });
lua["a"] = thing{};
REQUIRE_NOTHROW(lua.safe_script("assert(is_thing(a))"));
{
auto result = lua.safe_script("assert(is_thing(a))", sol::script_pass_on_error);
REQUIRE(result.valid());
}
}
}